现在的位置: 首页 > 综合 > 正文

Inline hook ObReferenceObjectByHandle,附加问题笔记做记录

2012年07月19日 ⁄ 综合 ⁄ 共 13024字 ⁄ 字号 评论关闭

 

//禁止记事本结束 inline hook成功,原来的抄袭代码似乎有问题,不知道是不是环境问题:xp sp3+VM+双核CPU

//ObReferenceObjectByHandle是ntoskrnl.exe导出函数,采用HOOK前五个字节的方式

#include 
<ntddk.h>

#define dprintf DbgPrint

#include <windef.h> 

#include <ntstatus.h>

//字节型数据  unsigned char

ULONG  CR0VALUE;

BYTE  OriginalBytes[5]={0};             //保存原始函数前五个字节           

BYTE JmpAddress[
5]={0xE9,0,0,0,0};       //跳转到HOOK函数的地址

extern POBJECT_TYPE *PsProcessType;

NTKERNELAPI NTSTATUS ObReferenceObjectByHandle(

IN HANDLE  Handle,

IN ACCESS_MASK  DesiredAccess,

IN POBJECT_TYPE  ObjectType  OPTIONAL,

IN KPROCESSOR_MODE  AccessMode,

OUT PVOID  *Object,

OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL

);

//HOOK函数

NTSTATUS DetourMyObReferenceObjectByHandle(

IN HANDLE  Handle,           

IN ACCESS_MASK  DesiredAccess,

IN POBJECT_TYPE  ObjectType  OPTIONAL, 

IN KPROCESSOR_MODE  AccessMode,

OUT PVOID  *Object,

OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL);

//

//hook流程 HookObReferenceObjectByHandle---DetourMyObReferenceObjectByHandle---UnHookObReferenceObjectByHandle

void  HookObReferenceObjectByHandle()

{

//赋值前面定义的数组

KIRQL Irql;

//    DbgPrint("[ObReferenceObjectByHandle] :%08x\n",ObReferenceObjectByHandle);  //地址验证

//保存函数前五个字节内容

RtlCopyMemory(OriginalBytes,(BYTE 
*)ObReferenceObjectByHandle,5);

//保存新函数五个字节之后偏移

*(ULONG *)(JmpAddress+1)=(ULONG)DetourMyObReferenceObjectByHandle-((ULONG)ObReferenceObjectByHandle+5);

//开始inline hook

__asm{
//去掉内存保护

cli

mov eax,cr0

and eax,not 10000h

mov cr0,eax

}

//提升IRQL中断级

Irql
=KeRaiseIrqlToDpcLevel();

//函数开头五个字节写JMP 

RtlCopyMemory((BYTE 
*)ObReferenceObjectByHandle,JmpAddress,5);

//恢复Irql

KeLowerIrql(Irql);

//开启内存写保护

__asm{
//恢复内存保护 

mov eax,cr0

or eax,10000h

mov cr0,eax

sti

}

}

_declspec (naked) NTSTATUS    OriginalObReferenceObjectByHandle(IN HANDLE  Handle,

IN ACCESS_MASK  DesiredAccess,

IN POBJECT_TYPE  ObjectType  OPTIONAL,

IN KPROCESSOR_MODE  AccessMode,

OUT PVOID  *Object,

OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL)

{

_asm

{

mov edi,edi

push ebp

mov ebp,esp

mov eax,ObReferenceObjectByHandle

add eax,5

jmp eax                

}

}NTSTATUS   status;

char* ProtectName = "notepad.exe";

NTSTATUS DetourMyObReferenceObjectByHandle(

IN HANDLE  Handle,

IN ACCESS_MASK  DesiredAccess,

IN POBJECT_TYPE  ObjectType  OPTIONAL,

IN KPROCESSOR_MODE  AccessMode,

OUT PVOID  *Object,

OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL)

{

//调用原函数

status
=-1;

status=OriginalObReferenceObjectByHandle(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation);

if((DesiredAccess==0x1)&&(ObjectType== *PsProcessType))

{

if(( _stricmp((char *)((ULONG)(*Object)+0x174),ProtectName)==0))//&&(status=STATUS_SUCCESS))加入蓝屏见图一反汇编代码,原因不知,—。—,太菜,结束进程记事本,出现应用程序出错,进程没结束,但会耗死CPU。

{   

ObDereferenceObject(*Object);//??? 去除也可以 不蓝屏或出错

return STATUS_ACCESS_DENIED;

}

}

return status;

}

void UnHookObReferenceObjectByHandle()

{

//把五个字节再写回到原函数

KIRQL Irql;

//关闭写保护

__asm{
//去掉内存保护

cli

mov eax,cr0

and eax,not 10000h

mov cr0,eax

}

//提升IRQL到Dpc

Irql
=KeRaiseIrqlToDpcLevel();

RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,OriginalBytes,5);

KeLowerIrql(Irql);

//开启写保护

__asm{
//恢复内存保护 

mov eax,cr0

or eax,10000h

mov cr0,eax

sti

}

}

VOID OnUnload(    IN PDRIVER_OBJECT     DriverObject    )

{

UnHookObReferenceObjectByHandle();

dprintf("[UnHookObReferenceObjectByHandle] Unloaded\n");

}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj,PUNICODE_STRING      pRegistryString)

{

pDriverObj->DriverUnload = OnUnload;

HookObReferenceObjectByHandle();

return STATUS_SUCCESS;

}

代码

//禁止记事本结束 inline hook成功,原来的抄袭代码似乎有问题,不知道是不是环境问题:xp sp3+VM+双核CPU

//耗死CPU问题如何解决? 

//ObReferenceObjectByHandle是ntoskrnl.exe导出函数,采用HOOK前五个字节的方式

#include <ntddk.h>

#define dprintf DbgPrint

#include <windef.h> 

#include <ntstatus.h>

//字节型数据  unsigned char

ULONG  CR0VALUE;

BYTE  OriginalBytes[5]={0};             //保存原始函数前五个字节           

BYTE JmpAddress[5]={0xE9,0,0,0,0};       //跳转到HOOK函数的地址

extern POBJECT_TYPE *PsProcessType;

NTKERNELAPI NTSTATUS ObReferenceObjectByHandle(

IN HANDLE  Handle,

IN ACCESS_MASK  DesiredAccess,

IN POBJECT_TYPE  ObjectType  OPTIONAL,

IN KPROCESSOR_MODE  AccessMode,

OUT PVOID  *Object,

OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL

);

//HOOK函数

NTSTATUS DetourMyObReferenceObjectByHandle(

IN HANDLE  Handle,           

IN ACCESS_MASK  DesiredAccess,

IN POBJECT_TYPE  ObjectType  OPTIONAL, 

IN KPROCESSOR_MODE  AccessMode,

OUT PVOID  *Object,

OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL);

//

//hook流程 HookObReferenceObjectByHandle---DetourMyObReferenceObjectByHandle---UnHookObReferenceObjectByHandle

void  HookObReferenceObjectByHandle()

{

//赋值前面定义的数组

KIRQL Irql;

// DbgPrint("[ObReferenceObjectByHandle] :%08x\n",ObReferenceObjectByHandle);  //地址验证

//保存函数前五个字节内容

RtlCopyMemory(OriginalBytes,(BYTE *)ObReferenceObjectByHandle,5);

//保存新函数五个字节之后偏移

*(ULONG *)(JmpAddress+1)=(ULONG)DetourMyObReferenceObjectByHandle-((ULONG)ObReferenceObjectByHandle+5);

//开始inline hook

__asm{//去掉内存保护

cli

mov eax,cr0

and eax,not 10000h

mov cr0,eax

}

//提升IRQL中断级

Irql=KeRaiseIrqlToDpcLevel();

//函数开头五个字节写JMP 

RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,JmpAddress,5);

//恢复Irql

KeLowerIrql(Irql);

//开启内存写保护

__asm{//恢复内存保护 

mov eax,cr0

or eax,10000h

mov cr0,eax

sti

}

}

_declspec (naked) NTSTATUS    OriginalObReferenceObjectByHandle(IN HANDLE  Handle,

IN ACCESS_MASK  DesiredAccess,

IN POBJECT_TYPE  ObjectType  OPTIONAL,

IN KPROCESSOR_MODE  AccessMode,

OUT PVOID  *Object,

OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL)

{

_asm

{

mov edi,edi

push ebp

mov ebp,esp

mov eax,ObReferenceObjectByHandle

add eax,5

jmp eax                

}

}

char* ProtectName = "notepad.exe";

NTSTATUS DetourMyObReferenceObjectByHandle(

IN HANDLE  Handle,

IN ACCESS_MASK  DesiredAccess,

IN POBJECT_TYPE  ObjectType  OPTIONAL,

IN KPROCESSOR_MODE  AccessMode,

OUT PVOID  *Object,

OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL)

{

/调用原函数

NTSTATUS   status;

status=OriginalObReferenceObjectByHandle(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation);

 if((NT_SUCCESS(status))&&(ObjectType== *PsProcessType))//NT_SUCCESS(status)一定跟在调用函数后面,不然也蓝。

//&&(status=STATUS_SUCCESS))使用蓝屏见图一反汇编代码,换成NT_SUCCESS(status)可以了,原因不知,—.—,太菜,结束进程记事本,出现应用程序出错,进程没结束,但会耗死CPU。

  {  

if( _stricmp((char *)((ULONG)(*Object)+0x174),ProtectName)==0)

{if(DesiredAccess==0x0002 )//0x2为创建,一开始使用#define PROCESS_CREATE_PROCESS    (0x0080) // winnt怎么都没用,后来换成#define PROCESS_CREATE_THREAD     (0x0002) // winnt就行

{

ObDereferenceObject(*Object);

return STATUS_INVALID_HANDLE;

}

  }

 }

 

return status;

}

void UnHookObReferenceObjectByHandle()

{

//把五个字节再写回到原函数

KIRQL Irql;

//关闭写保护

__asm{//去掉内存保护

cli

mov eax,cr0

and eax,not 10000h

mov cr0,eax

}

//提升IRQL到Dpc

Irql=KeRaiseIrqlToDpcLevel();

RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,OriginalBytes,5);

KeLowerIrql(Irql);

//开启写保护

__asm{//恢复内存保护 

mov eax,cr0

or eax,10000h

mov cr0,eax

sti

}

}

VOID OnUnload(    IN PDRIVER_OBJECT DriverObject    )

{

UnHookObReferenceObjectByHandle();

dprintf("[UnHookObReferenceObjectByHandle] Unloaded\n");

}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj,PUNICODE_STRING      pRegistryString)

{

pDriverObj->DriverUnload = OnUnload;

HookObReferenceObjectByHandle();

return STATUS_SUCCESS;

图一:

以下为别处原来代码的

代码
[转]详谈内核三步走Inline Hook实现
(一)Inline hook原理
Inline hook通俗的说就是对函数执行流程进行修改,达到控制函数过滤操作的目的。理论上我们可以在函数任何地方把原来指令替换成我们的跳转指令,也确实有些人在inline
的时候做的很深,来躲避inline 的检测,前提是必须对函数的流程和指令非常熟悉,且这种深层次的inlline 不具有通用性,稳定性也是问题。本文讨论的是具有通用性的两类inline的实现。
Inline hook原理:解析函数开头的几条指令,把他们Copy到数组保存起来,然后用一个调用我们的函数的几条指令来替换,如果要执行原函数,则在我们函数处理完毕,再执行我们保存起来的开头几条指令,然后调回我们取指令之后的地址执行。
整个Inline hook的过程就大体这样,中间牵扯到对函数的检查,地址的获取就直接调用函数即可。
本文所要讨论的两类Inline hook都是基于上面原理。 

说明三点:
1、堆栈平衡是重中之重,参数压栈也需要格外注意
2、CR0寄存器中的WP位控制处理器是否允许往只读内存页写入,为0禁用保护机制。
3、提高中断级别到DISPATCH_LEVEL,禁止线程切换产生的中断
                    �
(二)inline hook应用
Inline hook可分为两类:
1)inline 导出函数,选择ObReferenceObjectByHandle做例子。
2)inline 未导出函数,选择KiInsertQueueApc做例子。
导出函数前几个字节可以利用windbg自己查看是什么内容,而未导出函数就需要自己解析指令确定需要hook几个字节,其间还有很多问题需要注意。当大家真正的弄懂了我这篇文章,回头再看inline hook就会觉得inline也不过如此。
下面通过2个例子来讲inline hook的使用(这部分知识网上也有很多,但都很零散不系统,本文部分思路及代码的确参考了网上资源,有抄袭之嫌,希望读者谅解。我一直强调“授人以鱼不如授人以渔”,代码并不重要,关键是思想。)
1、inline hook ObReferenceObjectByHandle保护进程
ObReferenceObjectByHandle属于ntoskrnl.exe导出函数,在内核中调用频繁。
NtCreateProcess创建进程需要调用ObReferenceObjectByHandle,NtTerminateProcess需要调用ObReferenceObjectByHandle,基于这我们就可以利用Hook来保护进程同时屏蔽进程的创建。
效果:已经运行的记事本任务管理器无法结束
流程:
HookObReferenceObjectByHandle
------DetourMyObReferenceObjectByHa ndle----------UnHookObReferenceObjectByHandle
核心代码分析如下:
//=======================================inline HOOK ObReferenceObjectByHandle===========================

//ObReferenceObjectByHandle是ntoskrnl.exe导出函数,采用HOOK前五个字节的方式

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

extern POBJECT_TYPE *PsProcessType;

NTKERNELAPI NTSTATUS ObReferenceObjectByHandle(
                        �
                         IN HANDLE  Handle,
                         IN ACCESS_MASK  DesiredAccess,
                         IN POBJECT_TYPE  ObjectType  OPTIONAL,
                         IN KPROCESSOR_MODE  AccessMode,
                         OUT PVOID  *Object,
                         OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL
                        �
                         );

//HOOK函数

NTSTATUS DetourMyObReferenceObjectByHandle(
                      �
                       IN HANDLE  Handle,          �
                       IN ACCESS_MASK  DesiredAccess
                       IN POBJECT_TYPE  ObjectType  OPTIONAL,�
                       IN KPROCESSOR_MODE  AccessMode,
                       OUT PVOID  
*Object,
                       OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL);

//

//hook流程 HookObReferenceObjectByHandle---DetourMyObReferenceObjectByHandle---UnHookObReferenceObjectByHandle

void  HookObReferenceObjectByHandle()

{
 �
  //赋值前面定义的数组
  KIRQL Irql;
  KdPrint((
"[ObReferenceObjectByHandle] :0x%x",ObReferenceObjectByHandle));  //地址验证
  
//保存函数前五个字节内容
  RtlCopyMemory(OriginalBytes,(BYTE *)ObReferenceObjectByHandle,5);
  
//保存新函数五个字节之后偏移
  *(ULONG *)(JmpAddress+1)=(ULONG)DetourMyObReferenceObjectByHandle-((ULONG)ObReferenceObjectByHandle+5);
  
//开始inline hook
  
//关闭内存写保护
  _asm
   �
  {
    push eax
     �
      mov eax, cr0�
      mov CR0VALUE, eax�
      and eax, 0fffeffffh �
      mov cr0, eax
      pop eax
  }
 �
  
//提升IRQL中断级
  Irql=KeRaiseIrqlToDpcLevel();
  
//函数开头五个字节写JMP�
  RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,JmpAddress,5);
  
//恢复Irql
  KeLowerIrql(Irql);
  
//开启内存写保护
 �
  __asm
   �
  {      �
   �
    push eax
     �
      mov eax, CR0VALUE�
     �
      mov cr0, eax
     �
      pop eax
     �
  }
 �
}

_declspec (naked) NTSTATUS OriginalObReferenceObjectByHandle(IN HANDLE  Handle,
                              �
                               IN ACCESS_MASK  DesiredAccess,
                              �
                               IN POBJECT_TYPE  ObjectType  OPTIONAL,
                              �
                               IN KPROCESSOR_MODE  AccessMode,
                              �
                               OUT PVOID  *Object,
                              �
                               OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL)
                              �
{
 �
  _asm
   �
  {  �
   �
    mov edi,edi
      push ebp
      mov ebp,esp
      mov eax,ObReferenceObjectByHandle
      add eax,
5
      jmp eax               �
     �
  }
 �
}

NTSTATUS DetourMyObReferenceObjectByHandle(
                      �
                       IN HANDLE  Handle,
                      �
                       IN ACCESS_MASK  DesiredAccess,
                      �
                       IN POBJECT_TYPE  ObjectType  OPTIONAL,
                 �
                       IN KPROCESSOR_MODE  AccessMode,
                      �
                       OUT PVOID  *Object,
                      �
                       OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL)
                      �
{
 �
  NTSTATUS status;
 �
  
//调用原函数
 �
  status
=OriginalObReferenceObjectByHandle(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation);
 �
  
if((status==STATUS_SUCCESS)&&(DesiredAccess==1))//这样写在我机器出蓝屏,虚拟机也一样蓝,,看来要学的挺多的
   �
  {  �
   �
    
if(ObjectType== *PsProcessType)
     �
    {
     �
      
if( _stricmp((char *)((ULONG)(*Object)+0x174),"notepad.exe")==0)
       �
      {  �
       �
        ObDereferenceObject(
*Object);
       �
        
return STATUS_INVALID_HANDLE;
       �
      }
     �
    }
   �
  }
 �
  
return status;
 �
}

void UnHookObReferenceObjectByHandle()

{
 �
  //把五个字节再写回到原函数
 �
  KIRQL Irql;
 �
    
//关闭写保护
 �
  _asm
   �
  {
   �
    push eax
     �
      mov eax, cr0�
     �
      mov CR0VALUE, eax�
     �
      and eax, 0fffeffffh �
     �
      mov cr0, eax
     �
      pop eax
     �
  }
 �
    
//提升IRQL到Dpc
 �
    Irql
=KeRaiseIrqlToDpcLevel();
 �
  RtlCopyMemory((BYTE 
*)ObReferenceObjectByHandle,OriginalBytes,5);
 �
  KeLowerIrql(Irql);
 �
    
//开启写保护
 �
  __asm
   �
  {      �
   �
        push eax
      mov eax, CR0VALUE�
      mov cr0, eax
     �
      pop eax
     �
  }
}

驱动加载后,结束记事本程序如下:

    (图 一)

详细分析:
1、ObReferenceObjectByHandle分析
NTSTATUS�
  ObReferenceObjectByHandle(
    IN HANDLE  Handle,
    IN ACCESS_MASK  DesiredAccess,
    IN POBJECT_TYPE  ObjectType  OPTIONAL,
    IN KPROCESSOR_MODE  AccessMode,
    OUT PVOID  
*Object,
    OUT POBJECT_HANDLE_INFORMATION  HandleInformation  OPTIONAL
    );
函数原型如上,由句柄获取对象指针,函数返回值:
STATUS_SUCCESS                        调用成功
STATUS_OBJECT_TYPE_MISMATCH       �
STATUS_ACCESS_DENIED                 权限不够
STATUS_INVALID_HANDLE                无效句

抱歉!评论已关闭.