• 2706阅读
  • 2回复

[转]SYSENTER-HOOK [复制链接]

上一主题 下一主题
离线iokey
 

发帖
15
金钱
854
威望
759
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看楼主 倒序阅读 楼主   发表于: 2019-07-02
7o0zny3?  
原文地址 ei<0,w[V1{  
0$]iRE;O]  
FieDESsX>  
SYSENTER-HOOK 4EHrd;|   
m`l9d4p w?  
实验环境:win7虚拟机 x9,jXd  
示例是对内核层进行SYSENTER-HOOK实现保护进程的功能 @AF<Xp{  
5Yhcnwdm!  
SYSENTER-HOOK也成称为KiFastCallEntry-Hook,它相当于是内核层的Inline-Hook,通过修改SYSENTER_EIP_MSR 寄存器使其指向我们自己的函数,那么我们就可以在自己的的函数中对所有来自3环的函数调用进行第一手过滤。 =gs-#\%  
'f!U[Qatg  
一会儿会用到的API是OpenProcess,在3环也就是用户层调用此API它保存一些信息传入到0环内核层后实际调用的是ZwOpenProcess函数,所以先使用OD随意打开一个.exe可执行程序,然后在kernel32模块里面查找OpenProcess函数,经过2个jmp后进入下一层,找到一个call进入其中便是ZwOpenProcess的调用。 s-_D,$ |  
<n4` #d  
j)2I+[aoB  
Z4EmRa30 p  
l2LLM{B  
Lo~ ;pvv  
下面调用API代码才是我们需要注意的,每个API函数调用时在进入关键函数之前都有: R0}1:1}$Sn  
3*& Y'/!  
•一句汇编代码mov eax,0xXX,这是用eax保存一个调用号。 'S1u@p,q  
*I)J%#  
•mov edx,0x7ffe0300 ,这用edx保存的是KiFastSystemCall函数 >v%js!`f  
o]~\u{o#.  
-?-XO<I  
`0N7Gc  
•调用号 g_1#if&  
Jup)A`64  
调用号的作用就相当于给函数指定一个序号,通过这个序号就能在内核层中找到我们要调用的函数。进入0环时调用号是eax传递的,但这个调用号并不只是一个普通的数字作为索引序号,系统会把他用32位数据表示,拆分成19:1:12的格式,如下: ~L"$(^/  
HT6 [Z1  
6q\*{_CPB  
G0{Z@CvO'  
其中0-11这低12位组成一个真正的索引号,第12位表示服务表号,13-31位没有使用。 GPGE7X'  
•KiFastSystemCall函数 [Q0V5P~Q'  
>;^/B R=  
而0x7ffe0300保存的KiFastSystemCall函数的地址,因为下一条指令SYSENTER就是进入内核层,由于每个线程都有一套线程上下文,都有一个独立的栈.。进入到内核后,内核也会使用自己的内核栈,所以这里先用edx保存栈顶esp。 ~%8P0AP  
]bJz-6u#:  
|82q|@e  
ly-(F2  
那么就要关注一个最重要的问题, SYSENTER 执行之后就进入到内核层, 那到底进入到内核层的哪个地址? 要想弄明白这个问题就需要了解执行 SYSENTER 指令系统到底做了些什么。 d?8OY  
*m}8L%<HT  
​ 首先,SYSENTER 执行的时候,会读取三个特殊寄存器,从这三个特殊寄存器中取出内核栈的栈顶( esp ) ,内核代码段段选择子( cs ) ,以及代码的首地址( eip ),保存这三个值得寄存器是MSR寄存器组。这组寄存器没有名字,只有编号,由于没有名字,无法通过正常的汇编指令来存取值,Intel提供了两条指令来读写这些寄存器: HMCLJ/  
•rdmsr 读取MSR寄存器 其中高32位存放在EDX 低32位存放在EAX(64位和32位是一样,只是64位时rdx和rcx的高32位会被清零),使用ECX传递寄存器编号 |ZL?Pqki  
•wrmsr 写入MSR寄存器,和读取一样写入时是用EDX表示高32位,EAX表示低32位,使用ECX传递寄存器编号  <@<bX  
pY`$k#5  
也就是说, Windows在启动,进行初始化的时候会将内核栈栈顶,内核CS段选择子,以及代码段地址(KiFastCallEntry 函数)的地址一一存放到MSR寄存器组的这几个编号的寄存器中。当 SYSENTER 被执行,,CPU就直接使用这些寄存器的值来初始化真正的CS , EIP , ESP 寄存器。因此, SYSENTER 执行之后, 就跑到内核的 KiFastCallEntry 函数中执行代码了。 {_Wrs.a'8  
G;3%k.{  
而进行SYSENTER-HOOK时我们只需要关注代码的地址( SYSENTER_EIP_MSR )即可,它的编号是0x176。用类似于3环的Inline-Hook的方法,直接把该地址改为jmp xxx,而xxx是我们自己的函数地址,这样就能实现HOOK了。具体用法如下: n&njSj/  
~<?Zj  
安装钩子 cv aG[N F  
;NR|Hi]  
  1. //安装钩子
  2. void __declspec(naked) InstallHook()
  3. {
  4.         __asm
  5.         {
  6.                 push eax;
  7.                 push ecx;
  8.                 push edx;
  9.                 //保存原始函数
  10.                 mov ecx, 0x176;//KiFastCallEntry函数地址的所在编号寄存器
  11.                 rdmsr;                   //读取编号寄存器中的值到edx:eax
  12.                 mov [g_OldKiFastCallEntry],eax;//保存
  13.                 //替换自己的函数
  14.                 mov eax, MyKiFastCallEntry;
  15.                 xor edx, edx;
  16.                 wrmsr;//把自己的函数地址写入进入
  17.                 pop edx;
  18.                 pop ecx;
  19.                 pop eax;
  20.                 ret;
  21.         }
  22. }
R(d<PlZ  
7ocUFY0"  
自己的函数 ZQ]qJDk  
KGYbPty}  
  1. //Hook关键代码
  2. void _declspec(naked) MyKiFastCallEntry()
  3. {
  4.         __asm
  5.         {
  6.                 cmp eax, 0xbe;//对比是否是NtOpenProcess的调用号
  7.                 jne _End;     //不是则不处理
  8.                 push eax;     //保存寄存器
  9.                 mov eax, [edx + 0x14];//获取第4个参数PCLIENT_ID
  10.                 mov eax, [eax];//获取PCLIENT_ID第一个字段PID
  11.                                //PCLIENT_ID->UniqueProcess的值                
  12.                 cmp eax, g_Pid;//判断是否是要保护的进程
  13.                 pop eax;
  14.                 jne _End;                
  15.                 cmp[edx + 0xc], 1;//判断是否是关闭操作
  16.                 jne _End;
  17.                 mov[edx + 0xc], 0;//是就把访问权限设为无
  18.         _End:
  19.                 jmp g_OldKiFastCallEntry;//调用原来的函数
  20.         }
  21. }
?1D!%jfi  
 d 2d-Mk  
$ ]s^M=8  
编译生成.sys文件后使用工具安装驱动服务,然后打开任务管理器,关闭被保护的进程,就可以看到拒绝访问,到此保护进程就成功了。在学习SYSENTER-HOOK时,我们用3环的Inline-Hook对比着学习,这样可以加快对这种HOOK方法的理解。 (T_-`N|  
~=*o  
9h amxi  
E ?Mgbd3  
x%l(0K  
内核层完整代码如下: AP=h*1udk  
  1. #include <ntifs.h>
  2. //原来的KiFastCallEntry
  3. ULONG_PTR g_OldKiFastCallEntry = 0;
  4. //要保护进程的ID
  5. ULONG g_Pid = 5616;
  6. ULONG g_Access = 1;//关闭权限的宏PROCESS_TERMINATE
  7. //安装钩子
  8. void InstallHook();
  9. //卸载钩子
  10. void UninstallHook();
  11. //Hook关键代码
  12. void MyKiFastCallEntry();
  13. void OutLoad(DRIVER_OBJECT* obj)
  14. {        
  15.         obj;
  16.         //卸载钩子
  17.         UninstallHook();
  18. }
  19. //驱动入口主函数
  20. NTSTATUS DriverEntry(DRIVER_OBJECT* driver, UNICODE_STRING* path)
  21. {
  22.         path;
  23.         KdPrint(("驱动启动成功!\n"));
  24.         DbgBreakPoint();
  25.         //安装钩子
  26.         InstallHook();
  27.         driver->DriverUnload = OutLoad;
  28.         return STATUS_SUCCESS;
  29. }
  30. //安装钩子
  31. void __declspec(naked) InstallHook()
  32. {
  33.         __asm
  34.         {
  35.                 push eax;
  36.                 push ecx;
  37.                 push edx;
  38.                 //保存原始函数
  39.                 mov ecx, 0x176;//KiFastCallEntry函数地址的所在编号寄存器
  40.                 rdmsr;                   //读取编号寄存器中的值到edx:eax
  41.                 mov [g_OldKiFastCallEntry],eax;//保存
  42.                 //替换自己的函数
  43.                 mov eax, MyKiFastCallEntry;
  44.                 xor edx, edx;
  45.                 wrmsr;//把自己的函数地址写入进入
  46.                 pop edx;
  47.                 pop ecx;
  48.                 pop eax;
  49.                 ret;
  50.         }
  51. }
  52. //卸载钩子
  53. void UninstallHook()
  54. {
  55.         __asm
  56.         {
  57.                 push eax;
  58.                 push ecx;
  59.                 push edx;
  60.                 //还原原来的函数地址
  61.                 mov ecx, 0x176;
  62.                 mov eax, [g_OldKiFastCallEntry];
  63.                 xor edx, edx;
  64.                 wrmsr;
  65.                 pop edx;
  66.                 pop ecx;
  67.                 pop eax;
  68.         }
  69. }
  70. //Hook关键代码
  71. void _declspec(naked) MyKiFastCallEntry()
  72. {
  73.         __asm
  74.         {
  75.                 cmp eax, 0xbe;//对比是否是NtOpenProcess的调用号
  76.                 jne _End;     //不是则不处理
  77.                 push eax;     //保存寄存器
  78.                 mov eax, [edx + 0x14];//获取第4个参数PCLIENT_ID
  79.                 mov eax, [eax];//获取PCLIENT_ID第一个字段PID
  80.                                //PCLIENT_ID->UniqueProcess的值                
  81.                 cmp eax, g_Pid;//判断是否是要保护的进程
  82.                 pop eax;
  83.                 jne _End;                
  84.                 cmp[edx + 0xc], 1;//判断是否是关闭操作
  85.                 jne _End;
  86.                 mov[edx + 0xc], 0;//是就把访问权限设为无
  87.         _End:
  88.                 jmp g_OldKiFastCallEntry;//调用原来的函数
  89.         }
  90. }
/)6T>/  
.;]WcC<3  
M bWby'  
WM'!|lg  
d ItfR'$  
广海社区提醒您:
1.忘记账号、密码、安全问题等常见站务问题,请查看论坛左上角站点帮助
2.请理性对待商业信息,如有交易,强烈建议您选择广海中介进行交易
3.欢迎购买广海社区广告位,感谢您的支持,报价及位置详见广海社区广告服务
4.特殊会员售价50元,积分(金钱和威望)无限,更多权限,欢迎到广海淘宝购买
5.广海社区唯一域名ghoffice.cc,唯一QQ190959022,其他均为假冒,谨防上当受骗
6.如您被骗,请查看广海社区举报中心,按照要求和流程提交举报材料,未经核实的举报帖子将一律删除
7.如您发现违规违法内容,欢迎点击帖子右下角举报按钮进行举报,也可到站务办公版块匿名发帖举报
免责声明
文中内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。 私下交易造成损失的,本站概不负责。
 
离线check5201314

发帖
1
金钱
301
威望
301
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 沙发   发表于: 2019-07-02
代码就代码,发图片干嘛
........
离线newworld2

发帖
1
金钱
301
威望
301
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看该作者 板凳   发表于: 2019-07-02
现在不都64位系统吗
快速回复
限150 字节
如果您在写长篇帖子又不马上发表,建议存为草稿
 
上一个 下一个