偶然间想到一种无需DLL跨进程HOOK的方法
这个方法的原理就是:①首先在API头部写一个CC断点
②中断的时候程序收到消息,并且读出参数
需要注意的地方只有修正EIP寄存器,和读取参数的问题。
因为API采用STDCALL的方式调用,所以参数是从右向左压进堆栈的。
还有就是API的开头是
mov edi,edi
push ebp
mov ebp,esp
我们要注意,因为我们是在头部断下的,还没有执行push ebp,而执行了push ebp之后esp会减4,也就是说,我们在头部中断的时候要把esp-4才能拿ESP来读取参数!
还要注意的就是,如何不执行API直接跳转到返回地址,一般ESP储存的地址指向的就是返回地址,所以我们只要把EIP修改就好,如果你要设置返回值,那么就修改EAX为返回值。(记得修正ESP)
如何单步?这也是一个问题,我们可以在第一条指令中断之后,在第二条指令下CC断点,同时还原第一条指令,等到第二条指令触发中断事件时,我们再在第一条指令上下CC断点,再还原第二条指令,这就模拟了一次单步。
我把代码贴出来,使用VC2010编译
#include <stdio.h>
#include <windows.h>
#define SE_DEBUG_PRIVILEGE 20
typedefDWORD(WINAPI *PRtlAdjustPrivilege) ///未文档化函数声明
(
ULONG Privilege,
BOOLEAN Enable,
BOOLEAN CurrentThread,
PBOOLEAN Enabled
);
void WINAPI AdjustPrivilege() ///ntdll中的提权函数
{
BOOLEAN Enabled;
PRtlAdjustPrivilege RtlAdjustPrivilege = (PRtlAdjustPrivilege)GetProcAddress(LoadLibrary((LPCSTR)"ntdll.dll"), "RtlAdjustPrivilege");
RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &Enabled);
}
int main(void)
{
DWORD pid;
DWORD lpapi;
BYTE code;
BYTE _code;
BYTE cc = 0xCC;
PDWORD p;
HANDLE hProcess;
HANDLE hThread;
HMODULE hMod;
int yes = TRUE;
DEBUG_EVENT dbg;
CONTEXT ct;
int wType;
char text;
char caption;
int hwin;
DWORD pt;
char ch;
AdjustPrivilege(); ///提升进程权限到DEBUG
printf("请输入要HOOK的进程ID:____\b\b\b\b");
scanf("%d", &pid); ///获取要HOOK的进程的ID
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
hMod = GetModuleHandle("user32.dll"); ///获取模块句柄
if (!hMod)
hMod = LoadLibrary("user32.dll"); ///如果没有获取到模块句柄,则加载模块
lpapi = (DWORD)GetProcAddress(hMod, "MessageBoxA"); ///取API地址
ReadProcessMemory(hProcess, (LPVOID)lpapi, code, 2, NULL); ///获取API头部两字节数据,即第一条指令
ReadProcessMemory(hProcess, (LPVOID)(lpapi + 2), &_code, 1, NULL); ///获取API第二条指令第一字节数据
WriteProcessMemory(hProcess, (LPVOID)lpapi, &cc, 1, NULL);
DebugActiveProcess(pid); ///开启调试会话
while (yes)
{
if(WaitForDebugEvent(&dbg, 20) == 0) ///如果当前还没有触发调试信息
{
Sleep(50);
continue;
}
if(dbg.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) ///如果是调试事件
{
if(dbg.u.Exception.ExceptionRecord.ExceptionCode != EXCEPTION_BREAKPOINT) ///如果不是中断事件
{
ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_EXCEPTION_NOT_HANDLED); ///继续调试
continue;
}
if((DWORD)dbg.u.Exception.ExceptionRecord.ExceptionAddress == lpapi)
{
hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dbg.dwThreadId); ///打开线程
ct.ContextFlags = CONTEXT_ALL;
SuspendThread(hThread); ///暂停线程,否则不可以读取线程寄存器信息
GetThreadContext(hThread, &ct); ///读取线程寄存器信息
printf("拦截到进程MessageBoxA调用!\n");
///这里为什么要-4?因为函数头部是push ebp,mov ebp,esp,而push了ebp之后,esp会-4,我们下CC断点的地方是函数头部
///所以此时ESP还未-4,所以我们读取的时候要把ESP-4
ReadProcessMemory(hProcess, (LPVOID)(ct.Esp + 0x10), &hwin, 4, NULL); ///读取HWND参数
ReadProcessMemory(hProcess, (LPVOID)(ct.Esp + 0xC), &pt, 4, NULL); ///读取Text参数的指针
ReadProcessMemory(hProcess, (LPVOID)pt, text, 255, NULL); ///读取Text参数
ReadProcessMemory(hProcess, (LPVOID)(ct.Esp + 0x8), &pt, 4, NULL); ///读取Caption参数的指针
ReadProcessMemory(hProcess, (LPVOID)pt, caption, 255, NULL); ///读取Caption参数
ReadProcessMemory(hProcess, (LPVOID)(ct.Esp + 0x4), &wType, 4, NULL); ///读取wType参数
ReadProcessMemory(hProcess, (LPVOID)(ct.Esp), &pt, 4, NULL); ///读取返回地址
printf("hwnd:%d\nlpText:%s\nlpCaption:%s\nwType:%d\n", hwin, text, caption, wType);
printf("返回地址:%#x\n", pt);
printf("输入Y允许执行,输入N不允许执行,输入其他则退出:_\b");
fflush(stdin);
scanf("%c", &ch);
if(ch == 'Y' || ch == 'y')
{
///允许执行,模拟OD单步事件
WriteProcessMemory(hProcess, (LPVOID)(lpapi + 2), &cc, 1, NULL); ///在API的第二条指令下断点
WriteProcessMemory(hProcess, (LPVOID)lpapi, code, 2, NULL); ///还原第一条指令
ct.Eip--; ///修改EIP寄存器,使其-1,重新指向API头第一字节
SetThreadContext(hThread, &ct);
ResumeThread(hThread);
CloseHandle(hThread);
}
else if(ch == 'N' || ch == 'n')
{
///不允许执行
ct.Esp+= 0x14; ///修正堆栈
ct.Eip = pt; ///修正EIP到返回地址
SetThreadContext(hThread, &ct);
ResumeThread(hThread);
CloseHandle(hThread);
}
else
{
///退出
ct.Eip--;
SetThreadContext(hThread, &ct);
WriteProcessMemory(hProcess, (LPVOID)lpapi, code, 2, NULL); ///还原API头部信息
WriteProcessMemory(hProcess, (LPVOID)(lpapi + 2), &_code, 1, NULL);
ResumeThread(hThread);
CloseHandle(hThread);
yes = FALSE;
}
}
else if((DWORD)dbg.u.Exception.ExceptionRecord.ExceptionAddress == (lpapi + 2)) ///如果是中断在第二条指令
{
hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dbg.dwThreadId); ///打开线程
ct.ContextFlags = CONTEXT_ALL;
SuspendThread(hThread); ///暂停线程,否则不可以读取线程寄存器信息
GetThreadContext(hThread, &ct); ///读取线程寄存器信息
WriteProcessMemory(hProcess, (LPVOID)lpapi, &cc, 1, NULL); ///重新在API第一条指令上设置CC断点
WriteProcessMemory(hProcess, (LPVOID)(lpapi + 2), &_code, 1, NULL); ///还原第二条指令
ct.Eip--; ///修正EIP
SetThreadContext(hThread, &ct);
ResumeThread(hThread);
CloseHandle(hThread);
}
ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_CONTINUE);
}
ContinueDebugEvent(dbg.dwProcessId, dbg.dwThreadId, DBG_CONTINUE);
}
DebugActiveProcessStop(pid);
return 0;
}
代码下载:
多谢楼主分享! 看不懂 好高深 我也看不懂,还是感谢LZ分享 这个高明{:7_236:}
多谢楼主分享! 这个利用调试来实现感觉有点没必要,如果进程检测调试,整个HOOK就没用了。。。。
页:
[1]