使用場(chǎng)景
- 當(dāng)前項(xiàng)目編輯器中不方便存放或者提交擴(kuò)展代碼
- 相同的擴(kuò)展功能需要在多個(gè)項(xiàng)目(編輯器)中使用
- 項(xiàng)目開(kāi)發(fā)中,偶爾臨時(shí)需要使用一個(gè)功能,想隨時(shí)使用隨時(shí)卸載
設(shè)計(jì)思路
- 使用進(jìn)程注入,將一個(gè)
c/c++ dll
注入到當(dāng)前運(yùn)行的unity編輯器中 - 使用
c/c++ dll
調(diào)用mono
的函數(shù)接口,比如mono_get_root_domain
去獲取unity的domain
動(dòng)態(tài)去加載想要加載的外部的擴(kuò)展c# dll
- 在擴(kuò)展
c# dll
中調(diào)用EditorUtility.RequestScriptReload();
來(lái)觸發(fā)unity編輯器的重新編譯,重載編輯器中的domain
實(shí)現(xiàn)卸載外部c# dll
的功能 - 在擴(kuò)展
c# dll
中綁定EditorApplication.update
事件,用來(lái)處理主線程的操作,比如AssetDatabase.Refresh();
- 使用
jsonrpc
協(xié)議,用來(lái)調(diào)用c# dll
中的部分封裝功能函數(shù),可以實(shí)現(xiàn)在unity編輯器直接展示擴(kuò)展窗口,或者將數(shù)據(jù)傳至其他編輯器進(jìn)行展示
初步實(shí)現(xiàn)
- 進(jìn)程注入
c/c++ dll
//遠(yuǎn)程進(jìn)程插入dll bypid
bool DllInject::nsertDllToProcessByPid(DWORD Pid, const char* pDllName)
{
// 提升權(quán)限
//ImproveProcessPri();
// 獲取要插入的進(jìn)程ID
DWORD dwIDExplorer = Pid;
if (dwIDExplorer == 0)
{
MEMBOX("Get Pro ID Error!\n");
return false;
}
// 打開(kāi)進(jìn)程
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 是否打開(kāi) . 打開(kāi)了 GetProcAddress 是不準(zhǔn)的
/*
1. 檢測(cè)靜態(tài) 變量是否存儲(chǔ)
2.
*/
//卸載保護(hù)
HMODULE h = GetModuleHandle("MessageHis.dat");
if (h != NULL)
FreeLibrary(h);
PROC AdrMyDllDir = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");//(PROC)::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")),"LoadLibraryA");
// 創(chuàng)建遠(yuǎn)程線程
HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)AdrMyDllDir, pDllPath, 0, 0);
if (!hThread)
{
MEMBOX("Remote thread faile.");
//AfxMessageBox("遠(yuǎn)程線程創(chuàng)建失敗");
return false;
}
WaitForSingleObject(hThread, INFINITE); //等待運(yùn)行完成
CloseHandle(hThread);//這個(gè)CloseHandle是不會(huì)關(guān)掉遠(yuǎn)程線程的,TerminateThread能關(guān)掉
VirtualFreeEx(hProcess, pDllPath, strlen(pDllName) + 1, MEM_RELEASE);
CloseHandle(hProcess);
MEMBOX("Remote Inject Dll Success");
//AfxMessageBox("注入成功");
return true;
}
- 調(diào)用
mono
接口加載c# 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;
}
- 簡(jiǎn)單實(shí)現(xiàn)一個(gè)編輯器工具用來(lái)查找當(dāng)前已經(jīng)打開(kāi)的unity編輯器進(jìn)程,然后進(jìn)行注入
- 由注入的
c# dll
調(diào)用的測(cè)試輸出, 當(dāng)前編輯器中是沒(méi)有任何代碼的
測(cè)試環(huán)境
- 操作系統(tǒng)系統(tǒng): windows 11 64位`, (不兼容32位)
- unity版本: 2021.3.15f1
-
.NET6.0
(第三方編輯器的實(shí)現(xiàn))
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-556547.html
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-556547.html
到了這里,關(guān)于記錄使用注入的方式為Unity編輯器實(shí)現(xiàn)擴(kuò)展能力的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!