简介:
这种方法的具体hook实施比较灵活, 这里采用对目标API入口地址下断点,当调用时即 断下,截获参数内容后进行修改.这时可以通过修改eip的值让其跳转到任意地址. 这种方式没有文件等其他操作,它就相当于实现了一个最简单的调试器,而对被调试进程
进行修改内存是很正常的事件,因此被查杀可能性低
下面是测试将notepad的内容在保存文件时小写全部转为大写
DWORD debugHook(DWORD pid) { HANDLE hProcess;//目标进程句柄 HANDLE hThread;//线程句柄 DEBUG_EVENT de; //调试事件 CONTEXT thread_context;//线程上下文,包括各个寄存器值 char* apiBase = 0;//API基址 //WriteFile的2个重要参数,要写入的内容和大小 char *buffer; DWORD nNumberOfBytesToWrite; DWORD bufferBase; BYTE fakeCode = 0xcc;//int 3指令 BYTE trueCode; //保存原来的指令 DWORD ret; if (!DebugActiveProcess(pid)) { return GetLastError(); } while (WaitForDebugEvent(&de, INFINITE)) { switch (de.dwDebugEventCode) { case EXIT_PROCESS_DEBUG_EVENT: return 1; case CREATE_PROCESS_DEBUG_EVENT: //目标程序创建进程, 附加到调试器,都会发送该调试事件 //获取进程句柄, 通过CreateProcessInfo 成员能获取更多信息 hProcess = de.u.CreateProcessInfo.hProcess; hThread = de.u.CreateProcessInfo.hThread; //获取目标api地址,由于kernel32.dll加载到任何进程中基址都是一样的.所以直接获取本进程的也是一样的 apiBase = (char*)GetProcAddress(GetModuleHandleA("kernel32.dll"), "WriteFile"); //备份原来的指令 ReadProcessMemory(hProcess, apiBase, &trueCode, sizeof(BYTE), &ret); //写入int 3指令 WriteProcessMemory(hProcess, apiBase, &fakeCode, sizeof(BYTE), &ret); ContinueDebugEvent(pid, de.dwThreadId, DBG_CONTINUE); break; case EXCEPTION_DEBUG_EVENT: //异常事件,程序发生异常时将发送该调试事件 //只关心我们设下的断点异常,其他一律不处理 if (de.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT) { if ((char*)de.u.Exception.ExceptionRecord.ExceptionAddress == apiBase) { //恢复hook WriteProcessMemory(hProcess, apiBase, &trueCode, sizeof(BYTE), &ret); //获取上下文 thread_context.ContextFlags = CONTEXT_CONTROL; GetThreadContext(hThread, &thread_context); //恢复正常执行流程,即将eip调整到函数入口处 thread_context.Eip--; SetThreadContext(hThread, &thread_context); //获取WriteFile的参数lpBuffer和nNumberOfBytesToWrite ReadProcessMemory(hProcess, (LPCVOID)(thread_context.Esp + 0xc), &nNumberOfBytesToWrite, 4, &ret); buffer = (char*)malloc(sizeof(char)*nNumberOfBytesToWrite); ReadProcessMemory(hProcess, (LPVOID)(thread_context.Esp + 0x8), &bufferBase, sizeof(DWORD), NULL); ReadProcessMemory(hProcess, (LPCVOID)bufferBase, (LPVOID)buffer, nNumberOfBytesToWrite, &ret); //转为大写 printf(" 原始字符: "); for (DWORD i = 0; i < nNumberOfBytesToWrite; i++) { printf("%c", buffer[i]); if (buffer[i] <= 0x7a && buffer[i] >= 0x61) { buffer[i] -= 0x20; } } WriteProcessMemory(hProcess, (LPVOID)(bufferBase), (LPCVOID)buffer, nNumberOfBytesToWrite, &ret); free(buffer); //继续运行程序 ContinueDebugEvent(pid, de.dwThreadId, DBG_CONTINUE); Sleep(0); //释放本线程时间片 //重新勾住 WriteProcessMemory(hProcess, apiBase, &fakeCode, sizeof(byte), &ret); } } ContinueDebugEvent(pid, de.dwThreadId, DBG_CONTINUE); break; default: ContinueDebugEvent(pid, de.dwThreadId, DBG_CONTINUE); break; } } }