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 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)
    – 0xC0000022L
    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?
    – mrduclaw
    Apr 6, 2013 at 9:10
  • @mrduclaw how do i Change the first byte of the driver's entry point to be an INT3?!??
    – AminM
    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!
    – mrduclaw
    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.
    – 0xC0000022L
    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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.