SymFromAddr() discrepancy vs dumpbin with ntoskrnl module.

I’ve disassembled ntoskrnl.exe with dumpbin. I’ve grabbed the RVA of a proc (KiIdleLoop) and use that in a test program using dbghelp’s SymFromAddr. Both dumpbin and the test program should be using the same pdb for ntoskernl, but SymFromAddr returns a different symbol than the expected KiIdleLoop. I use the sample program dia2dump and it gives the same result as my test program.

As a general question, what would be different from dumpbin’s disassembly and SymFromAddr? Why would the RVA from SymFromAddr be something different than the address in dumpbin’s disassembly?

well an output of what you did and what results verbatim could help
answer questions better than dry text

anyway i dont find it differing except for the imageBaseAddress in my system

here are the results for xpsp3 32 bit vc 2010 dumpbin versus 9200
windbg disasm on lkd

dumpbin notice 0xxxxxB10

C:\Program Files\Microsoft Visual Studio 10.0\VC>DUMPBIN /disasm:bytes C:\WINDOW
S\system32\ntkrnlpa.exe | grep -B 4 -A 4 -i kiidleloop.*:
0046AB02: 66 8B 42 30 mov ax,word ptr [edx+30h]
0046AB06: 66 89 41 66 mov word ptr [ecx+66h],ax
0046AB0A: C2 08 00 ret 8
0046AB0D: 8D 49 00 lea ecx,[ecx]
@KiIdleLoop@0:
0046AB10: 8D AB 80 09 00 00 lea ebp,[ebx+980h]
0046AB16: EB 08 jmp 0046AB20
0046AB18: 8D 8B 50 0C 00 00 lea ecx,[ebx+0C50h]
0046AB1E: FF 11 call dword ptr [ecx]

C:\Program Files\Microsoft Visual Studio 10.0\VC>

lkd> ? nt!KiIdleLoop - nt + poi(nt + poi(nt+3c)+18+1c) (offset for Imagebase )
Evaluate expression: 4631312 = 0046ab10
lkd> u nt!KiIdleLoop l3
nt!KiIdleLoop:
80541b10 8dab80090000 lea ebp,[ebx+980h]
80541b16 eb08 jmp nt!KiIdleLoop+0x10 (80541b20)
80541b18 8d8b500c0000 lea ecx,[ebx+0C50h]
lkd> ? nt!KiIdleLoop - nt

On 12/24/12, xxxxx@gmail.com
wrote:
> I’ve disassembled ntoskrnl.exe with dumpbin. I’ve grabbed the RVA of a proc
> (KiIdleLoop) and use that in a test program using dbghelp’s SymFromAddr.
> Both dumpbin and the test program should be using the same pdb for
> ntoskernl, but SymFromAddr returns a different symbol than the expected
> KiIdleLoop. I use the sample program dia2dump and it gives the same result
> as my test program.
>
> As a general question, what would be different from dumpbin’s disassembly
> and SymFromAddr? Why would the RVA from SymFromAddr be something different
> than the address in dumpbin’s disassembly?
>
>
> —
> WINDBG is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

Thanks for the reply! More detail.

lkd> u nt!KiIdleLoop
nt!KiIdleLoop:
fffff800030d1c70 4883ec28 sub rsp,28h fffff800030d1c74 488364242800 and qword ptr [rsp+28h],0
fffff800030d1c7a 65488b1c2520000000 mov rbx,qword ptr gs:[20h] fffff800030d1c83 eb25 jmp nt!KiIdleLoop+0x3a (fffff800030d1caa) fffff800030d1c85 f683dc2100003f test byte ptr [rbx+21DCh],3Fh
fffff800030d1c8c 7518 jne nt!KiIdleLoop+0x36 (fffff800030d1ca6)
fffff800030d1c8e 33c9 xor ecx,ecx fffff800030d1c90 440f22c1 mov cr8,rcx

*** dumpbin ***
KiIdleLoop:
0000000140076C70: 48 83 EC 28 sub rsp,28h
0000000140076C74: 48 83 64 24 28 00 and qword ptr [rsp+28h],0
0000000140076C7A: 65 48 8B 1C 25 20 mov rbx,qword ptr gs:[20h]
00 00 00
0000000140076C83: EB 25 jmp 0000000140076CAA
0000000140076C85: F6 83 DC 21 00 00 test byte ptr [rbx+21DCh],3Fh
3F
0000000140076C8C: 75 18 jne 0000000140076CA6
0000000140076C8E: 33 C9 xor ecx,ecx
0000000140076C90: 44 0F 22 C1 mov cr8,rcx

lkd> ? nt!KiIdleLoop - nt
Evaluate expression: 486512 = 00000000`00076c70

The following simple program reports 76C70 is routine ExfAcquirePushLockExclusive at address 47653d. I don?t understand why SymFromAddr wouldn’t yield KiIdleLoop.

int _tmain(int argc, _TCHAR* argv)
{
DWORD options = SymGetOptions();
options |= SYMOPT_DEBUG;
SymSetOptions(options);

if(!SymInitialize(GetCurrentProcess(), NULL, FALSE))
{
std::cout
<< "SymInitialize() failed with: "
<< GetLastError()
<< “\n\n”;

return -1;
}

DWORD64 base = SymLoadModuleEx(
GetCurrentProcess(),
NULL,
“c:\windows\system32\ntoskrnl.exe”,
NULL,
0,
0,
NULL,
0);

if(base == 0)
{
std::cout
<< "SymLoadModuleEx() failed with: "
<< GetLastError()
<< “\n\n”;

goto end;
}

char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
DWORD64 offset = 0x76ca0; // offset of KiIdleLoop

if(!SymFromAddr(GetCurrentProcess(), base + offset, NULL, symbol))
{
std::cout
<< "SymFromAddr() failed with: "
<< GetLastError()
<< “\n\n”;

goto end;
}

// returns ExfAcquirePushLockExclusive

end:
SymCleanup(GetCurrentProcess());
return 0;
}

ExfAcquirePushLockExclusive:
0000000140070000: 48 89 5C 24 18 mov qword ptr [rsp+18h],rbx
0000000140070005: 48 89 74 24 20 mov qword ptr [rsp+20h],rsi
000000014007000A: 57 push rdi
000000014007000B: 48 83 EC 70 sub rsp,70h
000000014007000F: 33 F6 xor esi,esi
0000000140070011: 48 8B F9 mov rdi,rcx

xxxxx@gmail.com wrote:

The following simple program reports 76C70 is routine ExfAcquirePushLockExclusive at address 47653d. I don?t understand why SymFromAddr wouldn’t yield KiIdleLoop.

Are you compiling this as a 32-bit app or a 64-bit app? Remember that,
in a 32-bit app, the path “c:\windows\system32\ntoskrnl.exe” is going
to get rewritten to “c:\windows\syswow64\ntoskrnl.exe”. The base load
address of syswow64\ntoskrnl.exe is 0x400000, and that’s exactly what
SymLoadModuleEx returns. So, you are asking for 0x476C70.

(On a separate issue, I don’t understand why SymLoadModuleEx would
return 400000 in this case, because that’s the base load address of the
executable itself. That’s NOT where ntoskrnl.exe is loaded.)


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thank you. That makes sense, I was building an x86 app. Now compiling an x64 app it’s a little closer, but still not what I would expect. Now SymFromAddr returns the symbol KiCpuId at address 1400765d0.

ntoskrnl.exe loads at the expected address now, 140000000. When asking for the symbol at 140000000 + 76C70, it yields KiCpuId. KiCpuId is at 1400765d0 as it says, but I was asking for a different address.

[Minor correction to the code: DWORD64 offset = 0x76c70; // offset of KiIdleLoop]

KiCpuId:
00000001400765D0: 48 53 push rbx
00000001400765D2: 8B C1 mov eax,ecx
00000001400765D4: 8B CA mov ecx,edx
00000001400765D6: 0F A2 cpuid

KiIdleLoop:
0000000140076C70: 48 83 EC 28 sub rsp,28h
0000000140076C74: 48 83 64 24 28 00 and qword ptr [rsp+28h],0
0000000140076C7A: 65 48 8B 1C 25 20 mov rbx,qword ptr gs:[20h]
00 00 00

hProcess in SymInitialize() is not recommended as per docs

is symbol search path _NT_SYMBOL_PATH env var set ?

also since you are loading exe and not pdb your exe might not pick up the pdb
so effectively giving you only export symbol
(exfacquirepushlockexclusive might be the nearest export function so
you might be getting the result )

read about getmodulefilenameex()

in syminit you are setting false for fInvade so after symloadmodule
you may need to a call to SymRefreshModule list

anyway to research i had to walk through the docs and put together
some lines of code
to test my hypothesis i submitted it to the doc of SymFromAddr as
community addition
pl check
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681323(v=vs.85).aspx

@ tim
ntkrnlpa imagebase in peheader is at 0x400000 so dumpbin loads it at
preferred imagebase
while in actuality nt is relocated to 8XXXXXXX range during boot

On 12/24/12, xxxxx@gmail.com
wrote:
> Thanks for the reply! More detail.
>
> lkd> u nt!KiIdleLoop
> nt!KiIdleLoop:
> fffff800030d1c70 4883ec28 sub rsp,28h<br>&gt; fffff800030d1c74 488364242800 and qword ptr [rsp+28h],0
> fffff800030d1c7a 65488b1c2520000000 mov rbx,qword ptr gs:[20h]<br>&gt; fffff800030d1c83 eb25 jmp nt!KiIdleLoop+0x3a
> (fffff800030d1caa)<br>&gt; fffff800030d1c85 f683dc2100003f test byte ptr [rbx+21DCh],3Fh
> fffff800030d1c8c 7518 jne nt!KiIdleLoop+0x36<br>&gt; (fffff800030d1ca6)
> fffff800030d1c8e 33c9 xor ecx,ecx<br>&gt; fffff800030d1c90 440f22c1 mov cr8,rcx
>
> dumpbin
> KiIdleLoop:
> 0000000140076C70: 48 83 EC 28 sub rsp,28h
> 0000000140076C74: 48 83 64 24 28 00 and qword ptr [rsp+28h],0
> 0000000140076C7A: 65 48 8B 1C 25 20 mov rbx,qword ptr gs:[20h]
> 00 00 00
> 0000000140076C83: EB 25 jmp 0000000140076CAA
> 0000000140076C85: F6 83 DC 21 00 00 test byte ptr [rbx+21DCh],3Fh
> 3F
> 0000000140076C8C: 75 18 jne 0000000140076CA6
> 0000000140076C8E: 33 C9 xor ecx,ecx
> 0000000140076C90: 44 0F 22 C1 mov cr8,rcx
>
>
> lkd> ? nt!KiIdleLoop - nt
> Evaluate expression: 486512 = 00000000`00076c70
>
> The following simple program reports 76C70 is routine
> ExfAcquirePushLockExclusive at address 47653d. I don?t understand why
> SymFromAddr wouldn’t yield KiIdleLoop.
>
>
> int _tmain(int argc, _TCHAR* argv)
> {
> DWORD options = SymGetOptions();
> options |= SYMOPT_DEBUG;
> SymSetOptions(options);
>
> if(!SymInitialize(GetCurrentProcess(), NULL, FALSE))
> {
> std::cout
> << "SymInitialize() failed with: "
> << GetLastError()
> << “\n\n”;
>
> return -1;
> }
>
> DWORD64 base = SymLoadModuleEx(
> GetCurrentProcess(),
> NULL,
> “c:\windows\system32\ntoskrnl.exe”,
> NULL,
> 0,
> 0,
> NULL,
> 0);
>
> if(base == 0)
> {
> std::cout
> << "SymLoadModuleEx() failed with: "
> << GetLastError()
> << “\n\n”;
>
> goto end;
> }
>
> char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
> PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
> symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
> symbol->MaxNameLen = MAX_SYM_NAME;
> DWORD64 offset = 0x76ca0; // offset of KiIdleLoop
>
> if(!SymFromAddr(GetCurrentProcess(), base + offset, NULL, symbol))
> {
> std::cout
> << "SymFromAddr() failed with: "
> << GetLastError()
> << “\n\n”;
>
> goto end;
> }
>
> // returns ExfAcquirePushLockExclusive
>
> end:
> SymCleanup(GetCurrentProcess());
> return 0;
> }
>
>
> ExfAcquirePushLockExclusive:
> 0000000140070000: 48 89 5C 24 18 mov qword ptr [rsp+18h],rbx
> 0000000140070005: 48 89 74 24 20 mov qword ptr [rsp+20h],rsi
> 000000014007000A: 57 push rdi
> 000000014007000B: 48 83 EC 70 sub rsp,70h
> 000000014007000F: 33 F6 xor esi,esi
> 0000000140070011: 48 8B F9 mov rdi,rcx
>
>
> —
> WINDBG is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

raj_r wrote:

@ tim
ntkrnlpa imagebase in peheader is at 0x400000 so dumpbin loads it at
preferred imagebase
while in actuality nt is relocated to 8XXXXXXX range during boot

Yes, but we’re asking to load it into a user-mode process for
symbol-fetching purposes. 0x400000 is the wrong answer.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

On 12/25/12, Tim Roberts wrote:

> Yes, but we’re asking to load it into a user-mode process for
> symbol-fetching purposes. 0x400000 is the wrong answer.

what should be right ? iirc an usermode process can never giveback
8XXXXXXX as a valid answer neither read there legally from usermode
address space isnt it ?

anyway dbh in windbg package normally loads any image at 0x10000000 including nt
and lets you rebase it to any address including 0x400000 and provides
the right symbol as follows

dbh: load c:\windows\system32\ntkrnlpa.exe

ntkrnlpa [1000000]: name KiIdleLoop

name : KiIdleLoop
addr : 106ab10
size : 0
flags : 0
type : 0
modbase : 1000000
value : 0
reg : 0
scope : SymTagPublicSymbol (a)
tag : SymTagPublicSymbol (a)
index : 1

ntkrnlpa [1000000]: base 400000

ntkrnlpa [400000]: name KiIdleLoop

name : KiIdleLoop
addr : 46ab10
size : 0
flags : 0
type : 0
modbase : 400000
value : 0
reg : 0
scope : SymTagPublicSymbol (a)
tag : SymTagPublicSymbol (a)
index : 1

ntkrnlpa [400000]: base 804d7000

ntkrnlpa [804d7000]: name KiIdleLoop

name : KiIdleLoop
addr : 80541b10
size : 0
flags : 0
type : 0
modbase : 804d7000
value : 0
reg : 0
scope : SymTagPublicSymbol (a)
tag : SymTagPublicSymbol (a)
index : 1

ntkrnlpa [804d7000]:

_NT_SYMBOL_PATH is set properly and dbghelp appears to be picking up the proper pdb.

I don’t invade the process because I simply want to look up a function by it’s RVA using the module’s pdb.

I considered loading the module’s pdb instead. So that’d require an API to get the pdb info, download it from the symbol server (potentially) and get an ultimate path to the pdb. An API that does all that would be nice if it exists.

I’ll check out your code you posted. Thank you.

Turns out my test program was picking up the wrong version of dbghelp and the symsrv load was failing. So who knows what pdb it was picking up. Fixed that and it now returns the proper symbol.

The overall problem was because I was originally building a 32-bit app.

Thank you all for your help!

oh that :frowning: that is always a potential problem

i always run my dbghelp related exes from latest windbg installation
folder or copy the dlls from latest windbg installation to current
working directory

it is almost always a silent failure :frowning:

On 12/25/12, xxxxx@gmail.com
wrote:
>
> Turns out my test program was picking up the wrong version of dbghelp and
> the symsrv load was failing. So who knows what pdb it was picking up. Fixed
> that and it now returns the proper symbol.
>
> The overall problem was because I was originally building a 32-bit app.
>
> Thank you all for your help!
>
>
> —
> WINDBG is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

I would never expect the value in any .exe/.dll and the value at runtime
for any symbol to be the same. The loader binds the addresses in the
process of loading. So what dumpbin tells me is of essentially zero
interest. I treat it as a random number (and I’ve had to do some
low-level debugging where I had to work from link maps. The HP16C
calculator is my best friend).
joe

hProcess in SymInitialize() is not recommended as per docs

is symbol search path _NT_SYMBOL_PATH env var set ?

also since you are loading exe and not pdb your exe might not pick up the
pdb
so effectively giving you only export symbol
(exfacquirepushlockexclusive might be the nearest export function so
you might be getting the result )

read about getmodulefilenameex()

in syminit you are setting false for fInvade so after symloadmodule
you may need to a call to SymRefreshModule list

anyway to research i had to walk through the docs and put together
some lines of code
to test my hypothesis i submitted it to the doc of SymFromAddr as
community addition
pl check
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681323(v=vs.85).aspx

@ tim
ntkrnlpa imagebase in peheader is at 0x400000 so dumpbin loads it at
preferred imagebase
while in actuality nt is relocated to 8XXXXXXX range during boot

On 12/24/12, xxxxx@gmail.com
wrote:
>> Thanks for the reply! More detail.
>>
>> lkd> u nt!KiIdleLoop
>> nt!KiIdleLoop:
>> fffff800030d1c70 4883ec28 sub rsp,28h<br>&gt;&gt; fffff800030d1c74 488364242800 and qword ptr [rsp+28h],0
>> fffff800030d1c7a 65488b1c2520000000 mov rbx,qword ptr gs:[20h]<br>&gt;&gt; fffff800030d1c83 eb25 jmp nt!KiIdleLoop+0x3a
>> (fffff800030d1caa)<br>&gt;&gt; fffff800030d1c85 f683dc2100003f test byte ptr [rbx+21DCh],3Fh
>> fffff800030d1c8c 7518 jne nt!KiIdleLoop+0x36<br>&gt;&gt; (fffff800030d1ca6)
>> fffff800030d1c8e 33c9 xor ecx,ecx<br>&gt;&gt; fffff800030d1c90 440f22c1 mov cr8,rcx
>>
>> dumpbin
>> KiIdleLoop:
>> 0000000140076C70: 48 83 EC 28 sub rsp,28h
>> 0000000140076C74: 48 83 64 24 28 00 and qword ptr [rsp+28h],0
>> 0000000140076C7A: 65 48 8B 1C 25 20 mov rbx,qword ptr
>> gs:[20h]
>> 00 00 00
>> 0000000140076C83: EB 25 jmp 0000000140076CAA
>> 0000000140076C85: F6 83 DC 21 00 00 test byte ptr
>> [rbx+21DCh],3Fh
>> 3F
>> 0000000140076C8C: 75 18 jne 0000000140076CA6
>> 0000000140076C8E: 33 C9 xor ecx,ecx
>> 0000000140076C90: 44 0F 22 C1 mov cr8,rcx
>>
>>
>> lkd> ? nt!KiIdleLoop - nt
>> Evaluate expression: 486512 = 00000000`00076c70
>>
>> The following simple program reports 76C70 is routine
>> ExfAcquirePushLockExclusive at address 47653d. I don?t understand why
>> SymFromAddr wouldn’t yield KiIdleLoop.
>>
>>
>> int _tmain(int argc, _TCHAR* argv)
>> {
>> DWORD options = SymGetOptions();
>> options |= SYMOPT_DEBUG;
>> SymSetOptions(options);
>>
>> if(!SymInitialize(GetCurrentProcess(), NULL, FALSE))
>> {
>> std::cout
>> << "SymInitialize() failed with: "
>> << GetLastError()
>> << “\n\n”;
>>
>> return -1;
>> }
>>
>> DWORD64 base = SymLoadModuleEx(
>> GetCurrentProcess(),
>> NULL,
>> “c:\windows\system32\ntoskrnl.exe”,
>> NULL,
>> 0,
>> 0,
>> NULL,
>> 0);
>>
>> if(base == 0)
>> {
>> std::cout
>> << "SymLoadModuleEx() failed with: "
>> << GetLastError()
>> << “\n\n”;
>>
>> goto end;
>> }
>>
>> char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
>> PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
>> symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
>> symbol->MaxNameLen = MAX_SYM_NAME;
>> DWORD64 offset = 0x76ca0; // offset of KiIdleLoop
>>
>> if(!SymFromAddr(GetCurrentProcess(), base + offset, NULL, symbol))
>> {
>> std::cout
>> << "SymFromAddr() failed with: "
>> << GetLastError()
>> << “\n\n”;
>>
>> goto end;
>> }
>>
>> // returns ExfAcquirePushLockExclusive
>>
>> end:
>> SymCleanup(GetCurrentProcess());
>> return 0;
>> }
>>
>>
>> ExfAcquirePushLockExclusive:
>> 0000000140070000: 48 89 5C 24 18 mov qword ptr
>> [rsp+18h],rbx
>> 0000000140070005: 48 89 74 24 20 mov qword ptr
>> [rsp+20h],rsi
>> 000000014007000A: 57 push rdi
>> 000000014007000B: 48 83 EC 70 sub rsp,70h
>> 000000014007000F: 33 F6 xor esi,esi
>> 0000000140070011: 48 8B F9 mov rdi,rcx
>>
>>
>> —
>> WINDBG is sponsored by OSR
>>
>> For our schedule of WDF, WDM, debugging and other seminars visit:
>> http://www.osr.com/seminars
>>
>> To unsubscribe, visit the List Server section of OSR Online at
>> http://www.osronline.com/page.cfm?name=ListServer
>>
>
> —
> WINDBG is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>