1

Is there a way to predict/calculate where in a module's memory a function will be located?

*Sigh* The first thing you'll tell me is: you have to have symbols for stuff to work well. I know. (Oh! Do I know!) It isn't an option for me, so I'm looking to make the most of what I have. I'm not trying to get the values of local variables or anything (which would require intimate knowledge of compiler optimizations, etc.). I just would like to know what DLL function we were in.

I have a memory dump from a crashed process. The process loads numerous DLL's, each of which have some exported functions. One thread in the process has some items on the call stack "within" this DLL. The Visual Studio debugger reports them as (the names are changed to protect the innocent):

msvcr120.dll!abort() Line 90     
msvcr120.dll!_XcptFilter(unsigned long xcptnum, _EXCEPTION_POINTERS * pxcptinfoptrs) Line 366    
MyProcess.exe!016c9a9a()     
[Frames below may be incorrect and/or missing, no symbols loaded for Mach4GUI.exe]   
[External Code]  
MyProcess.exe!016ca390()     
[External Code]  
ExtLib01.dll!6eb1f75c()  
ExtLib01.dll!6eb95991()  
ExtLib01.dll!6e658979()  
ExtLib01.dll!6e653bab()  
ExtLib01.dll!6e66d5dd()  
[External Code]  

The DLL wasn't built for debugging, and I don't have a .PDB or other source of symbols.

Visual Studio reports this about the DLL module:

Name            Path                     Address
----            ----                     -------
ExtLib01.dll    C:\MyProj\ExtLib01.dll   6E5E0000-6FE8800

The DLL, of course, has some exported functions (reported by dumpbin /exports ExtLib01.dll), like:

    ordinal hint RVA      name

          1    0 0009CE30 LibFunc1@16
          2    1 0009CDF0 LibFunc2@4
          3    2 0009CE60 LibFunc3@4
...
        482  1E1 0010FB40 LibFunc482
        483  1E2 0010FBD0 LibFunc483
        484  1E3 0010FAC0 LibFunc484

Not knowing any better, it seems like there might be enough information here to figure out what functions are in the call stack (if the return address is "within" one of the DLL functions).

Some simple arithmetic on the first item in the call stack, 0x6eb1f75c-0x6E5E0000, yields an offset into the ExtLib01.dll "module" in memory: +0x0053f75c, but this doesn't correspond at all to the relative virtual addresses listed in the DLL exports.

So, Visual Studio tells me nothing but the module name and an address (within that module) in the call stack. One might assume that this is because more information isn't available. My experience with Microsoft products suggests that they just might not have implemented such a feature—though in the case of their flagship development tool, surely they would try hard to make it useful.

More confusingly, WinDbg tells me different things about about the call stack for the same thread.

# ChildEBP RetAddr  
00 0022cdb8 7740171a ntdll!NtWaitForMultipleObjects+0x15
01 0022ce54 76c519fc KERNELBASE!WaitForMultipleObjectsEx+0x100
02 0022ce9c 76c541d8 kernel32!WaitForMultipleObjectsExImplementation+0xe0
03 0022ceb8 76c780bc kernel32!WaitForMultipleObjects+0x18
04 0022cf24 76c77f7b kernel32!WerpReportFaultInternal+0x186
05 0022cf38 76c77870 kernel32!WerpReportFault+0x70
06 0022cf48 76c777ef kernel32!BasepReportFault+0x20
07 0022cfd4 74fb4820 kernel32!UnhandledExceptionFilter+0x1af
08 0022cfe0 74fb4611 msvcr120!__crtUnhandledException+0x14 [f:\dd\vctools\crt\crtw32\misc\winapisupp.c @ 259] 
09 0022d318 74fb7676 msvcr120!_call_reportfault+0xfe [f:\dd\vctools\crt\crtw32\misc\invarg.c @ 201] 
0a 0022d328 74fb4e38 msvcr120!abort+0x38 [f:\dd\vctools\crt\crtw32\misc\abort.c @ 90] 
0b 0022d340 016c9a9a msvcr120!_XcptFilter+0x14b [f:\dd\vctools\crt\crtw32\misc\winxfltr.c @ 366] 
WARNING: Stack unwind information not available. Following frames may be wrong.
0c 0022f8c8 76c5336a MyProcess!SomeSymbol+0xa0d71a
0d 0022f8d4 77b39902 kernel32!BaseThreadInitThunk+0xe
0e 0022f914 77b398d5 ntdll!__RtlUserThreadStart+0x70
0f 0022f92c 00000000 ntdll!_RtlUserThreadStart+0x1b

I can perhaps understand some of the items at the top of the list (everything above UnhandledExceptionFilter, where Windows Error Reporting is doing its thing, capturing the memory dump, etc.), but why the discrepancy between the two call stacks? I see that both report "Following frames may be wrong." Is this information completely unreliable? What can be known or discerned from the information available?

What can be discerned about the items in the call stack from the information available?

Is it possible to know where a function from a loaded DLL is located in memory of a running process?

I'm willing to use WinDbg if it'll help. I'm willing to use PowerShell within Visual Studio's NuGet console. I'm not unwilling to do some work, but I have no real idea if it's even possible to know something these DLL functions.

Note: I realize the answer may very well be, "Nope. It's impossible." I'm looking for a good answer with an explanation (or references to some sort of authoritative source with an explanation) as to how the DLL's are loaded and its functions called and why a memory dump doesn't contain enough information to figure out where any given function "starts" in memory.

mojo
  • 4,050
  • 17
  • 24
  • 2
    If you do a `lm m MyProcess`, WinDbg should output "export symbols", which means it already resolves the exported methods. But that's just the exported ones, which are typically just a few. – Thomas Weller Jun 27 '17 at 13:15
  • All the "unhandled exception" messages should be a clue to what happened: you had a C++ or Win32 exception (probably C++) which was not caught. Exception handling involves unwinding the stack, and this unwinding failed. It's not entirely strange that unwinding failures lead to such stack dumps. – MSalters Jun 27 '17 at 13:18
  • Related: https://stackoverflow.com/a/38107794/480982 – Thomas Weller Jun 27 '17 at 13:19
  • `I don't have a .PDB` - here is key point - information about not exported functions RVAs containing in .pdb. if you want this information - you need pdb – RbMm Jun 27 '17 at 13:36
  • @MSalters The exception is happening outside any code I manage. Of course being unhandled is why the app crashed. I'm looking to find out what functions were in the call stack when the exception happened. That might at least give me a clue as to what might be influencing (or indirectly causing) the exception. – mojo Jun 27 '17 at 15:53
  • @mojo, Do you have the real symbols files for your crashed app in your side? https://github.com/Microsoft/WinObjC/wiki/Debugging-Stack-Traces-from-Crash-Dumps, it shared us how to use the VS to debug the dump file in our local machine. – Jack Zhai Jun 28 '17 at 10:35
  • @JackZhai-MSFT The link is just a basic howto for enabling crash dumps and using the debugger. I'm looking for much more of a hacker solution. – mojo Jun 28 '17 at 13:23
  • If you're able to reproduce the bug, the simplest way is to first try the same steps using the debug configuration. If the problem cannot be reproduced in debug, then try to build a release version with debug information (search MSDN on how to add debug info to release version). – zdf Jun 29 '17 at 13:43
  • @ZDF, If I could reproduce the bug, I wouldn't be trying so hard to do a forensic analysis of the memory dump. In this particular instance, I'm working with a crash dump from a customer machine on an issue that I can't reproduce in the lab. My question is in general, though. – mojo Jun 29 '17 at 14:15
  • @mojo I understand. Maybe remote debugging? – zdf Jun 29 '17 at 14:18
  • The problem is very intermittent. Plus, the customer is a long way off. We've put a debugger on the machine before. The setup of putting the app in the debugger and the false positives it catches make this more of a last resort because it interferes with their production machine and slows down the rate of work (I.e. costs $). – mojo Jun 29 '17 at 14:21
  • 1
    @mojo, This is related to stack walking. It’s not always possible. If WIndbg and VS can’t figure out the addresses of the functions, then he won’t probably won’t be able to either. Here’s directions on how to manually walk the stack using Windbg: https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/manually-walking-a-stack – Jack Zhai Jun 30 '17 at 06:33

0 Answers0