-
-
[原创]Windows平台hook工具
-
发表于: 4天前 1095
-
inline hook,支持x64/x86
驱动没有签名,需要关闭签名校验
首先尝试使用如下命令关闭:
bcdedit /set testsigning on
然后重启,如果不起作用,参考下图:

如上图所示进行操作即可,第一步重启的时候需要按住shift,最后一步是根据提示看关闭签名校验是第几个选项,一般是第7个,按F7即可
hook指定进程的某个位置
假设说你要hook notepad.exe的createfilew,你可以编写如下hookseq文件:
# UserModeHookHelper hook sequence file [hook] module=kernel32.dll offset=0x24e70 dllPath=C:\Users\x\Desktop\project\UserModeHookHelper-main\x64\Debug\VbsObjectCheck.dll export=HookNotepadCreateFileW
0x24e70是createfilew函数相对于kernel32.dll的偏移
C:\Users\x\Desktop\project\UserModeHookHelper-main\x64\Debug\VbsObjectCheck.dll是包含了你的hook逻辑代码的dll
HookNotepadCreateFileW是你的hook逻辑代码所在的导出函数
dll的编写请参考示例
如果你要hook 32位的进程,请在hook code的头部添加一行代码
PROLOGWin32(esp);
如果是64位进程,请添加
PROLOGX64(rsp);
这两个东西的作用是帮你恢复cpu执行到hook点时原始寄存器的值,你可以在你的hook code中直接引用这些寄存器,也可以修改寄存器的值
PROLOGX64的实现代码:
#define PROLOGX64(rsp) \
if (!(rsp)) { \
Log(L"Fatal Error, RSP==NULL\n"); \
return; \
} \
PVOID original_rsp = (PVOID)((DWORD64)(rsp) + 0x80); \
PVOID r15 = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x0); \
PVOID r14 = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x8); \
PVOID r13 = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x10); \
PVOID r12 = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x18); \
PVOID r11 = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x20); \
PVOID r10 = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x28); \
PVOID rbp = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x40); \
PVOID rdi = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x48); \
PVOID rsi = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x50); \
PVOID rbx = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x68); \
PVOID rax = (PVOID)*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x70);
比如说你想要修改rax寄存器的值,执行如下代码即可:
*(DWORD64*)((UCHAR*)(ULONG_PTR)(rsp) + 0x70) = new_rax_value;
添加hook list
首先需要将目标进程的路径添加到hooklist,有两种添加方式,第一种是在进程已经启动的情况下,右键添加,然后在进程下次启动的时候就会自动注入我们的master dll,以便进行后续的hookseq文件加载操作

另一种是通过菜单栏直接添加目标进程的路径:

instant hook 即刻hook
在上面的演示动画中,我们是在进程启动之后才加载hookseq文件对指定位置进行hook,但是某些场景下我们可能需要在某个dll加载后立刻hook其某个位置的代码,这个时候再使用上面的hook流程就有点太晚了,因此我引入instant hook功能,在目标dll加载后立刻对其目标代码进行hook
假设说我们现在要hook powershell进程的amsi.dll的AmsiScanBuffer函数,为了演示对x86的支持,我们使用32位的powershell进程来演示
我们的hook code的逻辑代码:
extern "C" __declspec(dllexport) VOID HookAmsiScanBuffer(ULONG esp) {
PROLOGWin32(esp);
// WRITE YOUR CODE HERE
Log(L"amsi scan buffer file path: %s\n", (WCHAR*)ecx);
// HOOK CODE END
return;
}hookseq文件内容:
# UserModeHookHelper hook sequence file [hook] module=amsi.dll offset=0x5960 dllPath=C:\Users\x\Desktop\project\UserModeHookHelper-main\Release\VbsObjectCheck.dll export=HookAmsiScanBuffer

这里简单介绍一下instant hook的原理,我们使用内核驱动在目标进程启动的时候通过APC将master dll注入进去,master dll会检查当前进程是否应用了instant hook,如果是,master dll就会hook ntdll!ldrloaddll函数的返回位置,在此处检查加载的dll的路径以及加载是否成功(eax/rax寄存器的值),在满足特定的条件之后,master dll就认为目标dll已经加载完毕,此时通过事件通知UMController(主控程序)根据hookseq文件对该dll的特定偏移进行注入,此时master dll会处于阻塞状态,目标dll将处于加载完成但未执行任何代码的状态,主控程序完成注入后会通过事件通知master dll注入已完成,此时master dll解除阻塞,ldrloaddll被放行,至此,整个instant hook流程就完成了
instant patch 即刻patch
在某些场景下,比如软件的试用期到了,弹窗让我们登录或者填写注册码,但是由于网络环境的限制(比如内网开发环境,没办法登录)导致我们无法正常使用,我这里就有一个现实的案例,内网开发环境安装vs2017,30天之后弹窗让我登录microsoft账户,但是由于我无法联网,登录不了,就想着看有没有办法不让他弹窗,挂上调试器在窗口创建函数下断点,最后找到激活窗口的创建位置是Microsoft_VisualStudio_ProductKeyDialog_ni+0x8a465,那么对于这种场景,instant patch就派上了用场
使用instant patch,我们可以直接把这个原本是call指令的地址patch成对应长度的nop指令,这个操作需要在Microsoft_VisualStudio_ProductKeyDialog_ni.dll加载之后立刻执行
编写如下patchseq文件:
[patch] module=Microsoft.VisualStudio.ProductKeyDialog.ni.dll offset=0x8a455 patch=909090909090
就是下面这种场景,导致我的vs2017无法使用:

使用instant patch绕过激活窗口:

kernel hook
除了用户模式的hook功能外,本工具还支持内核模式代码的hook,该功能以插件的形式提供,可以通过plugins菜单的KrnlModeHookHlp进入

和用户模式的hook一样,内核模式的hook也是通过读取hookseq文件来完成的

我们假设出来一个场景,我们需要在just_a_test.exe进程启动的时候断到调试器中,那么我们就可以通过hook进程创建的必经内核函数来实现这个操作,最先想到的必然是进程创建回调函数,我们用WinObjEx看一下有哪些已经注册了的回调函数:

那我们就使用第一个作为目标函数
需要注意的是,hook点不能包含带有间接寻址的非跳转指令,比如这里第一个回调函数:
0: kd> u nt+0x325710 nt!ViCreateProcessCallback: fffff807`24125710 4883ec28 sub rsp,28h fffff807`24125714 833dad798f0000 cmp dword ptr [nt!ViVerifierEnabled (fffff807`24a1d0c8)],0 fffff807`2412571b 488bc2 mov rax,rdx fffff807`2412571e 0f85942e1500 jne nt!ViCreateProcessCallback+0x152ea8 (fffff807`242785b8) fffff807`24125724 4883c428 add rsp,28h fffff807`24125728 c3 ret
可以看到第二条cmp指令里面有一个简介寻址,因此我们没办法在这个地方hook,不过我们可以选择第三条指令作为hook点,我们支持包含间接寻址的控制流类型指令
参考DriverHookCodeTemplate编写如下hook code:
VOID __declspec(dllexport) HookProcessCreate(PVOID rcx, PVOID rdx, PVOID r8, PVOID r9, PVOID rsp) {
PROLOGX64(rsp);
PUNICODE_STRING new_process_image_path = NULL;
NTSTATUS st=DRVHCLIB_NT_LocateImageByPID((HANDLE)rdx, &new_process_image_path);
if (0 == st && new_process_image_path!=NULL) {
UNICODE_STRING a;
RtlInitUnicodeString(&a, L"just_a_test.exe");
if (DRVHCLIB_STR_RtlSuffixUnicodeString(&a, new_process_image_path, TRUE)) {
DLog(L"new process image path: %wZ\n", new_process_image_path);
DbgBreakPoint();
}
ExFreePool(new_process_image_path);
}
else {
DLog(L"failed to get iamge path for pid=0x%x, status=0x%x\n", (HANDLE)rdx, st);
}
return;
}然后编写如下hookseq:
# UserModeHookHelper hook sequence file [hook] module=ntoskrnl.exe offset=0x32571B dllPath=C:\Users\user\Desktop\DriverHookCodeTemplate.sys export=HookProcessCreate
实际效果:

调试受保护进程
禁用PPL和进程对象回调
在我们的逆向工作中,经常需要动态调试,而有时被调试的进程可能是PPL进程且受到驱动保护,一般情况下驱动对进程的保护是通过ObProcess的pre回调来完成的,而PPL只需要修改对应进程EPROCESS的特定标志位即可绕过,如下:

禁用minifilter的PreCreateSection回调
某些安全厂商的驱动会注册这个回调函数以禁止不受信任的dll注入到自己的进程中,加载dll肯定会触发系统调用NtCreateSection,进而触发这个minifilter回调函数,内核驱动会在此处进行检查以拒绝不受信的dll被加载

强制注入dll
如果你临时想向一个进程中注入任意dll,可以右键选择force inject,然后再右键inject dll选择要注入的dll:

内核内存读写插件
KrnlMemWriter插件支持对任意内核内存进行指定长度的读写操作


early break
在某些场景下,你可能需要调试一个进程在启动阶段的代码,此时你就可以使用early break功能,首先将目标进程标记为early break,重启目标进程或者重启机器,我们的工具会在目标进程启动的时候中断到内核调试器中:

此时放行后目标进程会被umhh.dll中的sleep卡住,需要右键wake up来继续执行流,此时我们有时间使用用户态windbg来attach并进行调试
使用此功能有两种方式,一种是将目标进程添加至hook list,然后重启目标进程,另一种是开启Global Hook Mode然后重启计算机
[招生]科锐逆向工程师培训(2026年7月3日实地,远程教学同时开班, 第56期)!
赞赏
- [原创]Windows平台hook工具 1093
- [分享]用户模式hook工具 1508
- 清除windows日志 4221
- [分享] secureCRT通杀解密工具 6275
- API HOOK技术在MFC程序破解过程中的应用 6925