• 3352阅读
  • 2回复

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

上一主题 下一主题
离线iokey
 

发帖
15
金钱
854
威望
759
贡献值
0
诚信值
0
社区警告
0
纠纷记录
0
冻结资金
0
保证金
0
只看楼主 倒序阅读 楼主   发表于: 2019-07-02
RJMrSz$  
原文地址 gm;6v30e  
' k2Z$+  
/*B^@G|]'  
SYSENTER-HOOK P<@Yux#  
e [D'0L  
实验环境:win7虚拟机 U?dd+2^};t  
示例是对内核层进行SYSENTER-HOOK实现保护进程的功能 i,G )kt'H  
hGc')  
SYSENTER-HOOK也成称为KiFastCallEntry-Hook,它相当于是内核层的Inline-Hook,通过修改SYSENTER_EIP_MSR 寄存器使其指向我们自己的函数,那么我们就可以在自己的的函数中对所有来自3环的函数调用进行第一手过滤。 4BSSJ@ z  
nx<q]J uv\  
一会儿会用到的API是OpenProcess,在3环也就是用户层调用此API它保存一些信息传入到0环内核层后实际调用的是ZwOpenProcess函数,所以先使用OD随意打开一个.exe可执行程序,然后在kernel32模块里面查找OpenProcess函数,经过2个jmp后进入下一层,找到一个call进入其中便是ZwOpenProcess的调用。 Y)% CxaO `  
!Pmv  
vF45tw  
(C;oot,  
FBfyW- 7  
Umwd <o  
下面调用API代码才是我们需要注意的,每个API函数调用时在进入关键函数之前都有: v6{qKpU#  
gHS;RF9  
•一句汇编代码mov eax,0xXX,这是用eax保存一个调用号。 E&G_7->  
kzs}U'U  
•mov edx,0x7ffe0300 ,这用edx保存的是KiFastSystemCall函数 UYu 54`'kg  
!?Tu pi  
_J}vPm  
{ZK"K+;h  
•调用号 %dXfC!  
/?b<}am  
调用号的作用就相当于给函数指定一个序号,通过这个序号就能在内核层中找到我们要调用的函数。进入0环时调用号是eax传递的,但这个调用号并不只是一个普通的数字作为索引序号,系统会把他用32位数据表示,拆分成19:1:12的格式,如下: =A,32&;@N  
V+A1O k )  
BS }uv3  
Z4#lZS`'A  
其中0-11这低12位组成一个真正的索引号,第12位表示服务表号,13-31位没有使用。 mUi|vq)`=D  
•KiFastSystemCall函数 VK9I#   
@Bfwb?&  
而0x7ffe0300保存的KiFastSystemCall函数的地址,因为下一条指令SYSENTER就是进入内核层,由于每个线程都有一套线程上下文,都有一个独立的栈.。进入到内核后,内核也会使用自己的内核栈,所以这里先用edx保存栈顶esp。 z_XI,u}  
f#xqu +)Z  
@nN+F,phx  
G7lC'~}  
那么就要关注一个最重要的问题, SYSENTER 执行之后就进入到内核层, 那到底进入到内核层的哪个地址? 要想弄明白这个问题就需要了解执行 SYSENTER 指令系统到底做了些什么。 r>lC(x\B  
54 8w v  
​ 首先,SYSENTER 执行的时候,会读取三个特殊寄存器,从这三个特殊寄存器中取出内核栈的栈顶( esp ) ,内核代码段段选择子( cs ) ,以及代码的首地址( eip ),保存这三个值得寄存器是MSR寄存器组。这组寄存器没有名字,只有编号,由于没有名字,无法通过正常的汇编指令来存取值,Intel提供了两条指令来读写这些寄存器: C._I\:G^  
•rdmsr 读取MSR寄存器 其中高32位存放在EDX 低32位存放在EAX(64位和32位是一样,只是64位时rdx和rcx的高32位会被清零),使用ECX传递寄存器编号 ?k4O)?28  
•wrmsr 写入MSR寄存器,和读取一样写入时是用EDX表示高32位,EAX表示低32位,使用ECX传递寄存器编号 @:DS/#!  
|L{<=NNs:D  
也就是说, Windows在启动,进行初始化的时候会将内核栈栈顶,内核CS段选择子,以及代码段地址(KiFastCallEntry 函数)的地址一一存放到MSR寄存器组的这几个编号的寄存器中。当 SYSENTER 被执行,,CPU就直接使用这些寄存器的值来初始化真正的CS , EIP , ESP 寄存器。因此, SYSENTER 执行之后, 就跑到内核的 KiFastCallEntry 函数中执行代码了。 &Vi"m!B f  
[ @> 8Qhw  
而进行SYSENTER-HOOK时我们只需要关注代码的地址( SYSENTER_EIP_MSR )即可,它的编号是0x176。用类似于3环的Inline-Hook的方法,直接把该地址改为jmp xxx,而xxx是我们自己的函数地址,这样就能实现HOOK了。具体用法如下: Py(l+Ik`>  
;FYiXK%  
安装钩子 qIQvix$8  
Vxif0Bx&/d  
  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. }
[!>2[bbl  
g<~[k?~J  
自己的函数 !ViHC}:   
3"'|Ql.H  
  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. }
>u5}5O P7  
dL"$YU9 z  
~..h=  
编译生成.sys文件后使用工具安装驱动服务,然后打开任务管理器,关闭被保护的进程,就可以看到拒绝访问,到此保护进程就成功了。在学习SYSENTER-HOOK时,我们用3环的Inline-Hook对比着学习,这样可以加快对这种HOOK方法的理解。 5v8&C2Jy@  
c4CBpi?}  
LV=!nF0  
Dbr(Wg  
{: EQ  
内核层完整代码如下: kl[bDb1p  
  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. }
M3 8,SH<  
Ai iOs?  
'w.:I TJf  
&..![,)w^!  
N WB/N*  
广海社区提醒您:
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 字节
批量上传需要先选择文件,再选择上传
 
上一个 下一个