Zeichnen Sie die Verwendung von Injektion auf, um Erweiterungsfunktionen für den Unity-Editor zu erreichen

Szenen, die verwendet werden sollen

  1. Es ist umständlich, Erweiterungscode im aktuellen Projekteditor zu speichern oder zu übermitteln
  2. Die gleiche erweiterte Funktionalität muss in mehreren Projekten (Editoren) verwendet werden.
  3. Während der Projektentwicklung muss gelegentlich eine Funktion vorübergehend verwendet werden. Wenn Sie sie jederzeit verwenden möchten, können Sie sie jederzeit deinstallieren

Designideen

  1. Fügen Sie mithilfe der Prozessinjektion c/c++ dlleine in den aktuell ausgeführten Unity-Editor ein
  2. Verwenden Sie die aufgerufene Funktionsschnittstelle, um beispielsweise die Dynamik von Unity c/c++ dllzu erhalten und die externe Erweiterung zu laden, die Sie laden möchtenmonomono_get_root_domaindomainc# dll
  3. Wird in der Erweiterung c# dllaufgerufen EditorUtility.RequestScriptReload();, um die Neukompilierung des Unity-Editors auszulösen, wodurch die Implementierung im Editor überlastet wird, domainum externe c# dllFunktionen zu entladen
  4. c# dllBinden Sie Ereignisse in Erweiterungen EditorApplication.update, um Vorgänge im Hauptthread abzuwickeln, zAssetDatabase.Refresh();
  5. Mithilfe des Protokolls wird ein Teil der Kapselungsfunktion jsonrpcaufgerufen , mit dem das Erweiterungsfenster direkt im Unity-Editor angezeigt oder die Daten zur Anzeige an andere Editoren übertragen werden könnenc# dll

Erstimplementierung

  1. Prozessinjektionc/c++ dll
//远程进程插入dll bypid
bool DllInject::nsertDllToProcessByPid(DWORD Pid, const char* pDllName)
{
    
    
	// 提升权限
	//ImproveProcessPri();

	// 获取要插入的进程ID
	DWORD dwIDExplorer = Pid;
	if (dwIDExplorer == 0)
	{
    
    
		MEMBOX("Get Pro ID Error!\n");
		return false;
	}

	// 打开进程
	HANDLE hProcess = OpenProcess(/*PROCESS_ALL_ACCESS*/0x1F0FFF, FALSE, dwIDExplorer);
	if (hProcess == NULL)
	{
    
    
		MEMBOX("Open Process Error!\n");
		return false;
	}

	// 分配空间
	void* pDllPath = VirtualAllocEx(hProcess, 0, strlen(pDllName) + 1, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (!pDllPath)
	{
    
    
		MEMBOX("pRemoteThread = NULL!\n");
		return false;
	}
	if (!WriteProcessMemory(hProcess, pDllPath, pDllName, strlen(pDllName) + 1, 0))
	{
    
    
		MEMBOX("WriteProcessMemory Fail!\n");
		return false;
	}



	//看有Game.exe 是否打开   .   打开了  GetProcAddress 是不准的  

	/*
	   1. 检测静态 变量是否存储
	   2.

	*/
	

	//卸载保护
	HMODULE h = GetModuleHandle("MessageHis.dat");
	if (h != NULL)
		FreeLibrary(h);


	PROC AdrMyDllDir = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");//(PROC)::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")),"LoadLibraryA");

	// 创建远程线程
	HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)AdrMyDllDir, pDllPath, 0, 0);
	if (!hThread)
	{
    
    
		MEMBOX("Remote thread faile.");
		//AfxMessageBox("远程线程创建失败");
		return false;
	}
	WaitForSingleObject(hThread, INFINITE); //等待运行完成
	CloseHandle(hThread);//这个CloseHandle是不会关掉远程线程的,TerminateThread能关掉
	VirtualFreeEx(hProcess, pDllPath, strlen(pDllName) + 1, MEM_RELEASE);
	CloseHandle(hProcess);
	MEMBOX("Remote Inject Dll Success");

	//AfxMessageBox("注入成功");
	return true;
}
  1. Aufrufschnittstelle monowird geladenc# dll
bool MonoInjecter::InjectMonoAssembly()
{
    
    
    //GetProcAddress
    /* grab the root domain */
   // domain = fnGetRootDomain();
   // fnThreadAttach(domain);

    log_trace("Hello %s %s", "fnGeDomainFriendlyName", fnGeDomainFriendlyName(domain));
    log_trace("Hello %s %s", "fnGetRootDir", fnGetRootDir());

    //----------------------------
    domain = fnGetDomainById(1);
    log_trace("Hello %s %ld", "fnGetRootDomain", domain);
    fnThreadAttach(domain);

    log_trace("Hello %s %s", "fnGeDomainFriendlyName", fnGeDomainFriendlyName(domain));
    log_trace("Hello %s %s", "fnGetRootDir", fnGetRootDir());
    //----------------------------

    /* open payload assembly */
    std::string assemblyDir;
    /* Grab our root directory*/
    assemblyDir.append(fnGetRootDir());
    assemblyDir.append(ASSEMBLY_PATH);
    assembly = fnAssemblyOpen(assemblyDir.c_str(), NULL);
    if (assembly == NULL) return false;
    log_trace("Hello %s %ld", "fnAssemblyOpen", assembly);
    image = fnAssemblyGetImage(assembly);
    if (image == NULL) return false;
    log_trace("Hello %s %ld", "fnAssemblyGetImage", image);
    klass = fnClassFromName(image, PAYLOAD_NAMESPACE, PAYLOAD_CLASS);
    if (klass == NULL) return false;
    log_trace("Hello %s %ld", "fnClassFromName", klass);
    /* grab the hack entrypoint */
    method = fnMethodFromName(klass, PAYLOAD_MAIN, 0);
    if (method == NULL) return false;
    log_trace("Hello %s %ld", "fnMethodFromName", method);
    /* call our entrypoint */
    fnRuntimeInvoke(method, NULL, NULL, NULL);
    log_trace("\nHello %s", "run mono dll!\n\n");

    return true;
}
  1. Implementieren Sie einfach ein Editor-Tool, um den aktuell geöffneten Unity-Editor-Prozess zu finden, und fügen Sie ihn dann ein
    Fügen Sie hier eine Bildbeschreibung ein
  2. Die Testausgabe des injizierten c# dllAufrufs zeigt, dass im aktuellen Editor kein Code vorhanden ist
    Fügen Sie hier eine Bildbeschreibung ein

Test Umgebung

  1. Betriebssystem: Windows 11 64-Bit, (nicht kompatibel mit 32-Bit)
  2. Unity-Version: 2021.3.15f1
  3. .NET6.0(Implementierung von Dritteditoren)

おすすめ

転載: blog.csdn.net/qq992817263/article/details/131645576