本文介绍了修改钩子函数的out参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我想挂钩EnumProcesses(),作为第一个练习,从它填充的数组中删除一些进程ID。 这是一个out参数所以我不得不让函数执行,然后做我的脏东西。 基本思路,使用可以注入进程的DLL: - hook EnumProcesses()(做了这个) - 复制第一个(_Out_ DWORD * pProcessIds)和3rd(_Out_ DWORD * pBytesReturned)参数的地址(做了这个,但我存储了它们在一个全局变量中) - 保存当前的返回地址(在[ebp + 4])(做了这个,但也在一个全局变量中) - 改变回报地址,所以函数将在我的一个函数中返回 - 将控制权交还给EnumProcesses() 现在不是回到它被调用的地方,而是转到一个我的朋友们,它们将: - 将eax的返回值保存到局部变量中(只是为了安全) - 遍历数组进程ID,删除我要删除的内容 - 将返回值放回eax中 - 推送堆栈上的返回值,返回 这个按预期工作,有一个我不喜欢的小缺点:当我的原始程序(称为EnumProcesses的人)存在时,我得到:运行时检查失败#2 - 堆栈周围变量'allProcesses'已损坏,allProcesses是用作我的EnumProcesses调用的第一个参数的变量。 结果数组是预期的数组,但我不喜欢我的堆栈损坏。而且我也想知道我搞砸了哪里, 这里我保存了参数地址并更改了返回地址: __ declspec ( naked ) void __ stdcall InterceptEnumProc() { DWORD_PTR retAdr; FARPROC变化; HMODULE hModule; FARPROC oldFuncAdr; LPBYTE pJmpAdr; __ asm { // 重做我们用钩子写的叮咬 sub edi , edi push ebp mov ebp , esp sub esp ,_ _ LOCAL_SIZE mov eax ,[ ebp + 4 ] // 返回地址 mov g_returnAdrEnumProc, eax mov eax ,[ ebp + 8 ] // * pProcessIds mov g_pProcIds, eax mov eax ,[ ebp + 16 ] // * pBytesReturned mov g_pBytedReturned, eax // 保存寄存器 push esi 推送 ebx }; change =(FARPROC)ChangeEnumProc; // 更改输出 retAdr =(DWORD_PTR)更改; hModule = NULL; oldFuncAdr = NULL; hModule = LoadLibrary(TEXT( Psapi.dll)); // 错误检查此处省略了可能的LoadLibrary故障 oldFuncAdr = GetProcAddress( hModule, EnumProcesses); // 错误检查此处省略了可能的GetProcAddress pJmpAdr =(LPBYTE)(DWORD_PTR)oldFuncAdr + 5 ; __ asm { pop ebx pop esi mov eax ,retAdr // 新的返回地址 mov [ ebp + 4 ], eax mov esp , ebp jmp pJmpAdr }; } 我在这里更改结果: __ declspec ( naked ) void __ stdcall ChangeEnumProc() { DWORD rValue; DWORD bytesReturned; DWORD procsReturned; DWORD i; DWORD currentProcId; DWORD poz; / * 这就是问题: __asm { mov rValue,eax //保存返回值}; * / __ asm { // 创建一个stacj框架 push ebp mov ebp , esp sub esp ,_ _ LOCAL_SIZE mov rValue, eax push esi push ebx }; bytesReturned = *(DWORD *)g_pBytedReturned; procsReturned = bytesReturned / sizeof(DWORD); currentProcId = GetCurrentProcessId(); // 我只是从结果中隐藏当前流程 for (i = 0 ; i< procsReturned; i ++) { DWORD procId; procId = * g_pProcIds; if (procId == currentProcId) { poz = i; break ; } g_pProcIds ++; } g_pProcIds ++; for (i = poz + 1 ; i< procsReturned; i ++ ) { *(g_pProcIds - 1 )= * g_pProcIds; g_pProcIds ++; } // 同时,更改调用者应该的进程ID数量查找 bytesReturned = bytesReturned - sizeof (DWORD); *(DWORD *)g_pBytedReturned = bytesReturned; __ asm { pop ebx pop esi mov esp , ebp pop ebp mov eax ,rValue jmp g_returnAdrEnumProc // 返回来电者 }; } 全局变量: PDWORD g_pProcIds; PDWORD g_pBytedReturned; DWORD_PTR g_returnAdrEnumProc; EnumProcesses致电: DWORD allProcesses [ 1024 ]; DWORD bytesReturned = 0 ; if (!EnumProcesses(allProcesses, sizeof (allProcesses) ),& bytesReturned)) { // 等等 } 挂钩是基本内联挂钩,而不是写入前5个字节API。 当我操纵这些指针时,我认为我做了一些错误的事情。我利用了EnumProcesses需要第一个和第三个参数指针的事实,但我不确定整个方法有多正确。 作为一个方面 - 注意:我正在考虑松开全局变量,并在ChangeEnumProc的开头添加一些空格(用NOP填充它),然后用我需要的数据写入该空间。我也想对这个想法有一些反馈(好像过度杀人,但我从不喜欢全局变量)。 编辑:发现问题有点一步一步地跑。在为局部变量保留堆栈空间之前,我正在为局部变量赋值。编辑上面的代码来说明它。我仍然愿意接受反馈和建议。解决方案 I want to hook EnumProcesses() and, as a first exercise, remove some process IDs from the array it populates.This is an out parameter so I had to let the function to execute, and then to do my dirty thing.Basic idea, using a DLL that can be injected into a process:- hook EnumProcesses() (did this)- copy the address of the first (_Out_ DWORD *pProcessIds) and 3rd (_Out_ DWORD *pBytesReturned) parameters (did this, but I store them in a global variable)- save current return address (at [ebp + 4]) (did this, but also in a global variable)- change the return address so the function will return in one of my functions- give control back to EnumProcesses()Now instead of going back to where it was called, it goes to one of my friends, which will:- save the return value from eax into a local variable (just to be safe)- iterate through the array of process IDs, removing what I want to remove- put back the return value in eax- push the return value on the stack, returnThis works as intended with one little drawback which I don't like: when my original program (the one who called EnumProcesses) exists I get: "Run-Time Check Failure #2 - Stack around the variable 'allProcesses' was corrupted", allProcesses is the variable used as the first parameter for my EnumProcesses call.The resulting array is the expected one, but I don't like having my stack corrupted. And I also want to know where I messed up,Here I save the out parameters addresses and I change the return address:__declspec(naked)void__stdcallInterceptEnumProc(){ DWORD_PTR retAdr; FARPROC change; HMODULE hModule; FARPROC oldFuncAdr; LPBYTE pJmpAdr; __asm { // redo the bites we over written with our hook sub edi, edi push ebp mov ebp, esp sub esp, __LOCAL_SIZE mov eax, [ebp + 4] // return address mov g_returnAdrEnumProc, eax mov eax, [ebp + 8] // *pProcessIds mov g_pProcIds, eax mov eax, [ebp + 16] // *pBytesReturned mov g_pBytedReturned, eax // save registers push esi push ebx }; change = (FARPROC)ChangeEnumProc; // change the output retAdr = (DWORD_PTR)change; hModule = NULL; oldFuncAdr = NULL; hModule = LoadLibrary(TEXT("Psapi.dll")); // error checks for possible LoadLibrary failure omitted here oldFuncAdr = GetProcAddress(hModule, "EnumProcesses"); // error checks for possible GetProcAddress omitted here pJmpAdr = (LPBYTE)(DWORD_PTR)oldFuncAdr + 5; __asm { pop ebx pop esi mov eax, retAdr // new return address mov [ebp + 4], eax mov esp, ebp jmp pJmpAdr };}And here I change the result:__declspec(naked)void__stdcallChangeEnumProc(){ DWORD rValue; DWORD bytesReturned; DWORD procsReturned; DWORD i; DWORD currentProcId; DWORD poz; /* this was the problem: __asm { mov rValue, eax // save return value }; */ __asm { // create a stacj frame push ebp mov ebp, esp sub esp, __LOCAL_SIZE mov rValue, eax push esi push ebx }; bytesReturned = *(DWORD* )g_pBytedReturned; procsReturned = bytesReturned/sizeof(DWORD); currentProcId = GetCurrentProcessId(); // I just hide the current process from the results for(i = 0; i < procsReturned; i++) { DWORD procId; procId = *g_pProcIds; if(procId == currentProcId) { poz = i; break; } g_pProcIds++; } g_pProcIds++; for(i = poz + 1; i < procsReturned; i++) { *(g_pProcIds - 1) = *g_pProcIds; g_pProcIds++; } // also, change the number of process IDs the caller should look for bytesReturned = bytesReturned - sizeof(DWORD); *(DWORD* )g_pBytedReturned = bytesReturned; __asm { pop ebx pop esi mov esp, ebp pop ebp mov eax, rValue jmp g_returnAdrEnumProc // go back to the caller };}The global variables:PDWORD g_pProcIds;PDWORD g_pBytedReturned;DWORD_PTR g_returnAdrEnumProc;EnumProcesses call:DWORD allProcesses[1024];DWORD bytesReturned = 0;if(!EnumProcesses(allProcesses, sizeof(allProcesses), &bytesReturned)){ // etc, etc}The hooking is basic inline hooking, over writing the first 5 bytes of the API.I think I do some wrong things when I manipulate those pointers. I took advantage of the fact that EnumProcesses needs pointers for the first and 3rd argument, but I'm not sure how correct is the whole approach.As a side-note: I was thinking to loose the global variables, and let some space at the beginning of ChangeEnumProc (fill it wit NOPs) and then over write that space with the data I need. I will also like some feedback on this idea too (it seems like over kill, but I never liked global variables).EDIT: found the problem with a bit of step by step running. I was assigning a value to a local variable before I reserved space on the stack for my local variables. Edited the code above to illustrate it. I'm still open to feedback and advises. 解决方案 这篇关于修改钩子函数的out参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!