Call Tracing
When trying to understand closed-source binaries or collecting diagnostic data, it can be useful to capture a detailed call stack trace at any given point - especially from a function hook. The Vezel.Ruptura.Memory package provides the CallTrace API to do exactly that. For example:
Console.WriteLine(CallTrace.Capture());This will print something like:
0x7ffe4cfa0b09: Void Program.<Main>$(String[] args) in tests.dll
0x7ffeacabe823: coreclr_shutdown_2+0x16683 in coreclr.dll+0x16e823
0x7ffeac99a133: <unknown> in coreclr.dll+0x4a133
0x7ffeaca2d710: <unknown> in coreclr.dll+0xdd710
0x7ffeaca2efb6: <unknown> in coreclr.dll+0xdefb6
0x7ffeaca2f749: <unknown> in coreclr.dll+0xdf749
0x7ffeaca2dcb9: <unknown> in coreclr.dll+0xddcb9
0x7ffeaca93bd1: coreclr_execute_assembly+0xe1 in coreclr.dll+0x143bd1
0x7fff31f69148: <unknown> in hostpolicy.dll+0x19148
0x7fff31f6941c: <unknown> in hostpolicy.dll+0x1941c
0x7fff31f69d17: corehost_main+0x107 in hostpolicy.dll+0x19d17
0x7fff3947b459: hostfxr_close+0xfb9 in hostfxr.dll+0xb459
0x7fff3947e4f6: hostfxr_close+0x4056 in hostfxr.dll+0xe4f6
0x7fff394807cf: hostfxr_close+0x632f in hostfxr.dll+0x107cf
0x7fff3947eb52: hostfxr_close+0x46b2 in hostfxr.dll+0xeb52
0x7fff394781cb: hostfxr_main_startupinfo+0xab in hostfxr.dll+0x81cb
0x7ff61aba255b: <unknown> in tests.exe+0x1255b
0x7ff61aba28cb: <unknown> in tests.exe+0x128cb
0x7ff61aba3d78: <unknown> in tests.exe+0x13d78
0x7fff79193fed: BaseThreadInitThunk+0x1d in kernel32.dll+0x13fed
0x7fff7a6142a8: RtlUserThreadStart+0x28 in ntdll.dll+0x42a8Of course, the captured CallTrace object has plenty of details that you can inspect programmatically. For example, you could print a bit more information about the RIP, RSP, and RBP registers in each CallFrame:
You will now get:
Symbolication
CallTrace tries very hard internally to fill in as much information as it can. For managed frames, information is pulled from CoreCLR internals, while for unmanaged frames, the DbgHelp library will consult export names, symbol files, etc. These are implemented in the ManagedCallFrameSymbolicator and NativeCallFrameSymbolicator singleton classes, respectively, and both derive from the CallFrameSymbolicator class.
There is a CallTrace.Capture() overload that allows you to specify the CallFrameSymbolicator instances you would like to use in a call trace instead of or in addition to the aforementioned two. This allows you to implement your own symbolicators that can pull on whatever data you would like. For instance, you could symbolicate based on signature matching, or based on a symbol table manually constructed from reverse engineering.
Symbol Servers
For NativeCallFrameSymbolicator, it is worth noting that the DbgHelp library shipped with Windows does not have symbol server support (symsrv.dll). That is why the call traces above had rather poor, export-based symbolication for coreclr.dll and related libraries.
If you obtain a standalone version of the DbgHelp library consisting of dbghelp.dll and symsrv.dll, you can simply drop them into your application directory and Ruptura will pick them up. Setting the _NT_SYMBOL_PATH environment variable to https://msdl.microsoft.com/download/symbols or similar will then enable symsrv.dll to actually download Microsoft symbol files. Doing that, you will get a much better call trace:
Last updated