17

When you unpack manually a Windows user-mode executable, you can easily break at its EntryPoint (or TLS), then trace until you reach the original EntryPoint. However that's not possible with a packed driver.

How can you reliably unpack a Windows driver manually?

1
  • Who doesn't miss the greatest of all of them, Softice Commented Feb 24, 2017 at 9:21

4 Answers 4

16

I kind of like your answer about changing the subsystem, especially if you're not a fan of kernel debugging. I'm a big fan of Windbg, though. The way I do this is:

  1. Hook up my kernel debugger to a VM
  2. Change the first byte of the driver's entry point to be an INT3 (0xCC).
  3. Fix-up the PE checksum (I'm a fan of letting pefile do this work for me).
  4. Load the driver in the VM ( OSR has a great driver loader )

The kernel should call DriverEntry() on your driver and break into your debugger for you. Then you can trace the code until you find the OEP as you would have done anyway. The main advantage I see to this method is that you don't have to fake kernel DLLs or calls that the driver might do during unpacking, and it works on x64.

4
  • 1
    You might hit the wall on newer Windows versions, though. The answer of the OP is more versatile in that sense, but yours is certainly more professional :) ... also don't forget devcon for the driver loading needs (comes with source in the DDKs/WDKs) Commented Apr 2, 2013 at 14:41
  • 1
    @0xC0000022L I haven't had a problem with this on newer versions of Windows; just do the normal stuff like enable test signing, etc. Admittedly, I haven't tried it on Windows 8, though. Did something change? Commented Apr 6, 2013 at 9:10
  • @mrduclaw how do i Change the first byte of the driver's entry point to be an INT3?!?? Commented Jan 1, 2016 at 21:39
  • 1
    @AminM Sorry for the late response, I haven't checked this account in a long time. Open the file in IDA, find the bytes of where the entry-point is. Open it in a hex editor and chnage it to a 0xCC (break-point). Or, you can probably edit it directly in IDA these days. Good luck! Commented Jan 23, 2017 at 5:51
11
  1. change the driver subsystem to GUI (turning it into a user-mode binary)
  2. clear the imports' RVA, or use a set of fake kernel DLLs (only in 32 bits) to enable imports loading
  3. launch in your debugger and proceed as if it was user-mode - you'll probably need to simulate some API calls before reaching the original EntryPoint.
8

An alternative to patching the DriverInit function with an INT3 is to put a breakpoint in the IopLoadDriver function which is responsible for calling DriverInit. On Windows XP SP3, the breakpoint should be added at IopLoadDriver+0x66a which is call dword ptr [edi+2Ch] (0x2C is _DRIVER_OBJECT.DriverInit).

  1. Find IopLoadDriver with x nt!IopLoadDriver
  2. Add a breakpoint at IopLoadDriver+0x66a
  3. Load and start your driver

Offsets for other Windows versions:

  • Windows 7 Pro SP1 32-bit German: nt!IopLoadDriver+0x7eb
  • Windows 7 Ultimate 64-bit US: nt!IopLoadDriver+0xA04
  • Windows 10 Pro x64 US: nt!IopLoadDriver+0x51C (Build 10586.420)

(If you have offsets for other versions of Windows, please edit this answer)

1
  • Nice bit of info. It is always valuable to have bits and pieces which you can put together as reverser. Also remember you can get a good guess of the implementation details in Windows by looking at the ReactOS source code. Commented Aug 13, 2013 at 20:42
6

nt!IopLoadDriver indirect call is used only for SERVICE_DEMAND start driver entry

for boot loading drivers you would need to break on nt!IopInitializeBuiltInDriver indirect call as well

you can see a short example on message #17 & #18 in this link

http://www.osronline.com/showthread.cfm?link=231280

this is a dormant script (slightly edited to use gc (go from conditional instead of go as recommended ) that keeps waiting forever and will print out the !drvobj details when ever any driver is loaded in a kernel debugging session

no word wraps the command should be in a single line

.foreach /pS 1 /ps 10 ( place { # call*dword*ptr*\[*\+*\] nt!IopInitializeBuiltinDriver} ) {bu place ".printf \"%msu\\n\", poi(esp+4);r $t0 = poi(esp); gu; !drvobj $t0 2;gc"} .foreach /pS 1 /ps 10 ( place { # call*dword*ptr*\[*\+*\] nt!IoploadDriver} ) {bu place ".printf \"%msu\\n\", poi(esp+4);r $t1 = poi(esp); gu; !drvobj $t1 2;gc"} 

xp sp3 vm

in a connected kd session do sxe ibp; .reboot kd will request an initial break on rebooting (equivalent to /break switch in boot.ini) when broken run this script

$$>a< "thisscript.extension" 

in addition to printing all the system driver entry points and their driver objects

if your application loads an additional driver their details will be printed too

a sample output for sysinternals dbgview opened in the target vm

the dbgv.sys entry point is called when you check mark the enable kernel capture (ctrl+k)

\REGISTRY\MACHINE\SYSTEM\ControlSet001\Services\DBGV *** ERROR: Module load completed but symbols could not be loaded for Dbgv.sys Driver object (ffbd6248) is for: \Driver\DBGV DriverEntry: f6d89185 Dbgv DriverStartIo: 00000000 DriverUnload: 00000000 AddDevice: 00000000 Dispatch routines: [00] IRP_MJ_CREATE f6d87168 Dbgv+0x1168 [01] IRP_MJ_CREATE_NAMED_PIPE 804fa87e nt!IopInvalidDeviceRequest [02] IRP_MJ_CLOSE f6d87168 Dbgv+0x1168 [03] IRP_MJ_READ 804fa87e nt!IopInvalidDeviceRequest [04] IRP_MJ_WRITE 804fa87e nt!IopInvalidDeviceRequest [05] IRP_MJ_QUERY_INFORMATION 804fa87e nt!IopInvalidDeviceRequest [06] IRP_MJ_SET_INFORMATION 804fa87e nt!IopInvalidDeviceRequest [07] IRP_MJ_QUERY_EA 804fa87e nt!IopInvalidDeviceRequest [08] IRP_MJ_SET_EA 804fa87e nt!IopInvalidDeviceRequest [09] IRP_MJ_FLUSH_BUFFERS 804fa87e nt!IopInvalidDeviceRequest [0a] IRP_MJ_QUERY_VOLUME_INFORMATION 804fa87e nt!IopInvalidDeviceRequest [0b] IRP_MJ_SET_VOLUME_INFORMATION 804fa87e nt!IopInvalidDeviceRequest [0c] IRP_MJ_DIRECTORY_CONTROL 804fa87e nt!IopInvalidDeviceRequest [0d] IRP_MJ_FILE_SYSTEM_CONTROL 804fa87e nt!IopInvalidDeviceRequest [0e] IRP_MJ_DEVICE_CONTROL f6d87168 Dbgv+0x1168 [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL 804fa87e nt!IopInvalidDeviceRequest [10] IRP_MJ_SHUTDOWN 804fa87e nt!IopInvalidDeviceRequest [11] IRP_MJ_LOCK_CONTROL 804fa87e nt!IopInvalidDeviceRequest [12] IRP_MJ_CLEANUP 804fa87e nt!IopInvalidDeviceRequest [13] IRP_MJ_CREATE_MAILSLOT 804fa87e nt!IopInvalidDeviceRequest [14] IRP_MJ_QUERY_SECURITY 804fa87e nt!IopInvalidDeviceRequest [15] IRP_MJ_SET_SECURITY 804fa87e nt!IopInvalidDeviceRequest [16] IRP_MJ_POWER 804fa87e nt!IopInvalidDeviceRequest [17] IRP_MJ_SYSTEM_CONTROL 804fa87e nt!IopInvalidDeviceRequest [18] IRP_MJ_DEVICE_CHANGE 804fa87e nt!IopInvalidDeviceRequest [19] IRP_MJ_QUERY_QUOTA 804fa87e nt!IopInvalidDeviceRequest [1a] IRP_MJ_SET_QUOTA 804fa87e nt!IopInvalidDeviceRequest [1b] IRP_MJ_PNP 804fa87e nt!IopInvalidDeviceRequest 

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.