Ring 0 Inline Hook
2016-01-22 15:58
295 查看
本文讲 用inline hook的方式修改NtOpenKey函数的一个例子
hook 计算机里面一般是指 挂钩某函数,也可以是替换掉原来的函数。
inline hook 是直接在以前的函数替里面修改指令,用一个跳转或者其他指令来达到挂钩的目的。 这是相对普通的hook来说,因为普通的hook只是修改函数的调用地址,而不是在原来的函数体里面做修改。
一般来说 普通的hook比较稳定使用。 inline hook 更加高级一点,一般也跟难以被发现。所以很多人比如病毒制作者都比较推崇inline hook。
SSDT的全称是System Services Descriptor Table,系统服务描述符表
一般来说此表与链接系统内核的API密切相关,对此有一项应用就是杀毒软件的主动防御,当然病毒也可以通过修改主动防御的SSDT来绕过杀软的主动防御。SSDT hook一般是用来隐藏进程运行程序的,前面已经讲了。
在函数头部inline hook太容易被发现, 在函数中间inline 不容易被发现, 下面demo实现在函数中间inline
hook NtOpenFile函数, 使用PCHunter查看, 发现NtOpenFile已经被QQ的QQFrmMgr.sys hook了
取ssdt表NtOpenFile的当前地址(QFrmMgr.sys hook地址), 在函数头+48的地方替换5个字节的 机器码 来跳转, 在QFrmMgr.sys里面加了一个inline hook
模块执行流程 ntkrnlpa.exe ---> QQFrmMgr.sys ---> myinline.sys
先用PCHunter查看下NtOpenKey的序号
![](http://images2015.cnblogs.com/blog/377260/201601/377260-20160125005117375-232924563.png)
![](http://images2015.cnblogs.com/blog/377260/201601/377260-20160125005148781-234497695.png)
![](http://images2015.cnblogs.com/blog/377260/201601/377260-20160125005156047-983942945.png)
完整代码
hook 计算机里面一般是指 挂钩某函数,也可以是替换掉原来的函数。
inline hook 是直接在以前的函数替里面修改指令,用一个跳转或者其他指令来达到挂钩的目的。 这是相对普通的hook来说,因为普通的hook只是修改函数的调用地址,而不是在原来的函数体里面做修改。
一般来说 普通的hook比较稳定使用。 inline hook 更加高级一点,一般也跟难以被发现。所以很多人比如病毒制作者都比较推崇inline hook。
SSDT的全称是System Services Descriptor Table,系统服务描述符表
一般来说此表与链接系统内核的API密切相关,对此有一项应用就是杀毒软件的主动防御,当然病毒也可以通过修改主动防御的SSDT来绕过杀软的主动防御。SSDT hook一般是用来隐藏进程运行程序的,前面已经讲了。
在函数头部inline hook太容易被发现, 在函数中间inline 不容易被发现, 下面demo实现在函数中间inline
hook NtOpenFile函数, 使用PCHunter查看, 发现NtOpenFile已经被QQ的QQFrmMgr.sys hook了
取ssdt表NtOpenFile的当前地址(QFrmMgr.sys hook地址), 在函数头+48的地方替换5个字节的 机器码 来跳转, 在QFrmMgr.sys里面加了一个inline hook
模块执行流程 ntkrnlpa.exe ---> QQFrmMgr.sys ---> myinline.sys
先用PCHunter查看下NtOpenKey的序号
![](http://images2015.cnblogs.com/blog/377260/201601/377260-20160125005117375-232924563.png)
![](http://images2015.cnblogs.com/blog/377260/201601/377260-20160125005148781-234497695.png)
![](http://images2015.cnblogs.com/blog/377260/201601/377260-20160125005156047-983942945.png)
完整代码
#include "ntddk.h" extern "C" { #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; //仅适用于checked build版本 unsigned int NumberOfServices; unsigned char *ParamTableBase; } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; #pragma pack() __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; void PageProtectOn()//恢复内存保护 { __asm { mov eax,cr0 or eax,10000h mov cr0,eax sti } } void PageProtectOff()//去掉内存保护 { __asm{ cli mov eax,cr0 and eax,not 10000h mov cr0,eax } } ULONG g_ntopenkey; ULONG g_jmp_orig_ntopenkey; UCHAR g_orig_funcode[5]; char *pp="my de inline hook"; void FilterNtOpenFile(char* p1) { KdPrint(("kk:%s",pp)); KdPrint(("kk:%s",(char*)PsGetCurrentProcess()+0x16c)); } //__declspec(naked) 告诉编译器函数代码的汇编语言为自己的所写,不需要编译器添加任何汇编代码 __declspec(naked) void NewNtOpenFile() { __asm{ PUSHAD//保存所有寄存器 push pp call FilterNtOpenFile POPAD//还原所有寄存器 xor ecx,ecx mov eax,esi inc ecx jmp g_jmp_orig_ntopenkey } } void HookNtOpenKey() { UCHAR jmp_code[5]="";//存放修改指令的数组 ULONG changeva=48;//相对于函数入口偏移48的位置hook g_ntopenkey = KeServiceDescriptorTable.ServiceTableBase[179];//NtOpenKey的入口地址 g_jmp_orig_ntopenkey = g_ntopenkey + changeva+ 5;//调回的地址, 29从入口地址偏移29的地方改写指令, 指令长度5 ULONG u_jmp_temp = (ULONG)NewNtOpenFile - g_ntopenkey - changeva - 5;//计算 newNtOpenKey相对于NtOpenKey的偏移量 jmp_code[0] = 0xE9;//0xE9对应jmp指令。 (上一篇使用E8(call)指令跳转, 需要在pop eax, jmp不需要) *(ULONG*)&jmp_code[1] = u_jmp_temp;//生成完整的修改指令 PageProtectOff();//解锁内存 RtlCopyMemory(g_orig_funcode,(PVOID)(g_ntopenkey+changeva), 5);//备份 原始指令, 已便还原 RtlCopyMemory((PVOID)(g_ntopenkey+changeva), jmp_code, 5);//修改指令 PageProtectOn();//锁定内存 } void UnHookOpenFile() { PageProtectOff(); RtlCopyMemory((PVOID)(g_ntopenkey+48),g_orig_funcode,5);//还原指令, 卸载hook PageProtectOn(); } VOID MyUnload(PDRIVER_OBJECT pDriverObject) { UnHookOpenFile();//卸载 } NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING Reg_Path) { HookNtOpenKey(); g_ntopenkey = KeServiceDescriptorTable.ServiceTableBase[179];//179==NtOpenFile 函数的 ssdt表的数组下标 pDriverObject->DriverUnload = MyUnload; return STATUS_SUCCESS; } }
相关文章推荐
- shader
- iOS中如何优化Cell中图片的下载性能
- 一Java设计模式——需要遵守的六个原则
- QT sleep
- Windows Server 2003开机自动登录
- 【scikit-learn】评估分类器性能的度量,像混淆矩阵、ROC、AUC等
- QPushButton设置成带下划线的效果
- 在suse下rpm包安装
- Win10系统电脑空闲两分钟后会黑屏的解决办法
- 不要被谎言蒙住了你的爱国心
- 初识storm
- LeetCode-3.Longest Substring Without Repeating Characters
- Linux技术——linux下查看内存和CPU的使用情况
- GPT分区表详解
- iOS 开发 -- 常见坑(PCH问题)
- 使用ARToolkit时发生的DsRenderer.ax丢失错误
- 用subString取出字符串中括号中的字符串
- webx流程举例
- 【scikit-learn】网格搜索来进行高效的参数调优
- c#解析xml字符串 分析 EntityName 时出错