Windows Symbol Address Definition

817 Views Asked by At

I have extracted a dump file of system call addresses called in windows using ETW. I had some confusions about the addresses. I just use NtOpenFile for future examples.

1-

I dump the Kernel PDB file received from Microsoft symbol server (ntkrnlmp.pdb) using cvdump. it's entry for NtOpenfile is like this:

S_PUB32: [000D:000DF320], Flags: 00000002, NtOpenFile

Then I open ntoskrnl.exe using Dependency Walker (DP). I scroll down and see the entry for NtOpenFile:

enter image description here

Then I receive the Kernel Base address using this little piece of code:

hNtdll = GetModuleHandle("ntdll.dll");
NtQuerySystemInformation = (NtQuerySystemInformationFunc)GetProcAddress(hNtdll, "NtQuerySystemInformation");
NtQuerySystemInformation(SystemModuleInformation, &ModuleInfo, sizeof(ModuleInfo), NULL);
KernelBase = (ULONG64)ModuleInfo.Modules[0].ImageBase;

The kernel base address is: fffff802f7616000

The actual address for NtOpenFile extracted using windbg is fffff802f7b0e320 nt!NtOpenFile

Adding the kernel base with address extracted from the pdb file gives me the wrong address (adding with the address from DP results correct). Why?

2-

Why don't functions in win32k.sys like NtGdiFlush exist in the .sys file opened by DP? In Windows 10, there is another file named win32kfull.sys which contains those symbols but not in Windows 7.

3-

I cannot map functions like NtQueryVirtualMemory at all. it exists in the ntkrnlmp.pdb dump, but as I said in part 1, the address seems wrong! And also it exists in ntoskrnl.exe opened by DP as ZwQueryVirtualMemory. But it differs from NtQueryVirtualMemory address extracted by windbg.exe How do these map to each other? How can I extract this function's address using DP or PDB files?

4-

How can I find win32k.sys system call addresses (like NtGdiFlush's address) using windbg? the command kd> x /D nt!Nt* does not give me these symbol addresses.

1

There are 1 best solutions below

2
On

I am not clear what your use case is if it was just obtaining an address for an api from just a pdb file you could use the dbh.exe tool that comes with windbg package in batch mode

it loads the pdb at a default base (normally 0x10000000) and provides you the address of the api relative to that base

example

:\>dbh e:\SYMBOLS\ntkrpamp.pdb\E4AF624F009A4D99A4F85690E0164DBC2\ntkrpamp.pdb n ntopenfile

   name : NtOpenFile
   addr :  1232d81
   size : 0
  flags : 400000
   type : 0
modbase :  1000000
  value :        0
    reg : 0
  scope : SymTagPublicSymbol (a)
    tag : SymTagPublicSymbol (a)
  index : 1

you can confirm also with sysinternals livekd.exe

:\>livekd -b -c \"? nt!NtOpenFile;? nt; ? (nt!NtOpenFile-nt);q\" | grep -B 3 quit:
Evaluate expression: -2096693887 = 8306fd81
Evaluate expression: -2098999296 = 82e3d000
Evaluate expression: 2305409 = 00232d81
quit:

:\>dbh e:\SYMBOLS\ntkrpamp.pdb\E4AF624F009A4D99A4F85690E0164DBC2\ntkrpamp.pdb n ntopenfile

   name : NtOpenFile
   addr :  1232d81
   size : 0
  flags : 400000
   type : 0
modbase :  1000000
  value :        0
    reg : 0
  scope : SymTagPublicSymbol (a)
    tag : SymTagPublicSymbol (a)
  index : 1

:\>

as for as finding an api from all the loaded modules you can employ wildcards like *. etc

kd> x *!*ntgdiflu*
76cc5fd2          GDI32!NtGdiFlush (<no parameter info>)
98257991          win32k!NtGdiFlush (<no parameter info>)
9824c664          win32k!NtGdiFlushUserBatch (<no parameter info>)
kd> x Win*!*ntgdiflu*
98257991          win32k!NtGdiFlush (<no parameter info>)
9824c664          win32k!NtGdiFlushUserBatch (<no parameter info>)
kd>

It doesn't appear to be that simple as adding the S_PUB32 Value spat out by cvdump for a symbol to the segment offset

it seems that the S_PUB32 value was written before optimization function chunking etc all happened

cvdump in its headers has two different header information

one appears to be the actual header that is embedded in the final executable one one appears to be the original header pre optimization ? or whatever would be done after writing this header

E:\cvdump>cvdump.exe -headers ntkrpamp.pdb | grep -i original -A 500 | grep -i #8 -A 10 | grep -i virtual
  1A604E virtual size
  166000 virtual address

E:\cvdump>cvdump.exe -headers ntkrpamp.pdb | grep -i #8 -A 10 | grep -i virtual
  1AD618 virtual size
  16C000 virtual address
  1A604E virtual size
  166000 virtual address

the S_PUB32 value is added to the original segment offset in this case

E:\cvdump>cvdump.exe -p ntkrpamp.pdb | grep -i ntopenfile
S_PUB32: [0008:000620C8], Flags: 00000002, _NtOpenFile@24

0x620c8 is added to 0x166000 the virtual address of original header's section #8 (this isn't reflected in dumpbin.exe /headers so dumpbin is kinda useless )

now omapf for this seems to show the actual function offset in the final executable

E:\cvdump>cvdump.exe -omapf ntkrpamp.pdb | grep -i 1c80c8
    001C80C8   00232D81

the pattern appears to be consistent for a few functions i tried

checking some random api

E:\cvdump>cvdump.exe -p ntkrpamp.pdb | grep -i rtlfreehot
S_PUB32: [0008:0011C32E], Flags: 00000002, _RtlFreeHotPatchData@4

E:\cvdump>cvdump.exe -headers ntkrpamp.pdb | grep -i original -A 500 | grep -i #8 -A 10 | grep -i virtual
  1A604E virtual size
  166000 virtual address

E:\cvdump>python -c "print \"%x\" % (0x11c32e+0x166000)"
28232e

E:\cvdump>cvdump.exe -omapf ntkrpamp.pdb | grep -i 28232e
    0028232E   002E88C0

E:\cvdump>dbh ntkrpamp.pdb n RtlFreeHotPatchData

   name : RtlFreeHotPatchData
   addr :  12e88c0
   size : 0
  flags : 400000
   type : 0
modbase :  1000000
  value :        0
    reg : 0
  scope : SymTagPublicSymbol (a)
    tag : SymTagPublicSymbol (a)
  index : 1

E:\cvdump>

if fpo data is available you can get the function size prolog no of params no of locals etc too

E:\cvdump>cvdump.exe -fpo ntkrpamp.pdb | grep -i 28232e
0028232E         2E        1        3        0     N   N    fpo        0

this exactly matches the windbg .fnent function output

kd> .fnent nt!RtlFreeHotPatchData
Debugger function entry 030b5b70 for:
(831258c0)   nt!RtlFreeHotPatchData   |  (831258
Exact matches:
    nt!RtlFreeHotPatchData (<no parameter info>)

OffStart:  002e88c0
ProcSize:  0x2e
Prologue:  0x3
Params:    0n0 (0x0 bytes)
Locals:    0n1 (0x4 bytes)
Registers: 0n0
kd>