内核级利用通用Hook函数方法检测进程
介绍通用Hook的一点思想:
在系统内核级中,MS的很多信息都没公开,包括函数的参数数目,每个参数的类型等。在系统内核中,访问了大量的寄存器,而很多寄存器的值,是上层调用者提供的。如果值改变系统就会变得不稳定。很可能出现不可想象的后果。另外有时候对需要Hook的函数的参数不了解,所以不能随便就去改变它的堆栈,如果不小心也有可能导致蓝屏。所以Hook的非常好的原则是在自己的Hook函数中呼叫原函数的时候,所有的寄存器值,堆栈里面的值和Hook前的信息一样。这样就能保证在原函数中不会出错。一般我们自己的Hook的函数都是写在C文件里面的。例如Hook的目标函数KiReadyThread。
那么一般就自己实现一个:
MyKiReadyThread(...)
{
......
call KiReadyThread
......
}
但是用C编译器编译出来的代码会出现一个堆栈帧:
Push ebp
mov ebp,esp
这就和我们的初衷不改变寄存器的数违背了。所以我们可以自己用汇编来实现MyKiReadyThread。
_func@0 proc
pushad ;保存通用寄存器
call _cfunc@0 ;这里是在进入原来函数前进行的一些处理。
popad ;恢复通用寄存器
push eax
mov eax,[esp+4] ;得到系统在call 目标函数时入栈的返回地址。
mov ds:_OrgRet,eax ;保存在一个临时变量中
pop eax
mov [esp],retaddr ;把目标函数的返回地址改成自己的代码空间的返回地址,使其返回 后能接手继续的处理
jmp _OrgDestFunction ;跳到原目标函数中
retaddr:
pushad ;原函数处理完后保存寄存器
call _HookDestFunction@0 ;再处理
popad ;回复寄存器
jmp ds:_OrgRet ;跳到系统调用目标函数的下一条指令。
_func@0 endp
当我们要拦截目标API的时候,只要修改原函数头5个字节的机器为一个JMP _func就行了。
然后把原来的5字节保存。在跳入原函数时,恢复那5个字节即可。
Hook KiReadyThread检测系统中的进程:
在线程调度抢占的的时候会调用KiReadyThread,它的原型为
VOID FASTCALL KiReadyThread (IN PRKTHREAD Thread)
在进入KiReadyThread时,ecx指向Thread。
所以完全可以Hook KiReadyThread 然后用ecx的值得到但前线程的进程信息。
KiReadyThread没被ntosknrl.exe导出,所以通过硬编码来。在2000Sp4中地址为0x8043141f
具体实现:
////////////////////////////////
// 1.cpp
////////////////////////////////http://www.hacker.cn/News/xtaq/2006-2/24/0622411115614258.shtml
在系统内核级中,MS的很多信息都没公开,包括函数的参数数目,每个参数的类型等。在系统内核中,访问了大量的寄存器,而很多寄存器的值,是上层调用者提供的。如果值改变系统就会变得不稳定。很可能出现不可想象的后果。另外有时候对需要Hook的函数的参数不了解,所以不能随便就去改变它的堆栈,如果不小心也有可能导致蓝屏。所以Hook的非常好的原则是在自己的Hook函数中呼叫原函数的时候,所有的寄存器值,堆栈里面的值和Hook前的信息一样。这样就能保证在原函数中不会出错。一般我们自己的Hook的函数都是写在C文件里面的。例如Hook的目标函数KiReadyThread。
那么一般就自己实现一个:
MyKiReadyThread(...)
{
......
call KiReadyThread
......
}
但是用C编译器编译出来的代码会出现一个堆栈帧:
Push ebp
mov ebp,esp
这就和我们的初衷不改变寄存器的数违背了。所以我们可以自己用汇编来实现MyKiReadyThread。
_func@0 proc
pushad ;保存通用寄存器
call _cfunc@0 ;这里是在进入原来函数前进行的一些处理。
popad ;恢复通用寄存器
push eax
mov eax,[esp+4] ;得到系统在call 目标函数时入栈的返回地址。
mov ds:_OrgRet,eax ;保存在一个临时变量中
pop eax
mov [esp],retaddr ;把目标函数的返回地址改成自己的代码空间的返回地址,使其返回 后能接手继续的处理
jmp _OrgDestFunction ;跳到原目标函数中
retaddr:
pushad ;原函数处理完后保存寄存器
call _HookDestFunction@0 ;再处理
popad ;回复寄存器
jmp ds:_OrgRet ;跳到系统调用目标函数的下一条指令。
_func@0 endp
当我们要拦截目标API的时候,只要修改原函数头5个字节的机器为一个JMP _func就行了。
然后把原来的5字节保存。在跳入原函数时,恢复那5个字节即可。
Hook KiReadyThread检测系统中的进程:
在线程调度抢占的的时候会调用KiReadyThread,它的原型为
VOID FASTCALL KiReadyThread (IN PRKTHREAD Thread)
在进入KiReadyThread时,ecx指向Thread。
所以完全可以Hook KiReadyThread 然后用ecx的值得到但前线程的进程信息。
KiReadyThread没被ntosknrl.exe导出,所以通过硬编码来。在2000Sp4中地址为0x8043141f
具体实现:
////////////////////////////////
// 1.cpp
////////////////////////////////http://www.hacker.cn/News/xtaq/2006-2/24/0622411115614258.shtml
0
相关文章