Kam,
In general you don't need symbols to know the entry point of a PE image. The entry point is conveniently stored to the PE header and can be read from it. Further the OS loader loads an image into memory (be it an EXE, DLL, or kernel mode driver) and calls its entry point thereafter. In other words by the time DriverEntry is called the driver will always be loaded. If all you need is break into WinDbg after a driver is loaded but before its entry point is called the situation is simple. And if you want to break even before the image is loaded into memory the situation is still simple enough. I described both scenarios bellow.
1) TODOs - break after driver load & before its entry point is called
1) Break into WinDbg -> Debug (menu) -> Event Filters
2) In the "Event Filters" select the "
Load module" event
> select
Execution -> Enabled
> click
Arguments and enter the name of the driver in question (
77fba431 in our case)
With this settings WinDbg will brake after loading any driver with the name 77fba431 and
before calling its entry point. Here is what happens:
0: kd>
.lastevent
Last event: Load module
77fba431.sys at
ba644000
debugger time: Wed Mar 31 21:12:56.937 2010 (GMT+2)
0: kd>
lm vm 77fba431
start end module name
ba644000 ba645e00 77fba431 (deferred)
Image path: 77fba431.sys
Image name: 77fba431.sys
Timestamp: Tue Mar 30 20:10:51 2010 (4BB23EAB)
CheckSum: 0000AD61
ImageSize: 00001E00
Translations: 0000.04b0 0000.04e4 0409.0
4b0 0409.04e4
;get ImageEntry (== DriverEntry)
0: kd>
? $iment( ba644000)
Evaluate expression: -1167828646 =
ba64595a
;now that we have the DriverEntry address we can conveniently set a breakpoint on it
0: kd>
bp ba64595a
*** ERROR: Module load completed but symbols could not be loaded for 77fba431.sys
0: kd>
bl
0 e
ba64595a 0001 (0001) 77fba431+0x195a
0: kd>
g
Breakpoint 0 hit
77fba431+0x195a:
ba64595a 8bff mov edi,edi
2) TODOs - break before our driver is loaded into memory (XP SP 3)
Behind the scenes a driver is loaded by
nt!IopLoadDriver. Its pseudo-code looks like this:
nt!IopLoadDriver( hRegKeyOfDriver, ...)
{
// get full path of our driver
UNICODE_STRING driverPath = call nt!IopBuildFullDriverPath(...);
// load driver into memory
call nt!MmLoadSystemImage( driverPath , ...)
// retrieve drivers entry point and call it
call nt!RtlImageNtHeader
call nt!IopPrepareDriverLoading
call dword ptr [edi+2Ch] // call DriverEntry
}
With this on mind we can use the following conditional breakpoint. It will cause WinDbg to break if the driver being loaded contains the name "77fba431" and continue execution in any other cases:
bu nt!IopLoadDriver ".block {as /c HandleOutput !handle poi(@esp+4)}; .block {.if ( $spat( \"${HandleOutput}\", \"*77fba431*\" ) ) { .echo ***** Loading our driver *****; ad *; } .else { ad *; g;}};"
Explanation:
- !handle poi(@esp+4) ...... get handle information and registry path of hRegKeyOfDriver; store it into HandleOutput (string alias)
- $spat( "${HandleOutput}", "*77fba431*" ) .... is 77fba431 found in HandleOutput? If yes break. If not go (g)
I peeked into
nt!IopLoadDriver on Windows XP SP3. It might bee slightly different on Windows Vista or Windows 7 installations. Nevertheless I think you got the idea and will be able to change the breakpoint if necessary. You could set a similar conditional breakpoint on
nt!MmLoadSystemImage. Note that its first parameter is the path of the driver:
0: kd>
kb
ChildEBP RetAddr Args to Child
ba507c74 8058107b
ba507cf8 00000000 00000000
nt!MmLoadSystemImage
ba507d54 80581487 80000748 00000001 00000000 nt!IopLoadDriver+0x371
ba507d7c 80538789 80000748 00000000 8a8e8640 nt!IopLoadUnloadDriver+0x45
ba507dac 805cff72 ae22acb0 00000000 00000000 nt!ExpWorkerThread+0xef
ba507ddc 8054611e 8053869a 00000001 00000000 nt!PspSystemThreadStartup+0x34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16
0: kd>
dS ba507cf8
e10e69b8 "\??\C:\CpDrv\77fba431.sys"
I hope this helps,
Robert