Loading... # 一、模块隐藏 ```c++ class XHideDll { public: XHideDll(); ~XHideDll(); //static PVOID GetProcessPEB(); static void PrintModuleList(); static bool HideInLoadOrderLinks(unsigned long long dllBase); static bool HideInMemoryOrderLinks(unsigned long long dllBase); static bool HideInInitializationOrderLinks(unsigned long long dllBase); static void HideModule(unsigned long long hModule, bool DeleteAfter); static void LM_CreateFakeThread(unsigned __int64 Threadfunc, unsigned __int64 fakeAddr); }; ``` ```c++ #include "XHideDll.h" #include "ntdll/ntdll.h" #include <TlHelp32.h> #include <intrin.h> #include <tchar.h> #include <stdio.h> #include <stdarg.h> #ifndef _WIN64 #pragma comment(lib,"ntdll/ntdll_x86.lib") #else #pragma comment(lib,"ntdll/ntdll_x64.lib") #endif #include <psapi.h> //#include <winternl.h> #pragma comment(lib, "Psapi.lib") #ifdef _DEBUG #define DbgPrint(_x_) Print _x_ #else #define DbgPrint(_x_) #endif typedef LPVOID WINAPI VIRTUALALLOC( _In_opt_ LPVOID lpAddress, _In_ SIZE_T dwSize, _In_ DWORD flAllocationType, _In_ DWORD flProtect ); typedef void *MEMCPY( void *dest, const void *src, size_t count ); typedef bool UNLOADMODULE( HMODULE hModule, LPVOID lpNewBaseAddr, ULONG_PTR SizeOfImage ); typedef NTSTATUS WINAPI NTQUERYINFORMATIONPROCESS( _In_ HANDLE ProcessHandle, _In_ PROCESSINFOCLASS ProcessInformationClass, _Out_ PVOID ProcessInformation, _In_ ULONG ProcessInformationLength, _Out_opt_ PULONG ReturnLength ); typedef struct _LDR_MODULE { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; LIST_ENTRY HashTableEntry; ULONG TimeDateStamp; } LDR_MODULE, *PLDR_MODULE; //PsGetCurrentProcess(); void Print(const LPTSTR fmt, ...) { va_list args; va_start(args, fmt); int len = _vsctprintf(fmt, args); LPTSTR buffer = (LPTSTR)new TCHAR[len + 1]; _vsntprintf_s(buffer, len + 1, _TRUNCATE, fmt, args); va_end(args); OutputDebugString(buffer); delete[]buffer; } //bool IncModuleRefCount(HMODULE hModule) { // HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); // if (hSnapShot == INVALID_HANDLE_VALUE) { // DbgPrint((TEXT("CreateToolhelp32Snapshot failed, Error: %d\n"), GetLastError())); // return false; // } // // MODULEENTRY32 ModuleEntry = { 0 }; // ModuleEntry.dwSize = sizeof(MODULEENTRY32); // if (!Module32First(hSnapShot, &ModuleEntry)) { // DbgPrint((TEXT("Module32First failed, Error: %d\n"), GetLastError())); // CloseHandle(hSnapShot); // return false; // } // // do { // if (ModuleEntry.hModule != hModule) // LoadLibrary(ModuleEntry.szModule); // } while (Module32Next(hSnapShot, &ModuleEntry)); // // CloseHandle(hSnapShot); // return true; //} bool SetThreadsState(bool IsResume) { HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hSnapShot == INVALID_HANDLE_VALUE) { DbgPrint(((LPSTR)("CreateToolhelp32Snapshot failed, Error: %d\n"), GetLastError())); return false; } THREADENTRY32 ThreadEntry = { 0 }; ThreadEntry.dwSize = sizeof(ThreadEntry); DWORD ThreadId = GetCurrentThreadId(); DWORD ProcessId = GetCurrentProcessId(); if (!Thread32First(hSnapShot, &ThreadEntry)) { DbgPrint(((LPSTR)("Thread32First failed, Error: %d\n"), GetLastError())); CloseHandle(hSnapShot); return false; } do { if (ProcessId == ThreadEntry.th32OwnerProcessID && ThreadId != ThreadEntry.th32ThreadID) { HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, ThreadEntry.th32ThreadID); if (hThread != NULL) { if (IsResume) { ResumeThread(hThread); } else { SuspendThread(hThread); } CloseHandle(hThread); } } } while (Thread32Next(hSnapShot, &ThreadEntry)); CloseHandle(hSnapShot); return true; } void PrintModulesInformation() { NTQUERYINFORMATIONPROCESS *pfnNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS *)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationProcess"); if (pfnNtQueryInformationProcess != NULL) { PROCESS_BASIC_INFORMATION PBI = { 0 }; DWORD ReturnLength = 0; if (NT_SUCCESS(pfnNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &PBI, sizeof(PBI), &ReturnLength))) { PLDR_MODULE LdrModule = NULL; PLIST_ENTRY Head = PBI.PebBaseAddress->Ldr->InMemoryOrderModuleList.Flink; PLIST_ENTRY Current = Head; do { LdrModule = (PLDR_MODULE)CONTAINING_RECORD(Current, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); Print((LPSTR)("Name: %s, BaseAddress: %p, LoadCount: %d\n"), LdrModule->BaseDllName.Buffer, LdrModule->BaseAddress, LdrModule->LoadCount); Current = Current->Flink; } while (Current != Head); } } } void AdjustModuleReferenceCount(HMODULE hModule) { NTQUERYINFORMATIONPROCESS *pfnNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS *)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "NtQueryInformationProcess"); if (pfnNtQueryInformationProcess != NULL) { PROCESS_BASIC_INFORMATION PBI = { 0 }; DWORD ReturnLength = 0; if (NT_SUCCESS(pfnNtQueryInformationProcess(GetCurrentProcess(), ProcessBasicInformation, &PBI, sizeof(PBI), &ReturnLength))) { PLDR_MODULE LdrModule = NULL; PLIST_ENTRY Head = PBI.PebBaseAddress->Ldr->InMemoryOrderModuleList.Flink; PLIST_ENTRY Current = Head; do { LdrModule = (PLDR_MODULE)CONTAINING_RECORD(Current, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); // The LoadCount of DLLs that are static linked is -1, that kind of DLLs can't be freed // by FreeLibrary. So I modify that LoadCount to 1 in case that this DLL is static linked. if (LdrModule->BaseAddress == hModule) { // Add the reference count of DLLs that this module relies on LoadLibraryW(LdrModule->BaseDllName.Buffer); LdrModule->LoadCount = 1; break; } Current = Current->Flink; } while (Current != Head); } } } bool UnloadModule(HMODULE hModule, LPVOID lpNewBaseAddr, ULONG_PTR SizeOfImage) { LPVOID lpBaseOfDll = (LPVOID)hModule; MEMCPY *pfnMemCpy = (MEMCPY *)GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "memcpy"); VIRTUALALLOC *pfnVirtualAlloc = (VIRTUALALLOC *)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "VirtualAlloc"); bool ret = false; if (!FreeLibrary(hModule)) { DbgPrint(((LPSTR)("FreeLibrary for the module failed, Error: %d\n"), GetLastError())); } // After FreeLibrary, we can't use any functions whose addresses are not retrieved before. // And the strings are invalid also. LPVOID OriBaseAddr = pfnVirtualAlloc(lpBaseOfDll, SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (OriBaseAddr == NULL) { // DbgPrint((TEXT("pfnVirtualAlloc for OriBaseAddr failed, Error: %d\n"), GetLastError())); } else if (OriBaseAddr != lpBaseOfDll) { // DbgPrint((TEXT("OriBaseAddr is not equal to lpBaseOfDll\n"))); } else { pfnMemCpy(OriBaseAddr, lpNewBaseAddr, SizeOfImage); ret = true; } return ret; } XHideDll::XHideDll() { } XHideDll::~XHideDll() { } PVOID GetProcessPEB() { #ifdef _WIN64 return (PVOID)__readgsqword(0x60); #else return (PVOID)__readfsdword(0x30); #endif } bool XHideDll::HideInLoadOrderLinks(DWORD64 dllBase) { BOOL r = FALSE; PPEB peb = (PPEB)GetProcessPEB(); PLIST_ENTRY OrderModuleHead, OrderModuleTail; PLDR_DATA_TABLE_ENTRY pLdrDataEntry = NULL; OrderModuleHead = OrderModuleTail = peb->Ldr->InLoadOrderModuleList.Blink; do { pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(OrderModuleHead, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); if (pLdrDataEntry->DllBase == NULL) { break; } // _tprintf(_T("DLLBase:%p Size:%08X ShortName:%s FullName:%s\n\n"), pLdrDataEntry->DllBase, pLdrDataEntry->SizeOfImage, // pLdrDataEntry->BaseDllName.Buffer, pLdrDataEntry->FullDllName.Buffer); if (pLdrDataEntry->DllBase == (HMODULE)dllBase) { RemoveEntryList(OrderModuleHead); r = TRUE; } OrderModuleHead = OrderModuleHead->Blink; } while (OrderModuleHead != OrderModuleTail); // _tprintf(_T("--------------------------------------------------------------\n")); return r; } bool XHideDll::HideInMemoryOrderLinks(DWORD64 dllBase) { BOOL r = FALSE; PPEB peb = (PPEB)GetProcessPEB(); PLIST_ENTRY OrderModuleHead, OrderModuleTail; PLDR_DATA_TABLE_ENTRY pLdrDataEntry = NULL; OrderModuleHead = OrderModuleTail = peb->Ldr->InMemoryOrderModuleList.Blink; do { pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(OrderModuleHead, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); if (pLdrDataEntry->DllBase == NULL) { break; } // _tprintf(_T("DLLBase:%p Size:%08X ShortName:%s FullName:%s\n\n"), pLdrDataEntry->DllBase, pLdrDataEntry->SizeOfImage, // pLdrDataEntry->BaseDllName.Buffer, pLdrDataEntry->FullDllName.Buffer); if (pLdrDataEntry->DllBase == (HMODULE)dllBase) { RemoveEntryList(OrderModuleHead); r = TRUE; } OrderModuleHead = OrderModuleHead->Blink; } while (OrderModuleHead != OrderModuleTail); // _tprintf(_T("--------------------------------------------------------------\n")); return r; } bool XHideDll::HideInInitializationOrderLinks(DWORD64 dllBase) { bool r = FALSE; PPEB peb = (PPEB)GetProcessPEB(); PLIST_ENTRY OrderModuleHead, OrderModuleTail; PLDR_DATA_TABLE_ENTRY pLdrDataEntry = NULL; OrderModuleHead = OrderModuleTail = peb->Ldr->InInitializationOrderModuleList.Blink; do { pLdrDataEntry = (PLDR_DATA_TABLE_ENTRY)CONTAINING_RECORD(OrderModuleHead, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks); if (pLdrDataEntry->DllBase == NULL) { break; } // _tprintf(_T("DLLBase:%p Size:%08X ShortName:%s FullName:%s\n\n"), pLdrDataEntry->DllBase, pLdrDataEntry->SizeOfImage, // pLdrDataEntry->BaseDllName.Buffer, pLdrDataEntry->FullDllName.Buffer); if (pLdrDataEntry->DllBase == (HMODULE)dllBase) { RemoveEntryList(OrderModuleHead); r = TRUE; } OrderModuleHead = OrderModuleHead->Blink; } while (OrderModuleHead != OrderModuleTail); // //_tprintf(_T("--------------------------------------------------------------\n")); return r; } void XHideDll::PrintModuleList() { HANDLE hSnaphot; MODULEENTRY32 md32 = { 0 }; BOOL exist; md32.dwSize = sizeof(md32); hSnaphot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); exist = Module32First(hSnaphot, &md32); while (exist) { //_tprintf(_T("%s\n"), md32.szModule); exist = Module32Next(hSnaphot, &md32); } CloseHandle(hSnaphot); //_tprintf(_T("--------------------------------------------")); } void XHideDll::HideModule(unsigned long long hModule1, bool DeleteAfter) { MODULEINFO ModuleInfo = { 0 }; HMODULE hModule = (HMODULE)hModule1; if (!GetModuleInformation(GetCurrentProcess(), hModule, &ModuleInfo, sizeof(ModuleInfo))) { DbgPrint(((LPSTR)("GetModuleInformation0 failed, Error: %d\n"), GetLastError())); return; } LPVOID lpNewBaseAddr = VirtualAlloc(NULL, ModuleInfo.SizeOfImage, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (lpNewBaseAddr == NULL) { DbgPrint(((LPSTR)("VirtualAlloc for lpNewBaseAddr failed, Error: %d\n"), GetLastError())); return; } memcpy(lpNewBaseAddr, ModuleInfo.lpBaseOfDll, ModuleInfo.SizeOfImage); UNLOADMODULE *pfnUnloadModule = (UNLOADMODULE *)((ULONG_PTR)UnloadModule - (ULONG_PTR)ModuleInfo.lpBaseOfDll + (ULONG_PTR)lpNewBaseAddr); /*Print((LPSTR)("\n----------------------------------------------------------------------------\n")); Print((LPSTR)("Check the modules before adjusting the reference count of the loaded modules\n")); PrintModulesInformation();*/ AdjustModuleReferenceCount(hModule); /*Print((LPSTR)("\n---------------------------------------------------------------------------\n")); Print((LPSTR)("Check the modules after adjusting the reference count of the loaded modules\n")); PrintModulesInformation();*/ TCHAR FileName[MAX_PATH] = { 0 }; bool HasFileName = false; if (DeleteAfter) { if (!GetModuleFileName(hModule, FileName, _countof(FileName))) { DbgPrint(((LPSTR)("GetModuleFileName failed, Error: %d\n"), GetLastError())); } else { HasFileName = true; } } SetThreadsState(false); // Jump to the new space, and free the original dll in the new space if (!pfnUnloadModule(hModule, lpNewBaseAddr, ModuleInfo.SizeOfImage)) { DbgPrint(((LPSTR)("UnloadModule failed, Error: %d\n"), GetLastError())); } // Jump back to the original space SetThreadsState(true); //Print((LPSTR)("\n---------------------------------------------\n")); //Print((LPSTR)("Check the modules after FreeLibrary is called\n")); //PrintModulesInformation(); if (!VirtualFree(lpNewBaseAddr, 0, MEM_DECOMMIT)) { DbgPrint(((LPSTR)("VirtualFree for lpNewBaseAddr failed, Error: %d\n"), GetLastError())); } if (HasFileName) { if (!DeleteFile(FileName)) { DbgPrint(((LPSTR)("DeleteFile failed, Error: %d\n"), GetLastError())); } } } void XHideDll::LM_CreateFakeThread(unsigned __int64 Threadfunc, unsigned __int64 fakeAddr) { CONTEXT ctx; HANDLE tHand = CreateRemoteThread(GetCurrentProcess(), 0, 0, (LPTHREAD_START_ROUTINE)fakeAddr, 0, 0, 0); SuspendThread(tHand); ctx.ContextFlags = CONTEXT_INTEGER; GetThreadContext(tHand, &ctx); ctx.Rax = Threadfunc; ctx.ContextFlags = CONTEXT_INTEGER; SetThreadContext(tHand, &ctx); ResumeThread(tHand); } ``` # 二、utils工具函数 ```c++ #pragma once #include <string> #include <windows.h> namespace utils { void log(char* _format, ...);// void log(const char* _format, ...); template<class T> T read(const DWORD64& obj) { T value = { 0 }; __try { value = *(T*)(obj); } __except (1) { log("read ptr:%I64x error!", obj); } return value; } template<class T> bool write(const DWORD64& obj, T value) { __try { *(T*)(obj) = value; return true; } __except (1) { log("write ptr:%I64x error!", obj); return false; } } //ascii 文本转 utf-8文本 int mb2u8(const char* cont, char* lpsz); //utf-8文本转ascii文本 int u82mb(const char* cont, char* lpsz); //64位指针转文本 std::string ptr2str(DWORD64 ptr); void StrToHex(char* pbDest, char* pszSrc, int nLen); //十六进制转字符串 void HexToStr(char* pszDest,unsigned char* pbSrc, int nLen); //获取进程指定窗口句柄 HWND GetWindowHwndByPorcessID(DWORD dwProcessID, char* className, char* windowName); } ``` ```c++ #include "Utils.h" void utils::log(char* _format, ...) { #ifdef _DEBUG std::string temp; va_list marker = { 0 }; va_start(marker, _format); size_t num_of_chars = _vscprintf(_format, marker); if (num_of_chars > temp.capacity()) { temp.reserve(num_of_chars + 1); } vsprintf_s(const_cast<char*>(temp.c_str()), num_of_chars + 1, _format, marker); OutputDebugString(temp.c_str()); #endif } void utils::log(const char* _format, ...) { #ifdef _DEBUG std::string temp; va_list marker = { 0 }; va_start(marker, _format); size_t num_of_chars = _vscprintf(_format, marker); if (num_of_chars > temp.capacity()) { temp.reserve(num_of_chars + 1); } vsprintf_s(const_cast<char*>(temp.c_str()), num_of_chars + 1, _format, marker); OutputDebugString(temp.c_str()); #endif } int utils::mb2u8(const char* cont, char* lpsz) { if (NULL == cont || lpsz == NULL) { return 0; } int num = MultiByteToWideChar(CP_ACP, NULL, cont, -1, NULL, NULL); if (num <= 0) { return 0; } wchar_t* buffw = new (std::nothrow) wchar_t[num + 1]; if (NULL == buffw) { return 0; } MultiByteToWideChar(CP_ACP, NULL, cont, -1, buffw, num); int len = WideCharToMultiByte(CP_UTF8, 0, buffw, num - 1, NULL, NULL, NULL, NULL); if (len <= 0) { delete[] buffw; return 0; } //lpsz = new (std::nothrow) char[len + 1]; //ZeroMemory(lpsz, len + 1); if (NULL == lpsz) { delete[] buffw; return 0; } WideCharToMultiByte(CP_UTF8, 0, buffw, num - 1, lpsz, len, NULL, NULL); lpsz[len] = '\0'; delete[] buffw; return len + 1; } int utils::u82mb(const char* cont, char* lpsz) { int iLen = 0; if (NULL == cont || lpsz == nullptr) { return iLen; } int num = MultiByteToWideChar(CP_UTF8, NULL, cont, -1, NULL, NULL); if (num <= 0) { return iLen; } wchar_t* buffw = new (std::nothrow) wchar_t[num]; if (NULL == buffw) { return iLen; } MultiByteToWideChar(CP_UTF8, NULL, cont, -1, buffw, num); int len = WideCharToMultiByte(CP_ACP, 0, buffw, num - 1, NULL, NULL, NULL, NULL); if (len <= 0) { delete[] buffw; return iLen; } //char* lpsz = new (std::nothrow) char[len + 1]; if (NULL == lpsz) { delete[] buffw; return iLen; } ZeroMemory(lpsz, len + 1); WideCharToMultiByte(CP_ACP, 0, buffw, num - 1, lpsz, len, NULL, NULL); lpsz[len] = '\0'; delete[] buffw; /*std::string rtn(lpsz); delete[] lpsz;*/ return len; } std::string utils::ptr2str(DWORD64 ptr) { char tmp[256] = "\0"; sprintf_s(tmp, "%I64x", ptr); return std::string(tmp); } void utils::StrToHex(char* pbDest, char* pszSrc, int nLen) { char h1, h2; char s1, s2; for (int i = 0; i < nLen; i++) { h1 = pszSrc[2 * i]; h2 = pszSrc[2 * i + 1]; s1 = toupper(h1) - 0x30; if (s1 > 9) s1 -= 7; s2 = toupper(h2) - 0x30; if (s2 > 9) s2 -= 7; pbDest[i] = s1 * 16 + s2; } } void utils::HexToStr(char* pszDest, unsigned char* pbSrc, int nLen) { char ddl, ddh; for (int i = 0; i < nLen; i++) { ddh = 48 + pbSrc[i] / 16; ddl = 48 + pbSrc[i] % 16; if (ddh > 57) ddh = ddh + 7; if (ddl > 57) ddl = ddl + 7; pszDest[i * 3] = ddh; pszDest[i * 3 + 1] = ddl; pszDest[i * 3 + 2] = 0x20; } } HWND utils::GetWindowHwndByPorcessID(DWORD dwProcessID, char* className, char* windowName) { HWND tempH = NULL; do { tempH = ::FindWindowExA(NULL, tempH, className, windowName); DWORD pid; ::GetWindowThreadProcessId(tempH, &pid); if (pid == dwProcessID) { return tempH; } } while (tempH != NULL); return NULL; } ``` # 三、对象遍历 该游戏对象存储使用单链链表存储,因此,其遍历如下所示: ```c++ // TODO: 在此添加控件通知处理程序代码 auto ptr = utils::read<DWORD64>(g_ModuleHandle + offset::CurMgrPointer); std::string str = "ptr:" + utils::ptr2str(ptr)+"\r\n"; ptr = utils::read<DWORD64>(ptr + offset::FirstObject); int index = 0; while (ptr != 0 && ptr % 2 != 1 && index<500) { //auto objptr = ptr + offset::FirstObject; str += "obj:" + utils::ptr2str(ptr); auto type = utils::read<UINT8>(ptr + offset::ObjectType); str += "\ttype:" + std::to_string(type); DWORD64 namePtr = 0; if (type == 3) //unit { namePtr = utils::read<DWORD64>(ptr + offset::UnitName1); namePtr = utils::read<DWORD64>(namePtr + offset::UnitName2); float x=0.0, y = 0.0, z = 0.0, rotation = 0.0, pitch = 0.0; x = utils::read<float>(ptr + offset::UnitX); y = utils::read<float>(ptr + offset::UnitX+4); z = utils::read<float>(ptr + offset::UnitX+0x8); rotation = utils::read<float>(ptr + offset::UnitX+0x10); pitch = utils::read<float>(ptr + offset::UnitX+0x14); str += "\t" + std::to_string(x) + "," + std::to_string(y) + "," + std::to_string(z) + ":" + std::to_string(rotation) + "-" + std::to_string(pitch); } else if (type == 6) //Object { namePtr = utils::read<DWORD64>(ptr + offset::ObjectName1); namePtr = utils::read<DWORD64>(namePtr + offset::ObjectName2); float x = 0.0, y = 0.0, z = 0.0, rotation = 0.0, pitch = 0.0; x = utils::read<float>(ptr + offset::ObjectX); y = utils::read<float>(ptr + offset::ObjectX + 4); z = utils::read<float>(ptr + offset::ObjectX + 0x8); rotation = utils::read<float>(ptr + offset::ObjectX + 0x10); str +="\t"+ std::to_string(x) + "," + std::to_string(y) + "," + std::to_string(z) + ":" + std::to_string(rotation); } if (namePtr != 0) { char tmp[250] = ""; utils::u82mb((const char*)namePtr, tmp); str += "\t name:" + std::string(tmp) ; } else { str += "\t name:"; } //hp&lv auto descriptor = utils::read<DWORD64>(ptr + offset::UnitDescript); DWORD hp = 0, lv = 0; hp = utils::read<DWORD>(descriptor + offset::UnitHp); lv = utils::read<DWORD>(descriptor + offset::UnitLv); str += "\thp:" + std::to_string(hp) + "\tlv:"+std::to_string(lv); //localGUID char guid[64] = "\0"; utils::HexToStr(guid,(unsigned char*) (ptr + offset::LocalGUID), 16); str += "\tguid:" + std::string(guid) + "\r\n"; ptr = utils::read<DWORD64>(ptr + offset::NextObject); index++; } SetDlgItemText(IDC_EDIT1, str.c_str()); ``` 其对象类型枚举类如下: ```c++ enum ObjType : uint8_t { Object = 0, Item = 1, Container = 2, Unit = 3, Player = 4, ActivePlayer = 5, GameObject = 6, DynamicObject = 7, Corpse = 8, AreaTrigger = 9, SceneObject = 10, Conversation = 11, AIGroup = 12, Scenario = 13, Loot = 14, Invalid } ``` # 四、主线程调用 采用窗口子类化的方式实现,其他方式可参考:APC插入、dxd endscen hook、虚表hook等。 ```c++ //窗口子类化 g_oldProcFunc = GetWindowLongPtr(g_hwnd, -4); SetWindowLongPtrA(g_hwnd, -4, (LONG_PTR)MyCallBack);//如果需要安全卸载DLL,退出处需要将处理函数恢复。 LRESULT MyCallBack(HWND h, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case MSG_LUA_RUN: //Frame_ExcuteBuffer { break; } case MSG_PLAYER_RUN: //clickTo { break; } case MSG_LUA_RET: //Frame_GetText { break; } case MSG_LUA_REGISTER: { //Frame_RigisterFunction break; } default: break; } return CallWindowProc((WNDPROC)g_oldProcFunc, h, msg, wParam, lParam); } ``` # 五、lua脚本执行 处理`MSG_LUA_RUN`消息: ```c++ DWORD64 ptr = 0; if (utils::read<char>((DWORD64)lParam) != '\0') { utils::log("MSG_LUA_RUN:%s", (char*)lParam); __try { g_Frame_ExcuteScript((DWORD64)lParam, (DWORD64)lParam, 0); } __except (1) //接收处理 游戏 retaddr 不通过后产生的异常 { utils::log("g_Frame_ExcuteScript error:%s", (char*)lParam); } } else { utils::log((char*)"******* lua run error *******"); } } ``` 调用: ```c++ // TODO: 在此添加控件通知处理程序代码 CString str; GetDlgItemText(IDC_EDIT5, str); _call_lua_without_ret(str.GetBuffer()); str.ReleaseBuffer(); void _call_lua_without_ret(const char* str) { char tmpUtf[LUA_COMMAND_MAX_LENGTH] = { 0 }; int iLen = utils::mb2u8(str, tmpUtf); DWORD dwMemPro = NULL; if (iLen <= 0) return; ::SendMessage(g_hwnd, MSG_LUA_RUN, 0, (LPARAM)tmpUtf); } ``` # 六、lua返回值获取 处理`MSG_LUA_RET`消息: ```c++ DWORD64 rdx = -1; char c[250] = "retn"; char* temp_utf_8 = NULL; if (*(char*)lParam != '\0') //*(char*)lParam!='\0' lizi { __try { g_Frame_ExcuteScript((DWORD64)lParam, (DWORD64)lParam, 0);//脚本执行 } __except (1) { utils::log("g_Frame_ExcuteScript error:%s",(char*) lParam); } } else { utils::log((char*)"******* lua run error *******"); break; } if (*(char*)lParam != '\0' && c != 0 && rdx != 0) { __try { temp_utf_8 = (char*)g_Frame_GetText((DWORD64)c, rdx, 0, 0);//获取返回值 } __except (1) { utils::log("g_Frame_GetText error:%s", (char*)lParam); } } else { utils::log((char*)"******My_lua_runret_func error ********"); break; } if (temp_utf_8) { ZeroMemory(g_RetText, 1000); utils::u82mb(temp_utf_8, g_RetText); //编码转换为ascii } else { utils::log((char*)"******temp_utf_8 is null ********"); } ``` 调用: ```c++ CString str; GetDlgItemText(IDC_EDIT6, str); char tmpUtf[LUA_COMMAND_MAX_LENGTH] = { 0 }; char tmpcommand[LUA_COMMAND_MAX_LENGTH] = { 0 }; sprintf_s(tmpUtf, "retn=%s", str.GetBuffer()); //utils::log(tmpUtf); int iLen = utils::mb2u8(tmpUtf, tmpcommand); if (iLen <= 0) return ; ::SendMessage(g_hwnd, MSG_LUA_RET, 0, (LPARAM)tmpcommand); str.ReleaseBuffer(); SetDlgItemText(IDC_EDIT9, g_RetText); ``` # 七、角色移动 处理消息: ```c++ Position* targetpos = (Position*)lParam; DWORD64 playerAddr = getLocalPlayerPtr(); //获取本地玩家指针 if (targetpos != 0 && playerAddr != 0) { g_Func_ClickTo(playerAddr, (DWORD64)targetpos, 0); //点击移动 } else { utils::log((char*)"******My_lua_pyrun_func error ********"); } ``` 调用: ```c++ CString strx, stry, strz; GetDlgItemText(IDC_EDIT2, strx); GetDlgItemText(IDC_EDIT3, stry); GetDlgItemText(IDC_EDIT4, strz); float x = std::atof(strx.GetBuffer()); float y = std::atof(stry.GetBuffer()); float z = std::atof(strz.GetBuffer()); strx.ReleaseBuffer(); stry.ReleaseBuffer(); strz.ReleaseBuffer(); Position p{ x,y,z }; ::SendMessage(g_hwnd, MSG_PLAYER_RUN, 0, (LPARAM)&p); ``` # 八、登陆 这里就很简单了,测试了个账号、密码输入: ```c++ _call_lua_without_ret("AccountLogin.UI.PasswordEditBox:SetText(\'*****\')");//输入密码 Sleep(1000); _call_lua_without_ret("C_Login.Login(\'*****\', AccountLogin.UI.PasswordEditBox)");//输入账号并登陆 ``` # 九、下一步工作  对各功能进行封装,实现lua脚本调用。 最后修改:2021 年 09 月 22 日 11 : 39 AM © 禁止转载