NT内核下的inline hook

inline hook原理大概如下:
     修改被HOOK函数A的头5个字节,使其跳转到我们自定义的函数B,函数B的类型与函数A要相同。因为我们是使用JMP直接跳转到函数B,
 而不是使用正常的CALL指令。在函数B内,我们可以检查函数参数,然后可以直接返回。也可以再调用函数A的一个副本。这个副本在HOOK动作发生的同时,就保存下来了。
     代码非常简单,工程打包供大家学习。高手飘过


/*
 * krembo.c, Demonstration of inline hooking (aka. Detouring) within driver/kernel.
 * - izik@tty64.org
 */

#include <ntddk.h>

// Assembly JMP opcode value

#ifndef X86_JMP
#define X86_JMP 0xE9
#endif

// Number of bytes to overwrite

#ifndef JMP_LENGTH
#define JMP_LENGTH sizeof(X86_JMP) + sizeof(int)
#endif

// Size of a page (4k)

#ifndef PAGE_SIZE
#define PAGE_SIZE 0x1000
#endif

// Pointers macros

#define PAGE_MASK(ptr) (ptr & 0xFFFFF000)

#define OFFSET_IN_PAGE(ptr) (ptr - (ptr & 0xFFFFF000))

// RtlRandom pointer prototype

typedef unsigned long (*RTLRANDOM)(
  unsigned long *seed
);

// Pointers to duplicated (original) and current versions of RtlRandom

RTLRANDOM pDupRtlRandom;
RTLRANDOM pCurRtlRandom;

/*
 * DetourFunction, Detour a function (Install Detour)
 * * pFcnAddr, Pointer to the soon-to-be-detoured function
 * * iHookAddr, Address of the hook function
 * * iPoolType, Pool type of allocated memory
 */

void *DetourFunction(char *pFcnAddr, int iHookAddr, int iPoolType) {
  void *pOrigPage;
    
  // Allocate a `PAGE_SIZE` for the original function (duplicate)
  
  pOrigPage = ExAllocatePoolWithTag(iPoolType, PAGE_SIZE, 0xdeadbeef);//分配一页内存,该函数在WIN 2000下可能不存在,XP下没问题
  
  // Is there enough resources?
  
  if (pOrigPage == NULL) {
    return NULL;
  }
  
  // Duplicate the entire page
  
  RtlCopyMemory(pOrigPage, (char *)PAGE_MASK((int)pFcnAddr), PAGE_SIZE);//拷贝函数内容,把函数所在的一整页都拷贝下来。如果函数不仅仅占据一页呢?
  
  // Calculate the relocation to `iHookAddr`
  
  iHookAddr -= ((int)pFcnAddr + 5);//iHookAddr = iHookAddr - (pFcnAddr +5)  iHookAddr是跳转的相对地址
  
  _asm
  {
    CLI          // disable interrupt
    MOV EAX, CR0    // move CR0 register into EAX
    AND EAX, NOT 10000H // disable WP bit 
    MOV CR0, EAX    // write register back 
  }
  
  // Overwrite the first `JMP_LENGTH` bytes of pFcnAddr (Detour it) 
  
  *(pFcnAddr) = X86_JMP;
  *(pFcnAddr+1) = (iHookAddr & 0xFF);
  *(pFcnAddr+2) = (iHookAddr >> 8) & 0xFF;
  *(pFcnAddr+3) = (iHookAddr >> 16) & 0xFF;
  *(pFcnAddr+4) = (iHookAddr >> 24) & 0xFF;
  
  _asm 
  {
    MOV EAX, CR0    // move CR0 register into EAX
    OR EAX, 10000H    // enable WP bit 
    MOV CR0, EAX    // write register back 
    STI          // enable interrupt
  }
  
  // Return pointer to the duplicate function (within the duplicate page)
  
  return (void *)((int)pOrigPage + OFFSET_IN_PAGE((int)pFcnAddr));//返回我们保存的函数副本地址(原件)
}

/*
 * MyRtlRandom, RtlRandom hook
 * * seed, given seed
 */

unsigned long MyRtlRandom(unsigned long *seed) {//HOOK发生时,原始函数跳转到该函数位置,★该函数的类型与原始函数相同
  unsigned long retval;

  DbgPrint(("MyRtlRandom invoked "));
  
  retval = pDupRtlRandom(seed);  //retval 是被HOOK函数的原件的地址,见DriverEntry(),在该函数内部又调用原始函数的原件(副本)
  
  //DbgPrint(("Returning value = %d, from OldRtlRandom(%d)/n"));
  
  return retval;
}

/*
 * RestoreDetouredFunction, Restore a detoured function (Remove detour)
 * * pDupFcn, Pointer to the duplicated function
 * * pOrigFcn, Pointer to the original function
 */

void RestoreDetouredFunction(char *pOrigFcn, char *pDupFcn) { //移除HOOK
  int offset;
  
  _asm
  {
    CLI          // disable interrupt
    MOV EAX, CR0    // move CR0 register into EAX
    AND EAX, NOT 10000H // disable WP bit 
    MOV CR0, EAX    // write register back 
  }

  // Uninstall the detour, Restore `JMP_LENGHT` bytes from the duplicate function.
  
  for (offset = 0; offset < JMP_LENGTH; offset++) {
    pOrigFcn[offset] = pDupFcn[offset];
  }
  
  _asm 
  {
    MOV EAX, CR0    // move CR0 register into EAX
    OR EAX, 10000H    // enable WP bit 
    MOV CR0, EAX    // write register back 
    STI          // enable interrupt
  }
  
  // Deallocate the duplicate page
  
  ExFreePoolWithTag((void *)((int)pDupFcn - OFFSET_IN_PAGE((int)pOrigFcn)), 0xdeadbeef);
  
  return ;
}

/*
 * DriverUnload, Driver unload point
 * * DriverObject, self (Driver)
 */

void DriverUnload(IN PDRIVER_OBJECT DriverObject) {
  unsigned long seed;

  if (pDupRtlRandom != NULL) { //pDupRtlRandom为我们保存的原始函数原件

    DbgPrint(("Removeing detour from RtlRandom/n"));

    // Remove detour

    RestoreDetouredFunction((char *)pCurRtlRandom, (char *)pDupRtlRandom);  

    // Do another self-test

    seed = 31337;

    pCurRtlRandom(&seed);
    
    // No bugcheck? ;-)
  }
  
  //DbgPrint(("Krembo unloaded!/n"));
  
  return ;
}

/*
 * DriverEntry, Driver Single Entry Point
 * * DriverObject, self (Driver)
 * * RegistryPath, given RegistryPath
 */

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
  UNICODE_STRING pFcnName;
  unsigned long seed;

  //DbgPrint(("Krembo loaded!/n"));
  
  // Register unload routine
  
  DriverObject->DriverUnload = DriverUnload;
  
  // Lookup RtlRandom address
  
  RtlInitUnicodeString(&pFcnName, L"RtlRandom");
  
  pCurRtlRandom = MmGetSystemRoutineAddress(&pFcnName);
  
  //DbgPrint(("Found RtlRandom @ 0x%08x/n", pCurRtlRandom));
  
  // Detour RtlRandom

  pDupRtlRandom = DetourFunction((char *)pCurRtlRandom, (int)MyRtlRandom, (int)NonPagedPool);

  // Detour status?

  if (pDupRtlRandom == NULL) {
    
    // Unable to detour
         
    DbgPrint(("Unable to detour RtlRandom! (Not enough resources?)/n"));
  
  } else {
  
    //DbgPrint(("Duplicate Function @ 0x%08x/n", pDupRtlRandom));

    // Detour installed, do a self-test
  
    DbgPrint(("Detour installed, going into a self-test .../n"));
    DbgPrint(("Detour installed, going into a self-test .../n"));
    
    // Dummy seed for the self-test
    
    seed = 31337;

    pCurRtlRandom(&seed);
    
  }
  
  return STATUS_SUCCESS;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值