Inline Hook IofCallDriver 截获所有IRP

Inline Hook IofCallDriver 截获所有IRP 

首先声明这个是菜鸟我的学习日记,不是什么高深文章,高手们慎看.

前段时间搞了一些Inline HOOK APIdemo,例如对NtQueryDirectoryFile Inline HOOK 进行文件的隐藏,(恰好NtQueryDirectoryFile SSDT有导出,也可以采用改SSDT来实现HOOK.,只不过Inline HOOK 隐蔽性好点).NtQueryDirectoryFile是调用IofCallDriver(我猜的),那么HOOK IofCallDriver过滤掉关于MajorFunction == IRP_MJ_QUERY_INFORMATIONIO包就应该能隐藏文件的(我猜的,到底是不是这个MajorFunction,不知道),一开始就说明了我是个菜鸟,所以怎么过滤掉特定的IO包没写出来,只写了HOOK IofCallDriver的方法.流氓作者们有本事你就A,能A是你们的本事,反正我不怕流氓.

因为在SSDT里面是不存在这个函数的,那么就要Inline HOOK IofCallDriver, 我上网找了好久都没有现成的代码(或许是我愚笨找不到),So自己动手.

这里说明一下IoCallDriver不是函数,是一个宏指向IofCallDriver.恰好IofCallDriver已经导出,我们不用MmGetSystemRoutineAddress来去IofCallDriver的地址了.

要用WinDbg来看下IofCallDriver的入口是什么东西:

由于微软对单核和多核的CPU编写了不同的内核, ntoskrnl.exe用于单核CPU的机器,而ntkrnlpa.exe则为多核,由于我的VPC是虚拟出单核的,所以本文主要围绕ntoskrnl.exe的IofCallDriver来写.(如果现实中的机器有两台就好了,可以调试ntkrnlpa.exe的IofCallDriver.)

    

The beginning of the IofCallDriver function

     ---------------------------------------------------------------------------------------

     nt!IoCallDriver: if ntoskrnl.exe

     804e47c5 ff2500395580    jmp     dword ptr [nt!KeTickCount+0x1480 (80553900)]<-Detour here

     804e47cb 90              nop

     804e47cc 90              nop

     804e47cd 90              nop

     804e47ce 90              nop

     804e47cf 90              nop

     804e47d0 fe4a23          dec     byte ptr [edx+23h]     I try to detour here yet,and work.

     804e47d3 8a4223          mov     al,byte ptr [edx+23h]  But I think is not well.

     804e47d6 84c0            test    al,al

     804e47d8 0f8e40840300    jle     nt!IoSetFileOrigin+0x3ce2 (8051cc1e)

     804e47de 8b4260          mov     eax,dword ptr [edx+60h]

     804e47e1 83e824          sub     eax,24h

     804e47e4 56              push    esi

     804e47e5 894260          mov     dword ptr [edx+60h],eax

     804e47e8 894814          mov     dword ptr [eax+14h],ecx

     804e47eb 0fb600          movzx   eax,byte ptr [eax]

     804e47ee 8b7108          mov     esi,dword ptr [ecx+8]

     804e47f1 52              push    edx

     804e47f2 51              push    ecx

     804e47f3 ff548638        call    dword ptr [esi+eax*4+38h]

     ---------------------------------------------------------------------------------------

     nt!IofCallDriver: if ntkrnlpa.exe

     804ef09c ff2580475580    jmp     dword ptr [nt!KeTickCount+0x1780 (80554780)]<-Detour here

     804ef0a2 cc              int     3

     804ef0a3 cc              int     3

     804ef0a4 cc              int     3

     804ef0a5 cc              int     3

     804ef0a6 cc              int     3

     804ef0a7 cc              int     3

 

这里要用WinDbg来跟踪IofCallDriver的走向,我也是刚刚学会这么做,不会的朋友可以参考 使用VPC进行Windows内核调试这篇文章,在这里

804e47c5 ff2500395580    jmp     dword ptr [nt!KeTickCount+0x1480 (80553900)]

设置断点,并单步跟进,这时发现运行流程是这样的:

V--  804e47c5 ff2500395580    jmp     dword ptr [nt!KeTickCount+0x1480 (80553900)]

|    804e47cb 90              nop

|    804e47cc 90              nop

|    804e47cd 90              nop

|    804e47ce 90              nop

|    804e47cf 90              nop

-->  804e47d0 fe4a23          dec     byte ptr [edx+23h]

     804e47d3 8a4223          mov     al,byte ptr [edx+23h]

     804e47d6 84c0            test    al,al

     804e47d8 0f8e40840300    jle     nt!IoSetFileOrigin+0x3ce2 (8051cc1e)

     804e47de 8b4260          mov     eax,dword ptr [edx+60h]

我尝试过两种做法都可行,这里假设0xFFFFFFFF是自己函数的地址(最后给出的代码将会实现第二种做法):

l          804e47d0 fe4a23          dec     byte ptr [edx+23h]

     804e47d3 8a4223          mov     al,byte ptr [edx+23h]

     804e47d6 84c0            test    al,al

     改成: 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x00, 0x90 刚好8个字节

l          804e47c5 ff2500395580    jmp     dword ptr [nt!KeTickCount+0x1480 (80553900)]

804e47cb 90              nop

改成:0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x00 刚好7个字节

然后在自己的函数中回跳到 804e47d7 或 804e47cc :

_emit 0xEA

_emit 0xd7 or cc

_emit 0x47

_emit 0x4e

_emit 0x80

_emit 0x80

_emit 0x00

,至此思路和原理已经有了,下面是实现Inline Hook IofCallDriver的代码(实现上面第二种方法)

inline_hook_IofCallDriver.c///

#include <ntddk.h>

 

#define SystemModuleInformation 11

 

typedef struct _SYSTEM_MODULE_INFORMATION {//Information Class 11

     ULONG    Reserved[2];

     PVOID    Base;

     ULONG    Size;

     ULONG    Flags;

     USHORT   Index;

     USHORT   Unknown;

     USHORT   LoadCount;

     USHORT   ModuleNameOffset;

     CHAR ImageName[256];

} SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION;

 

typedef struct _MODULES{

     ULONG                            dwNumberOfModules;

     SYSTEM_MODULE_INFORMATION   smi;

} MODULES, *PMODULES;

 

NTSYSAPI

NTSTATUS

NTAPI

NtQuerySystemInformation(

     IN ULONG SysInfoClass,

     IN OUT PVOID SystemInformation,

     IN ULONG SystemInformationLength,

     OUT PULONG RetLen

     );

 

ULONG nCountCPU;

PDEVICE_OBJECT _DeviceObject;

PIRP _Irp;

PIO_STACK_LOCATION _Iosl;

ANSI_STRING Ansi;

 

// assembles to jmp far 0008:FFFFFFFF where FFFFFFFF is address of

// our detour function, plus one NOP to align up the patch

char DetourCode[] = { 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x00 };

char BackupCode[] = { 0xFF, 0x25, 0x00, 0x39, 0x55, 0x80, 0x90 };

 

__declspec(naked) NTSTATUS __fastcall

Detour_IofCallDriver(IN PDEVICE_OBJECT DeviceObject,

                        IN OUT PIRP Irp)

{

     __asm

     {

         pushad

         pushfd

     }

 

     __asm

     {

         push ecx

         pop dword ptr _DeviceObject

         push edx

         pop dword ptr _Irp

     }

 

     _Iosl = IoGetNextIrpStackLocation(_Irp);

     RtlUnicodeStringToAnsiString(&Ansi,&_DeviceObject->DriverObject->DriverName,TRUE);

     DbgPrint("Irp: 0x%02X - Driver: %s/n", _Iosl->MajorFunction, Ansi.Buffer);

     RtlFreeAnsiString(&Ansi);

 

     __asm

     {

         popfd

         popad

     }

 

     __asm

     {

         cmp nCountCPU, 2

         jae MoreCPU

         // jmp FAR 0x08:FFFFFFFF

         _emit 0xEA

         _emit 0xFF

         _emit 0xFF

         _emit 0xFF

         _emit 0xFF

         _emit 0x08

         _emit 0x00

MoreCPU:

         // 由于不会调试,所以ntkrnlpa.exe的IofCallDriver的hook就放在这里先啦

         _emit 0xEA

         _emit 0xFF

         _emit 0xFF

         _emit 0xFF

         _emit 0xFF

         _emit 0x08

         _emit 0x00

     }

}

 

VOID InterruptEnable()

{

     __asm

     {

         MOV EAX, CR0  //move CR0 register into EAX

         OR EAX, 10000H     //enable WP bit

         MOV CR0, EAX  //write register back

         STI                //enable interrupt

     }

}

 

VOID InterruptDisable()

{

     __asm

     {

         CLI                    //dissable interrupt

         MOV EAX, CR0       //move CR0 register into EAX

         AND EAX, NOT 10000H    //disable WP bit

         MOV CR0, EAX       //write register back

     }

}

 

NTSTATUS DetourFunctionIofCallDriver()

{

     int i = 0;

     MODULES pModules;

     //Get kernel filename,ntoskrnl.exe if single CPU,else ntkrnlpa.exe

     NtQuerySystemInformation(SystemModuleInformation, &pModules, sizeof(MODULES), NULL);

     if(memcmp(pModules.smi.ModuleNameOffset+pModules.smi.ImageName, "ntoskrnl.exe", sizeof("ntoskrnl.exe")) == 0)

         nCountCPU = 1;

     else if(memcmp(pModules.smi.ModuleNameOffset+pModules.smi.ImageName, "ntkrnlpa.exe", sizeof("ntkrnlpa.exe")) == 0)

         nCountCPU = 2;

     else return STATUS_UNSUCCESSFUL;

 

     // now, stamp in the return jmp into our detour function

     while(++i)

     {

         // we found the address 0xFFFFFFFF stamp it w/ the correct address

         if(!memcmp((unsigned char *)Detour_IofCallDriver + i, &DetourCode[1], 4))

         {

              *( (unsigned long *)((unsigned char *)Detour_IofCallDriver + i) ) = (unsigned long)IofCallDriver + 0x0B;

              break;

         }

     }

 

     // stamp in the target address of the far jmp

     *( (unsigned long *)(&DetourCode[1]) ) = (unsigned long)Detour_IofCallDriver;

 

     //overwrite the bytes in the kernel function

     //to apply the detour jmp

     InterruptDisable();

     memcpy(BackupCode, IofCallDriver, 7);

     memcpy(IofCallDriver, DetourCode, 7);

     InterruptEnable();

     return STATUS_SUCCESS;

}

 

VOID UnDetourFunctionIofCallDriver()

{

     //recovery kernel function

     InterruptDisable();

     memcpy(IofCallDriver, BackupCode, 7);

     InterruptEnable();

}

 

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )

{

    UnDetourFunctionIofCallDriver();

}

 

NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )

{

     DriverObject->DriverUnload = OnUnload;

    if(STATUS_SUCCESS != DetourFunctionIofCallDriver())

     {

        DbgPrint("Detour Failure on IofCallDriver!/n");

        return STATUS_UNSUCCESSFUL;

    }   

    else return STATUS_SUCCESS;

}

         至此,文章都写完了,其实都没什么高深的知识,只是我觉得难而已^_^.hook这个函数的过程中遇到了好多困难,也去提过问题,这里要感谢hopy大哥.也参考了一些文章,例如: “IRP 乱杂谈”“【原创】从内核层保护文件不被删除- 看雪软件安全论坛”“使用VPC进行Windows内核调试”“天书夜读(完整版)”.非常感谢作者们的技术共享精神,同时我也鄙视那些怕人A你代码而不公开代码的人,技术不共享是不能进步的,同时就算有流氓利用的话,杀软的查杀也会进步的,相反没公开的技术被小部分人利用,后果好恐怖.

原来用Word 写可以写得好漂亮的.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值