现在的位置: 首页 > 综合 > 正文

SERVICE_BOOT_START 驱动程序逆向

2013年11月01日 ⁄ 综合 ⁄ 共 15832字 ⁄ 字号 评论关闭
 今天发现了 syser debugger  的 SDbgMsg.sys。 这个驱动程序就是SERVICE_BOOT_START  类型的驱动程序, 在windows 启动后最新给出提示信息 "Press "ESC" to Cancel Load Syser Boot  Module ",我想看看到底是怎样编程实现的:

打开 IDA 载入 SDbgMsg.sys 程序, 反汇编代码如下:


; int __stdcall start(PDEVICE_OBJECT DeviceObject)
public start
start           proc near

SymbolicLinkName    = UNICODE_STRING ptr -18h
DeviceName              = UNICODE_STRING ptr -10h
SystemRoutineName = UNICODE_STRING ptr -8
DeviceObject             = dword ptr  8       

.text:00010850 push    ebp             
.text:00010851 mov     ebp, esp                  ; 打开栈帧

 

.text:00010853 sub       esp, 18h
.text:00010856 push     ebx
.text:00010857 push     esi
.text:00010858 mov      esi, [ebp+DeviceObject]
.text:0001085B push    edi
.text:0001085C push    1Bh
.text:0001085E lea       edx, [esi+38h]
.text:00010861 pop      ecx                         ; 给ecx赋值 1Bh
.text:00010862 mov     eax, offset loc_10428
.text:00010867 mov     edi, edx
.text:00010869 rep stosd

上面的反汇编代码可能有问题, DeviceObject 应该是 DirverObject。如果是 DeviceObject ,那偏移 38H 位置是
DeviceObject->Queue.Blink 或者是 DeviceObject->Queue.Wcb.WaitQueueEntry.Blink 。我想不出 DeviceObject 的这些成员怎么使用。一般情况下程序开始时就是设置 Dispatch 例程, 而 DriverObject 的 Dispatch 例程就是在 38H 偏移位置, 所以我可以认为这里的 DeviceObject 就是 DriverObject。
可见 loc_10428 例程就是通用的派遣例程.

下面是DeviceObject 的偏移为38H 位置的结构图
       下面是 DriverObject 偏移为 38H 位置的结构图


.text:0001086B mov     edi, ds:RtlInitUnicodeString
.text:00010871 push    offset aDeviceSyserdbg ;          "
//Device//SyserDbgMsg"
.text:00010876 lea       eax, [ebp+DeviceName]
.text:00010879 push    eax             ; DestinationString

; 设置 DirverObject->DriverUnload = sub_10702
.text:0001087A mov     dword ptr [esi+34h], offset sub_10702

; 设置 DirverObject->MajorFunction[IRP_MJ_CREATE] = loc_103DC
.text:00010881 mov     dword ptr [edx], offset loc_103DC    

; 设置 DirverObject->MajorFunction[IRP_MJ_READ] = sub_10646
.text:00010887 mov     dword ptr [esi+44h], offset sub_10646

; 设置 DirverObject->MajorFunction[IRP_MJ_CLOSE] = loc_103F8
.text:0001088E mov     dword ptr [esi+40h], offset loc_103F8

; 设置 DirverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = loc_10442
.text:00010895 mov     dword ptr [esi+70h], offset loc_10442

.text:0001089C call    edi ; RtlInitUnicodeString

.text:0001089E                 lea       eax, [ebp+DeviceObject]
.text:000108A1                 push    eax             ; DeviceObject
.text:000108A2                 xor      ebx, ebx
.text:000108A4                 push    ebx             ; Exclusive
.text:000108A5                 push    ebx             ; DeviceCharacteristics
.text:000108A6                 push    22h             ; DeviceType
.text:000108A8                 lea       eax, [ebp+DeviceName]
.text:000108AB                 push    eax             ; DeviceName
.text:000108AC                 push    ebx             ; DeviceExtensionSize
.text:000108AD                 push    esi             ; DriverObject
.text:000108AE                 call     ds:IoCreateDevice

.text:000108B4                 test      eax, eax
.text:000108B6                 jl          short loc_108E6
.text:000108B8                 mov      eax, 2000h
.text:000108BD                 push    eax             ; BugCheckParameter1
.text:000108BE                 mov     dword_1221C, eax
.text:000108C3                 mov     dword_12220, ebx
.text:000108C9                 call      sub_10FD6
.text:000108CE                 cmp     eax, ebx
.text:000108D0                 pop      ecx
.text:000108D1                 mov     dword_12224, eax
.text:000108D6                 jnz       short loc_108F0
.text:000108D8                 push    [ebp+DeviceObject] ; DeviceObject
.text:000108DB                 call     ds:IoDeleteDevice

NTSTATUS NtStatus= IoCreateDevice( esi, 
      0,
      "
//Device//SyserDbgMsg",  // UNICODE_STRING 类型的变量
      22h,                                   // FILE_DEVICE_UNKNOWN 
      0,
      0,
      DeviceObject );
if (STATUS_SUCCESS != NtStatus)
{
   退出; 
}

sub_10FD6 ( , 2000h);

.text:000108F0                 mov     eax, [ebp+DeviceObject]
.text:000108F3                 or        dword ptr [eax+1Ch], 4
.text:000108F7                 mov     eax, [ebp+DeviceObject]
.text:000108FA                 and      byte ptr [eax+1Ch], 7Fh
.text:000108FE                 push    offset a??Syserdbgms_0 ; "
//??//SyserDbgMsg"
.text:00010903                 lea        eax, [ebp+SymbolicLinkName]
.text:00010906                 push     eax             ; DestinationString
.text:00010907                 call       edi ; RtlInitUnicodeString
.text:00010909                 lea        eax, [ebp+DeviceName]
.text:0001090C                 push    eax             ; DeviceName
.text:0001090D                 lea       eax, [ebp+SymbolicLinkName]
.text:00010910                 push    eax             ; SymbolicLinkName
.text:00010911                 call      ds:IoCreateSymbolicLink
.text:00010917                 push    offset SpinLock ; SpinLock
.text:0001091C                 call     ds:KeInitializeSpinLock

RtlInitUnicodeString (SymbolicLinkName , L"//??//SyserDbgMsg");

// SymbolicLinkName: "//??//SyserDbgMsg"
// DeviceName:       "
//Device//SyserDbgMsg"
IoCreateSymbolicLink( SymbolicLinkName , DeviceName) ;

.text:00010938                 push    offset aDbgsetdebugpri ; "DbgSetDebugPrintCallback"
.text:0001093D                 lea      eax, [ebp+SystemRoutineName]
.text:00010940                 push    eax             ; DestinationString
.text:00010941                 call      edi ; RtlInitUnicodeString
.text:00010943                 mov     esi, ds:MmGetSystemRoutineAddress
.text:00010949                 lea       eax, [ebp+SystemRoutineName]
.text:0001094C                 push    eax             ; SystemRoutineName
.text:0001094D                 call      esi ; MmGetSystemRoutineAddress
.text:0001094F                 cmp     eax, ebx
.text:00010951                 mov      dword_12000, eax
.text:00010956                 jz         short loc_109A3
.text:00010958                 push    1
.text:0001095A                 push    offset sub_10D8A
.text:0001095F                 call      eax
.text:00010961                 test      eax, eax
.text:00010963                 jl          short loc_109A3
.text:00010965                 push     offset aDbgsetdebugfil ; "DbgSetDebugFilterState"
.text:0001096A                 lea       eax, [ebp+SystemRoutineName]
.text:0001096D                 push    eax             ; DestinationString
.text:0001096E                 mov     byte_11FFC, 1
.text:00010975                 call      edi ; RtlInitUnicodeString
.text:00010977                 lea       eax, [ebp+SystemRoutineName]
.text:0001097A                 push    eax             ; SystemRoutineName
.text:0001097B                 call      esi ; MmGetSystemRoutineAddress
.text:0001097D                 cmp     eax, ebx
.text:0001097F                 mov     dword_12004, eax
.text:00010984                 jz        short loc_109A3
.text:00010986                 xor      edi, edi

RtlInitUnicodeString (uniSystemRoutineName, L"DbgSetDebugPrintCallback");
dword_12000 = MmGetSystemRoutineAddress(uniSystemRoutineName);

RtlInitUnicodeString (uniSystemRoutineName, L"DbgSetDebugFilterState");
dword_12004 = MmGetSystemRoutineAddress(uniSystemRoutineName);

if ( (dword_12000 == NULL) && (dword_12004 == NULL) )
{

.text:000109AB                 push    ebx             ; DeferredContext
.text:000109AC                 push    offset DeferredRoutine ; DeferredRoutine
.text:000109B1                 mov     edi, offset Dpc
.text:000109B6                 push    edi             ; Dpc
.text:000109B7                 call      ds:KeInitializeDpc
.text:000109BD                 mov     esi, offset unk_11FB0
.text:000109C2                 push    esi             ; Timer
.text:000109C3                 call      ds:KeInitializeTimer
.text:000109C9                 push    edi             ; Dpc
.text:000109CA                 push    3E8h            ; Period
.text:000109CF                 or        ecx, 0FFFFFFFFh
.text:000109D2                 push    ecx
.text:000109D3                 mov     eax, 0FF676980h
.text:000109D8                 push    eax             ; DueTime
.text:000109D9                 push    esi             ; Timer
.text:000109DA                 call     ds:KeSetTimerEx
.text:000109E0                 jmp     short loc_109F3

DeferredContext = 0;
KTIMER  g_Timer ;

KeInitializeDpc( &g_Dpc , DeferredRoutine, 0);

KeInitializeTimer(  &g_Timer );

KeSetTimerEx( &g_Timer, 0FF676980h, 3E8h, &g_Dpc );

.text:000109F3 loc_109F3:                              ; CODE XREF: start+159j
.text:000109F3                                         ; start+190j
.text:000109F3                 xor     eax, eax
.text:000109F5
.text:000109F5 loc_109F5:                              ; CODE XREF: start+9Bj
.text:000109F5                 pop     edi
.text:000109F6                 pop     esi
.text:000109F7                 pop     ebx
.text:000109F8                 leave
.text:000109F9                 retn    8
.text:000109F9 start          endp

程序结束
}

下面是关于延迟过程调用和Timer的说明:
If the Dpc parameter is specified, a DPC object is associated with the timer object.
When the timer expires, the timer object is removed from the system timer queue and it is set to a signaled state.
If a DPC object was associated with the timer when it was set, the DPC object is inserted in the system DPC queue to be executed as soon as conditions permit after the timer interval expires.

总结:
(1)DeferredRoutine 是一个延迟过程调用, 在该例程中会做些什么呢? 我想可能是先前执行的某段代码由于执行时机的原因而没有成功,  在该例程中会重复执行直至成功为止.

(2)sub_10702:  DriverUnload
        loc_103DC:  SDbgMsgCreate
        sub_10646:  SDbgMsgRead
        loc_103F8:  SDbgMsgClose
        loc_10442:  SDbgMsgDeviceIoControl

在 IDA 中分别选中这些函数名,然后 鼠标右键-->"rename" ,把这些函数替换为上面容易记忆的名字;

(3) 上面的 DirverEntry 例程中通过 MmGetSystemRoutineAddress 来得到 DbgSetDebugPrintCallback和 DbgSetDebugFilterState 系统例程, 并分别存在 dword_12000 和 dword_12004 内存位置.以后的代码中肯定使用这 2 个值(函数的地址), 我们可以在代码中找到 对dword_12000 和 dword_12004 访问的代码并把它改成具体的例程名 "DbgSetDebugPrintCallback" 和 "DbgSetDebugFilterState "

 

.text:000104D2 ; void __stdcall DeferredRoutine(struct _KDPC *,PVOID,PVOID,PVOID)
.text:000104D2 DeferredRoutine proc near               ; DATA XREF: start+15Co
.text:000104D2                 xor     ecx, ecx
.text:000104D4                 cmp     dword_12220, ecx
.text:000104DA                 jz      short locret_104EE
.text:000104DC                 mov     eax, Event
.text:000104E1                 cmp     eax, ecx
.text:000104E3                 jz      short locret_104EE
.text:000104E5                 push    ecx             ; Wait
.text:000104E6                 push    ecx             ; Increment
.text:000104E7                 push    eax             ; Event
.text:000104E8                 call    ds:KeSetEvent
.text:000104EE
.text:000104EE locret_104EE:                           ; CODE XREF: DeferredRoutine+8j
.text:000104EE                                         ; DeferredRoutine+11j
.text:000104EE                 retn    10h
.text:000104EE DeferredRoutine endp

这是上面  KeInitializeDpc 例程设置延迟调用过程, 第二个参数为NULL, 再该例程中如果 dword_12220 不为 0, 就设置事件,这个event 变量是全局

if (dword_12220 != 0)
{
        if (g_event != NULL)
 {
  KeSetEvent(g_event, NULL, NULL);  
 }
}

 

//--------------------下面是 IRP_MJ_CREATE 对应的例程--------------------------

.text:000103DC SDbgMsgCreate:                          ; DATA XREF: start+31o
.text:000103DC                 mov     ecx, [esp+8]
.text:000103E0                 and     dword ptr [ecx+18h], 0
.text:000103E4                 xor     dl, dl
.text:000103E6                 mov     dword ptr [ecx+1Ch], 1
.text:000103ED                 call    ds:IofCompleteRequest
.text:000103F3                 xor     eax, eax
.text:000103F5                 retn    8

NTSTATUS  SDbgMsgCreate(PDEVICE_OBJECT pDeviceObject, PIRP Irp)
{
 Irp->IoStatus.Status = STATUS_SUCCESS;
 Irp->IoStatus.Information = 1;
 
        //
        // IofCompleteRequest 例程是 _fastcall 调用方式
        // 采用 ecx 和 edx 传递参数
        //
 
   IoCompleteRequest( ecx , edx );   
       
        return Irp->IoStatus.Status ;
}

//--------------------下面是 IRP_MJ_READ 对应的派遣例程-------------------------
下面的代码是由 IDA 自动生成, SDbgMsgRead 是我根据在 DriverObject 例程中的分析得处的该例程对应着 IRP_MJ_READ

; int __stdcall SDbgMsgRead(int,KIRQL NewIrql)
.text:00010646 SDbgMsgRead     proc near               ; DATA XREF: start+37o
.text:00010646
.text:00010646 NewIrql         = byte ptr  18h
.text:00010646
.text:00010646                 push    ebx
.text:00010647                 push    ebp
.text:00010648                 push    esi
.text:00010649                 push    edi
.text:0001064A                 mov     edi, dword ptr [esp+NewIrql]
.text:0001064E                 mov     ebp, [edi+60h]
.text:00010651                 mov     ebx, offset SpinLock
.text:00010656                 mov     ecx, ebx        ; SpinLock
.text:00010658                 xor     esi, esi
.text:0001065A                 call    ds:KfAcquireSpinLock
.text:00010660                 mov     [esp+NewIrql], al
.text:00010664                 mov     eax, dword_12220
.text:00010669                 test    eax, eax
.text:0001066B                 jz      short loc_106BB
.text:0001066D                 mov     esi, [ebp+4]
.text:00010670                 inc     eax
.text:00010671                 cmp     esi, eax
.text:00010673                 jle     short loc_10677
.text:00010675                 mov     esi, eax
.text:00010677
// 上面的反汇编代码可能又有问题: NewIrql 是从哪来得?

  MOV edi, dword ptr [esp+NewIrql]
  MOV ebp, [edi+60h]
可以猜测出, 第二个参数应该是 Irp 才对, 这样Irp偏移量为 60H是 CurrentStackLocation

   
   

    ULONG UlLength;
    PVOID SystemBuffer = NULL ;

    ebp = IoGetCurrentIrpStackLocation(Irp);
   
    KfAcquireSpinLock(&g_SpinLock);       // __fastcall 调用方式
  
    UlLength  = ebp->Parameters.Read.Length;

    if (dword_12220 != 0)
 {
     if ( ebp->Parameters.Read.Length > dword_12220+1 )
  {
   UlLength = dword_12220+1;        // 应该是和存放读取数据的缓冲区有关, 取小值   
  } 

            if (UlLength == 0) 
  {
   ; 完成 Irp
                        ; 退出
  }
           
            // 取得读取数据的缓冲区
            pSystemBuffer = Irp->AssociatedIrp.SystemBuffer ;                                                   
.text:00010677 loc_10677:                              ; CODE XREF: SDbgMsgRead+2Dj
.text:00010677                 test    esi, esi        ; 比较  pSystemBuffer 是否为 NULL
.text:00010679                 jz      short loc_106BB
.text:0001067B                 mov     eax, [edi+0Ch]
.text:0001067E                 test    eax, eax
.text:00010680                 jz      short loc_106BB

   if ( pSystemBuffer == NULL)
  {
                        ; 完成 Irp
                        ; 退出
  }
.text:00010682                 push    esi             ; 读取数据的长度
.text:00010683                 push    dword_12224    
.text:00010689                 push    eax             ; 存放数据缓冲区的地址
.text:0001068A                 call    sub_1050E
 
          // 从数据存放的缓冲区中读取指定大小的字节
          retValue = sub_1050E( pSystemBuffer, dword_12224, UlLength);
         
.text:0001068F                 cmp     esi, dword_12220
.text:00010695                 jge     short loc_106B4
.text:00010697                 mov     eax, dword_12224
.text:0001069C                 lea     ecx, [eax+esi-1]
.text:000106A0                 push    ecx
.text:000106A1                 push    eax
.text:000106A2                 call    sub_104F2
        if (esi < dword_12220) 
        {
  sub104f2_Retvalue = sub_104F2 (dword_12224 , dword_12224+esi-1 );

.text:000106A7                 xor     eax, eax
.text:000106A9                 inc     eax
.text:000106AA                 sub     eax, esi
.text:000106AC                 add     dword_12220, eax
.text:000106B2                 jmp     short loc_106BB
               
                sub104f2_Retvalue = 1;
               
                sub104f2_Retvalue -= UlLength;
               
                dword_12220 +=  eax;      
               
        }else
        {
.text:000106B4 loc_106B4:                              ; CODE XREF: SDbgMsgRead+4Fj
.text:000106B4                 and     dword_12220, 0
  dword_12220 = 0;
        }

label :loc_106BB:      
.text:000106BB loc_106BB:                              ; CODE XREF: SDbgMsgRead+25j
.text:000106BB                                         ; SDbgMsgRead+33j ...
.text:000106BB                 mov     dl, [esp+NewIrql] ; NewIrql
.text:000106BF                 mov     ecx, ebx        ; SpinLock
.text:000106C1                 call    ds:KfReleaseSpinLock
         KfReleaseSpinLock(g_SpinLock);

.text:000106C7                 and     dword ptr [edi+18h], 0
.text:000106CB                 xor     dl, dl
.text:000106CD                 mov     ecx, edi        ; Irp
.text:000106CF                 mov     [edi+1Ch], esi                  ; esi 实际读取了多少字节的数据
.text:000106D2                 call    ds:IofCompleteRequest
.text:000106D8                 pop     edi
.text:000106D9                 pop     esi
.text:000106DA                 pop     ebp
.text:000106DB                 xor     eax, eax
.text:000106DD                 pop     ebx
.text:000106DE                 retn    8
 
 Irp->IoStatus.Status = STATUS_SUCCESS;
  Irp->IoStatus.Information = esi ;     // 实际读取了多少字节的数据    
 
 IofCompleteRequest(Irp, 0);         
 }

抱歉!评论已关闭.