Safe kernel memory access - Am I crazy or is Windows?

I’m currently working on a security research project where I would like to hash portions of the windows XP kernel memory to integrity check it. But I am having an apparent problem doing this safely, especially for one chunk of the ntkrnlpa.exe which I have in my VMs.

Here’s what I’ve determined about the problem thus far:
* If I DO NOT try to lock memory with an MDL and MmProbeAndLock memory, then the memory reads/hashing works just fine. Because my code runs at IRQL Dispatch, this means that all the memory in question must be paged in.
* If I DO lock/unlock memory. I get an eventual bugcheck about a corrupt PFN list entry for a memory space that I had previously successfully locked and unlocked. But the PFN in question had a reference count of 0 when I locked it, and it seems like locking and unlocking the page with reference count 0 somehow then makes it active for other kernel modules. Here’s the details of it and contextual information. I’m pretty sure I know what’s going on, and the only question which still remains is whether my proposed method for safe memory access is valid, and if so, how do I do it…

Sorry, copy paste fail...

Working backward, here's the bugcheck:

PFN_LIST_CORRUPT (4e)
Typically caused by drivers passing bad memory descriptor lists (ie: calling
MmUnlockPages twice with the same list, etc). If a kernel debugger is
available get the stack trace.
Arguments:
Arg1: 00000007, A driver has unlocked a page more times than it locked it
Arg2: 00000657, page frame number
Arg3: 000030d6, current share count
Arg4: 00000000, 0

Debugging Details:



BUGCHECK_STR: 0x4E_7

DEFAULT_BUCKET_ID: DRIVER_FAULT

PROCESS_NAME: svchost.exe

LAST_CONTROL_TRANSFER: from 804f8dd9 to 8052a980

SYMBOL_ON_RAW_STACK: 1

STACK_ADDR_RAW_STACK_SYMBOL: fffffffff7b2a128

STACK_COMMAND: dds F7B2A128-0x20 ; kb

STACK_TEXT:
f7b2a108 00000000
f7b2a10c 00000000
f7b2a110 00000000
f7b2a114 00000000
f7b2a118 00000000
f7b2a11c 81bcb2c0
f7b2a120 f66288ec
f7b2a124 f97d8502 atapi!IdePortNotification+0xee
f7b2a128 81bce458
f7b2a12c 81bcd374
f7b2a130 806eaa3c hal!READ_PORT_UCHAR
f7b2a134 8129e1dc
f7b2a138 f6628924
f7b2a13c f97d2da1 atapi!AtapiInterrupt+0x6ef
f7b2a140 00000001
f7b2a144 81bcd370
f7b2a148 00000000
f7b2a14c 81bce7a8
f7b2a150 804fb8af nt!KeInsertQueueDpc+0x12f
f7b2a154 81bce7a8
f7b2a158 81bcd0e8
f7b2a15c f6628900
f7b2a160 00000000
f7b2a164 05bce458
f7b2a168 f6628938
f7b2a16c f97d5614 atapi!IdePortInterrupt+0x34
f7b2a170 ffdff9c0
f7b2a174 00000000
f7b2a178 00000000
f7b2a17c 81bcea0c
f7b2a180 f66289e4
f7b2a184 f662895c

FOLLOWUP_IP:
atapi!IdePortNotification+ee
f97d8502 5f pop edi

SYMBOL_NAME: atapi!IdePortNotification+ee

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: atapi

IMAGE_NAME: atapi.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 41107b4d

FAILURE_BUCKET_ID: 0x4E_7_atapi!IdePortNotification+ee

BUCKET_ID: 0x4E_7_atapi!IdePortNotification+ee

Followup: MachineOwner
--------------------------------------------------------------------
Here's the call stack (my driver isn't in it). In particular we can see this bugcheck occurred in MiDecrementReferenceCount, at a location

where it checks if it's trying to decrement a 0.

nt!RtlpBreakWithStatusInstruction
nt!KiBugCheckDebugBreak+0x19
nt!KeBugCheck2+0x574
nt!KeBugCheckEx+0x1b
nt!MiDecrementReferenceCount+0x33
nt!MiDeferredUnlockPages+0x17c
nt!MiFreePoolPages+0xa4
nt!ExFreePoolWithTag+0x1ba
Ntfs!NtfsDeleteMdlAndBuffer+0x31
Ntfs!NtfsCommonWrite+0x188c
Ntfs!NtfsCommonWrite+0x182d
Ntfs!NtfsFsdWrite+0xf3
nt!IopfCallDriver+0x31
fltMgr!FltpDispatch+0x132
nt!IopfCallDriver+0x31
sr!SrWrite+0xaa
nt!IopfCallDriver+0x31
fltMgr!FltpLegacyProcessingAfterPreCallbacksCompleted+0x20b
fltMgr!FltpDispatch+0x104
nt!IopfCallDriver+0x31

So the bugcheck said "Arg2: 00000657, page frame number" so let's go look at that PFN.
kd> !pfn 0x657
PFN 00000657 at address 810A0184
flink 0000EA9A blink / share count 000030D6 pteaddress E11CFBB0
reference count 0000 Cached color 0
restore pte 818F6EC800000460 containing page 00AB13 Standby P
Shared

So yes, the PFN in question has a reference count of 0. HOWEVER, I have traced through my code, and found that the PFN in question was already

NOT on the active list (and hence had a reference count of 0) even when my driver first is loaded. Upon further investigation, I found that

this 4kb section corresponds to a portion of the PAGEVRFY section in ntkrnlpa.exe (and that at different times, different 4kb chunks of this

section are moved to different lists besides the active list).

Virtual Address 0x80656000 (My kernel is based at 804d7000)
Section - PAGEVRFY
PFN - 0x656

kd> !pfn 0x656
PFN 00000656 at address 810A0168
flink 00002BAD blink / share count 00000001 pteaddress C07119D8
reference count 0002 Cached color 0
restore pte 000000C0 containing page 006779 Active M
Modified

PFNs before lock:
810a0168 00002bad c07119d8 00000001 00011601 000000c0 00000000 00006779
810a0184 0000ea9a e11cfbb0 000030d6 00001208 00000460 818f6ec8 0000ab13
810a01a0 0000cd60 e392a770 0000245d 00001208 00000460 81698308 000079e6
810a01bc 000000e5 e1a235d8 00000001 00011608 00000420 81a89fc0 00004be8
810a01d8 00000db8 e4397c70 00002edb 00001208 000004c0 81a1d378 0000c849
810a01f4 0000f11c e38bdee0 0000779a 00001208 000004c0 8133afd0 0000da1b
810a0210 0000041d c006cd88 0000b15b 00001200 00000080 00008a2b 00006ff9
810a022c 00009c26 e70b8018 0000b40a 00001208 000004c0 81975c58 00005c8b
810a0248 0000ae7a e3a63238 00006939 00001208 000004c0 81a3fda0 00000a9b
810a0264 0000b0d0 e1a1af58 00003258 00001208 00000460 819fe058 00004bdf
810a0280 0000be25 c0712028 00000001 00011601 000000c0 00000000 000067ba
810a029c 000002ae e102a060 00000002 00011609 00000080 00000000 00002122
810a02b8 0000ba21 c006c7d8 0000cb63 00001200 00000080 000082b9 00006ff9
810a02d4 00005c5e e15c55e8 00000001 00011608 000004c0 81b96498 00002fb8
810a02f0 00000429 e70b8100 0000b923 00001208 000004c0 81975c58 00005c8b

So the PFN where the crash occurs is 0x657, so it's the second one, i.e.
810a0184 0000ea9a e11cfbb0 000030d6 00001208 00000460 818f6ec8 0000ab13

When looking for the reference count field in this display format, it is the most significant 4 nibbles of the 00001208 - i.e. for this 4KB

chunk, it's 0, as we saw before. Now the issue is that I CAN MmProbeAndLock all this memory, and indeed I see all of the first 4 nibbles

incremented by 1 (so it's 2, 1, 1, 2, 1 ... rather than the 1, 0, 0, 1, 0... that it is shown above), and I also see the MmUnlockPages succeed,

which is why the memory once again looks like the above at crash time.

I tried to use MmIsAddressValid(), to skip looking at the addresses for PAGEVRFY. However this did nothing. I investigated by stepping into the

function, and found that for the given virtual address, MmIsAddressValid first checks the PDE. If is has the large page bit set (0x80), then

the function always returns 1. Because this is a PAE system, it appears to be using 2MB pages for the kernel, and thus this bit is set, and the

function does nothing for me. This brings me to the first question: If the kernel is using 2MB pages, why do the PFN entries therein still

refer to 4KB chunks of memory?

It is my understanding based on reading Windows Internals 4, page 469, table 7-20 that for PFNs on the standby list "The PTE ... is marked

invalid...". So my next question is, could I potentially avoid reading these dicey pages by doing a manual lookup of the PTE for every virtual

memory address location, and then checking if it's invalid?

The related question I have is that I'm not really sure how to find the PTE for virtual memory address in a 2MB page. Acording to the Intel

Manual VOl 3a, page 3-36 (at least in my book) section 3.8.3 figure 3-19, there is no PTE level of indirection for 2MB pages with PAE. That is,

it only shows a PDE which points to a 2MB page, for which the 20 least significant bits of the linear address are the offset. The output for

!pte is as follows, I just don't actually know how it's calculated:

kd> !pte 0x80656000
VA 80656000
PDE at 00000000C0602018 PTE at 00000000C04032B0
contains 00000000006009E3 contains 0000000000000000
pfn 600 -GLDA--KWEV LARGE PAGE pfn 656

In this case it seems like the PFN for the PTE is at PFN_for_PDE+(0x56000/0x1000)...but I don't really want to do these sorts of calculations

until I know what's actually going on behind the scenes. (Also, I know the base of the PFN database isn't exported (except in debug symbols),

and if I have to deal with the PFN then I will have to hardcode it...but that's fine since this is just a proof of concept, but I would like to

avoid it if possible, by somehow being able to find and check virtual memory address validity at the PTE (if it's real)).

So that discussed ways which I want to work around this issue I'm having where if I lock and unlock some memory, it seems to cause the memory

to cause problems for other portions of the code. But aside from the workaround, does anyone have any theories on why locking and unlocking

memory with a reference count of 0 causes this problem? Is there maybe a race condition with my unlock not fully taking place combined with a

deferred unlock in nt!MiDeferredUnlockPages?

Thanks

Jack

Have you tried using driver verifier?

mm

I am certainly open to using driver verifier in the future, but based on this debugging, I’m not entirely sure that it would help me. The key reasoning being that the PFN which the error occurs on already has a 0 reference count before I load, and even if I don’t load my driver (since I have a VM the virtual address is always the same at each revert to snapshot, so I can just start the debugger and look at the same PFN. It has a 0 count. And actually, based on peridically breaking, all the PFN entries in the PAGEVRFY section are sort of in flux in that they are jumping around on different lists, having zero and non-zero reference counts, etc. In contrast the PFNs for the PAGELK section right before it are always stable with a reference count of 1, and listed as being on the active list.

Jack

I’m not sure what it is that you’re proposing. If you’re asserting that you think Windows is in error, I would be against that, but either way, I’d run the tool myself.

mm

> But the PFN in question had a reference count of 0 when I locked it, and it seems like

locking and unlocking the page with reference count 0 somehow then makes it active
for other kernel modules.

Actually, it is not so easy to understand what you are trying to say here, but in any case, if PFN has a refcount of zero, it means that it is free , i.e. it it not mapped to any virtual address at the moment… The very idea of locking memory is to ensure that a given virtual address is always backed up by a physical page so that page fault does not arise when you access it. Therefore, locking and unlocking operations applies only to virtual addresses. At the moment you lock/unlock a range physical pages that back it up are mapped to the virtual addresses corresponding to the target range, and, hence, are just bound to have non-zero refcounts…

Anton Bassov

I’m definitely not suggesting Windows is in error. So it’s pretty clear that one probably shouldn’t access (or even MmProbeAndLock/MmUnlockPages) on a virtual memory address range which contains within it a PFN which has a reference count of 0 and/or is not on the active list. But as far as I can see, Windows is giveing me no way to avoid this! MmIsAddressValid() just returns true! So since I need to be able to avoid this. According to WinInternals books, the PTE should be invalid, so if I can figure out how to check the PTE I can figure out how to avoid it. But because it’s a 2MB page, I’m pretty sure it doesn’t have a PTE. Thus, my other option is to try and find the PFN and parse it. But I have a feeling that if I have to do that, I could screw it up (not to mention the PFN database base address is not exported), so I don’t want to go that way unless necessary.

So the question remains, how can I *avoid* locking (and subsequently touching) memory regions which have a PFN with a reference count of 0?

Jack

> So it’s pretty clear that one probably shouldn’t access (or even MmProbeAndLock/MmUnlockPages)

on a virtual memory address range which contains within it a PFN which has a reference
count of 0 and/or is not on the active list. But as far as I can see, Windows is giveing me no way
to avoid this! MmIsAddressValid() just returns true! So since I need to be able to avoid this.
According to WinInternals books, the PTE should be invalid, so if I can figure out how to check the
PTE I can figure out how to avoid it. But because it’s a 2MB page, I’m pretty sure it doesn’t have a PTE. >Thus, my other option is to try and find the PFN and parse it.

Sorry, but the above paragraph further confirms my suspicions that you don’t see any difference between physical and virtual memory - you seem to use terms PTE (that describes virtual page) and PFN database entry (that describes physical page) interchangeably…

Any page that is mapped to a virtual address is bound to have its PTE regardless of page size - otherwise it would not be accessible to CPU in protected mode with paging enabled. MmIsAddressValid() just checks Present bit of PTE. Therefore, if it returns true, it means that a virtual address is backed up by a physical page at the time, which, in turn, means that PFN database entry that describes a given physical page has non-zero in its refcount field.

If virtual address is not backed up by a physical page at the moment, its PTE’s data is meaningless for CPU
(apart from Present bit indicating that CPU should not try to interpret other bits because page is not in RAM), i.e. virtual page is described by so-called “prototype PTE” that tells page fault handler how to locate target page’s data. It is understandable that speaking about PFN database entry does not make sense in this context…

I am afraid your “security research project” is doomed to failure - you want to validate the integrity of something without understanding how it actually works…

Anton Bassov

Let’s see… how about not trying to do what you’re doing? And not going behind the back of the OS and interpret the processor data structures might help.

Lots of people have tried to do what you’ve proposed (checksum some “parts” of the OS to ensure it hasn’t changed)… and I’m not aware of a single one that’s managed to get it done. As far as I can tell, this is a fundamentally impossible project. How do you know a priori exactly WHICH parts of the OS code are guaranteed to never change? And if one DOES change (oh, say, like as a result of a patch being applied to the OS) how do you know if your algorithm is wrong or the OS has been hacked?

Let me guess… this is a university assignment, right?

Peter
OSR

“Any page that is mapped to a virtual address is bound to have its PTE regardless
of page size - otherwise it would not be accessible to CPU in protected mode
with paging enabled.”

Anton, I totally respect you because I’ve seen you give good answers elsewhere, but I wish you would look at the things I cited in my original long post. If you would have done so you would have said “Hey, the figures you cite don’t exist in the latest Intel manual!”. And indeed, they don’t because I’m using a physical book which is apparently out of date (at least for reference purposes, not content-wise)

I’m sure you have a good understanding of how PAE normally works, that is to say in the kernel/userspace 4KB case. But because I can see that 2MB PAE pages are not addressed in either version 4 or 5 of the windows internals books, and I can’t find good descriptions of how it works through searching, I have to remain skeptical when people describe it, if it doesn’t jive with what I’m seeing.

OK, so here’s the relevant document:
http://www.intel.com/Assets/PDF/manual/253668.pdf

And the page to look at is:
4-18, Figure 4-6. How do I know it’s figure 4-6 and not 4-5? Because per page 4-20, table 4-9, if bit [7] is 1, then it is a 2MB page. Looking at the entry I posted before

kd> !pte 0x80656000
VA 80656000
PDE at 00000000C0602018 PTE at 00000000C04032B0
contains 00000000006009E3 contains 0000000000000000
pfn 600 -GLDA–KWEV LARGE PAGE pfn 656

If we look at the PDE, we see the value is 00000000006009E3. The 7th bit of this value is 1. Therefore, by definition, we are using figure 4-6, and at least in the Intel sense, there is no page table being used. This is why I said there was no PTE (and why the information in the Windows Internals book which says “The PTE is set to invalid” almost certainly doesn’t apply.

Anton, do you agree with my assessment that if the architecture in figure 4-6 is being used, there is no such thing as a PTE in the traditional sense? There is only the PDE, which per the debugger and windows internals, points at a PFN. Indeed, by looking at the above entry, we can see that the “pfn 600” line is derived from the uppermost portion of “6009E3”. This is in conflict which your statement
“Any page that is mapped to a virtual address is bound to have its PTE regardless
of page size - otherwise it would not be accessible to CPU in protected mode
with paging enabled.”

I must also take issue with your statement:
"MmIsAddressValid() just checks Present bit of PTE. "

Here is the relevant trace of assembly for MmIsAddressValid which shows that for the virtual address I am looking at, the *only* value which is being checked is the [7]th bit of the PDE (which I previously called the 0x80 bit.)

nt!MmIsAddressValid:
80512d9e 8bff mov edi,edi
80512da0 55 push ebp
80512da1 8bec mov ebp,esp
80512da3 51 push ecx
80512da4 51 push ecx
80512da5 8b4d08 mov ecx,dword ptr [ebp+8]

ecx now == the virtual address we passed in

80512da8 56 push esi
80512da9 8bc1 mov eax,ecx
80512dab c1e812 shr eax,12h
80512dae bef83f0000 mov esi,3FF8h
80512db3 23c6 and eax,esi
80512db5 2d0000a03f sub eax,3FA00000h

eax now is C0602018 - the page directory offset

80512dba 8b10 mov edx,dword ptr [eax]

edx is now 006009E3 - the PDE

80512dbc 8b4004 mov eax,dword ptr [eax+4]
80512dbf 8945fc mov dword ptr [ebp-4],eax
80512dc2 8bc2 mov eax,edx
80512dc4 57 push edi
80512dc5 83e001 and eax,1

yep, checking the present bit

80512dc8 33ff xor edi,edi
80512dca 0bc7 or eax,edi
80512dcc 7461 je nt!MmIsAddressValid+0x91 (80512e2f)
80512dce bf80000000 mov edi,80h
80512dd3 23d7 and edx,edi

Checking the [7]th bit. Because it’s set, the result is 0x80 in edx.

80512dd5 6a00 push 0
80512dd7 8955f8 mov dword ptr [ebp-8],edx
80512dda 58 pop eax
80512ddb 7404 je nt!MmIsAddressValid+0x43 (80512de1)
80512ddd 85c0 test eax,eax
80512ddf 7452 je nt!MmIsAddressValid+0x95 (80512e33)
It just pushed 0 and then popped it into eax…this jump will always be taken

80512e33 b001 mov al,1
80512e35 5f pop edi
80512e36 5e pop esi
80512e37 c9 leave
80512e38 c20400 ret 4

So there you have it folks, if it’s a 2MB page (0x80 bit set), MmIsAddressValid always returns true.

Now I have no prior experience dealing with PAE, only regular paging as implemented in (you guessed it Peter) my university OS class. The concept of anything except a 4KB page and especiallythe PFN database is quite foreign to me. However, as I previously described, and I’m looking for evidence to the contrary, as far as I can tell, the only way which this 2MB page can be translatable (in the absense of that page table level of indirection), is if Windows just stacks all the PFN entries together when ntkrnlpa.exe is loaded, so that as I said before, to find the PFN for 0x80656000, you first get the PFN for the PDE (which as you can see above is 0x600) and then do PFN_for_PDE+(0x56000/0x1000), which equals PFN 0x656.

So basically, like I said before, my charter is to read and hash the memory, and I don’t really want to give up until I understand why it’s impossible (since hopefully the previous discussions can convince people that I may be a little more capable than those who came before me ;). And in particular, if I’m way off base, I would love it if someone could prove it by just popping open WinDbg, finding the base of the kernel by putting “nt” into an address bar, and then showing the !pte output, and explaining how you correctly translate from virtual address to PFN and/or physical address. :slight_smile:

Thanks

Jack

I feel like I’m missing something in this whole debate. But, I guess if I focus on one sentence at a time, I might feel more grounded.

MmIsAddressValid returns TRUE if touching the address specified will NOT cause a page fault (at the time of MmIsAddressValid is called… so this might not be true by the time MmIsAddressValid returns… but that’s a different story). Right?

Windows doesn’t page large pages (which, by the way, are also always read/write and can’t be read-only). How WOULD it? It’d have to page all 2MB out at a time…

I’m still not sure how you know what address range to checksum, and when it changes, how you know whether the change is legit or malware induced.

Peter
OSR

Jack,

> “Any page that is mapped to a virtual address is bound to have its PTE regardless of page size - >>otherwise it would not be accessible to CPU in protected mode with paging enabled.”

Anton, I totally respect you because I’ve seen you give good answers elsewhere, but I wish you
would look at the things I cited in my original long post. If you would have done so you would have
said “Hey, the figures you cite don’t exist in the latest Intel manual!”.

Sorry, I did not read it carefully - now I see where your mistake is rooted…

In any case, please note that layouts of tables for both large and small pages in PAE mode, as well as non-PAE and 32e one, is thoroughly described in Intel Manuals…

Concerning a check for large page by MmIsAddressValid() , it is done on both PAE and non-PAE kernels
(in the latter case large page is 4M) . You just make a bold assumption that the whole thing should end at this point because you mistakenly believe page has to be large. This is where your mistake is rooted.
The assumption that kernel portion of address space would rely only on large pages under Windows is simply baseless . Just to give you an idea, quite often the system has to map MDLs describing user buffers that are backed up by 4K pages into the kernel address space…

Anton Bassov

> Anton, do you agree with my assessment that if the architecture in figure 4-6 is being used,

there is no such thing as a PTE in the traditional sense?

Actually, PTE is still there even if it describes a large page - please note that page directory happens to be a page table as well…

Anton Bassov

Adding to what’s written:

  1. In general, you should not care whether a particular address is mapped through a large page. Just go in 4K increments.
  2. As soon as you admit possibility that the kernel memory can be maliciously tampered with and you think you only have to detect that to be safe, the game is lost. You need to prevent that, not detect that after the fact. You use Windows security (NEVER give your users administrative rights; also use software restrictions if necessary, disable the stupid autorun, etc), and administrative procedures (limiting physical access to the hardware, etc).

Jack,

It looks like finally I realized what your problem is really about and what erroneous assumption about large kernel pages is based upon - the thing is, you crash whenever you encounter a large page, and it happens because you try to lock it…

As long as you deal with virtual ranges that are backed up by 4K pages everything is fine and dandy.
However, let’s look at what happens if page is large. Depending on CPU support for PAE, it is composed of 512 or 1024 small pages. Every physical page has an entry in PFN database. Therefore, PFN entries for all these small pages are, apparently, set up to indicate that a given page has no life on its own and is a part of a large page (apparently, this is why you get refcount of 0 when if examine PFN database entry). Once large pages are not swapped out to the disk, MmProbeAndLockPages() assumes that it deals only with 4K pages. Therefore, apparently it modifies PFN database entries for all small pages that comprise a large one to indicate that a given page is locked, effectively screwing up PFN database. Pure and simple.

What you have to do here is to check whether page is large or small whenever your target buffer is aligned on 2M boundary, and avoid calling MmProbeAndLockPages() in the former case …

Anton Bassov

> In general, you should not care whether a particular address is mapped through a large page.

Just go in 4K increments.

This is what he does, and crashes, apparently, exactly for the reason that he does not care about page size…

Anton Bassov

wrote in message news:xxxxx@ntdev…

> 2. As soon as you admit possibility that the kernel memory can be
> maliciously tampered with and you think you only have to detect that to be
> safe, the game is lost. You need to prevent that, not detect that after
> the fact.

No, the game is not lost. Consider scanning a snapshot of a virtual
machine.
This can be done from outside of the VM (from hypervisor or something like
AMT).
If you detect bad things in a VM, some recovery options still are
available.

Regards,
–pa

I agree that some sort of out of band execution capability does offer some possibilities, especially in the prevention department, and also in the way of recovery, but I think that the means you describe still fall under ‘prevention’ for all practical purposes, because they have to be in place before everything else and ensure that they do not get removed/compromised/subverted.

mm

What OS is this? Can you post the output of “vertarget” and “!dh nt”?


Pavel Lebedinsky/Windows Kernel Test
This posting is provided “AS IS” with no warranties, and confers no rights.

Pavel:

kd> vertarget
Windows XP Kernel Version 2600 (Service Pack 2) MP (1 procs) Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 2600.xpsp_sp2_qfe.070227-2300
Machine Name:
Kernel base = 0x804d7000 PsLoadedModuleList = 0x8055c700
Debug session time: Thu Aug 6 14:17:40.656 2009 (GMT-4)
System Uptime: 0 days 9:41:41.812
kd> !dh nt

File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (i386)
19 number of sections
45E5484A time date stamp Wed Feb 28 04:15:54 2007

0 file pointer to symbol table
0 number of symbols
E0 size of optional header
12E characteristics
Executable
Line numbers stripped
Symbols stripped
App can handle >2gb addresses
32 bit word machine

OPTIONAL HEADER VALUES
10B magic #
7.10 linker version
1A1400 size of code
5C000 size of initialized data
0 size of uninitialized data
1C8C04 address of entry point
1000 base of code
----- new -----
00400000 image base
1000 section alignment
200 file alignment
1 subsystem (Native)
5.01 operating system version
5.01 image version
5.01 subsystem version
20B000 size of image
600 size of headers
1FB950 checksum
00040000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
0 DLL characteristics
197000 [B57D] address [size] of Export Directory
1E8174 [50] address [size] of Import Directory
1E9000 [10708] address [size] of Resource Directory
0 [0] address [size] of Exception Directory
0 [0] address [size] of Security Directory
1FA000 [100BC] address [size] of Base Relocation Directory
1170 [1C] address [size] of Debug Directory
0 [0] address [size] of Description Directory
0 [0] address [size] of Special Directory
0 [0] address [size] of Thread Storage Directory
9F58 [40] address [size] of Load Configuration Directory
0 [0] address [size] of Bound Import Directory
1000 [168] address [size] of Import Address Table Directory
0 [0] address [size] of Delay Import Directory
0 [0] address [size] of COR20 Header Directory
0 [0] address [size] of Reserved Directory

SECTION HEADER #1
.text name
6E46C virtual size
1000 virtual address
6E600 size of raw data
600 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
68000020 flags
Code
Not Paged
(no align specified)
Execute Read

Debug Directories(1)
Type Size Address Pointer
cv 25 9fa0 95a0 Format: RSDS, guid, 1, ntkrpamp.pdb

SECTION HEADER #2
POOLMI name
11F9 virtual size
70000 virtual address
1200 size of raw data
6EC00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
68000020 flags
Code
Not Paged
(no align specified)
Execute Read

SECTION HEADER #3
MISYSPTE name
6CB virtual size
72000 virtual address
800 size of raw data
6FE00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
68000020 flags
Code
Not Paged
(no align specified)
Execute Read

SECTION HEADER #4
POOLCODE name
12AE virtual size
73000 virtual address
1400 size of raw data
70600 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
68000020 flags
Code
Not Paged
(no align specified)
Execute Read

SECTION HEADER #5
.data name
18CE8 virtual size
75000 virtual address
7C00 size of raw data
71A00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C8000040 flags
Initialized Data
Not Paged
(no align specified)
Read Write

SECTION HEADER #6
INITDATA name
38 virtual size
8E000 virtual address
200 size of raw data
79600 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C8000040 flags
Initialized Data
Not Paged
(no align specified)
Read Write

SECTION HEADER #7
INITCONS name
1A65 virtual size
8F000 virtual address
1C00 size of raw data
79800 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
48000040 flags
Initialized Data
Not Paged
(no align specified)
Read Only

SECTION HEADER #8
PAGE name
DECDF virtual size
91000 virtual address
DEE00 size of raw data
7B400 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

SECTION HEADER #9
PAGELK name
E520 virtual size
170000 virtual address
E600 size of raw data
15A200 file pointer to raw data
80647000 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

SECTION HEADER #A
PAGEVRFY name
EAA6 virtual size
17F000 virtual address
EC00 size of raw data
168800 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

SECTION HEADER #B
PAGEWMI name
1703 virtual size
18E000 virtual address
1800 size of raw data
177400 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

SECTION HEADER #C
PAGEKD name
3D93 virtual size
190000 virtual address
3E00 size of raw data
178C00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

SECTION HEADER #D
PAGESPEC name
E21 virtual size
194000 virtual address
1000 size of raw data
17CA00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

SECTION HEADER #E
PAGEHDLS name
1DB8 virtual size
195000 virtual address
1E00 size of raw data
17DA00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

SECTION HEADER #F
.edata name
B57D virtual size
197000 virtual address
B600 size of raw data
17F800 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
(no align specified)
Read Only

SECTION HEADER #10
PAGEDATA name
15B8 virtual size
1A3000 virtual address
1600 size of raw data
18AE00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
(no align specified)
Read Write

SECTION HEADER #11
PAGECONS name
3040 virtual size
1A5000 virtual address
3200 size of raw data
18C400 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
(no align specified)
Read Only

SECTION HEADER #12
PAGEKD name
C021 virtual size
1A9000 virtual address
C200 size of raw data
18F600 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
(no align specified)
Read Write

SECTION HEADER #13
PAGECONS name
18C virtual size
1B6000 virtual address
200 size of raw data
19B800 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
(no align specified)
Read Write

SECTION HEADER #14
PAGELKCO name
88 virtual size
1B7000 virtual address
200 size of raw data
19BA00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
(no align specified)
Read Only

SECTION HEADER #15
PAGEVRFC name
3449 virtual size
1B8000 virtual address
3600 size of raw data
19BC00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
(no align specified)
Read Only

SECTION HEADER #16
PAGEVRFD name
648 virtual size
1BC000 virtual address
800 size of raw data
19F200 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
(no align specified)
Read Write

SECTION HEADER #17
INIT name
2BB18 virtual size
1BD000 virtual address
2BC00 size of raw data
19FA00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
E2000020 flags
Code
Discardable
(no align specified)
Execute Read Write

SECTION HEADER #18
.rsrc name
10708 virtual size
1E9000 virtual address
10800 size of raw data
1CB600 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
(no align specified)
Read Only

SECTION HEADER #19
.reloc name
108F4 virtual size
1FA000 virtual address
10A00 size of raw data
1DBE00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable
(no align specified)
Read Only