Windbg script - automatically parse each frame of a stack

0

Hullo,

I am looking at a few stacks recently, and I'm manually finding a certain thing that I want to get the address of so that I can delve inside it with ??.

For example:

00 00000005`9c88a558 00007ffa`bc2713ed ntdll!NtWaitForMultipleObjects+0xa
01 00000005`9c88a560 00007ffa`be477d51 KERNELBASE!WaitForMultipleObjectsEx+0xed
02 00000005`9c88a840 00007ffa`be477773 kernel32!WerpLaunchAeDebug+0x23a1
03 00000005`9c88adb0 00007ffa`bc351c1f kernel32!WerpLaunchAeDebug+0x1dc3
04 00000005`9c88ade0 00007ffa`bedaf1b3 KERNELBASE!UnhandledExceptionFilter+0x23f
05 00000005`9c88aed0 00007ffa`bed91e26 ntdll!memset+0xaaf3
06 00000005`9c88af10 00007ffa`beda349d ntdll!_C_specific_handler+0x96
07 00000005`9c88af80 00007ffa`bed648d7 ntdll!_chkstk+0x9d
08 00000005`9c88afb0 00007ffa`beda262a ntdll!RtlRaiseException+0xf67
09 00000005`9c88b680 00007ffa`aafc1b52 ntdll!KiUserExceptionDispatcher+0x3a
0a 00000005`9c88bd80 00007ffa`ab14e820 function1(class foo1 * bar1 = 0x00000000`0eee4e10)+0xd2 [c:\path\source1.cpp @ 783]
0b 00000005`9c88bdc0 00007ffa`ab11b854 function2(class foo2 * bar2 = 0x00000000`0f034010)+0x540 [c:\path\source2.cpp @ 23044]
0c 00000005`9c88d420 00007ffa`ab06151c function3(class foo3 * bar3 = 0x00000005`9c88dd50)+0x584 [c:\path\source3.cpp @ 5671]
0d 00000005`9c88dcf0 00007ffa`aae1ef08 function4(class foo3 * bar3 = 0x00000000`80001a55)+0x3bc [c:\path\source4.cpp @ 218]
0e 00000005`9c88e7c0 00007ffa`aae2956b function5(unsigned short fcode = 0x3032, class foo3 * bar3 = 0x00007ffa`ab08e8de)+0x1fb8 [path\source5.cpp @ 108]
0f 00000005`9c88fab0 00007ffa`bed254f4 kernel32!BaseThreadInitThunk+0x22
10 00000005`9c88fae0 00000000`00000000 ntdll!RtlUserThreadStart+0x34

I'm interested in extracting the 3 addresses of 0x000000059c88dd50, 0x0000000080001a55 and 0x00007ffaab08e8de and passing them automatically to a bunch of ?? ((foo3*) 0x000000059c88dd50)->WhatIAmInterestedIn etc. commands so that I can quickly scan the output for results of interest.

Is there a way to script this parsing so I can trawl the stack of the current thread for any instances of bar3, grab that address and use it in n x ?? commands, just echoing whatever it finds to the Command Window, even if it's a memory access error, it could speed things up for me.

I was thinking about !for_each_frame but I must admit, I don't even know how to interrogate a specific frame for the presence or absence of a bar3 and address, inside Windbg, except by doing it with my own eyes!

scripting
windbg
asked on Stack Overflow Sep 17, 2018 by Hippogriff

2 Answers

1

Any recent version of the debugger has built-in capabilities to script against the target with JavaScript. WinDbg Preview in the store has UI with limited Intellisense for this as well. You can do something like this easily. Take the following example:

"use strict";

function* returnAllParameters(localName)
{
    var stack = host.currentThread.Stack;
    for (var frame of stack.Frames)
    {
        // Catch any exceptions that might occur due to inability to find PDB
        try
        {
            var locals = frame.Parameters;
            var local = locals[localName];
            if (local !== undefined)
            {
                yield local;
            }
        }
        catch(ex)
        {
        }
    }
}

An example of the result of this:

0:000> dx @$scriptContents.returnAllParameters("pExceptionRecord")
@$scriptContents.returnAllParameters("pExceptionRecord")                 : [object Generator]
    [0x0]            : 0x8be2f0ed00 [Type: _EXCEPTION_RECORD *]
answered on Stack Overflow Sep 17, 2018 by William Messmer
0

if you have source then you can follow messmers script and check the Parameters and Locals
(without source and a private pdb Parameters and Locals will spit undefined error )

if you do not have source and would like to grope the string output you can use some thing like this

function test(argstr)
{
    var backtrace = host.namespace.Debugger.Utility.Control.ExecuteCommand("kb")
    var collection = []
    var i = 0
    for (var frame of backtrace ) 
    {
        if( frame.toString().includes(argstr) ) {
        host.diagnostics.debugLog("found " + argstr + " at " + frame + "\n" )
        collection[i++] = frame.toString().split(" ")
        }
    }
    return collection
}

here is a stack and an output of text parsing

0:003> dx @$scriptContents.test("Rtl")

found Rtl at 03 02cdfe8c 76df37be 76e2f1d3 00000000 00000000 ntdll!__RtlUserThreadStart+0x70
found Rtl at 04 02cdfea4 00000000 76e2f1d3 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b
@$scriptContents.test("Rtl")                 : 

    length           : 0x2
    [0x0]            : 03,
    [0x1]            : 04,
clicking the dml 0x0 
you get the first collection and so on as below

0:003> dx -r1 @$scriptContents.test("Rtl")[0]
found Rtl at 03 02cdfe8c 76df37be 76e2f1d3 00000000 00000000 ntdll!__RtlUserThreadStart+0x70
found Rtl at 04 02cdfea4 00000000 76e2f1d3 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b
@$scriptContents.test("Rtl")[0]                 : 03,02cdfe8c,76df37be,76e2f1d3,00000000,00000000,ntdll!__RtlUserThreadStart+0x70
    length           : 0x7
    [0x0]            : 03
    [0x1]            : 02cdfe8c
    [0x2]            : 76df37be
    [0x3]            : 76e2f1d3
    [0x4]            : 00000000
    [0x5]            : 00000000
    [0x6]            : ntdll!__RtlUserThreadStart+0x70
0:003> dx -r1 @$scriptContents.test("Rtl")[1]
found Rtl at 03 02cdfe8c 76df37be 76e2f1d3 00000000 00000000 ntdll!__RtlUserThreadStart+0x70
found Rtl at 04 02cdfea4 00000000 76e2f1d3 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b
@$scriptContents.test("Rtl")[1]                 : 04,02cdfea4,00000000,76e2f1d3,00000000,00000000,ntdll!_RtlUserThreadStart+0x1b
    length           : 0x7
    [0x0]            : 04
    [0x1]            : 02cdfea4
    [0x2]            : 00000000
    [0x3]            : 76e2f1d3
    [0x4]            : 00000000
    [0x5]            : 00000000
    [0x6]            : ntdll!_RtlUserThreadStart+0x1b
0:003> kb
 # ChildEBP RetAddr  Args to Child              
00 02cdfe10 76e2f20f 747e8f74 00000000 00000000 ntdll!DbgBreakPoint
01 02cdfe40 752ced6c 00000000 02cdfe8c 76df37eb ntdll!DbgUiRemoteBreakin+0x3c
02 02cdfe4c 76df37eb 00000000 747e8fb8 00000000 kernel32!BaseThreadInitThunk+0xe
03 02cdfe8c 76df37be 76e2f1d3 00000000 00000000 ntdll!__RtlUserThreadStart+0x70
04 02cdfea4 00000000 76e2f1d3 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b
answered on Stack Overflow Sep 17, 2018 by blabb • edited Sep 17, 2018 by blabb

User contributions licensed under CC BY-SA 3.0