After the company did some project/people shuffling, I inherited a
prototype (proof-of-concept) windows filter driver. I’m a Unix kernel
developer so I am trying to learn the window’s I/O model and the driver
code while fixing some bugs (great way to learn, huh?). I am chasing a
problem that has me stumped so I am hoping someone can point me in the
right direction. This problem is on a XP SP1 system (but I think it may
be applicable to other versions).
In DriverEntry(), ZwQuerySystemInformation() is invoked using
sub-function SystemModuleInformation. The returned buffer is scanned
for an entry for ‘ntdll.dll’ and the module’s base address in memory is
used to find an entry point for later use (note: after doing some
reading and lurking, I understand the horrors of leveraging all of this
undocumented stuff…I didn’t write the code, just trying to
understand/fix it!).
During system initialization (boot), the address lookup is performed, as
described above, and actually yields the correct results. If the driver
is unloaded, which seems to work, and then reloaded, the system will
blue screen intermittently. These blue screens seem to depend on system
load and how ‘busy’ the system is. The system crashes while attempting
to reference ntdll.dll’s module base address that was obtained as
described above. In other words, what appears to have worked before
during system initialization and can be referenced, after the system has
been running for some time, the same memory is no longer accessible.
Looking at the memory dump produced, windbg indicates that a page fault
occurred in a nonpaged area. The address I am trying to reference (the
module’s base address) appears to be in the nonpaged pool. OK, so I
used !pte and !vad on the address and the page tables don’t indicate the
address is valid. I then used !address which displays the base address
of ntdll.dll (the address I am trying to read), the correct size and the
usage of ‘KernelSpaceUsageImage’, so it appears that the address that I
have for the base is ‘correct’ and is associated with ntdll.dll. Then I
used !imgreloc and amongst the printout it had a line that said “Unable
to read image header at xxxxxx” where xxxxx is the address I am trying
to reference, the module base address of ntdll.dll. In addition to the
“unable to read…” that I saw for ntdll.dll, there were six (6) others
for: win32k.sys, ati2dvag.dll, ati2cqag.dll, ati3d1ag.dll, hpblff2.dll
and dxg.sys; all of these addresses are in the b800000 through bff80000
range. I attempted to display some of these memory locations and windbg
always displays ‘???’ so I assume they are not valid addresses.
So, other than the fact that this is a great illustration of why you
should never use undocumented stuff, I have the following questions:
-
Why would an address for a system interface module be perfectly
usable during boot (and while a system is not busy) but not usable later
on after the system has been running for some time? I assume the answer
is that this memory is released later on if/when needed. If released,
why the memory associated with ntdll.dll? -
Why would memory in nonpaged pool not be available? I thought if it
was in nonpaged pool it is still usable. -
I am still slogging through trying to understand the MmXxxxx()
routines; is there a way to obtain visibility to this memory *if* the
data is still valid?
And yes, one of my action items is to get to the point of getting rid of
all of this undocumented cruft…as soon as I understand what is going
on.
Thanks for any and all advice