欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

天书夜读上 Inline Hook ZwCreateSection

天书夜读上 Inline Hook ZwCreateSection

新手初来乍到,老鸟飞过,菜鸟共同学习……
源码见附件
部分源码及分析贴出……
#include "xde.h"
#include <ntddk.h>
#include <WinDef.h>
unsigned long  g_uCr0;
unsigned long Addr_ZwCreateSection,Addr_ZwCreateSection_Body;
//模仿天书InlineHook,填写绝对跳转指令
unsigned long my_address;    // 我要跳转的地址
unsigned long length;
unsigned char code[12];      //使用一个比较大的空间来容纳未知指令
struct xde_instr myjmp = {0};
static unsigned char * g_new_address =NULL;
static unsigned long total_length = 0;
//关闭内存写保护 WriteProtectOff
void WriteProtectOff()
{
  unsigned long 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 WriteProtectOn()
{
  _asm
  {
    sti
    push eax;
    mov eax, g_uCr0; //恢原有 CR0 性
    mov cr0, eax;
    pop eax;
  };
}
//由函数名 获得 函数地址
unsigned long GetFunctionAddr( IN PCWSTR FunctionName)
{
  UNICODE_STRING UniCodeFunctionName;
  RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
  return (unsigned long)MmGetSystemRoutineAddress( &UniCodeFunctionName );   
}
//Hook函数所作的工作
NTSTATUS  DetourZwCreateSection( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG SectionPageProtection, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL )
{
  KdPrint(("\n\nSectionHandle:%X\nFileHandle:%X\n\n",SectionHandle,FileHandle));
  return STATUS_SUCCESS;
}
//中继函数
static __declspec(naked) MyZwCreateSectionRelay( OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN PLARGE_INTEGER MaximumSize OPTIONAL, IN ULONG SectionPageProtection, IN ULONG AllocationAttributes, IN HANDLE FileHandle OPTIONAL )
{//__declspec(naked)表示不希望编译器帮我们将参数压栈,所以这里需要我们手动将参数压栈
  if (g_new_address == NULL)
  {
    __asm    
    {
      //这里的操作是将参数压入栈空间
      push ebp
      mov ebp,esp
      push [ebp + 1ch]
      push [ebp + 18h]
      push [ebp + 14h]
      push [ebp + 10h]
      push [ebp + 0ch]
      push [ebp + 8h]
      push [ebp + 4h]
      //上面的代码为参数压栈操作
      //下面这两句的代码是将下面的函数内指令地址(old_codes)保存到全局变量(g_new_address)中,
      //以便我们向这里拷贝我们想要执行的指令,在这里是ZwCreateSection开头的total_length个字节的指令
      push old_codes
        pop g_new_address
        //下面的代码用于参数的弹出操作
      mov edx, [ebp + 4h]
      pop edx
      mov edx, [ebp + 8h]
      pop edx
      mov edx, [ebp + 0ch]
      pop edx
      mov edx, [ebp + 10h]
      pop edx
      mov edx, [ebp + 14h]
      pop edx
      mov edx, [ebp + 18h]
      pop edx
      mov edx, [ebp + 1ch]
      pop edx
      mov esp, ebp
      pop ebp        
      ret 0x1c
    }
  }
  else
  {
    __asm
    {
      //这里的操作是将参数压入栈空间
      push ebp
      mov ebp,esp
      push [ebp + 1ch]
      push [ebp + 18h]
      push [ebp + 14h]
      push [ebp + 10h]
      push [ebp + 0ch]
      push [ebp + 8h]
      push [ebp + 4h]
      //上面的代码为参数压栈操作
    }
    //这里调用我们的挂钩函数,实现我们想要的操作
    DetourZwCreateSection(SectionHandle,DesiredAccess,ObjectAttributes,MaximumSize,SectionPageProtection,AllocationAttributes,FileHandle);
    _asm
    {
      mov edx, [ebp + 4h]
      pop edx
      mov edx, [ebp + 8h]
      pop edx
      mov edx, [ebp + 0ch]
      pop edx
      mov edx, [ebp + 10h]
      pop edx
      mov edx, [ebp + 14h]
      pop edx
      mov edx, [ebp + 18h]
      pop edx
      mov edx, [ebp + 1ch]
      pop edx
      mov esp, ebp
      pop ebp 
      //上面这些是为了堆栈平衡

old_codes:
      //在这里写入足够多的nop,形成一片空间来容纳拷贝过来的旧代码
        nop          //1        
        nop          //2
        nop          //3
        nop          //4
        nop          //5
        nop          //6
        nop          //7
        nop          //8
        nop          //9
        nop          //10
        nop          //11
        nop          //12
        nop          //13
        nop          //14
        nop          //15
        //跳转到ZwCreateSection+total_length的位置继续执行
        jmp Addr_ZwCreateSection_Body
    };
  }
}
//安装HOOK的函数
NTSTATUS HookZwCreateSection()
{
  KIRQL Irql;
  unsigned long length;
  struct xde_instr code_instr = { 0 } ;
  Addr_ZwCreateSection_Body = GetFunctionAddr(L"ZwCreateSection");  //获得ZwCreateSection的开始地址;
  Addr_ZwCreateSection =  Addr_ZwCreateSection_Body;
  while (total_length < 7)
  {
    //反汇编一条指令
    length = xde_disasm((unsigned char*)Addr_ZwCreateSection_Body,&code_instr);
    if (length == 0)        //如果有指令解析失败,就直接返回失败
    {
      return STATUS_FILE_INVALID;
    }
    total_length += length;  //计算已经反汇编的指令的总长度
    Addr_ZwCreateSection_Body += length;//解析地址移动
  }
  //开始InlineHook
  //关闭内存写保护,在下面要有写操作
  WriteProtectOff();
  //提升IRQL中断级到DISPATCH_LEVEL,防止线程切换
  Irql = KeRaiseIrqlToDpcLevel();
  if (g_new_address != NULL)
  {
    //保存要Hook的内核函数前total_length个字节的内容
    RtlCopyMemory(g_new_address,(unsigned char *)Addr_ZwCreateSection,total_length);
  }
  else
  {
    MyZwCreateSectionRelay(NULL,0,NULL,NULL,0,0,NULL);
    //保存要Hook的内核函数前total_length个字节的内容
    RtlCopyMemory(g_new_address,(unsigned char *)Addr_ZwCreateSection,total_length);
  }
  //向要Hook的内核函数的开头total_length个字节写入JMP指令,使其跳转到新定义的钩子函数中
  //RtlCopyMemory((unsigned char *)Addr_ZwCreateSection,JmpAddress,total_length);
  RtlCopyMemory((unsigned char *)Addr_ZwCreateSection,code,total_length);
  //恢复IRQL中断级到
  KeLowerIrql(Irql);
  //开启写保护
  WriteProtectOn();
  return STATUS_SUCCESS;
}
//卸载Hook函数
void UnHookZwCreateSection()
{
  //把开头五个字节再写会到原函数
  KIRQL Irql;
  //关闭写保护
  WriteProtectOff();
  //提升中断级
  Irql = KeRaiseIrqlToDpcLevel();
  //还原原来的五个字节
  RtlCopyMemory((unsigned char *)Addr_ZwCreateSection,g_new_address,total_length);
  //降低中断级
  KeLowerIrql(Irql);
  //打开写保护
  WriteProtectOn();  
}
//卸载函数
VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
  DbgPrint("My Driver Unloaded!");
  UnHookZwCreateSection();
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING uniRegistry)
{
  pDriverObject->DriverUnload = OnUnload;
  my_address = (unsigned long)MyZwCreateSectionRelay;    //我要跳转的地址,即中继函数的地址
  myjmp.opcode = 0xea;        //填写指令码eah ,对应的汇编码为jmp
  myjmp.addrsize = 4;          //地址长度为4个字节(32位)
  myjmp.datasize = 2;          //选择子作为立即数,长度为2个字节
  myjmp.addr_l[0] = my_address;//填写我要跳转的地址
  myjmp.data_s[0] = 8;          //选择子,内核代码段选择子为8
  length = xde_asm(code,&myjmp);//将绝对跳转指令写到code变量中
  HookZwCreateSection();
  return STATUS_SUCCESS;
}
环境 vs2008+ddkwizard+VMware 7.1+WinXP sp3

上传的附件 TianShuInlineHook0.1.rar

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功