You cannot step into kernel mode from Ollydbg. You need a kernel debugger like windbg
, as ollydbg
is a user mode debugger.
Since you posed the question, I assume you neither have a kernel debugging connection,
nor the driver where that control code is sent for analyzing it, as answered by Jonathon.
Usage of proper security measures to deal with malware assumed and emphasized from here onward.
I assume the malware is running already as your query states that you are on DeviceIoControl
.
I am going to use ollydbg 2.01.
Attach ollydbg to an unknown process
Press Ctrl+G and start typing ntdll.ntDeviceIo
and the list box will show
ntdll.ntDeviceIoControl
now select it and follow label
.
Press F2 to set a breakpoint, and F9 to run the attached process.
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 should break when a control code is sent and stack should look like this:
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
From the specs of DeviceIoControlCode
, the first argument points to handle
and the sixth argument is the control code
Having windbg installed can make things easier from here, but we will not use windbg at this moment as it has a steep learning curve.
Open ollydbg handle window and find what does the handle point to (0x90
in the above paste) - it points to a device:
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
Now run Process Explorer from SysInternals
. Select the unknown process, and press Ctrl+H to make the lower pane show handles.
Select the handle 90
, right click and select properties
. Process Explorer will show the address of the Device Object as noted by Ollydbg. This device object is a File Object:

ollydbg 2.01
can show memory above 0x7fffffff
(kernel mode memory) we will use that feature to find the driver associated with this device
Read about the FILE_OBJECT
structure relevant to your OS. In Windows XP you will find the address of device object at +4 from file object.
Select the dump window press Ctrl+G and type in the address process explorer showed 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†
So 8651d3a8
in the paste above points to the device object for this file object.
Read about DEVICE_OBJECT
structure. In Windows XP, the address of the driver object is at device object + 8. Following there with Ctrl+G -> follow expression
as done earlier
CPU Dump
Address Hex dump ASCII
8651D3A8 03 00 B8 00|01 00 00 00|48 2C F1 86|00 00 00 00| ¸ H,ñ†
notice 86f12c48
is driver object. Read about DRIVER_OBJECT
structure.
+0xc is Driver Start
and +0x10 is Driver Size
--> Ctrl+G to follow:
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
is DriverStart
and size of driver is 3d00
.
Ctrl+G to follow:
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| ¸ @
The famous IMAGE_DOS_HEADER
is noticeable.
Select from a92a3000
to a92a6d00
, Right-Click -> Edit
-> binary copy and paste the bytes to a new file in any hex editor (HxD for example), and save it as 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
:\>
You can now analyze the driver statically.
Read about DRIVER_OBJECT
structure carefully to find you can readily know the handler for IRP_MJ_DEVICE_IO_CONTROL
handler in ollydbg. It would be at +0x70
from Driverobject in XP. For this particular driver, the IRP_MJ_DEVICE_IO_CONTROL_HANDLER
is at
CPU Dump
Address Value ASCII Comments
86F12CB8 A92A4168 hA*©
You can follow and disassemble this memory in ollydbg. Select cpu dump press ctrl+g to disassemble an unknown driver
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
Here the ioctl code is handled:
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
The control code does this work and sends some 320 on some condition
[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
The driver analysed here is the driver loaded by dbgview (dbgv.sys) from SysInternals. This control code checks for an incompatible version of driver loaded in memory. Follow through can be practiced with the specific driver and specific version:
(4.75) build time Thu Aug 07 04:51:27 2008
EDIT
With windbg inastalled you can do the same with just few commands as posted below
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
An explanation for the commands above as follows
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