本博文由CSDN博主zuishikonghuan所作,版权归zuishikonghuan所有,转载请注明出处:http://blog.csdn.net/zuishikonghuan/article/details/51302024
以前写过两篇“[Win32] API Hook(1)在32/64位系统上的实现”博客,介绍并给出了 API inline hook 代码,如下:
blog.csdn.net/zuishikonghuan/article/details/47976067
blog.csdn.net/zuishikonghuan/article/details/47979603
在这两篇博文中,我简要说了API inline hook的缺陷:
API inline hook的方法是修改API函数的前几个字节,让这几个字节执行无条件跳转指令,跳转到我们自己的函数里,这时候我们就可以根据参数进行一些判断,如果我们愿意放行,还可以恢复函数的前几字节并重新调用原函数,不愿意放行,就直接返回错误,Ring3级的进程保护就是这样实现的。
API inline hook在16位的系统上确实可以非常正常的工作,因为16位系统是单任务的!而如果是在32位的多任务抢占式操作系统上,系统可能会随时切换线程上下文,如果我们刚把函数前几个字节恢复了,系统突然把线程切换到了另一个线程,而那个线程又无巧不成书的调用了我们hook的这个函数,那么后果就是,出现了漏网之鱼!
而IAThook可以克服这个问题,但是IAThook的缺陷更是灾难性的!因为IAThook是通过修改导入地址表实现的,如果动态调用API,IAThook根本无法拦截。
当时我说这是一个小瑕疵,是的,在一些老系统(例如XP)上的确可以算是比较好的工作,但是现在看来,这个问题已经非常严重了,在Win8、8.1、10系统上,如果在explorer里Hook,会造成explorer特别容易崩溃!!(特别是 Hook NT Native API)
我希望找到新的解决方案,IAT HOOK 首先被否决了,因为 IAT HOOK 拦截不住 API 动态调用,在 Ring 0 中 Hook 更是行不通,因为在 amd64 平台上是有驱动程序强制签名的,买签名是很贵的,而且还不能干坏事。
那么我们就要认命吗?
于是我试图从 Inline Hook 的实现方法上找原因,这是我写的 Inline Hook 代码(x86 和 amd 64)
没错,原理就是修改要 Hook 函数的前几个字节,问题关键就在于,如何能避免还原时恢复函数的这几个字节呢?
//进行 Inline Hook
HMODULE hdll = LoadLibrary(TEXT("kernel32.dll"));
addr = GetProcAddress(hdll, "OpenProcess");
if (addr){
#ifdef _M_IX86
code[0] = 0xe9;
aint a = (aint)MyOpenProcess - (aint)addr - 5;
RtlMoveMemory(code + 1, &a, 4);
DWORD old;
if (VirtualProtectEx(GetCurrentProcess(), addr, 5, PAGE_EXECUTE_READWRITE, &old)){
RtlMoveMemory(oldcode, addr, 5);
WriteProcessMemory(GetCurrentProcess(), addr, code, 5, NULL);
VirtualProtectEx(GetCurrentProcess(), addr, 5, old, &old);
}
#elif _M_X64
code[0] = 0x48;
code[1] = 0xB8;
code[10] = 0x50;
code[11] = 0xC3;
aint a = (aint)MyOpenProcess;
RtlMoveMemory(code + 2, &a, 8);
DWORD old;
if (VirtualProtectEx(GetCurrentProcess(), addr, 12, PAGE_EXECUTE_READWRITE, &old)){
RtlMoveMemory(oldcode, addr, 12);
WriteProcessMemory(GetCurrentProcess(), addr, code, 12, NULL);
VirtualProtectEx(GetCurrentProcess(), addr, 12, old, &old);
}
#endif
}