Registre el uso de inyección para lograr capacidades de extensión para el editor de Unity

Escenas a utilizar

  1. Es un inconveniente almacenar o enviar el código de extensión en el editor de proyectos actual
  2. La misma funcionalidad extendida debe usarse en múltiples proyectos (editores)
  3. Durante el desarrollo del proyecto, ocasionalmente se necesita usar una función temporalmente, y si desea usarla en cualquier momento, puede desinstalarla en cualquier momento.

Ideas de diseño

  1. Usando la inyección de proceso, c/c++ dllinyecte uno en el editor de Unity que se está ejecutando actualmente
  2. Use la interfaz de función llamada, como para c/c++ dllobtener la dinámica de la unidad para cargar la extensión externa que desea cargarmonomono_get_root_domaindomainc# dll
  3. c# dllLlamado en la extensión EditorUtility.RequestScriptReload();para desencadenar la recompilación del editor de Unity, sobrecargando la implementación en el editor para descargar funciones domainexternasc# dll
  4. c# dllEnlace eventos en extensiones EditorApplication.updatepara manejar operaciones en el subproceso principal, comoAssetDatabase.Refresh();
  5. Usando jsonrpcel protocolo, se usa para llamar c# dlla parte de la función de encapsulación, que puede mostrar directamente la ventana de extensión en el editor de Unity, o transferir los datos a otros editores para su visualización.

implementación inicial

  1. inyección de procesoc/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. monocarga de la interfaz de llamadasc# 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. Simplemente implemente una herramienta de edición para encontrar el proceso de edición de Unity actualmente abierto y luego inyéctelo.
    inserte la descripción de la imagen aquí
  2. La salida de prueba por la c# dllllamada inyectada, no hay código en el editor actual
    inserte la descripción de la imagen aquí

entorno de prueba

  1. Sistema operativo: windows 11 de 64 bits`, (no compatible con 32 bits)
  2. Versión de unidad: 2021.3.15f1
  3. .NET6.0(implementación de editores de terceros)

Supongo que te gusta

Origin blog.csdn.net/qq992817263/article/details/131645576
Recomendado
Clasificación