LX*T<|c`' 原文地址 of{wZU\J+9 eJ7A.O Fnll&TF SYSENTER-HOOK
q;B-np?U
299; N 实验环境:win7虚拟机
c#CX~ 示例是对内核层进行SYSENTER-HOOK实现保护进程的功能
}Qg9l| 4fpz;
2% SYSENTER-HOOK也成称为KiFastCallEntry-Hook,它相当于是内核层的Inline-Hook,通过修改SYSENTER_EIP_MSR 寄存器使其指向我们自己的函数,那么我们就可以在自己的的函数中对所有来自3环的函数调用进行第一手过滤。
z,DEBRT+ J0|/g2%0 一会儿会用到的API是OpenProcess,在3环也就是用户层调用此API它保存一些信息传入到0环内核层后实际调用的是ZwOpenProcess函数,所以先使用OD随意打开一个.exe可执行程序,然后在kernel32模块里面查找OpenProcess函数,经过2个jmp后进入下一层,找到一个call进入其中便是ZwOpenProcess的调用。
! daXF&q 'lIT7MK
hiP^*5h U_M > Q_r(
>rYP}k UyK|KL 下面调用API代码才是我们需要注意的,每个API函数调用时在进入关键函数之前都有:
]
J:^$] i]F,Y;&| •一句汇编代码mov eax,0xXX,这是用eax保存一个调用号。
(h`||48d npbNUKdz •mov edx,0x7ffe0300 ,这用edx保存的是KiFastSystemCall函数
trgj]|?M ULQ*cW&;?
8$3 Tu"+; cB?HMLbG> •调用号
e ~*qi&,4 i:{a-Bd 调用号的作用就相当于给函数指定一个序号,通过这个序号就能在内核层中找到我们要调用的函数。进入0环时调用号是eax传递的,但这个调用号并不只是一个普通的数字作为索引序号,系统会把他用32位数据表示,拆分成19:1:12的格式,如下:
c9f~^}jNb 4[+n;OI
-Ux/ Ug@ H>_%ZXL 其中0-11这低12位组成一个真正的索引号,第12位表示服务表号,13-31位没有使用。
uCUQxFp •KiFastSystemCall函数
\Sg&Qv` :K2N7?shA 而0x7ffe0300保存的KiFastSystemCall函数的地址,因为下一条指令SYSENTER就是进入内核层,由于每个线程都有一套线程上下文,都有一个独立的栈.。进入到内核后,内核也会使用自己的内核栈,所以这里先用edx保存栈顶esp。
*qKwu?]?> >Qt#6X|
Ybd){Je
"z :5h&f 那么就要关注一个最重要的问题, SYSENTER 执行之后就进入到内核层, 那到底进入到内核层的哪个地址? 要想弄明白这个问题就需要了解执行 SYSENTER 指令系统到底做了些什么。
\zgRzO'N LFg<j1Gk` 首先,SYSENTER 执行的时候,会读取三个特殊寄存器,从这三个特殊寄存器中取出内核栈的栈顶( esp ) ,内核代码段段选择子( cs ) ,以及代码的首地址( eip ),保存这三个值得寄存器是MSR寄存器组。这组寄存器没有名字,只有编号,由于没有名字,无法通过正常的汇编指令来存取值,Intel提供了两条指令来读写这些寄存器:
\JN<