Friday, August 12, 2011

Hook Specials 5: inline hook In my humble opinion as beginner

Author:skymelai
It is unoccupied to work recently,has read things to not touched on work,That include inLine Hook,Next is understand of me,I wonder whether it is correct or no or not.
Usual step:Function Address is finded in memory and save first a few bytes of original function(The code was getted by kernel's debugging).  Write to jump  to our function address on original function startting(Calculate to get addrees).Regain first some bytes of original function on oneself function and jump to original function.

I believe stack' change that is important,Have two kinds of cases,Watch

The image show be hook of function passed parameter with stack,So We can't change value of EBP or value of ESP.

The image show be hook of function passed parameter with register(FASTCALL),So we can free use on our function, That don't change aprropriate register while entry be hook of function

next code will show two kinds of cases

code 1:
#include <ntddk.h>
#include <ntifs.h>
#include <windef.h>
ULONG g_KiInsertQueueApc;
ULONG g_uCr0;

BYTE g_HookCode[5] = { 0xe9, 0, 0, 0, 0 };
BYTE g_OrigCode[5] = { 0 }; // 原函数的前字节内容
BYTE jmp_orig_code[7] = { 0xEA, 0, 0, 0, 0, 0x08, 0x00 };

BOOL g_bHooked = FALSE;

VOID
fake_KiInsertQueueApc (
    PKAPC Apc,
    KPRIORITY Increment
    );
   
VOID
Proxy_KiInsertQueueApc (
    PKAPC Apc,
    KPRIORITY Increment
    );

void WPOFF()
{
  
    ULONG uAttr;
  
    _asm
    {
        push eax;
        mov eax, cr0;
        mov uAttr, eax;
        and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
        mov cr0, eax;
        pop eax;
        cli
    };
  
    g_uCr0 = uAttr; //保存原有的 CRO 性
  
}

VOID WPON()
{
  
    _asm
    {
        sti
        push eax;
        mov eax, g_uCr0; //恢原有 CR0 性
        mov cr0, eax;
        pop eax;
    };
  
}


//
// 停止inline hook
//
VOID UnHookKiInsertQueueApc ()
{
    KIRQL  oldIrql;

    WPOFF();
    oldIrql = KeRaiseIrqlToDpcLevel();
   
    RtlCopyMemory ( (BYTE*)g_KiInsertQueueApc, g_OrigCode, 5 );

    KeLowerIrql(oldIrql);
    WPON();

    g_bHooked = FALSE;
}


//
// 开始inline hook --  KiInsertQueueApc
//
VOID HookKiInsertQueueApc ()
{
    KIRQL  oldIrql;

    if (g_KiInsertQueueApc == 0) {
        DbgPrint("KiInsertQueueApc == NULL\n");
        return;
    }

    //DbgPrint("开始inline hook --  KiInsertQueueApc\n");
    DbgPrint( "KiInsertQueueApc的地址t0x%08x\n", (ULONG)g_KiInsertQueueApc );
    // 保存原函数的前字节内容
    RtlCopyMemory (g_OrigCode, (BYTE*)g_KiInsertQueueApc, 5);
    *( (ULONG*)(g_HookCode + 1) ) = (ULONG)fake_KiInsertQueueApc - (ULONG)g_KiInsertQueueApc - 5;
   
   
    // 禁止系统写保护,提升IRQL到DPC
    WPOFF();
    oldIrql = KeRaiseIrqlToDpcLevel();

    RtlCopyMemory ( (BYTE*)g_KiInsertQueueApc, g_HookCode, 5 );
    *( (ULONG*)(jmp_orig_code + 1) ) = (ULONG) ( (BYTE*)g_KiInsertQueueApc + 5 );
   
    RtlCopyMemory ( (BYTE*)Proxy_KiInsertQueueApc, g_OrigCode, 5);
    RtlCopyMemory ( (BYTE*)Proxy_KiInsertQueueApc + 5, jmp_orig_code, 7);

    // 恢复写保护,降低IRQL
    KeLowerIrql(oldIrql);
    WPON();

    g_bHooked = TRUE;
   
   
}

//
// 跳转到我们的函数里面进行预处理
//
__declspec (naked)
VOID
fake_KiInsertQueueApc (
    PKAPC Apc,
    KPRIORITY Increment
    )
{
 

    // 去掉DbgPrint,不然这个hook会产生递归
    //DbgPrint("inline hook --  KiInsertQueueApc 成功\n");
 
    __asm
    {
               jmp Proxy_KiInsertQueueApc
    }
}

//
// 代理函数,负责跳转到原函数中继续执行
//
__declspec (naked)
VOID
Proxy_KiInsertQueueApc (
    PKAPC Apc,
    KPRIORITY Increment
    )
{
 
    __asm {  // 共字节
            _emit 0x90
            _emit 0x90
            _emit 0x90
            _emit 0x90
            _emit 0x90  // 前字节实现原函数的头字节功能
            _emit 0x90  // 这个填充jmp
            _emit 0x90
            _emit 0x90
            _emit 0x90
            _emit 0x90  // 这字节保存原函数+5处的地址
            _emit 0x90 
            _emit 0x90  // 因为是长转移,所以必须是0x0080
    }
}




ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
    UNICODE_STRING UniCodeFunctionName;
    RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
    return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );  

}

//根据特征值,从KeInsertQueueApc搜索中搜索KiInsertQueueApc
ULONG FindKiInsertQueueApcAddress()
{
  char * Addr_KeInsertQueueApc = 0;
  int i = 0;
  char Findcode[] = { 0xE8, 0xcc, 0x29, 0x00, 0x00 };
  ULONG Addr_KiInsertQueueApc = 0;
    Addr_KeInsertQueueApc = (char *) GetFunctionAddr(L"KeInsertQueueApc");
  for(i = 0; i < 100; i ++)
  {
        if( Addr_KeInsertQueueApc[i] == Findcode[0] &&
      Addr_KeInsertQueueApc[i + 1] == Findcode[1] &&
      Addr_KeInsertQueueApc[i + 2] == Findcode[2] &&
      Addr_KeInsertQueueApc[i + 3] == Findcode[3] &&
      Addr_KeInsertQueueApc[i + 4] == Findcode[4]
      )
    {
      Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc[i] + 0x29cc + 5;
      break;
    }
  }
  return Addr_KiInsertQueueApc;
}


VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
  DbgPrint("My Driver Unloaded!");
  UnHookKiInsertQueueApc();
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
  DbgPrint("My Driver Loaded!");
  theDriverObject->DriverUnload = OnUnload;
   
  g_KiInsertQueueApc = FindKiInsertQueueApcAddress();
  HookKiInsertQueueApc();

  return STATUS_SUCCESS;
}

Code 2:
//===================inline hook KiInsertQueueApc====================
//KiInsertQueueApc为内核未导出函数,可以从导出函数KeInsertQueueApc定位
//修改KiInsertQueueApc开头5字节
//处理函数思路:apc-->kthread---apc_state--eprocess--进程名字
//HookKiInsertQueueApc---DetourMyKiInsertQueueApc---UnHookKiInsertQueueApc
#include "ntddk.h"

ULONG CR0VALUE;
ULONG g_KiInsertQueueApc;
          
unsigned char JmpAddress[5]={0xE9,0,0,0,0};       //跳转到HOOK函数的地址
unsigned char  OriginalBytes[5]={0};             //保存原始函数前五个字

VOID FASTCALL DetourMyKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment);

VOID WPOFF()
{
        _asm
               
        {
               
                push eax
                       
                        mov eax, cr0
                       
                        mov CR0VALUE, eax
                       
                        and eax, 0fffeffffh 
                       
                        mov cr0, eax
                       
                        pop eax
                        cli
                       
        };
       
}

VOID WPON()
{
    __asm
               
        {      
                sti
                push eax
                       
                        mov eax, CR0VALUE
                       
                        mov cr0, eax
                       
                        pop eax
                       
        };
}
//1、获取KiInsertQueueApc地址
ULONG GetFunctionAddr( IN PCWSTR FunctionName)     //PCWSTR常量指针,指向16位UNICODE
{
        UNICODE_STRING UniCodeFunctionName;
        RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
        return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );  
}

ULONG GetKiInsertQueueApcAddr()
{
        ULONG sp_code1=0x28,sp_code2=0xe8,sp_code3=0xd88a;  //特征码,sp_code3 windbg显示错误,应该为d88a
        ULONG address=0;
        PUCHAR addr;
        PUCHAR p;
        addr=(PUCHAR)GetFunctionAddr(L"KeInsertQueueApc");
        for(p=addr;p<p+PAGE_SIZE;p++)
        {
                if((*(p-1)==sp_code1)&&(*p==sp_code2)&&(*(PUSHORT)(p+5)==sp_code3))
                {
                        address=*(PULONG)(p+1)+(ULONG)(p+5);
                        break;
                }
        }
        KdPrint(("[KeInsertQueueApc] addr %x\n",(ULONG)addr));
    KdPrint(("[KiInsertQueueApc] address %x\n",address));
    return address;
}

VOID HookKiInsertQueueApc()
{  
        KIRQL Irql;
        g_KiInsertQueueApc=GetKiInsertQueueApcAddr();
        KdPrint(("[KiInsertQueueApc] KiInsertQueueApc %x\n",g_KiInsertQueueApc));
    // 保存原函数的前字节内容
    RtlCopyMemory (OriginalBytes, (unsigned char*)g_KiInsertQueueApc, 5);
        //新函数对原函数的偏移地址
    *( (ULONG*)(JmpAddress + 1) ) = (ULONG)DetourMyKiInsertQueueApc - (ULONG)g_KiInsertQueueApc - 5;
    // 禁止系统写保护,提升IRQL到DPC
    WPOFF();
    Irql = KeRaiseIrqlToDpcLevel();
    //inline hook函数
        RtlCopyMemory ( (unsigned char*)g_KiInsertQueueApc, JmpAddress, 5 );
    // 恢复写保护,降低IRQL
    KeLowerIrql(Irql);
    WPON();       
}
//原函数
_declspec (naked) VOID FASTCALL OriginalKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment)
{
        _asm
        {
                //前五个字节
                mov edi,edi
                        push ebp
                        mov ebp,esp
                       
                        mov eax,g_KiInsertQueueApc
                        add eax,5
                        jmp eax
        }
}
//处理函数
//apc--kthread--apc_state--eprocess
VOID FASTCALL DetourMyKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment)
{
        ULONG thread;
        ULONG process;

  /*OriginalKiInsertQueueApc(Apc,Increment);*/

   
        if(MmIsAddressValid((PULONG)((ULONG)Apc+0x008)))    //地址验证 KAPC结构+008--->kthread
                thread=*((PULONG)((ULONG)Apc+0x008));
        else
                return ;
        if(MmIsAddressValid((PULONG)((ULONG)thread+0x044))) //kthread+30-->KAPC_STATE+10-->eprocess
                process=*((PULONG)((ULONG)thread+0x044));
        else
                return ;
    if(MmIsAddressValid((PULONG)((ULONG)process+0x174)))  //eprocess+174---->进程名字
        {
                if((_stricmp((char *)((ULONG)process+0x174),"notepad.exe")==0)&&(Increment==2))
                {
                        return ;

                }
                else
                        OriginalKiInsertQueueApc(Apc,Increment);

        }
        else
                return;
   
}

//卸载函数
VOID UnHookKiInsertQueueApc()
{
        KIRQL Irql;
    WPOFF();
    Irql = KeRaiseIrqlToDpcLevel();
    //inline hook函数
    RtlCopyMemory ( (unsigned char*)g_KiInsertQueueApc, OriginalBytes, 5);
    // 恢复写保护,降低IRQL
    KeLowerIrql(Irql);
    WPON();       
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
  DbgPrint("My Driver Unloaded!");

  UnHookKiInsertQueueApc();
}
NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
  DbgPrint("My Driver Loaded!");
 
 
  // TODO!!
  theDriverObject->DriverUnload = OnUnload;

  HookKiInsertQueueApc();
 
  return STATUS_SUCCESS;
}

No comments:

Post a Comment