Win32,如何在编译的程序中使用C ++挂钩函数?

拿这个function来说吧(在Ollydbgdebugging器中查看) 在这里输入图像说明

第一个PUSH EBP指令是void * f(int32_t n)(idk返回值,只是猜测void *)的开始,我知道input参数n在堆栈中,EBP + 8是指向该variables,我想这将是像int * n =(int *)(uint32_t(EBP)+ 0x08); / *假设EBP是void *和sizeof(EBP)== sizeof(uint32_t)== sizeof(void *),并且+8math在c ++ uint32_t和x86程序集中是相同的。* /

我想做一个钩子,它会检查n是否大于7或小于0,如果是,则将其更改为1.使用ollydbg,直接写入汇编代码,我可以这样做:修补第一个MOV EBP, ESP指令到JMP SHORT后面的INT3指令(我需要7个字节),然后将(未使用的)INT3改为MOV EBP,ESP JMP LONG 0068BCCD,其中0068BCCD是文件末尾未使用的0x000000000000 在这里输入图像说明

,那么在0068BCCD,我可以写汇编代码来检查EBP + 8指向的int,并在必要时修改它:

PUSHAD CMP DWORD PTR SS:[EBP+8],7 JA SHORT Error CMP DWORD PTR SS:[EBP+8],0 JL SHORT Error JMP SHORT Finished Error: PUSHAD PUSH OFFSET TheString CALL Onlink-x86.App::Output ADD ESP,4 POPAD MOV DWORD PTR SS:[EBP+8],1 Finished: POPAD JMP LONG 00447493 TheString: "Warning: label assertion failed, but (pretending its 1 and) trying to ignore.."+0x00 

在这里输入图像说明

哪(如果我没有搞砸)基本上相当于

 void FilterIntAtEBP_8(){ int i=*(int*)(uint32_t(EBP)+8); if(i>7 || i<0){ Output("Warning: label assertion failed, but (pretending its 1 and) trying to ignore.."); *(int*)(uint32_t(EBP)+8)=1; } return; } 

最后,这里是一个问题:我怎样才能使这个钩子,而不是与Ollydbg,但与C + +? (我看到一个源代码的方式,一个MMORPG作弊程序,挂钩客户端,这样做,但代码丢失给我)

Solutions Collecting From Web of "Win32,如何在编译的程序中使用C ++挂钩函数?"

首先,你需要在目标进程中注入一个dll。 为此,您可以使用以下代码:

Injector.h

 #ifndef INJECTOR_H_INCLUDED #define INJECTOR_H_INCLUDED #include <Windows.h> #include <string> class Injector { public: /** * Loads a DLL into the remote process * @Return true on sucess, false on failure */ bool InjectDll(DWORD processId, std::string dllPath); private: }; #endif // INJECTOR_H_INCLUDED 

Injector.cpp

 #include "Injector.h" bool Injector::InjectDll(DWORD processId, std::string dllPath) { HANDLE hThread, hProcess; void* pLibRemote = 0; // the address (in the remote process) where szLibPath will be copied to; HMODULE hcoreel32 = GetmoduleeHandle("coreel32"); HINSTANCE hInst = GetmoduleeHandle(NULL); char DllFullPathName[_MAX_PATH]; GetFullPathName(dllPath.c_str(), _MAX_PATH, DllFullPathName, NULL); // Get process handle hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId); // copy file path in szLibPath char szLibPath[_MAX_PATH]; strcpy_s(szLibPath, DllFullPathName); // 1. Allocate memory in the remote process for szLibPath pLibRemote = VirtualAllocEx( hProcess, NULL, sizeof(szLibPath), MEM_COMMIT, PAGE_READWRITE ); if (pLibRemote == NULL) { // probably because you don't have administrator's right return false; } // 2. Write szLibPath to the allocated memory WriteProcessMemory(hProcess, pLibRemote, (void*)szLibPath, sizeof(szLibPath), NULL); // 3. Force remote process to load dll hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) GetProcAddress(hcoreel32,"LoadLibraryA"), pLibRemote, 0, NULL); if (hThread == NULL) { return false; } return true; } 

main.cpp中

 #include "Injector.h" int main() { Injector injector; DWORD processId = 1653; // change the process id here. if (injector.InjectDll(processId, "injected.dll")) { printf("Good job, you injected the dll\n"); } else { printf("Something wrong happened\n"); } while (true); } 

那么你必须让你的DLL。 这是它变得更复杂一点。 首先一些包括:

injected.dll

 #include <Windows.h> #include <stdio.h> 

那么我们需要做一个绕道正确位置的功能:

 void DetourAddress(void* funcPtr, void* hook, BYTE* mem) { BYTE cmd[5] = { 0xE9, 0x00, 0x00, 0x00, 0x00 }; // jump place holder void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetmoduleeHandle(NULL)); // base + relative address // make memory readable/writable DWORD dwProtect; VirtualProtect(RVAaddr, 5, PAGE_EXECUTE_READWRITE, &dwProtect); // read memory ReadProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, &mem[2], 5, NULL); // write jmp in cmd DWORD offset = ((DWORD)hook - (DWORD)RVAaddr - 5); // (dest address) - (source address) - (jmp size) memcpy(&cmd[1], &offset, 4); // write address into jmp WriteProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, cmd, 5, 0); // write jmp // write mem VirtualProtect(mem, 13, PAGE_EXECUTE_READWRITE, &dwProtect); void* returnAdress = (void*)((DWORD)RVAaddr + 5); memcpy(&mem[8], &returnAdress, 4); // write return address into mem // reprotect VirtualProtect(RVAaddr, 5, dwProtect, NULL); } 

如果你需要在某个时候删除你的dll,你将需要恢复代码:

 void PatchAddress(void* funcPtr, BYTE* mem) { void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetmoduleeHandle(NULL)); // base + relative address // make memory readable/writable DWORD dwProtect; VirtualProtect(funcPtr, 5, PAGE_EXECUTE_READWRITE, &dwProtect); WriteProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, &mem[2], 5, NULL); // write jmp VirtualProtect(RVAaddr, 5, dwProtect, NULL); } 

接下来,我们需要从绕道的字节中做一个函数来让程序执行它们,这样它就不会受到我们绕道的影响。 将其添加到全局空间中:

 // memory (0x5E = pop esi, 0x68 = push DWORD, 0xC3 = RETN) BYTE detourMem[13] = { 0x5E, 0x5E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x00, 0x00, 0x00, 0x00, 0xC3 }; // Convert bytes array to function typedef void ( * pFunc)(); pFunc funcMem = (pFunc) &detourMem; // I also added a variable as an example of what you can do with it. DWORD var = 0; 

之后,你需要你的绕行功能:

 _declspec(naked) void DetourFunction() { // we need to push all flag and registers on the stack so we don't modify them by accident __asm { PUSHFD PUSHAD // You can do "whatever" you want here in assembly code // ex, put eax value into var: mov var, eax } printf("this code is executed everytime the detoured function is called\n"); // Do whatever you want in c++ here if (var < 7) { // eax was smaller than 7 } // We pop every flags and registers we first pushed so that the program continue as it was supposed to __asm { // we set everything back to normal POPAD POPFD push esi // we call our funcMem mov edx, funcMem; call edx } } 

最后,这里是你的DLLMain如何看起来像:

 BOOL APIENTRY DllMain( HMODULE hmodulee, DWORD ul_reason_for_call, LPVOID lpReserved ) { DWORD detouredAddress = 0x689B; // add the RELATIVE ADDRESS of the location you want to detour FILE *stream; switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // Only add this if you want a console to appears when you inject your dll (don't forget FreeConsole when you remove the dll) AllocConsole(); freopen_s(&stream, "CONOUT$", "w", stdout); // If you need to know the base address of the process your injected: printf("base address: 0x%X\n", (DWORD)GetmoduleeHandle(NULL)); // Our detour function DetourAddress((void*)detouredAddress, (void*)&DetourFunction, detourMem); break; case DLL_PROCESS_DETACH: // We restore the process to have what it was before it was injected PatchAddress((void*)detouredAddress, detourMem); FreeConsole(); break; } return true; } 

我明白这一切很多,所以如果你有任何问题,请不要犹豫!