我已经开始逆转这块恶意软件。在某个时候,它会创建一个服务并启动它,然后立即调用该函数DeviceIoControl
,恶意软件在 ollydbg 下从“暂停”变为“运行”。我搜索了一下,我知道这个函数用于与它刚刚创建的服务进行通信。
但我究竟该如何逆转呢?我怎么知道它的作用?我怎样才能继续踩到 ollydbg 下?或者我是否必须转移到windbg 或其他一些内核模式调试器?
我已经开始逆转这块恶意软件。在某个时候,它会创建一个服务并启动它,然后立即调用该函数DeviceIoControl
,恶意软件在 ollydbg 下从“暂停”变为“运行”。我搜索了一下,我知道这个函数用于与它刚刚创建的服务进行通信。
但我究竟该如何逆转呢?我怎么知道它的作用?我怎样才能继续踩到 ollydbg 下?或者我是否必须转移到windbg 或其他一些内核模式调试器?
你不能从 Ollydbg 进入内核模式。您需要一个内核调试器windbg
,如ollydbg
用户模式调试器。
既然您提出了这个问题,我假设您既没有内核调试连接,也没有发送控制代码以进行分析的驱动程序,正如 Jonathon 所回答的那样。
从这里开始假设和强调使用适当的安全措施来处理恶意软件。
我假设恶意软件已经在运行,因为您的查询表明您正在使用DeviceIoControl
.
我将使用 ollydbg 2.01。
将 ollydbg 附加到未知进程
按Ctrl+G并开始输入ntdll.ntDeviceIo
,列表框将显示
ntdll.ntDeviceIoControl
现在选择它和follow label
。
按F2设置断点,并F9运行附加的进程。
INT3 breakpoints, item 0
Address = 7C90D27E NtDeviceIoControlFile
Module = ntdll
Status = Active
Disassembly = MOV EAX, 42
Comment = ntdll.NtDeviceIoControlFile(guessed Arg1,Arg2,Arg3,Arg4,Arg5,Arg6,Arg7,Arg8,Arg9,Arg10)
Ollydbg 应该在发送控制代码时中断,堆栈应该如下所示:
CPU Stack
Address Value ASCII Comments
0013EF50 [7C801675 u€| ; /RETURN from ntdll.NtDeviceIoControlFile to kernel32.DeviceIoControl+4C
0013EF54 /00000090 ; |Arg1 = 90
0013EF58 |00000000 ; |Arg2 = 0
0013EF5C |00000000 ; |Arg3 = 0
0013EF60 |00000000 ; |Arg4 = 0
0013EF64 |0013EF88 ˆï ; |Arg5 = 13EF88
0013EF68 |83050024 $ ƒ ; |Arg6 = 83050024
0013EF6C |00000000 ; |Arg7 = 0
0013EF70 |00000000 ; |Arg8 = 0
0013EF74 |0013EFEC ìï ; |Arg9 = 13EFEC
0013EF78 |00000004 ; \Arg10 = 4
从 的规范来看DeviceIoControlCode
,第一个参数指向,handle
第六个参数是control code
安装windbg 可以让事情变得更容易,但我们现在不会使用windbg,因为它有一个陡峭的学习曲线。
打开 ollydbg 句柄窗口并找到句柄指向什么(0x90
在上面的粘贴中) - 它指向一个设备:
Handles, item 9
Handle = 00000090
Type = File (dev) <-------- it is a _FILE_OBJECT
Refs = 2.
Access = 0012019F (FILE_GENERIC_READ|FILE_GENERIC_WRITE)
Tag =
Info =
Translated name = \Device\Dbgv
现在运行进程资源管理器从SysInternals
。选择未知进程,然后按Ctrl+H使下方窗格显示句柄。
选择手柄90
,右键单击并选择properties
。Process Explorer将显示Ollydbg 记录的设备对象的地址。这个设备对象是一个文件对象:
ollydbg 2.01
可以在上面显示内存0x7fffffff
(内核模式内存)我们将使用该功能来查找与此设备关联的驱动程序
阅读FILE_OBJECT
与您的操作系统相关的结构。在 Windows XP 中,您将在文件对象的 +4 处找到设备对象的地址。
选择转储窗口按Ctrl+G并输入地址进程资源管理器显示 viz
863c87f0 and follow expression
CPU Dump
Address Hex dump ASCII
863C87F0 05 00 70 00|A8 D3 51 86|00 00 00 00|00 00 00 00| p ¨ÓQ†
所以8651d3a8
在上面的粘贴中指向这个文件对象的设备对象。
阅读DEVICE_OBJECT
结构。在 Windows XP 中,驱动程序对象的地址在设备对象 + 8 处。跟在那里之后是Ctrl+ G->follow expression
如前所述
CPU Dump
Address Hex dump ASCII
8651D3A8 03 00 B8 00|01 00 00 00|48 2C F1 86|00 00 00 00| ¸ H,ñ†
通知86f12c48
是驱动程序对象。阅读DRIVER_OBJECT
结构。
+0xc is Driver Start
和+0x10 is Driver Size
--> Ctrl+G跟随:
CPU Dump
Address Hex dump ASCII
86F12C48 04 00 A8 00|A8 D3 51 86|12 00 00 00|00 30 2A A9| ¨ ¨ÓQ† 0*©
86F12C58 00 3D 00 00|48 9C D8 86|F0 2C F1 86|18 00 18 00| = HœØ†ð,ñ†
a92a3000
是DriverStart
,驱动程序的大小是3d00
。
Ctrl+G关注:
CPU Dump
Address Hex dump ASCII
A92A3000 4D 5A 90 00|03 00 00 00|04 00 00 00|FF FF 00 00| MZ ÿÿ
A92A3010 B8 00 00 00|00 00 00 00|40 00 00 00|00 00 00 00| ¸ @
名气IMAGE_DOS_HEADER
是有目共睹的。
选择a92a3000
to a92a6d00
, Right-Click-> Edit
-> binary copy 并将字节粘贴到任何十六进制编辑器(例如 HxD)中的新文件中,并将其另存为malwaredriver.sys
:)
foo:\>dir malwaredriver.sys
26/03/2014 14:04 15,616 malwaredriver.sys
\>set /a 0x3d00
15616
\>file malwaredriver.sys
malwaredriver.sys; PE32 executable for MS Windows (native) Intel 80386 32-bit
:\>
您现在可以静态分析驱动程序。
DRIVER_OBJECT
仔细阅读结构,发现你可以很容易地知道IRP_MJ_DEVICE_IO_CONTROL
ollydbg 中处理程序的处理程序。它将+0x70
来自 XP 中的 Driverobject。对于这个特定的驱动程序,IRP_MJ_DEVICE_IO_CONTROL_HANDLER
在
CPU Dump
Address Value ASCII Comments
86F12CB8 A92A4168 hA*©
你可以在ollydbg中跟踪和拆解这段内存。选择 cpu dump 按 ctrl+g 反汇编未知驱动程序
CPU Disasm
Address Command Comments
A92A4168 MOV EDI, EDI ; IRP_MJ_DEVICE_IO_CONTROL_HANDLER(pdevob,pirp)
A92A416A PUSH EBP
A92A416B MOV EBP, ESP
A92A416D SUB ESP, 24
A92A4170 PUSH EBX
A92A4171 PUSH ESI
A92A4172 MOV ESI, DWORD PTR SS:[EBP+0C] ; irp
A92A4175 MOV EAX, DWORD PTR DS:[ESI+60] ; nt!_irp -y Tail.overlay.cur->maj
A92A4178 MOV EDX, DWORD PTR DS:[ESI+0C] ; nt!_irp Tail.overlay.cur->par.DeviceIo.ty
A92A417B XOR EBX, EBX
A92A417D PUSH EDI
A92A417E LEA EDI, [ESI+18]
A92A4181 MOV DWORD PTR DS:[EDI], EBX
A92A4183 MOV DWORD PTR DS:[ESI+1C], EBX
A92A4186 MOVZX ECX, BYTE PTR DS:[EAX]
A92A4189 SUB ECX, EBX
A92A418B JE SHORT A92A41F7 ; case 0 create
A92A418D DEC ECX
A92A418E DEC ECX
A92A418F JE SHORT A92A41CA ; case 2 close
A92A4191 SUB ECX, 0C
A92A4194 JNE A92A42BB ; unhandled
A92A419A MOV ECX, DWORD PTR DS:[EAX+0C] ; ioctl
A92A419D MOV EBX, ECX
A92A419F AND EBX, 00000003
A92A41A2 CMP BL, 3
A92A41A5 JNE SHORT A92A41AC ; buff align
A92A41A7 MOV EBX, DWORD PTR DS:[ESI+3C]
A92A41AA JMP SHORT A92A41AE
A92A41AC MOV EBX, EDX ; inbuff
A92A41AE PUSH DWORD PTR SS:[EBP+8] ; devobj
A92A41B1 PUSH EDI
A92A41B2 PUSH ECX
A92A41B3 PUSH DWORD PTR DS:[EAX+4] ; bufflen
A92A41B6 PUSH EBX
A92A41B7 PUSH DWORD PTR DS:[EAX+8] ; ioctlcode
A92A41BA PUSH EDX
A92A41BB PUSH 1
A92A41BD PUSH DWORD PTR DS:[EAX+18] ; fobj
A92A41C0 CALL A92A3EEC ; actual_handler
这里处理ioctl代码:
CPU Disasm
Address Command Comments
A92A3EF8 MOV ESI, DWORD PTR SS:[EBP+24]
A92A3EFB XOR EBX, EBX
A92A3EFD MOV DWORD PTR DS:[ESI], EBX
A92A3EFF MOV DWORD PTR DS:[ESI+4], EBX
A92A3F02 MOV ECX, DWORD PTR SS:[EBP+20]
A92A3F05 MOV EAX, 83050020
A92A3F0A CMP ECX, EAX
A92A3F0C JA A92A40F1 this code will take this path as 24 > 20
============
CPU Disasm
Address Hex dump Command Comments
A92A40F1 81F9 24000583 CMP ECX, 83050024
A92A40F7 74 3F JE SHORT A92A4138 path taken
控制代码完成这项工作并在某些条件下发送一些 320
[code]
CPU Disasm
Address Command Comments
A92A4138 PUSH 4
A92A413A POP EAX
A92A413B CMP DWORD PTR SS:[EBP+1C], EAX
A92A413E JB SHORT A92A4152
A92A4140 MOV ECX, DWORD PTR SS:[EBP+18]
A92A4143 CMP ECX, EBX
A92A4145 JE SHORT A92A4152
A92A4147 MOV DWORD PTR DS:[ECX], 320 <------------
A92A414D MOV DWORD PTR DS:[ESI+4], EAX
A92A4150 JMP SHORT A92A4158
A92A4152 MOV DWORD PTR DS:[ESI], C000000D
A92A4158 MOV AL, 1
A92A415A CALL A92A46D5
A92A415F RETN 24
这里分析的驱动是来自SysInternals的dbgview(dbgv.sys)加载的驱动。此控制代码检查内存中加载的不兼容版本的驱动程序。可以通过特定的驱动程序和特定版本来练习:
(4.75) build time Thu Aug 07 04:51:27 2008
安装windbg后,您只需使用下面发布的几个命令即可完成相同的操作
C:\>tlist | grep -i dbgview
3724 Dbgview.exe DebugView on \\ (local)
C:\>kd -kl -c ".foreach /pS 1 /ps 4 (place { .shell -ci \"!handle 0 3 0n3724 Fi
le \" grep File } ) {dt nt!_FILE_OBJECT -y Dev->Dri->DriverS place};q" | grep -i
+0x00c
+0x00c DriverStart : 0xf7451000 Void
+0x00c DriverStart : 0xf73c5000 Void
+0x00c DriverStart : 0xa87f9000 Void
+0x00c DriverStart : 0xf7451000 Void
+0x00c DriverStart : 0xf7451000 Void
C:\>kd -kl -c ".reload ; lm a (0xf7451000); lm a (0xf73c5000) ; lm a (0xa87f9000);q" | grep -i defer
f7451000 f746f880 ftdisk (deferred)
f73c5000 f73db880 KSecDD (deferred)
a87f9000 a87fcd00 Dbgv (deferred)
C:\>kd -kl -c ".writemem malware.sys a87f9000 a87fcfff ;q" | grep -A 1 lkd
lkd> kd: Reading initial command '.writemem malware.sys a87f9000 a87fcfff ;q'
Writing 4000 bytes........
C:\>file malware.sys
malware.sys; PE32 executable for MS Windows (native) Intel 80386 32-bit
对上述命令的解释如下
kd -kl is local kernel debugging
!handle command has the capability to search for kernel handle
when you input a Pid
The explanation for arguments for this commands are
0 = all handles
3 = default flag provides basic+object information
0n3724 = pid (can be from task manager
File = type of Object to search for
!dt can display memebers of nested structures with ease
-y with dt takes partial inputs (wild card entries )
and displays all matching structure members
and the output is manipulatable with any text / stream handling
software like grep , sed . awk . find etc
更具体地说,听起来您的可执行文件正在加载设备驱动程序。用户空间可执行文件通常通过IOCTL(或 I/O 控件)与驱动程序通信。
DeviceIoControl
就是这样:向驱动程序发送一个 IOCTL。请注意此函数的第二个参数:DWORD dwIoControlCode
. 这是识别程序请求驱动程序执行哪个 IOCTL 的代码。它只是一个 32 位的 DWORD 值。
现在,在驾驶员方面,您需要了解一些事项。(准备好游过几个结构!)
首次加载驱动程序时,DriverEntry
将调用其函数。这会传递一个指向驱动程序的DRIVER_OBJECT
. 在这个结构中有一个名为 的数组MajorFunction
,它是一组函数指针,当用户空间试图对驱动程序做一些事情(例如打开、关闭或发送 IOCTL)时,内核将调用这些函数指针。这些功能由IRP 主要功能代码标识。
在 ioctls 发送的情况下DeviceIoControl
,该IRP_MJ_DEVICE_CONTROL
函数被调用。任何ioctl都会调用此函数。现在要确定dwIoControlCode
传递给 的是DeviceIoControl
,ioctl 处理函数将查看Parameters.DeviceIoControl.IoControlCode
。
根据这个值,通常有一个 switch 语句,它根据控制代码选择不同的行为。
因此,首先,您要将.sys
驱动程序加载到 IDA 中。IDA 标记为的函数DriverEntry
实际上是由 DDK 生成的包装器。真正DriverEntry
的通常jmp
是在这个存根的末尾。
在 real 中DriverEntry
,您需要找到MajorFunction
填充条目的位置。它可能看起来像这样: