逆向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)
一个驱动程序可以提供多个调度例程,在这种情况下只有一个主要函数。
初始化代码段:
__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中的代码段:
__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; }
汇编代码段:
.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结构的指针。
在第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中,可以通过执行“右键单击->选择并集字段”来轻松完成此操作:
现在我已经确定了输入缓冲区的存储位置,让我看看如何对其进行解析:
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)
可以在这里找到代码,这个函数很小,将看到正确设置类型并重命名后,一切变得更加清晰。
我需要做的第一件事是将先前定义的结构DrvInputBuffer添加到IDA Pro。在“本地类型”子视图上,可以执行“右键单击->插入”,你可以在其中复制粘贴结构定义:
下一步,通过执行“右键单击变量->转换为结构*”,将第一个参数重命名为该结构的指针。
将得到如下内容:
__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/如若转载,请注明原文地址