Ask Learn
Preview
Please sign in to use this experience.
Sign inThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
People who develop debuggers would know in theory you cannot have a perfect disassembler (especially for x86) and stepper (especially for Step Over). People who develop commercial debuggers would know Function Evaluation (a.k.a. funceval) is a big challenge while implementing an Expression Evaluator. And people who develop the Visual Studio Debugger would face other difficulties - Interop Debugging, Edit & Continue.
In this article, I'm not going to explain the bloody details of funceval, I just demonstrate how to use funceval in WinDBG and how powerful it is.
Previously we mentioned the .call command in Microsoft Binary Technologies, at that time we were not able to invoke the function since we don't have private symbols - funceval requires private symbol since debugger needs to understand the calling convention, which is stripped out in public symbol.
While I cannot use private symbols writting articles for this blog (private symbol is Microsoft privacy, also debugging without private symbol is much more fun), the way I'd take is to create a proxy DLL:
#include <Windows.h>
VOID WINAPI SetLastError(DWORD dwErrCode){}
Now compile the code into a DLL, with PDB file generated:
cl.exe funceval.cpp /D UNICODE /Fd /GS- /LD /Od /Zi /link /NOENTRY /NODEFAULTLIB /RELEASE /SUBSYSTEM:CONSOLE
In order to use the proxy DLL, we will use the following approach:
Here is the automation script, enjoy!
$$ cdb.exe -xe cpr -c "$$>a< .\funceval.txt" notepad.exe
.echo [Launch Script]
$$ change the following value to the size of funceval.dll
r $t1 = 0n1536
bp @$exentry; g
.echo [Allocate Memory]
.foreach ( token { .dvalloc @$t1 } ) {
aS alias token
.block {
.if ($spat("${alias}", "[0-9a-f]+")) {
r $t2 = 0x${alias}
}
}
ad /q alias
}
.printf "[Load Helper DLL(base address = %p, size = %p)]\n", @$t2, @$t1
.readmem funceval.dll @$t2 (@$t1+@$t2-1)
.block {
.sympath .
}
$$.symopt+ 0x40
.reload /s /f funceval.dll=$t2
$$.symopt- 0x40
.echo [Function Evaluation]
.call /s funceval!SetLastError kernel32!SetLastError(7777)
g
!gle
.dvfree @$t2 0
And here is the output from my machine:
[Allocate Memory]
[Load Helper DLL(base address = 00020000, size = 00000600)]
Reading 600 bytes.
[Function Evaluation]
Thread is set up for call, 'g' will execute.
WARNING: This can have serious side-effects,
including deadlocks and corruption of the debuggee.
LastErrorValue: (Win32) 0x1e61 (7777) - <Unable to get error code text>
LastStatusValue: (NTSTATUS) 0 - STATUS_WAIT_0
Freed 0 bytes starting at 00020000
Please sign in to use this experience.
Sign in