拦截 WinAPI 调用






4.83/5 (28投票s)
2006年3月6日
3分钟阅读

155299

3757
一篇关于截取 WinAPI 调用的文章。
引言
API 调用截取是一项允许访问其他程序某些部分的任务。许多程序员花费时间开发和描述各种允许访问的方法。这种方法被用于许多反病毒和反间谍软件中。此外,有时,截取可以帮助您找到应用程序中的错误。然而,一些病毒也在使用它,这已不是什么秘密。我花了很多时间来寻找和理解截取技术。我想在这里描述我的研究结果。
方法描述
首先,您需要阅读以下文章以了解截取机制的基础知识:HookSys(由 Ivo Ivanov 撰写)。它对我有很大的帮助,并且我使用了其中的示例代码。但是,它并没有解决我的所有问题,因为 Ivo 的示例有时会遗漏非常重要的 API 调用。当应用程序启动太快并且截取服务没有时间注入 DLL 时,就会发生这种情况。经过一些研究,我发现了实际问题,它与使用内核模式函数 SetCreateProcessNotificationRoutine
相关。此函数用于接收有关任何新进程创建的通知事件。当进程已经启动时,通常会触发此类通知。因此,我需要找到一种方法来改进 Ivo 的代码。
据我所知,所有 Windows 进程的执行都包含以下步骤
- 初始进程加载;
- 以暂停状态为进程创建主线程;
- 将 NT.DLL 映射到进程的地址空间中;
- 映射所有需要的 DLL,并使用
DLL_PROCESS_ATTACH
原因调用它们的DllMain
; - 恢复主进程的线程。
在恢复主线程之前的步骤看起来最适合注入,因为进程处于暂停状态并且尚未执行任何指令。
进程创建的大部分工作都在内核模式下完成,因此要更改此算法,您需要截取内核模式函数 NtCreateProcess()
和 NtCreateThread()
。传递给函数 NtCreateThread()
的 CONTEXT
结构包含一个名为 EAX
的成员。我发现它等于用户模式下进程的起始地址,因此如果您可以更改它,那么您可以在进程创建之后和启动之前获得控制权。为了解决这个任务,我编写了一个内核模式驱动程序。它在系统启动时启动。
有一些初始化步骤
- 启动;
- 从用户模式接收配置;
- 截取内核模式函数,例如:
NtCreateProcess()
、NtCreateThread()
、NtTerminateProcess()
、NewNtCreateProcessEx()
- 适用于 Windows 2003 Server。
NtCreateThread()
函数的处理程序包含将完成大部分有趣工作的代码。这是其算法的简要描述
- 通过调用
ObReferenceObjectByHandle()
允许访问正在创建的进程; - 记住主线程的起始地址 (
ThreadContext->EAX
); - 通过调用
KeAttachProcess()
"跳转"到正在创建的进程的上下文中; - 通过调用
ZwAllocateVirtualMemory()
为我的代码分配内存,类似于用户模式下CreateRemoteThread()
的众所周知的技术; - 将小代码复制到将加载我的 DLL 的已分配内存中。这段代码看起来像
push pszDllName mov ebx, LoadLibraryAddr call [ebx] mov eax, Win32StartAddr push eax ret pszDllName: db 'example.dll';
- "跳转"到初始进程;
- 更改线程起始地址 (
ThreadContext->EAX
) 以使其指向已分配的内存。
就是这样。您可以下载并编译本文的完整源代码。注意:该示例功能齐全,并且足以进行基本理解,但对于实际使用,可能需要重写它。
编译代码
您需要在计算机上安装 NTDDK。我使用 MSVS 6.0 来编译 NtProcDrv,并使用 MSVS 7.1 来编译其余项目。
历史
- 2006-03-06 - 提交。
- 2006-05-31 - 源代码和二进制文件已更新。