Hook IofCallDriver 代码收集

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写可以写得好漂亮的.

 

简单防止删除文件和创建文件

 

   就是HOOK IofCallDriver.....不过只是闹着完..冰刃可以直接删除.但对付RING 3的一些病毒还是可以的....文件驱动刚学一俩天,感觉难死了,很多东西,监控指定路径老做不出....所以基本把整个C盘都防止创建文件了..防止重写文件,....应该可以防止病毒感染吧....不过偶尔蓝屏..晕...接下来努力学习........菜啊

#include "ntifs.h"
typedef NTSTATUS (FASTCALL*MyIofCallDriver)(
                  IN PDEVICE_OBJECT DeviceObject,
                  IN OUT PIRP Irp);

MyIofCallDriver old_piofcalldriver;

ULONG OldCR0;

NTSTATUS Filter_IRP_MJ_CREATE(IN PIRP Irp, IN PDEVICE_OBJECT DeviceObject)
{
NTSTATUS stat;
PIO_STACK_LOCATION pStackLocation;
PFILE_OBJECT pFileObject = NULL;
PDRIVER_OBJECT pDriverObject ;
WCHAR      *pstr = NULL;
POBJECT_NAME_INFORMATION      fileNameInformation;
NTSTATUS                    status;
ULONG      retSize,CreateDisposition;
UNICODE_STRING testmyProtectPath;

RtlInitUnicodeString(&testmyProtectPath,L"http://www.cnblogs.com/Safe3/admin/file://device//HarddiskVolume1");

pStackLocation=IoGetNextIrpStackLocation(Irp);

pFileObject=pStackLocation->FileObject;

pDriverObject=DeviceObject->DriverObject;

fileNameInformation = ExAllocatePool(NonPagedPool, 1024);

__try
{

    pstr = wcsrchr(pDriverObject->DriverName.Buffer, L'\\');
   
    pstr ++;

    if (_wcsnicmp(pstr, L"ntfs", 4) && _wcsnicmp(pstr, L"fastfat", 7))
    {
        goto pass;
    }


status = ObQueryNameString(pFileObject, fileNameInformation, 1024, &retSize);

if(! NT_SUCCESS(status) )
{
    DbgPrint("ObQueryNameString failed %d \n", status);
}


//wcscat(fileNameInformation->Name.Buffer,pFileObject->FileName.Buffer);
//DbgPrint("file name now is: %ws \n", fileNameInformation->Name.Buffer);

if(!_wcsnicmp(fileNameInformation->Name.Buffer, testmyProtectPath.Buffer,testmyProtectPath.Length))
{

CreateDisposition = (pStackLocation->Parameters.Create.Options>> 24) & 0x000000ff;
    if((CreateDisposition==FILE_CREATE)||(CreateDisposition==FILE_OPEN_IF )
    ||(CreateDisposition==FILE_OVERWRITE_IF))
{

Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);
ExFreePool(fileNameInformation);
return STATUS_ACCESS_DENIED;
}
}

   }

__except(1)
{
    goto pass;
}


pass:
__asm
{
mov ecx,DeviceObject
mov edx,Irp
Call old_piofcalldriver
mov stat,eax
}

}


NTSTATUS FASTCALL NewpIofCallDriver(
        IN PDEVICE_OBJECT DeviceObject,
        IN OUT PIRP Irp
)
{

NTSTATUS stat;
PIO_STACK_LOCATION pStackLocation;
pStackLocation=IoGetNextIrpStackLocation(Irp);
switch(pStackLocation->MajorFunction)
{

case IRP_MJ_SET_INFORMATION: break;

case IRP_MJ_CREATE: Filter_IRP_MJ_CREATE(Irp,DeviceObject); break;

default:
{
    __asm
{
mov ecx,DeviceObject
mov edx,Irp
Call old_piofcalldriver
mov stat,eax
}
return stat;
}

}

return STATUS_SUCCESS;

}


void UnHookIofCallDriver()
{
KIRQL oldIrql;
ULONG addr = (ULONG)IofCallDriver;

oldIrql = KeRaiseIrqlToDpcLevel();
__asm
{
   mov eax,cr0
   mov OldCR0,eax
   and eax,0xffffffff
   mov cr0,eax
  
   mov eax,addr
   mov esi,[eax+2]
   mov eax,old_piofcalldriver
   mov dword ptr [esi],eax
  
   mov eax,OldCR0
   mov cr0,eax
}
KeLowerIrql(oldIrql);
return ;
}

VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
   UnHookIofCallDriver();

}



void InlineHook_IofCallDriver()
{
KIRQL oldIrql;
ULONG addr = (ULONG)IofCallDriver;
__asm
{
   mov eax,addr
   mov esi,[eax+2]
   mov eax,[esi]
   mov old_piofcalldriver,eax
}
oldIrql = KeRaiseIrqlToDpcLevel();

__asm
{
   mov eax,cr0
   mov OldCR0,eax
   and eax,0xffffffff
   mov cr0,eax
  
   mov eax,addr
   mov esi,[eax+2]
   mov dword ptr [esi],offset NewpIofCallDriver
  
   mov eax,OldCR0
   mov cr0,eax
}
KeLowerIrql(oldIrql);
return ;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{

     DriverObject->DriverUnload=Unload;
     InlineHook_IofCallDriver();
     return STATUS_SUCCESS;
}

 

posted @ 2009-06-24 13:04  有安科技  阅读(1283)  评论(0编辑  收藏  举报