9

逆向XignCode3驱动程序:分析Dispatcher函数(part3)

 3 years ago
source link: http://os.51cto.com/art/202012/633627.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

BJ3Azmi.png!mobile

逆向XignCode3驱动程序:识别驱动程序入口点(part1)

逆向XignCode3驱动程序:分析init初始化函数(part2)

Dispatcher函数的主要功能是处理I / O请求数据包(IRP),处理来自主要函数代码IRP_MJ_WRITE的任何请求。

0x01 概述

1. 了解分派器例程的实现方式。

2. 逆向处理IRP_MJ_WRITE请求的解析方法。

3. 确定驱动程序使用的自定义结构,并在IDA上创建新的本地类型。

4. 通过遍历具有自定义结构的数组,了解驱动程序如何调度不同的硬编码句柄。

逆向Windows相关内容时,必须阅读MS文档。它们提供了许多有用的信息,这些信息会节省很多时间,例如它们使用的结构,参数和代码示例,我会浏览其存储库中可用的示例,并查找相似的代码段。驱动程序开发人员通常会重复使用这些示例中的许多代码,在二进制文件中寻找相似的模式可以为我提供有关上下文和在相似代码段内被调用的函数的大量信息。

在本文的结尾,你将找到有用的链接列表。

0x02 fn_DriverIOCTLDispatcher(0x140004604)

一个驱动程序可以提供多个调度例程,在这种情况下只有一个主要函数。

初始化代码段:

https://github.com/niemand-sec/Reversing-XignCode3-Driver/blob/master/XC3/fn_DriverIOCTLDispatcher_original.c

__int64 __fastcall sub_140004604(__int64 a1, _IRP *a2) 
{ 
 _IRP *v2; // rbx 
 unsigned int v3; // esi 
 unsigned int v4; // edi 
 _IRP *v5; // r14 
 __int64 v6; // rax 
 void *v7; // r8 
 __int64 v8; // rcx 
 __int64 *v9; // rdx 
 signed __int64 v10; // rax 
 PMDL MemoryDescriptorList; // [rsp+38h] [rbp-320h] 
 __int64 v13; // [rsp+40h] [rbp-318h] 
 
 v2 = a2; 
 v3 = 0; 
 v4 = -1073741823; 
 if (LODWORD(a2->Tail.Overlay.CurrentStackLocation->Parameters.Others.Argument1) == 0x270) 
 { 
  v5 = a2->AssociatedIrp.MasterIrp; 
  if (*&v5->Type == 0x270 && *(&v5->Size + 1) == 0x345821AB) 
  { 
   fn_DispatchIOCTLMethod(v5, &v13); 
   v6 = sub_140003DBC(*&v5->Flags, 762i64, &MemoryDescriptorList); 
   v7 = v6; 
   if (v6) 
   { 
    v8 = v6; 
    v9 = &v13; 
    v10 = 5i64; 
    do 
    { 
     *v8 = *v9; 
     *(v8 + 16) = *(v9 + 1); 
     *(v8 + 32) = *(v9 + 2); 
     *(v8 + 48) = *(v9 + 3); 
     *(v8 + 64) = *(v9 + 4); 
     *(v8 + 80) = *(v9 + 5); 
     *(v8 + 96) = *(v9 + 6); 
     v8 += 128i64; 
     *(v8 - 16) = *(v9 + 7); 
     v9 += 16; 
     --v10; 
    } while (v10); 
    *v8 = *v9; 
    *(v8 + 16) = *(v9 + 1); 
    *(v8 + 32) = *(v9 + 2); 
    *(v8 + 48) = *(v9 + 3); 
    *(v8 + 64) = *(v9 + 4); 
    *(v8 + 80) = *(v9 + 5); 
    *(v8 + 96) = *(v9 + 6); 
    *(v8 + 112) = v9[14]; 
    *(v8 + 120) = *(v9 + 60); 
    v4 = 0; 
    v3 = 762; 
    sub_140003980(MemoryDescriptorList, v7); 
   } 
  } 
 } 
 v2->IoStatus.Status = v4; 
 v2->IoStatus.Information = v3; 
 IofCompleteRequest(v2, 0); 
 return v4; 
} 

IDA中的代码段:

https://github.com/niemand-sec/Reversing-XignCode3-Driver/blob/master/XC3/fn_DriverIOCTLDispatcher_original.c

__int64 __fastcall sub_140004604(__int64 a1, _IRP *a2) 
{ 
 _IRP *v2; // rbx 
 unsigned int v3; // esi 
 unsigned int v4; // edi 
 _IRP *v5; // r14 
 __int64 v6; // rax 
 void *v7; // r8 
 __int64 v8; // rcx 
 __int64 *v9; // rdx 
 signed __int64 v10; // rax 
 PMDL MemoryDescriptorList; // [rsp+38h] [rbp-320h] 
 __int64 v13; // [rsp+40h] [rbp-318h] 
 
 v2 = a2; 
 v3 = 0; 
 v4 = -1073741823; 
 if (LODWORD(a2->Tail.Overlay.CurrentStackLocation->Parameters.Others.Argument1) == 0x270) 
 { 
  v5 = a2->AssociatedIrp.MasterIrp; 
  if (*&v5->Type == 0x270 && *(&v5->Size + 1) == 0x345821AB) 
  { 
   fn_DispatchIOCTLMethod(v5, &v13); 
   v6 = sub_140003DBC(*&v5->Flags, 762i64, &MemoryDescriptorList); 
   v7 = v6; 
   if (v6) 
   { 
    v8 = v6; 
    v9 = &v13; 
    v10 = 5i64; 
    do 
    { 
     *v8 = *v9; 
     *(v8 + 16) = *(v9 + 1); 
     *(v8 + 32) = *(v9 + 2); 
     *(v8 + 48) = *(v9 + 3); 
     *(v8 + 64) = *(v9 + 4); 
     *(v8 + 80) = *(v9 + 5); 
     *(v8 + 96) = *(v9 + 6); 
     v8 += 128i64; 
     *(v8 - 16) = *(v9 + 7); 
     v9 += 16; 
     --v10; 
    } while (v10); 
    *v8 = *v9; 
    *(v8 + 16) = *(v9 + 1); 
    *(v8 + 32) = *(v9 + 2); 
    *(v8 + 48) = *(v9 + 3); 
    *(v8 + 64) = *(v9 + 4); 
    *(v8 + 80) = *(v9 + 5); 
    *(v8 + 96) = *(v9 + 6); 
    *(v8 + 112) = v9[14]; 
    *(v8 + 120) = *(v9 + 60); 
    v4 = 0; 
    v3 = 762; 
    sub_140003980(MemoryDescriptorList, v7); 
   } 
  } 
 } 
 v2->IoStatus.Status = v4; 
 v2->IoStatus.Information = v3; 
 IofCompleteRequest(v2, 0); 
 return v4; 
} 

汇编代码段:

https://github.com/niemand-sec/Reversing-XignCode3-Driver/blob/master/XC3/fn_DriverIOCTLDispatcher.asm

.text:0000000140004604 ; =============== S U B R O U T I N E ======================================= 
.text:0000000140004604 
.text:0000000140004604 
.text:0000000140004604 sub_140004604   proc near               ; DATA XREF: DriverEntry+AC↓o 
.text:0000000140004604                                         ; .pdata:000000014000D3D8↓o ... 
.text:0000000140004604 
.text:0000000140004604 var_338         = dword ptr -338h 
.text:0000000140004604 var_334         = dword ptr -334h 
.text:0000000140004604 var_330         = qword ptr -330h 
.text:0000000140004604 var_328         = qword ptr -328h 
.text:0000000140004604 MemoryDescriptorList= qword ptr -320h 
.text:0000000140004604 v13             = qword ptr -318h 
.text:0000000140004604 var_18          = qword ptr -18h 
.text:0000000140004604 var_8           = byte ptr -8 
.text:0000000140004604 arg_0           = qword ptr  8 
.text:0000000140004604 arg_10          = qword ptr  18h 
.text:0000000140004604 arg_18          = qword ptr  20h 
.text:0000000140004604 
.text:0000000140004604 ; __unwind { // __GSHandlerCheck_SEH 
.text:0000000140004604                 mov     [rsp+arg_0], rbx 
.text:0000000140004609                 mov     [rsp+arg_10], rsi 
.text:000000014000460E                 mov     [rsp+arg_18], rdi 
.text:0000000140004613                 push    r14 
.text:0000000140004615                 sub     rsp, 350h 
.text:000000014000461C                 mov     rax, cs:__security_cookie 
.text:0000000140004623                 xor     rax, rsp 
.text:0000000140004626                 mov     [rsp+358h+var_18], rax 
.text:000000014000462E                 mov     rbx, rdx 
.text:0000000140004631                 mov     [rsp+358h+var_328], rdx 
.text:0000000140004636                 mov     rax, [rdx+0B8h] 
.text:000000014000463D                 xor     esi, esi 
.text:000000014000463F                 mov     [rsp+358h+var_338], esi 
.text:0000000140004643                 mov     edi, 0C0000001h 
.text:0000000140004648                 mov     [rsp+358h+var_334], edi 
.text:000000014000464C                 mov     ecx, 270h 
.text:0000000140004651                 cmp     [rax+8], ecx 
.text:0000000140004654                 jnz     loc_140004778 
.text:000000014000465A                 mov     r14, [rdx+18h] 
.text:000000014000465E                 cmp     [r14], ecx 
.text:0000000140004661                 jnz     loc_140004778 
.text:0000000140004667                 cmp     dword ptr [r14+4], 345821ABh 
.text:000000014000466F                 jnz     loc_140004778 
.text:0000000140004675                 lea     rdx, [rsp+358h+v13] ; a2 
.text:000000014000467A                 mov     rcx, r14        ; a1 
.text:000000014000467D                 call    fn_DispatchIOCTLMethod 
.text:0000000140004682                 mov     rcx, [r14+10h] 
.text:0000000140004686                 lea     r8, [rsp+358h+MemoryDescriptorList] 
.text:000000014000468B                 mov     r14d, 2FAh 
.text:0000000140004691                 mov     edx, r14d 
.text:0000000140004694                 call    sub_140003DBC 
.text:0000000140004699                 mov     r8, rax 
.text:000000014000469C                 mov     [rsp+358h+var_330], rax 
.text:00000001400046A1                 test    rax, rax 
.text:00000001400046A4                 jz      loc_140004778 
.text:00000001400046AA 
.text:00000001400046AA loc_1400046AA:                          ; DATA XREF: .rdata:0000000140008A5C↓o 
.text:00000001400046AA ;   __try { // __except at loc_140004759 
.text:00000001400046AA                 mov     rcx, rax 
.text:00000001400046AD                 lea     rdx, [rsp+358h+v13] 
.text:00000001400046B2                 lea     eax, [rsi+5] 
.text:00000001400046B5                 lea     r9d, [rax+7Bh] 
.text:00000001400046B9 
.text:00000001400046B9 loc_1400046B9:                          ; CODE XREF: sub_140004604+FD↓j 
.text:00000001400046B9                 movups  xmm0, xmmword ptr [rdx] 
.text:00000001400046BC                 movups  xmmword ptr [rcx], xmm0 
.text:00000001400046BF                 movups  xmm1, xmmword ptr [rdx+10h] 
.text:00000001400046C3                 movups  xmmword ptr [rcx+10h], xmm1 
.text:00000001400046C7                 movups  xmm0, xmmword ptr [rdx+20h] 
.text:00000001400046CB                 movups  xmmword ptr [rcx+20h], xmm0 
.text:00000001400046CF                 movups  xmm1, xmmword ptr [rdx+30h] 
.text:00000001400046D3                 movups  xmmword ptr [rcx+30h], xmm1 
.text:00000001400046D7                 movups  xmm0, xmmword ptr [rdx+40h] 
.text:00000001400046DB                 movups  xmmword ptr [rcx+40h], xmm0 
.text:00000001400046DF                 movups  xmm1, xmmword ptr [rdx+50h] 
.text:00000001400046E3                 movups  xmmword ptr [rcx+50h], xmm1 
.text:00000001400046E7                 movups  xmm0, xmmword ptr [rdx+60h] 
.text:00000001400046EB                 movups  xmmword ptr [rcx+60h], xmm0 
.text:00000001400046EF                 add     rcx, r9 
.text:00000001400046F2                 movups  xmm1, xmmword ptr [rdx+70h] 
.text:00000001400046F6                 movups  xmmword ptr [rcx-10h], xmm1 
.text:00000001400046FA                 add     rdx, r9 
.text:00000001400046FD                 sub     rax, 1 
.text:0000000140004701                 jnz     short loc_1400046B9 
.text:0000000140004703                 movups  xmm0, xmmword ptr [rdx] 
.text:0000000140004706                 movups  xmmword ptr [rcx], xmm0 
.text:0000000140004709                 movups  xmm1, xmmword ptr [rdx+10h] 
.text:000000014000470D                 movups  xmmword ptr [rcx+10h], xmm1 
.text:0000000140004711                 movups  xmm0, xmmword ptr [rdx+20h] 
.text:0000000140004715                 movups  xmmword ptr [rcx+20h], xmm0 
.text:0000000140004719                 movups  xmm1, xmmword ptr [rdx+30h] 
.text:000000014000471D                 movups  xmmword ptr [rcx+30h], xmm1 
.text:0000000140004721                 movups  xmm0, xmmword ptr [rdx+40h] 
.text:0000000140004725                 movups  xmmword ptr [rcx+40h], xmm0 
.text:0000000140004729                 movups  xmm1, xmmword ptr [rdx+50h] 
.text:000000014000472D                 movups  xmmword ptr [rcx+50h], xmm1 
.text:0000000140004731                 movups  xmm0, xmmword ptr [rdx+60h] 
.text:0000000140004735                 movups  xmmword ptr [rcx+60h], xmm0 
.text:0000000140004739                 mov     rax, [rdx+70h] 
.text:000000014000473D                 mov     [rcx+70h], rax 
.text:0000000140004741                 movzx   eax, word ptr [rdx+78h] 
.text:0000000140004745                 mov     [rcx+78h], ax 
.text:0000000140004749                 mov     edi, esi 
.text:000000014000474B                 mov     [rsp+358h+var_334], esi 
.text:000000014000474F                 mov     esi, r14d 
.text:0000000140004752                 mov     [rsp+358h+var_338], r14d 
.text:0000000140004757                 jmp     short loc_14000476B 
.text:0000000140004757 ;   } // starts at 1400046AA 
.text:0000000140004759 ; --------------------------------------------------------------------------- 
.text:0000000140004759 
.text:0000000140004759 loc_140004759:                          ; DATA XREF: .rdata:0000000140008A5C↓o 
.text:0000000140004759 ;   __except(1) // owned by 1400046AA 
.text:0000000140004759                 mov     esi, [rsp+358h+var_338] 
.text:000000014000475D                 mov     edi, [rsp+358h+var_334] 
.text:0000000140004761                 mov     r8, [rsp+358h+var_330] 
.text:0000000140004766                 mov     rbx, [rsp+358h+var_328] 
.text:000000014000476B 
.text:000000014000476B loc_14000476B:                          ; CODE XREF: sub_140004604+153↑j 
.text:000000014000476B                 mov     rdx, r8         ; BaseAddress 
.text:000000014000476E                 mov     rcx, [rsp+358h+MemoryDescriptorList] ; MemoryDescriptorList 
.text:0000000140004773                 call    sub_140003980 
.text:0000000140004778 
.text:0000000140004778 loc_140004778:                          ; CODE XREF: sub_140004604+50↑j 
.text:0000000140004778                                         ; sub_140004604+5D↑j ... 
.text:0000000140004778                 mov     [rbx+30h], edi 
.text:000000014000477B                 mov     edx, esi 
.text:000000014000477D                 mov     [rbx+38h], rdx 
.text:0000000140004781                 xor     edx, edx        ; PriorityBoost 
.text:0000000140004783                 mov     rcx, rbx        ; Irp 
.text:0000000140004786                 call    cs:IofCompleteRequest 
.text:000000014000478C                 mov     eax, edi 
.text:000000014000478E                 mov     rcx, [rsp+358h+var_18] 
.text:0000000140004796                 xor     rcx, rsp 
.text:0000000140004799                 call    __security_check_cookie 
.text:000000014000479E                 lea     r11, [rsp+358h+var_8] 
.text:00000001400047A6                 mov     rbx, [r11+10h] 
.text:00000001400047AA                 mov     rsi, [r11+20h] 
.text:00000001400047AE                 mov     rdi, [r11+28h] 
.text:00000001400047B2                 mov     rsp, r11 
.text:00000001400047B5                 pop     r14 
.text:00000001400047B7                 retn 
.text:00000001400047B7 ; } // starts at 140004604 
.text:00000001400047B7 sub_140004604   endp 
.text:00000001400047B7 

可以看到它接收到两个参数,MS文档解释说,IRP_MJ_WRITE调度程序函数接收PDEVICE_OBJECT作为第一个参数,然后接收指向IRP结构的指针。

mQJVf2m.png!mobile

在第16行,驱动程序控制输入缓冲区的长度等于0x270,这似乎是唯一可能的长度。

分析以下行时请小心:

v5 = a2->AssociatedIrp.MasterIrp; 

MasterIrp与Union(结构_IRP)内部的IrpCount和SystemBuffer共享相同的偏移量:

union { 
    struct _IRP     *MasterIrp; 
    __volatile LONG IrpCount; 
    PVOID           SystemBuffer; 
  } AssociatedIrp; 

在这种情况下,将尝试从IRP请求中检索SystemBuffer,它没有引用MasterIrp指针,我需要修复它。在IDA PRO中,可以通过执行“右键单击->选择并集字段”来轻松完成此操作:

zAFVveB.png!mobile

现在我已经确定了输入缓冲区的存储位置,让我看看如何对其进行解析:

v5 = a2->AssociatedIrp.SystemBuffer; 
if ( *(_DWORD *)v5 == 0x270 && *((_DWORD *)v5 + 1) == 0x345821AB ) 
{ 
sub_140001E00(v5, &v13); 

可以看到第一个DWORD预期等于0x270(长度的相同值);然后,下一个DWORD需要具有某种与0x345821AB匹配的Magic值。如果两个条件都满足,则调用函数sub_140001E00来发送第一个参数中的缓冲区,并在第二个参数上引用未知的结构,我决定调用此函数fn_DispatchIOCTLMethod,我将在下一部分中对其进行分析。

重命名变量后,可以得出结论,输入缓冲区的结构将如下所示:

struct DrvInputBuffer 
 { 
   _DWORD Size;                           // Offset 0x0 
   _DWORD MagicNumber;                    // Offset 0x4 
   _BYTE gap8[8];                         // Offset 0x8 
   void *pvoid10;                         // Offset 0x10 
 }; 

由于尚未分析所有调度方法,但是我想提供对输入缓冲区的完整分析,因此我将展示Driver正在使用的完整结构。

最终结构如下所示:

struct DrvInputBuffer 
{ 
  _DWORD Size;                           // Offset 0x0 
  _DWORD MagicNumber;                    // Offset 0x4 
  _DWORD RequestId;                      // Offset 0x8 
  _DWORD FnIndex;                        // Offset 0xc 
  void *pvoid10;                         // Offset 0x10 
  unsigned __int8 buffer[600];           // Offset 0x18 
}; 

此函数还可以执行其他操作,但是现在让我忽略它们。

0x03 fn_DispatchIOCTLMethod(0x140001E00)

bMzI7nj.png!mobile

可以在这里找到代码,这个函数很小,将看到正确设置类型并重命名后,一切变得更加清晰。

我需要做的第一件事是将先前定义的结构DrvInputBuffer添加到IDA Pro。在“本地类型”子视图上,可以执行“右键单击->插入”,你可以在其中复制粘贴结构定义:

6feYj2f.png!mobile

下一步,通过执行“右键单击变量->转换为结构*”,将第一个参数重命名为该结构的指针。

将得到如下内容:

__int64 __fastcall fn_DispatchIOCTLMethod(DrvInputBuffer *a1, __int64 a2) 
{ 
  int v2; // er8 
 
  v2 = 0; 
  if ( !dword_14000A240 ) 
    return 3221225473i64; 
  while ( dword_140009E40[4 * v2] != a1->FnIndex ) 
  { 
    if ( ++v2 >= dword_14000A240 ) 
      return 3221225473i64; 
  } 
  return (*&dword_140009E40[4 * v2 + 2])(a1, a2); 
} 

如果你已阅读以前的文章,则可以识别dword_14000A240,在分析fn_InitDispatchMethodArray时,我在第二篇文章中重命名了此变量:FunctionCount**。

dword_140009E40发生了相同的情况,在同一帖子上将其重命名为IOCTLFunctionArray,它是一个包含多个DispatcherStruct结构的数组:

00000000 DispatcherStruct struc ; (sizeof=0x10, mappedto_424) 
00000000                                         ; XREF: .data:_IOCTLFunctionArray/r 
00000000 Index           dd ?                    ; XREF: fn_InitDispatchMethodArray+1F/t 
00000004 padding         db 4 dup(?) 
00000008 FnPtr           dq ? 
00000010 DispatcherStruct ends 

基于此,我可以确定以下行为:首先,应用程序通过将FunctionsCount和NULL 进行比较来验证IOCTLFunctionArray是否已初始化。然后,在while循环中进行迭代,将每个元素的索引值与DWORD在输入缓冲区的偏移量0xC(在结构上定义为FnIndex)进行比较,它们增加计数器,直到达到存储在FunctionsCount中的最大值。

如果索引之间匹配,则调用存储在DispatcherStruct-> FnPtr中的函数;否则,将调用该函数。发送fn_DispatchIOCTLMethod的相同两个参数:SystemBuffer和对一个未知结构的引用。

最终函数:

__int64 __fastcall fn_DispatchIOCTLMethod(DrvInputBuffer *SystemBuffer, DrvOutputBuffer *a2) 
{ 
  int counter; // er8 
 
  counter = 0; 
  if ( !FunctionsCount ) 
    return 0xC0000001i64; 
  while ( IOCTLFunctionArray[counter].Index != SystemBuffer->FnIndex ) 
  { 
    if ( ++counter >= FunctionsCount ) 
      return 0xC0000001i64; 
  } 
  return (IOCTLFunctionArray[counter].FnPtr)(SystemBuffer, a2); 
} 

0x04 参考信息

  •  https://docs.microsoft.com/zh-cn/windows-hardware/drivers/kernel/writing-dispatch-routines
  •  https://docs.microsoft.com/zh-CN/windows-hardware/drivers/kernel/handling-irps
  •  https://github.com/microsoft/Windows-driver-samples
  •  https://docs.microsoft.com/zh-CN/windows-hardware/drivers/ddi/wdm/ns-wdm-_irp

本文翻译 自:https://niemand.com.ar/2020/01/24/reversing-xigncode3-driver-part-3-analyzing-dispatch-functions/如若转载,请注明原文地址。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK