inline hook --  KiInsertQueueApc 。但是总是BSOD,之前俺已经得到KiInsertQueueApc的地址了,至于inline hook部分,就是很普通的code了:


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;

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

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

    KeLowerIrql(oldIrql);
    WPON();

    g_bHooked = FALSE;
}


//
// 开始inline hook --  KiInsertQueueApc
//
VOID HookKiInsertQueueApc ()

    KIRQL  oldIrql;

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

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

    
    RtlCopyMemory ( (BYTE*)KiInsertQueueApc, g_HookCode, 5 );
    *( (ULONG*)(jmp_orig_code + 1) ) = (ULONG) ( (BYTE*)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;
    
    
}

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

    DbgPrint("inline hook --  KiInsertQueueApc 成功\n");
    Proxy_KiInsertQueueApc( Apc, Increment );
}

//
// 代理函数,负责跳转到原函数中继续执行
//
__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
    }
}


想来想去都不知道是哪里出问题了。神秘的 KiInsertQueueApc 啊。到底问题出在哪里呀? 


下面是Dump 文件的分析 --

BugCheck D1, {0, 2, 0, 0}

Probably caused by : ntoskrnl.exe ( nt!KiTrap0E+233 )

Followup: MachineOwner
---------

kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high.  This is usually
caused by drivers using improper addresses.
If kernel debugger is available get stack backtrace.
Arguments:
Arg1: 00000000, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000000, value 0 = read operation, 1 = write operation
Arg4: 00000000, address which referenced memory

Debugging Details:
------------------


READ_ADDRESS:  00000000 

CURRENT_IRQL:  2

FAULTING_IP: 
+0
00000000 ??              ???

PROCESS_NAME:  services.exe

DEFAULT_BUCKET_ID:  INTEL_CPU_MICROCODE_ZERO

BUGCHECK_STR:  0xD1

TRAP_FRAME:  f9ce5c94 -- (.trap 0xfffffffff9ce5c94)
ErrCode = 00000000
eax=00000201 ebx=00000000 ecx=00000009 edx=8055af48 esi=80d72958 edi=ffad2d38
eip=00000000 esp=f9ce5d08 ebp=ffad2d38 iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010206
00000000 ??              ???
Resetting default scope

LAST_CONTROL_TRANSFER:  from 00000000 to 804e287f

FAILED_INSTRUCTION_ADDRESS: 
+0
00000000 ??              ???

STACK_TEXT:  
f9ce5c94 00000000 badb0d00 8055af48 80562b40 nt!KiTrap0E+0x233
WARNING: Frame IP not in any known module. Following frames may be wrong.
f9ce5d04 ffad2d38 00000000 00000000 80590709 0x0
f9ce5d10 80590709 ffad2d38 80d72900 f9ce5d48 0xffad2d38
f9ce5d48 804df7ec 80d72958 7c94da87 000c5ac0 nt!NtQueueApcThread+0x80
f9ce5d48 7c92eb94 80d72958 7c94da87 000c5ac0 nt!KiFastCallEntry+0xf8
007dfe28 7c92e249 7c94da32 000001ac 7c94da87 0x7c92eb94
007dfe60 7c94dcb2 000001ac 00000000 007dfe80 0x7c92e249
007dfe70 01010bf2 000c5ac0 010144cb 007dfe8c 0x7c94dcb2
007dfe80 010144e3 00000438 007dfed8 7c947911 0x1010bf2
007dfe8c 7c947911 00000438 000c5a00 000c5ac0 0x10144e3
007dffa4 806efc35 7c947569 000d1a90 007dffec 0x7c947911
007dffa4 007dff74 7c947569 000d1a90 007dffec hal!HalpApcInterrupt+0xc5
7c99c3a0 00000000 00000000 00000000 00000000 0x7dff74


STACK_COMMAND:  kb

FOLLOWUP_IP: 
nt!KiTrap0E+233
804e287f f7457000000200  test    dword ptr [ebp+70h],20000h

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  nt!KiTrap0E+233

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: nt

IMAGE_NAME:  ntoskrnl.exe

DEBUG_FLR_IMAGE_TIMESTAMP:  45e54711

FAILURE_BUCKET_ID:  0xD1_CODE_AV_NULL_IP_nt!KiTrap0E+233

BUCKET_ID:  0xD1_CODE_AV_NULL_IP_nt!KiTrap0E+233

Followup: MachineOwner
---------

还忘大牛指点一二啊

  • 标 题:答复
  • 作 者:forgot
  • 时 间:2008-03-22 12:23

好像Proxy_KiInsertQueueApc 没处理 fake_KiInsertQueueApc 的 stackframe,出来之前要leave一次

  • 标 题:答复
  • 作 者:combojiang
  • 时 间:2008-03-24 09:58

这么写不会有问题。
#include <ntddk.h> 
#include <ntifs.h>
ULONG g_KiInsertQueueApc;
char g_oricode[8];
ULONG g_uCr0;
char *non_paged_memory;

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;
    };
   
}

__declspec(naked) my_function_detour_KiInsertQueueApc()
{
  __asm
  {    
    mov edi,edi
    push ebp
    mov  ebp, esp
    push ecx
    mov eax,ecx
    _emit 0xEA
    _emit 0xAA
    _emit 0xAA
    _emit 0xAA
    _emit 0xAA
    _emit 0x08
    _emit 0x00
  }
}

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 DetourFunctionKiInsertQueueApc()
{

  char *actual_function = (char *)g_KiInsertQueueApc;
  unsigned long detour_address;
  unsigned long reentry_address;
  KIRQL oldIrql;
  int i = 0;

  char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90 };

  reentry_address = ((unsigned long)g_KiInsertQueueApc) + 8; 

  non_paged_memory = ExAllocatePool(NonPagedPool, 256);
  
  for(i=0;i<256;i++)
  {
    ((unsigned char *)non_paged_memory)[i] = ((unsigned char *)my_function_detour_KiInsertQueueApc)[i];
  }

  detour_address = (unsigned long)non_paged_memory;
  
  *( (unsigned long *)(&newcode[1]) ) = detour_address;

  for(i=0;i<200;i++)
  {
    if( (0xAA == ((unsigned char *)non_paged_memory)[i]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+1]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+2]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+3]))
    {
      *( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address;
      break;
    }
  }


    oldIrql = KeRaiseIrqlToDpcLevel();
  for(i=0;i < 8;i++)
  {
    g_oricode[i] = actual_function[i];
    actual_function[i] = newcode[i];
  }
    KeLowerIrql(oldIrql);
}

VOID UnDetourFunction()
{
    char *actual_function = (char *)g_KiInsertQueueApc;
  KIRQL oldIrql;
  int i = 0;
  
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();

  for(i=0;i < 8;i++)
  {
    actual_function[i] = g_oricode[i];
  }
    KeLowerIrql(oldIrql);
    WPON();
  ExFreePool(non_paged_memory);
}

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

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

  return STATUS_SUCCESS;
}

  • 标 题:答复
  • 作 者:combojiang
  • 时 间:2008-03-24 11:04

这样也可以。
#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;
}