逆向XignCode3驅動程序:分析Dispatcher函數(part3)
逆向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結構的指針。
在第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/如若轉載,請注明原文地址。