Win32,如何使用C ++钩住编译程序中的函数? [英] Win32, How can i hook functions in compiled programs with C++?
问题描述
以此函数为例(在Ollydbg调试器中查看)
Take for instance this function (viewed in Ollydbg debugger)
第一个PUSH EBP指令是一个void * f(int32_t n)的开始(idk返回,只是猜测void *),我知道输入参数n在堆栈,并且EBP + 8是一个指向该变量的指针,我想这将像
int * n =(int *)(uint32_t(EBP)+ 0x08); / *假设EBP是一个void *和sizeof(EBP)== sizeof(uint32_t)== sizeof(void *),并且+8数学在c ++ uint32_t和x86程序集中是相同的。* /
The first PUSH EBP instruction is the start for a void* f(int32_t n) (idk what it returns, just guessing void*), I know that the input parameter n is at the stack, and that EBP+8 is a pointer to that variable, i guess it would be like int* n=(int*)(uint32_t(EBP)+0x08); /*assuming EBP is a void* and sizeof(EBP)==sizeof(uint32_t)==sizeof(void*) and that the +8 math is the same in c++ uint32_t and x86 assembly..*/
我想钩住一个钩子,这将检查n是否在7以上,或低于0,如果是,然后将其更改为1.使用ollydbg直接写入汇编代码,我可以做:
补丁第一个MOV EBP,ESP指令到JMP SHORT到它后面的INT3指令(我需要7个字节),然后将(未使用)INT3更改为
MOV EBP,ESP
JMP LONG 0068BCCD
其中0068BCCD是文件末尾的未使用的0x000000000000
I want to make a hook, that will check if n is above 7, or below 0, and if it is, then change it to 1. With ollydbg, writing the assembly code directly, i can do: patch the first MOV EBP,ESP instruction to JMP SHORT to the INT3 instructions behind it (I'll need 7 bytes), then change the (unused) INT3's to MOV EBP,ESP JMP LONG 0068BCCD where 0068BCCD is to the unused 0x000000000000's at the end of the file
,那么在0068BCCD,我可以编写汇编代码来检查EBP + 8指向的int,如果必要的:
, then at the 0068BCCD , i can write the assembly codes to check the int pointed at by EBP+8 , and modify it if necessary:
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
(如果我没有搞砸)基本上相当于
which (if i didn't mess up) is basically the equivalent of
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作弊程序,挂起客户端,这样做,但代码丢失了我)
Finally, here is the question: How can i make this hook, not with Ollydbg, but with C++ ? (I saw a source code way back, a MMORPG cheat program, hooking the client, do this, but the code is lost to me )
推荐答案
首先,您将要在目标进程中注入一个dll。为此,您可以使用以下代码:
First, you will want to inject a dll in the target process. To do so, you can use this code:
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
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 hKernel32 = GetModuleHandle("Kernel32");
HINSTANCE hInst = GetModuleHandle(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(hKernel32,"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。这是一个更复杂的地方。首先有些包括:
Then you have to make your dll. This is where it gets a little more complicated. First some includes:
inject.dll
#include <Windows.h>
#include <stdio.h>
然后我们需要创建一个可以绕过正确位置的函数:
Then we need to make a function that will detour the right location:
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)GetModuleHandle(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,则需要恢复代码:
If you need to remove your dll at some point, you will need to restore the code:
void PatchAddress(void* funcPtr, BYTE* mem)
{
void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetModuleHandle(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);
}
接下来,我们需要从迂回字节中创建一个函数,以便执行它们的程序,使其不受绕行的影响。在全局空间中添加:
Next, we need to make a function out of the detoured bytes in order for the program to execute them, so that it isn't affected by our detour. Add this in global space:
// 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;
之后,您需要您的迂回功能:
After that, you need your detouring function:
_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将如下所示:
Finaly, here is how your DLLMain would look like:
BOOL APIENTRY DllMain( HMODULE hModule, 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)GetModuleHandle(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;
}
我明白这是很多,所以如果你有任何问题不要犹豫!
I understand this is a lot all at once, so if you have any questions don't hesitate!
这篇关于Win32,如何使用C ++钩住编译程序中的函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!