调试某驱动


写个驱动,观察某驱动的运行,学学驱动而已。先注册映像加载通知例程。

PsSetLoadImageNotifyRoutine(LoadImageNotify);

代码:
VOID LoadImageNotify (
  PUNICODE_STRING FullImageName, 
  HANDLE ProcessId, 
  PIMAGE_INFO ImageInfo
  )
{
  ANSI_STRING  asImageName;
  PCHAR    Delimiter;
  NTSTATUS  Status;
  ULONG    Base;
  ULONG    Entry;
  ULONG    Patch;
  ULONG    i;
  
  
  RtlUnicodeStringToAnsiString(&asImageName, FullImageName, TRUE);
  
  if (!ImageInfo->SystemModeImage)
  {
    goto __End; //不是驱动
  }
  
  Delimiter = strrchr(asImageName.Buffer, '\\');
  if (Delimiter == NULL)
    goto __End;
  
  Delimiter++;
  
  if( _strnicmp(Delimiter,"xxx.sys",strlen("xxx.sys")) != 0)
    goto __End;

  Base = (ULONG)ImageInfo->ImageBase;
        
  DbgPrint("%s Loaded, MappingAddress=%08X, Size=%08X\n",
     asImageName.Buffer,
     ImageInfo->ImageBase,
     ImageInfo->ImageSize );
  

  //这里地址直接硬编码了,可以分析PE文件及使用反汇编引擎(原代码的地址删了,表找我麻烦)

  // 原驱动DriverEntry出口:
  //   leave
  //   retn    8
  //   
  //   

  Entry = Base + 0x1111;
  Patch = Base + 0x2222;
  g_ReturnAddress = Base + 0x3333;

  if (!(*(PULONG)Entry == 0x83EC8B55 &&  *(PUCHAR)(Entry+5) == 0x14)) //检查Entry
  {
    DbgPrint("Mismatched Entry!\n");
    goto __End;
  }

  if (*(PULONG)Patch != 0x0008C2C9)
  {
    DbgPrint("Mismatched Patch Point!\n");
    goto __End;
  }

  __asm
  {
    CLI
    MOV   EAX, CR0
    AND   EAX, NOT 10000H  //disable WP bit
    MOV   CR0, EAX
  }

  *(PUCHAR)Entry = 0xE9;
  *(PULONG)(Entry+1) = (ULONG)&SaveDriverObject - (Entry+5);

  *(PUCHAR)Patch = 0xE9;
  *(PULONG)(Patch+1) = (ULONG)&ReplaceDispatch - (Patch+5);
  

  __asm
  {
    MOV   EAX, CR0
    OR    EAX, 10000H  //enable WP bit
    MOV   CR0, EAX
    STI
  }
  
__End:
  RtlFreeAnsiString(&asImageName);
}
这个函数Patch原驱动2处:

原驱动的DriverEntry入口,目的是获取参数DriverObject,因为编译器的优化,在DriverEntry
执行过程中这个参数被清0了, 所以先保存一份。

第2是DriverEntry的出口,在这里替换DriverObject内注册的派遣函数。

代码:
VOID __declspec (naked) SaveDriverObject()
{
  // 55               push    ebp
  // 8B EC            mov     ebp, esp
  // 83 EC 14         sub     esp, 14h

  __asm {
    pushad
    mov  eax, [esp+20h+4]
    mov  g_DrvObj, eax
    popad

    push ebp ; 原代码
    mov  ebp, esp
    sub  esp, 14h

    jmp  [g_ReturnAddress]
  }
}


VOID __declspec (naked) ReplaceDispatch()
{
  __asm {
    pushad
    
    mov  eax, g_DrvObj  

    mov  ecx, [eax+18h]  ; DriverExtension
    
      
    mov  ebx, [eax+34h]  ; Unload
    mov  g_Unload, ebx
    mov  ebx, MyUnload
    mov  [eax+34h], ebx
    
    mov  ebx, [eax+38h]
    mov  g_Create, ebx
    mov  ebx, MyCreateCloseCleanup
    mov  [eax+38h], ebx  ; Create
    mov  [eax+40h], ebx  ; Close
    mov  [eax+80h], ebx  ; CleanUp
      
    mov  ebx, [eax+70h]
    mov  g_DeviceControl, ebx
    mov  ebx, MyDeviceControl
    mov  [eax+70h], ebx
    
    popad

    //执行原出口代码

    __emit 0xC9 //VC6的汇编不支持leave
    retn  8
  }
}
然后,可以挂上自己的代码,开始只要PassThru就行:

代码:
VOID MyUnload( PDRIVER_OBJECT DriverObject )
{
  DbgPrint("MyUnload\n");
  ((PDRIVER_UNLOAD)g_Unload)(DriverObject);
  return;
}


NTSTATUS MyCreateCloseCleanup( PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
  DbgPrint("MyCreateCloseCleanup\n");
  return ((PDRIVER_DISPATCH)g_Create)(DeviceObject, Irp);
}


NTSTATUS MyDeviceControl( PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
  PIO_STACK_LOCATION  irpSp;
  PVOID            inputBuff, outputBuff;
      ULONG            inputLen, outputLen, ctlCode;
  NTSTATUS          Status = STATUS_UNSUCCESSFUL;
    

  irpSp = IoGetCurrentIrpStackLocation(Irp);

  // Buffered io

  inputBuff  = Irp->AssociatedIrp.SystemBuffer;
      outputBuff = Irp->AssociatedIrp.SystemBuffer;
  inputLen   = irpSp->Parameters.DeviceIoControl.InputBufferLength;
      outputLen  = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  ctlCode    = irpSp->Parameters.DeviceIoControl.IoControlCode;

  switch (ctlCode)
  {
  case IOCTL_INIT:
      //逆的代码...
      break;

  default:
      DbgPrint("DeviceControl : Not Implemented IOCTL=%08X\n", ctlCode);
      return ((PDRIVER_DISPATCH)g_DeviceControl)(DeviceObject, Irp);
      break;
  }

__End:
  Irp->IoStatus.Information = outputLen;
  Irp->IoStatus.Status = Status;
      IoCompleteRequest (Irp, IO_NO_INCREMENT);
  return Status;
}
然后,就没什么了。逆IOCTL处理代码,逐个替换。换完了,就不要这个Hook版本了,自己
实现一个完整的,当然只实现功能部分,保护的代码就不要了。加载自己的驱动站住坑,
想干啥干啥吧。

  • 标 题:答复
  • 作 者:Bughoho
  • 时 间:2008-08-27 20:55

IRP Hook