[Unity学习教程] 记载利用注入的方式为Unity编辑器实现扩展能力

[复制链接]
查看607 | 回复0 | 2023-8-23 12:06:20 | 显示全部楼层 |阅读模式 来自 中国北京
利用场景


  • 当前项目编辑器中不方便存放大概提交扩展代码
  • 雷同的扩展功能须要在多个项目(编辑器)中利用
  • 项目开辟中,偶尔暂时须要利用一个功能,想随时利用随时卸载
设计思绪


  • 利用进程注入,将一个c/c++ dll注入到当前运行的unity编辑器中
  • 利用c/c++ dll调用mono的函数接口,比如mono_get_root_domain去获取unity的domain动态去加载想要加载的外部的扩展c# dll
  • 在扩展c# dll中调用 EditorUtility.RequestScriptReload();来触发unity编辑器的重新编译,重载编辑器中的domain实现卸载外部c# dll的功能
  • 在扩展c# dll中绑定EditorApplication.update事件,用来处置处罚主线程的操纵,比如AssetDatabase.Refresh();
  • 利用jsonrpc协议,用来调用c# dll中的部分封装功能函数,可以实如今unity编辑器直接展示扩展窗口,大概将数据传至其他编辑器进行展示
开端实现


  • 进程注入c/c++ dll
  1. //远程进程插入dll bypid
  2. bool DllInject::nsertDllToProcessByPid(DWORD Pid, const char* pDllName)
  3. {
  4.         // 提升权限
  5.         //ImproveProcessPri();
  6.         // 获取要插入的进程ID
  7.         DWORD dwIDExplorer = Pid;
  8.         if (dwIDExplorer == 0)
  9.         {
  10.                 MEMBOX("Get Pro ID Error!\n");
  11.                 return false;
  12.         }
  13.         // 打开进程
  14.         HANDLE hProcess = OpenProcess(/*PROCESS_ALL_ACCESS*/0x1F0FFF, FALSE, dwIDExplorer);
  15.         if (hProcess == NULL)
  16.         {
  17.                 MEMBOX("Open Process Error!\n");
  18.                 return false;
  19.         }
  20.         // 分配空间
  21.         void* pDllPath = VirtualAllocEx(hProcess, 0, strlen(pDllName) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
  22.         if (!pDllPath)
  23.         {
  24.                 MEMBOX("pRemoteThread = NULL!\n");
  25.                 return false;
  26.         }
  27.         if (!WriteProcessMemory(hProcess, pDllPath, pDllName, strlen(pDllName) + 1, 0))
  28.         {
  29.                 MEMBOX("WriteProcessMemory Fail!\n");
  30.                 return false;
  31.         }
  32.         //看有Game.exe 是否打开   .   打开了  GetProcAddress 是不准的  
  33.         /*
  34.            1. 检测静态 变量是否存储
  35.            2.
  36.         */
  37.        
  38.         //卸载保护
  39.         HMODULE h = GetModuleHandle("MessageHis.dat");
  40.         if (h != NULL)
  41.                 FreeLibrary(h);
  42.         PROC AdrMyDllDir = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");//(PROC)::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")),"LoadLibraryA");
  43.         // 创建远程线程
  44.         HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)AdrMyDllDir, pDllPath, 0, 0);
  45.         if (!hThread)
  46.         {
  47.                 MEMBOX("Remote thread faile.");
  48.                 //AfxMessageBox("远程线程创建失败");
  49.                 return false;
  50.         }
  51.         WaitForSingleObject(hThread, INFINITE); //等待运行完成
  52.         CloseHandle(hThread);//这个CloseHandle是不会关掉远程线程的,TerminateThread能关掉
  53.         VirtualFreeEx(hProcess, pDllPath, strlen(pDllName) + 1, MEM_RELEASE);
  54.         CloseHandle(hProcess);
  55.         MEMBOX("Remote Inject Dll Success");
  56.         //AfxMessageBox("注入成功");
  57.         return true;
  58. }
复制代码

  • 调用mono接口加载c# dll
  1. bool MonoInjecter::InjectMonoAssembly()
  2. {
  3.     //GetProcAddress
  4.     /* grab the root domain */
  5.    // domain = fnGetRootDomain();
  6.    // fnThreadAttach(domain);
  7.     log_trace("Hello %s %s", "fnGeDomainFriendlyName", fnGeDomainFriendlyName(domain));
  8.     log_trace("Hello %s %s", "fnGetRootDir", fnGetRootDir());
  9.     //----------------------------
  10.     domain = fnGetDomainById(1);
  11.     log_trace("Hello %s %ld", "fnGetRootDomain", domain);
  12.     fnThreadAttach(domain);
  13.     log_trace("Hello %s %s", "fnGeDomainFriendlyName", fnGeDomainFriendlyName(domain));
  14.     log_trace("Hello %s %s", "fnGetRootDir", fnGetRootDir());
  15.     //----------------------------
  16.     /* open payload assembly */
  17.     std::string assemblyDir;
  18.     /* Grab our root directory*/
  19.     assemblyDir.append(fnGetRootDir());
  20.     assemblyDir.append(ASSEMBLY_PATH);
  21.     assembly = fnAssemblyOpen(assemblyDir.c_str(), NULL);
  22.     if (assembly == NULL) return false;
  23.     log_trace("Hello %s %ld", "fnAssemblyOpen", assembly);
  24.     image = fnAssemblyGetImage(assembly);
  25.     if (image == NULL) return false;
  26.     log_trace("Hello %s %ld", "fnAssemblyGetImage", image);
  27.     klass = fnClassFromName(image, PAYLOAD_NAMESPACE, PAYLOAD_CLASS);
  28.     if (klass == NULL) return false;
  29.     log_trace("Hello %s %ld", "fnClassFromName", klass);
  30.     /* grab the hack entrypoint */
  31.     method = fnMethodFromName(klass, PAYLOAD_MAIN, 0);
  32.     if (method == NULL) return false;
  33.     log_trace("Hello %s %ld", "fnMethodFromName", method);
  34.     /* call our entrypoint */
  35.     fnRuntimeInvoke(method, NULL, NULL, NULL);
  36.     log_trace("\nHello %s", "run mono dll!\n\n");
  37.     return true;
  38. }
复制代码

  • 简朴实现一个编辑器工具用来查找当前已经打开的unity编辑器进程,然后进行注入

  • 由注入的c# dll调用的测试输出, 当前编辑器中是没有任何代码的

测试情况


  • 操纵体系体系: windows 11 64位`, (不兼容32位)
  • unity版本: 2021.3.15f1
  • .NET6.0(第三方编辑器的实现)

来源:https://blog.csdn.net/qq992817263/article/details/131645576
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则