• 2515阅读
  • 2回复

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

上一主题 下一主题
离线iokey
 

发帖
15
金钱
854
威望
759
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看楼主 倒序阅读 楼主   发表于: 2019-07-02
t7|uZHKK  
原文地址 J 00<NRxj"  
[zp v3Uw  
7.4Q  
SYSENTER-HOOK x\ieWF1  
Z5aU7  
实验环境:win7虚拟机 sjOyg!e  
示例是对内核层进行SYSENTER-HOOK实现保护进程的功能 T( @y#09  
5IeF |#g  
SYSENTER-HOOK也成称为KiFastCallEntry-Hook,它相当于是内核层的Inline-Hook,通过修改SYSENTER_EIP_MSR 寄存器使其指向我们自己的函数,那么我们就可以在自己的的函数中对所有来自3环的函数调用进行第一手过滤。 D[.; H)V  
%JBFG.+  
一会儿会用到的API是OpenProcess,在3环也就是用户层调用此API它保存一些信息传入到0环内核层后实际调用的是ZwOpenProcess函数,所以先使用OD随意打开一个.exe可执行程序,然后在kernel32模块里面查找OpenProcess函数,经过2个jmp后进入下一层,找到一个call进入其中便是ZwOpenProcess的调用。  %x_c2  
+^% y&8e  
-^=sxi,V  
b&.j>=  
i_OoR"J%  
G_EU/p<Q  
下面调用API代码才是我们需要注意的,每个API函数调用时在进入关键函数之前都有: h>v;1Q O9D  
@=o1q=5@8  
•一句汇编代码mov eax,0xXX,这是用eax保存一个调用号。 8>.l4:`  
p8<Y5:`  
•mov edx,0x7ffe0300 ,这用edx保存的是KiFastSystemCall函数 G)28#aH  
 V"n0"\k,  
Skgvnmk[U  
XGE:ZVpW  
•调用号 9g3J{pKcZ  
B9`^JYT<  
调用号的作用就相当于给函数指定一个序号,通过这个序号就能在内核层中找到我们要调用的函数。进入0环时调用号是eax传递的,但这个调用号并不只是一个普通的数字作为索引序号,系统会把他用32位数据表示,拆分成19:1:12的格式,如下: J{$+\  
]PVPt,c  
[u[`!L=  
ra \Moy  
其中0-11这低12位组成一个真正的索引号,第12位表示服务表号,13-31位没有使用。 V$u~}]z  
•KiFastSystemCall函数 y=y=W5#;77  
O_8ERxj g]  
而0x7ffe0300保存的KiFastSystemCall函数的地址,因为下一条指令SYSENTER就是进入内核层,由于每个线程都有一套线程上下文,都有一个独立的栈.。进入到内核后,内核也会使用自己的内核栈,所以这里先用edx保存栈顶esp。 %)[mbb  
d # :&Uw  
k 8^!5n  
h4C DZ  
那么就要关注一个最重要的问题, SYSENTER 执行之后就进入到内核层, 那到底进入到内核层的哪个地址? 要想弄明白这个问题就需要了解执行 SYSENTER 指令系统到底做了些什么。 T1bP  I/  
n`";ctQT  
​ 首先,SYSENTER 执行的时候,会读取三个特殊寄存器,从这三个特殊寄存器中取出内核栈的栈顶( esp ) ,内核代码段段选择子( cs ) ,以及代码的首地址( eip ),保存这三个值得寄存器是MSR寄存器组。这组寄存器没有名字,只有编号,由于没有名字,无法通过正常的汇编指令来存取值,Intel提供了两条指令来读写这些寄存器: w[w{~`([",  
•rdmsr 读取MSR寄存器 其中高32位存放在EDX 低32位存放在EAX(64位和32位是一样,只是64位时rdx和rcx的高32位会被清零),使用ECX传递寄存器编号 ]_NN,m>z  
•wrmsr 写入MSR寄存器,和读取一样写入时是用EDX表示高32位,EAX表示低32位,使用ECX传递寄存器编号 Vx_ lI #3  
?qr-t+  
也就是说, Windows在启动,进行初始化的时候会将内核栈栈顶,内核CS段选择子,以及代码段地址(KiFastCallEntry 函数)的地址一一存放到MSR寄存器组的这几个编号的寄存器中。当 SYSENTER 被执行,,CPU就直接使用这些寄存器的值来初始化真正的CS , EIP , ESP 寄存器。因此, SYSENTER 执行之后, 就跑到内核的 KiFastCallEntry 函数中执行代码了。 7 }`c:u~j  
8%s ^>.rG  
而进行SYSENTER-HOOK时我们只需要关注代码的地址( SYSENTER_EIP_MSR )即可,它的编号是0x176。用类似于3环的Inline-Hook的方法,直接把该地址改为jmp xxx,而xxx是我们自己的函数地址,这样就能实现HOOK了。具体用法如下: t ZUZNKODW  
K @3 yS8F  
安装钩子 u9>zC QRO  
ZN!OM)@:!  
  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. }
4HlOv % 8  
IWeQMwg  
自己的函数 *z4n2"<l  
)'8DK$.  
  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. }
,)mqd2)+"  
fII;t-(x  
"Y@rNmBj  
编译生成.sys文件后使用工具安装驱动服务,然后打开任务管理器,关闭被保护的进程,就可以看到拒绝访问,到此保护进程就成功了。在学习SYSENTER-HOOK时,我们用3环的Inline-Hook对比着学习,这样可以加快对这种HOOK方法的理解。 =jvM$  
@xR7>-$0p  
e:H7ht:  
CC 1\0$ /  
6'y+Ev$9  
内核层完整代码如下: QC.WR'.  
  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. }
xq_%|p}y  
0T2h3,  
Ws?BAfP  
"?_adot5v  
}K,:aN,44\  
广海社区提醒您:
1.忘记账号、密码、安全问题等常见站务问题,请查看论坛左上角站点帮助
2.请理性对待商业信息,如有交易,强烈建议您选择广海中介进行交易
3.欢迎购买广海社区广告位,感谢您的支持,报价及位置详见广海社区广告服务
4.特殊会员售价50元,积分(金钱和威望)无限,更多权限,欢迎到广海淘宝购买
5.广海社区唯一域名ghoffice.net,唯一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 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
上一个 下一个