导语:在第1部分中,我确定了驱动程序的Dispatcher函数以及两个正在初始化驱动程序的某些变量的函数(**fn_InitDispatchMethodArray**和**fn_ObtainKernelFunctions**)。 逆向这两个函数,分析一下它们的功能,这会帮助我了解在此驱动程序上实现的Dispatcher函数。
在第1部分中,我确定了驱动程序的Dispatcher函数以及两个正在初始化驱动程序的某些变量的函数(fn_InitDispatchMethodArray和fn_ObtainKernelFunctions)。
逆向这两个函数,分析一下它们的功能,这会帮助我了解在此驱动程序上实现的Dispatcher函数。
0x01 概述
1. 该驱动程序的一些基本初始化机制
2. 确定用于索引和存储所有可用方法的自定义结构。
3. 确定函数地址在内存中的位置,例如ObRegisterCallbacks。
0x02 fn_InitDispatchMethodArray(0x1400015F8)
该函数的代码片段:
__int64 sub_1400015F8() { __int64 result; // rax memset(&dword_140009E40, 0, 0x400ui64); dword_140009E40 = 774; qword_140009E48 = (__int64)sub_140001058; qword_140009E58 = (__int64)sub_14000101C; qword_140009E68 = (__int64)sub_140001CC8; qword_140009E78 = (__int64)sub_140001BFC; qword_140009E88 = (__int64)sub_140001DC0; qword_140009E98 = (__int64)sub_140001B50; qword_140009EA8 = (__int64)sub_140001C3C; qword_140009EB8 = (__int64)sub_140001D04; qword_140009EC8 = (__int64)sub_14000137C; qword_140009ED8 = (__int64)sub_14000191C; qword_140009EE8 = (__int64)sub_140001340; qword_140009EF8 = (__int64)sub_140001A58; qword_140009F08 = (__int64)sub_1400019A4; qword_140009F18 = (__int64)sub_140001224; qword_140009F28 = (__int64)sub_14000187C; qword_140009F38 = (__int64)sub_140001488; qword_140009F48 = (__int64)sub_140001548; qword_140009F58 = (__int64)sub_1400013B8; qword_140009F68 = (__int64)sub_140001264; qword_140009F78 = (__int64)sub_14000150C; qword_140009F88 = (__int64)sub_140001174; qword_140009F98 = (__int64)sub_1400015CC; qword_140009FA8 = (__int64)sub_14000107C; qword_140009FB8 = (__int64)sub_140001D4C; qword_140009FC8 = (__int64)sub_140001D88; result = 0i64; dword_140009E50 = 775; dword_140009E60 = 776; dword_140009E70 = 777; dword_140009E80 = 778; dword_140009E90 = 779; dword_140009EA0 = 790; dword_140009EB0 = 782; dword_140009EC0 = 783; dword_140009ED0 = 785; dword_140009EE0 = 786; dword_140009EF0 = 787; dword_140009F00 = 788; dword_140009F10 = 789; dword_140009F20 = 791; dword_140009F30 = 792; dword_140009F40 = 793; dword_140009F50 = 794; dword_140009F60 = 796; dword_140009F70 = 797; dword_140009F80 = 798; dword_140009F90 = 799; dword_140009FA0 = 800; dword_140009FB0 = 801; dword_140009FC0 = 802; dword_14000A240 = 25; return result; }
汇编代码段:
.text:00000001400015F8 ; =============== S U B R O U T I N E ======================================= .text:00000001400015F8 .text:00000001400015F8 .text:00000001400015F8 sub_1400015F8 proc near ; CODE XREF: DriverEntry+110↓p .text:00000001400015F8 ; DATA XREF: .pdata:000000014000D084↓o .text:00000001400015F8 sub rsp, 28h .text:00000001400015FC xor edx, edx ; Val .text:00000001400015FE lea rcx, dword_140009E40 ; Dst .text:0000000140001605 mov r8d, 400h ; Size .text:000000014000160B call memset .text:0000000140001610 lea rax, sub_140001058 .text:0000000140001617 mov cs:dword_140009E40, 306h .text:0000000140001621 mov cs:qword_140009E48, rax .text:0000000140001628 lea rax, sub_14000101C .text:000000014000162F mov cs:qword_140009E58, rax .text:0000000140001636 lea rax, sub_140001CC8 .text:000000014000163D mov cs:qword_140009E68, rax .text:0000000140001644 lea rax, sub_140001BFC .text:000000014000164B mov cs:qword_140009E78, rax .text:0000000140001652 lea rax, sub_140001DC0 .text:0000000140001659 mov cs:qword_140009E88, rax .text:0000000140001660 lea rax, sub_140001B50 .text:0000000140001667 mov cs:qword_140009E98, rax .text:000000014000166E lea rax, sub_140001C3C .text:0000000140001675 mov cs:qword_140009EA8, rax .text:000000014000167C lea rax, sub_140001D04 .text:0000000140001683 mov cs:qword_140009EB8, rax .text:000000014000168A lea rax, sub_14000137C .text:0000000140001691 mov cs:qword_140009EC8, rax .text:0000000140001698 lea rax, sub_14000191C .text:000000014000169F mov cs:qword_140009ED8, rax .text:00000001400016A6 lea rax, sub_140001340 .text:00000001400016AD mov cs:qword_140009EE8, rax .text:00000001400016B4 lea rax, sub_140001A58 .text:00000001400016BB mov cs:qword_140009EF8, rax .text:00000001400016C2 lea rax, sub_1400019A4 .text:00000001400016C9 mov cs:qword_140009F08, rax .text:00000001400016D0 lea rax, sub_140001224 .text:00000001400016D7 mov cs:qword_140009F18, rax .text:00000001400016DE lea rax, sub_14000187C .text:00000001400016E5 mov cs:qword_140009F28, rax .text:00000001400016EC lea rax, sub_140001488 .text:00000001400016F3 mov cs:qword_140009F38, rax .text:00000001400016FA lea rax, sub_140001548 .text:0000000140001701 mov cs:qword_140009F48, rax .text:0000000140001708 lea rax, sub_1400013B8 .text:000000014000170F mov cs:qword_140009F58, rax .text:0000000140001716 lea rax, sub_140001264 .text:000000014000171D mov cs:qword_140009F68, rax .text:0000000140001724 lea rax, sub_14000150C .text:000000014000172B mov cs:qword_140009F78, rax .text:0000000140001732 lea rax, sub_140001174 .text:0000000140001739 mov cs:qword_140009F88, rax .text:0000000140001740 lea rax, sub_1400015CC .text:0000000140001747 mov cs:qword_140009F98, rax .text:000000014000174E lea rax, sub_14000107C .text:0000000140001755 mov cs:qword_140009FA8, rax .text:000000014000175C lea rax, sub_140001D4C .text:0000000140001763 mov cs:qword_140009FB8, rax .text:000000014000176A lea rax, sub_140001D88 .text:0000000140001771 mov cs:qword_140009FC8, rax .text:0000000140001778 xor eax, eax .text:000000014000177A mov cs:dword_140009E50, 307h .text:0000000140001784 mov cs:dword_140009E60, 308h .text:000000014000178E mov cs:dword_140009E70, 309h .text:0000000140001798 mov cs:dword_140009E80, 30Ah .text:00000001400017A2 mov cs:dword_140009E90, 30Bh .text:00000001400017AC mov cs:dword_140009EA0, 316h .text:00000001400017B6 mov cs:dword_140009EB0, 30Eh .text:00000001400017C0 mov cs:dword_140009EC0, 30Fh .text:00000001400017CA mov cs:dword_140009ED0, 311h .text:00000001400017D4 mov cs:dword_140009EE0, 312h .text:00000001400017DE mov cs:dword_140009EF0, 313h .text:00000001400017E8 mov cs:dword_140009F00, 314h .text:00000001400017F2 mov cs:dword_140009F10, 315h .text:00000001400017FC mov cs:dword_140009F20, 317h .text:0000000140001806 mov cs:dword_140009F30, 318h .text:0000000140001810 mov cs:dword_140009F40, 319h .text:000000014000181A mov cs:dword_140009F50, 31Ah .text:0000000140001824 mov cs:dword_140009F60, 31Ch .text:000000014000182E mov cs:dword_140009F70, 31Dh .text:0000000140001838 mov cs:dword_140009F80, 31Eh .text:0000000140001842 mov cs:dword_140009F90, 31Fh .text:000000014000184C mov cs:dword_140009FA0, 320h .text:0000000140001856 mov cs:dword_140009FB0, 321h .text:0000000140001860 mov cs:dword_140009FC0, 322h .text:000000014000186A mov cs:dword_14000A240, 19h .text:0000000140001874 add rsp, 28h .text:0000000140001878 retn .text:0000000140001878 sub_1400015F8 endp .text:0000000140001878
还原后的代码:
__int64 fn_InitDispatchMethodArray() { __int64 result; // rax memset(IOCTLFunctionArray, 0, 0x400ui64); IOCTLFunctionArray[0].Index = 774; // 9E40 IOCTLFunctionArray[0].FnPtr = sub_140001058; IOCTLFunctionArray[1].FnPtr = sub_14000101C; IOCTLFunctionArray[2].FnPtr = sub_140001CC8; IOCTLFunctionArray[3].FnPtr = sub_140001BFC; IOCTLFunctionArray[4].FnPtr = sub_140001DC0; IOCTLFunctionArray[5].FnPtr = sub_140001B50; IOCTLFunctionArray[6].FnPtr = sub_140001C3C; IOCTLFunctionArray[7].FnPtr = sub_140001D04; IOCTLFunctionArray[8].FnPtr = sub_14000137C; IOCTLFunctionArray[9].FnPtr = sub_14000191C; IOCTLFunctionArray[10].FnPtr = sub_140001340; IOCTLFunctionArray[11].FnPtr = sub_140001A58; IOCTLFunctionArray[12].FnPtr = sub_1400019A4; IOCTLFunctionArray[13].FnPtr = sub_140001224; IOCTLFunctionArray[14].FnPtr = sub_14000187C; IOCTLFunctionArray[15].FnPtr = sub_140001488; IOCTLFunctionArray[16].FnPtr = sub_140001548; IOCTLFunctionArray[17].FnPtr = sub_1400013B8; IOCTLFunctionArray[18].FnPtr = fn_ReadFileContent_; IOCTLFunctionArray[19].FnPtr = fn_IOCTL_ValidatePidPEB; IOCTLFunctionArray[20].FnPtr = fn_IOCTL_ControlCallbackRoutines; IOCTLFunctionArray[21].FnPtr = sub_1400015CC; IOCTLFunctionArray[22].FnPtr = sub_14000107C; IOCTLFunctionArray[23].FnPtr = sub_140001D4C; // CR0 IOCTLFunctionArray[24].FnPtr = sub_140001D88; result = 0i64; IOCTLFunctionArray[1].Index = 775; IOCTLFunctionArray[2].Index = 776; IOCTLFunctionArray[3].Index = 777; IOCTLFunctionArray[4].Index = 778; IOCTLFunctionArray[5].Index = 779; IOCTLFunctionArray[6].Index = 790; IOCTLFunctionArray[7].Index = 782; IOCTLFunctionArray[8].Index = 783; IOCTLFunctionArray[9].Index = 785; IOCTLFunctionArray[10].Index = 786; IOCTLFunctionArray[11].Index = 787; IOCTLFunctionArray[12].Index = 788; IOCTLFunctionArray[13].Index = 789; IOCTLFunctionArray[14].Index = 791; IOCTLFunctionArray[15].Index = 792; IOCTLFunctionArray[16].Index = 793; IOCTLFunctionArray[17].Index = 794; IOCTLFunctionArray[18].Index = 796; IOCTLFunctionArray[19].Index = 797; IOCTLFunctionArray[20].Index = 798; IOCTLFunctionArray[21].Index = 799; IOCTLFunctionArray[22].Index = 800; IOCTLFunctionArray[23].Index = 801; IOCTLFunctionArray[24].Index = 802; FunctionsCount = 0x19; return result; }
可以在此函数中看到正在初始化的自定义结构:
.text:0000000140001617 mov cs:dword_140009E40, 306h .text:0000000140001621 mov cs:qword_140009E48, rax .text:0000000140001628 lea rax, sub_14000101C .text:000000014000162F mov cs:qword_140009E58, rax .text:0000000140001636 lea rax, sub_140001CC8 .text:000000014000163D mov cs:qword_140009E68, rax
上面的汇编代码中,可以看到它们首先将int值分配给特定的内存地址,然后再移动8个字节将指针写入函数,我将这种结构称为IOCTLFunctionArray,该数组将在调度请求时发挥重要作用。
结构如下所示:
typedef struct DispatcherStruct { int Index; char padding[4]; PVOID FnPtr; };
在IDA Pro中:
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
此函数重复了25次,所以称其为array,它们在数组中存储相同结构25次。
将dword_14000A240重命名为FunctionsCount的变量:
.text:000000014000186A mov cs:FunctionsCount , 19h
之后将看到在Dispatcher上如何使用此变量,基于此函数,可以确定驱动程序没有调用所有可用方法的列表,并提供某种索引值,可以调用它们。
最终整理的代码片段:
__int64 fn_InitDispatchMethodArray() { __int64 result; // rax memset(IOCTLFunctionArray, 0, 0x400ui64); IOCTLFunctionArray[0].Index = 774; // 9E40 IOCTLFunctionArray[0].FnPtr = sub_140001058; IOCTLFunctionArray[1].FnPtr = sub_14000101C; IOCTLFunctionArray[2].FnPtr = sub_140001CC8; IOCTLFunctionArray[3].FnPtr = sub_140001BFC; IOCTLFunctionArray[4].FnPtr = sub_140001DC0; IOCTLFunctionArray[5].FnPtr = sub_140001B50; IOCTLFunctionArray[6].FnPtr = sub_140001C3C; IOCTLFunctionArray[7].FnPtr = sub_140001D04; IOCTLFunctionArray[8].FnPtr = sub_14000137C; IOCTLFunctionArray[9].FnPtr = sub_14000191C; IOCTLFunctionArray[10].FnPtr = sub_140001340; IOCTLFunctionArray[11].FnPtr = sub_140001A58; IOCTLFunctionArray[12].FnPtr = sub_1400019A4; IOCTLFunctionArray[13].FnPtr = sub_140001224; IOCTLFunctionArray[14].FnPtr = sub_14000187C; IOCTLFunctionArray[15].FnPtr = sub_140001488; IOCTLFunctionArray[16].FnPtr = sub_140001548; IOCTLFunctionArray[17].FnPtr = sub_1400013B8; IOCTLFunctionArray[18].FnPtr = fn_ReadFileContent_; IOCTLFunctionArray[19].FnPtr = fn_IOCTL_ValidatePidPEB; IOCTLFunctionArray[20].FnPtr = fn_IOCTL_ControlCallbackRoutines; IOCTLFunctionArray[21].FnPtr = sub_1400015CC; IOCTLFunctionArray[22].FnPtr = sub_14000107C; IOCTLFunctionArray[23].FnPtr = sub_140001D4C; // CR0 IOCTLFunctionArray[24].FnPtr = sub_140001D88; result = 0i64; IOCTLFunctionArray[1].Index = 775; IOCTLFunctionArray[2].Index = 776; IOCTLFunctionArray[3].Index = 777; IOCTLFunctionArray[4].Index = 778; IOCTLFunctionArray[5].Index = 779; IOCTLFunctionArray[6].Index = 790; IOCTLFunctionArray[7].Index = 782; IOCTLFunctionArray[8].Index = 783; IOCTLFunctionArray[9].Index = 785; IOCTLFunctionArray[10].Index = 786; IOCTLFunctionArray[11].Index = 787; IOCTLFunctionArray[12].Index = 788; IOCTLFunctionArray[13].Index = 789; IOCTLFunctionArray[14].Index = 791; IOCTLFunctionArray[15].Index = 792; IOCTLFunctionArray[16].Index = 793; IOCTLFunctionArray[17].Index = 794; IOCTLFunctionArray[18].Index = 796; IOCTLFunctionArray[19].Index = 797; IOCTLFunctionArray[20].Index = 798; IOCTLFunctionArray[21].Index = 799; IOCTLFunctionArray[22].Index = 800; IOCTLFunctionArray[23].Index = 801; IOCTLFunctionArray[24].Index = 802; FunctionsCount = 0x19; return result; }
0x03 fn_ObtainKernelFunctions(0x140002A18)
下面的函数很简单,为了继续进行初始化,驱动程序需要一些特定例程的地址:
这样做可以确保这些函数在运行的Windows版本上可用,并获得指向它们的指针,只需要将它们存储在一个变量中,然后通过将其转换为属性函数定义来使用它们来调用这些例程。
也可以在汇编函数中发现:
.text:0000000140002A1C lea rdx, SourceString ; "ObGetFilterVersion" .text:0000000140002A23 lea rcx, [rsp+38h+DestinationString] ; DestinationString .text:0000000140002A28 call cs:RtlInitUnicodeString .text:0000000140002A2E lea rcx, [rsp+38h+DestinationString] ; SystemRoutineName .text:0000000140002A33 call cs:MmGetSystemRoutineAddress .text:0000000140002A39 lea rdx, aObregistercall ; "ObRegisterCallbacks" .text:0000000140002A40 mov cs:qword_14000A288, rax .text:0000000140002A47 lea rcx, [rsp+38h+DestinationString] ; DestinationString .text:0000000140002A4C call cs:RtlInitUnicodeString .text:0000000140002A52 lea rcx, [rsp+38h+DestinationString] ; SystemRoutineName .text:0000000140002A57 call cs:MmGetSystemRoutineAddress
本文翻译自:https://niemand.com.ar/2020/01/16/reversing-xigncode3-driver-part-2-analyzing-init-functions/如若转载,请注明原文地址: