Repository: TimMisiak/WinDbgCookbook
Branch: main
Commit: 4766733522b9
Files: 6
Total size: 14.2 KB
Directory structure:
gitextract_r9j2lm4a/
├── LICENSE
├── README.md
├── dependencyTree.js
├── stackCollector.js
├── ttdUtil.js
└── watchForStackCorruption.js
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2022 Tim Misiak
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# WinDbgCookbook
This is a repo for small, useful scripts, extensions, and debugger data model "dx" queries.
Feel free to add your own scripts or update any of the scripts here. If you add a new script, just add a line in this readme file giving a summary of your script.
# Modules
Find if a module called "dbgeng.dll" has any imports called "RegGetValue".
```dx @$curprocess.Modules["dbgeng.dll"].Contents.Imports.SelectMany(x => x.Functions).Where(x => x.ToDisplayString().Contains("RegGetValue"))```
Set a breakpoint on every export of "symsrv.dll". (The ```.Where(x => false)``` makes the command silent and makes sure everything gets evaluated instead of stopping at 100 breakpoints)
```dx @$curprocess.Modules["symsrv"].Contents.Exports.Select(x => Debugger.Utility.Control.ExecuteCommand("bp " + x.CodeAddress.ToDisplayString("x"))).Where(x => false)```
Get a table of every import from a module "dbghelp":
```dx -g @$curprocess.Modules["dbghelp"].Contents.Imports.SelectMany(m => m.Functions.Select(f => new {Mod = m, Func = f})), 1000```
Find any modules that import module "foo.dll":
```dx @$curprocess.Modules.Where(m => m.Contents.Imports.Any(x => x.ModuleName.ToLower() == "foo.dll"))```
# Threads
Find any threads that are currently executing for a module called "mymodule.dll" or "mymodule.exe"
```dx @$curprocess.Threads.Where(x => x.Stack.Frames.Any(f => f.ToDisplayString().Contains("mymodule!")))```
# Environment variables
Find an environment variable by name
```
dx @$getEnvVar=(var) => @$curprocess.Attributes.Environment.Variables.Where(x => x.ToLower().StartsWith(var.ToLower() + "="))
```
Example:
```
0:000> dx @$getEnvVar("tmp")
@$getEnvVar("tmp")
[0x0] : TMP=C:\Users\tmisiak\AppData\Local\Temp
```
# .NET Managed objects with "dx"
You can "cast" a managed object pointer to "System.Object" and dx will give you the full object information.
```
dx (System_Private_CoreLib!System.Object *)0x1234
```
# stackCollector.js
This script adds a function that can be called from inside a breakpoint condition to capture the stack trace at the time the breakpoint was hit, and add it to a call graph. For instance, load the script and then set a breakpoint like:
```bp /w "@$scriptContents.onBreakpoint(), false" kernelbase!ReadFile```
Then run the program and later you can view the graph using a command like this:
```
0:007> dx -r3 @$scriptContents.stackRoot
@$scriptContents.stackRoot : undefined - 0
KERNELBASE!ReadFile : KERNELBASE!ReadFile - 173
ucrtbase!_read_nolock : ucrtbase!_read_nolock - 2
ucrtbase!_read : ucrtbase!_read - 2
shcore!CFileStream::Read : shcore!CFileStream::Read - 156
XmlLite!CharacterSource::Bytes::ReadMore : XmlLite!CharacterSource::Bytes::ReadMore - 70
dbgeng!ConvertStreamToUnicode : dbgeng!ConvertStreamToUnicode - 86
msvcrt!read_nolock : msvcrt!read_nolock - 1
msvcrt!read : msvcrt!read - 1
dbghelp!IStreamFileWinAPI::Read : dbghelp!IStreamFileWinAPI::Read - 4
dbghelp!MSF_HB::readPnOffCb : dbghelp!MSF_HB::readPnOffCb - 4
dbgeng!ReadImageData : dbgeng!ReadImageData - 10
dbgeng!IMAGE_HEADER_INFO::Read : dbgeng!IMAGE_HEADER_INFO::Read - 5
dbgeng!IMAGE_HEADER_INFO::ReadLoadConfigDir : dbgeng!IMAGE_HEADER_INFO::ReadLoadConfigDir - 1
dbgeng!IMAGE_HEADER_INFO::ReadDebugDir : dbgeng!IMAGE_HEADER_INFO::ReadDebugDir - 4
```
# watchForStackCorruption.js
This script adds a function that can watch for stack corruptions in a function on the target.
Use it by running:
```
0:000> dx @$scriptContents.watchFunctionForStackCorruption("OverflowFunc")
@$scriptContents.watchFunctionForStackCorruption("OverflowFunc")
0:000> g
Stack corruption detected!
WindowsConsoleApp!OverflowFunc+0x3b:
00007ff7`56cb117b f3aa rep stos byte ptr [rdi]
```
# ttdUtil.js
Find all calls to exports of a specific module for a TTD trace:
```
0:000> dx -g @$scriptContents.AllExportCalls("symsrv")
===========================================================================================================================================================================================================================================================================================================================
= = (+) EventType = (+) ThreadId = (+) UniqueThreadId = (+) TimeStart = (+) TimeEnd = (+) Function = (+) FunctionAddress = (+) ReturnAddress = (+) ReturnValue = (+) Parameters = (+) SystemTimeStart = (+) SystemTimeEnd =
===========================================================================================================================================================================================================================================================================================================================
= [0x0] - 0x0 - 0x8610 - 0x2 - 10A0BD:77 - 10A0BF:BC - symsrv!SymbolServerSetOptionsW - 0x7ffa9d5627c0 - 0x7ffa340b876a - 1 - {...} - Thursday, September 15, 2022 23:17:59.836 - Thursday, September 15, 2022 23:17:59.836 =
= [0x1] - 0x0 - 0x8610 - 0x2 - 10A0C0:15 - 10A0C0:A4 - symsrv!SymbolServerSetOptionsW - 0x7ffa9d5627c0 - 0x7ffa340b87b1 - 1 - {...} - Thursday, September 15, 2022 23:17:59.836 - Thursday, September 15, 2022 23:17:59.836 =
= [0x2] - 0x0 - 0x8610 - 0x2 - 10A0CA:15 - 10A0CA:A3 - symsrv!SymbolServerSetOptionsW - 0x7ffa9d5627c0 - 0x7ffa340b87b1 - 1 - {...} - Thursday, September 15, 2022 23:17:59.836 - Thursday, September 15, 2022 23:17:59.836 =
= [0x3] - 0x0 - 0x8610 - 0x2 - 10A0CE:15 - 10A0CE:9F - symsrv!SymbolServerSetOptionsW - 0x7ffa9d5627c0 - 0x7ffa340b87b1 - 1 - {...} - Thursday, September 15, 2022 23:17:59.836 - Thursday, September 15, 2022 23:17:59.836 =
= [0x4] - 0x0 - 0x8610 - 0x2 - 10A0D0:18 - 10A0D1:0 - symsrv!SymbolServerGetOptionData - 0x7ffa9d562db0 - 0x7ffa340b8857 - 0 - {...} - Thursday, September 15, 2022 23:17:59.836 - Thursday, September 15, 2022 23:17:59.836 =
```
# Javascript tips
With `dx`, you can often index into a collection dynamically via multiple keys. For instance, ```@$curprocess.Modules[0]``` works as well as ```@$curprocess.Modules["foo.dll"]``` and ```@$curprocess.Modules["foo"]```. The same thing doesn't work directly from JavaScript because it doesn't support dynamic indexing. Instead the data model projects this in as `.getValueAt`, so you can do:
```
host.currentProcess.Modules.getValueAt("foo")
```
# Other collections of scripts and queries
* Official WinDbg samples: https://github.com/microsoft/WinDbg-Samples
* Yarden Shafir's WinDbg Scripts: https://github.com/yardenshafir/WinDbg_Scripts
* Hugsy's WinDbg JS scripts: https://github.com/hugsy/windbg_js_scripts
* Axel Souchet's scripts: https://github.com/0vercl0k/windbg-scripts
================================================
FILE: dependencyTree.js
================================================
"use strict";
function initializeScript()
{
return [new host.apiVersionSupport(1, 7)];
}
function __getModByName(modName)
{
modName = modName.toLowerCase();
var matches = host.currentProcess.Modules.Where(function (x) { return x.Name.toLowerCase() == modName; });
if (matches.Count() == 0)
{
matches = host.currentProcess.Modules.Where(function (x) { return x.Name.toLowerCase().includes(modName); });
}
if (matches.Count() == 0)
{
return undefined;
}
return matches.First();
}
class dependencyWalker
{
constructor(modName)
{
this.__modName = modName;
}
*[Symbol.iterator]()
{
var rootMod = __getModByName(this.__modName);
if (rootMod === undefined)
{
return;
}
for (var mod of rootMod.Contents.Imports)
{
yield new dependencyWalker(mod.ModuleName);
}
}
toString()
{
return this.__modName;
}
}
class reverseDependencyWalker
{
constructor(modName)
{
this.__modName = modName;
}
getModByName(modName)
{
modName = modName.toLowerCase();
var matches = host.currentProcess.Modules.Where(function (x) { return x.Name.toLowerCase() == modName; });
if (matches.Count() == 0)
{
matches = host.currentProcess.Modules.Where(function (x) { return x.Name.toLowerCase().includes(modName); });
}
if (matches.Count() == 0)
{
return undefined;
}
return matches.First();
}
*[Symbol.iterator]()
{
var rootMod = this.getModByName(this.__modName);
if (rootMod === undefined)
{
return;
}
var cleanModName = rootMod.Name;
if (cleanModName.includes("\\"))
{
cleanModName = cleanModName.substring(cleanModName.lastIndexOf("\\") + 1);
}
cleanModName = cleanModName.toLowerCase();
var matches = host.currentProcess.Modules.Where(function (x)
{
return x.Contents.Imports.Any(function (y)
{
//host.diagnostics.debugLog(y.ModuleName.toLowerCase() + "<>" + cleanModName + "\r\n");
return y.ModuleName == cleanModName;
});
});
for (var mod of matches)
{
yield new reverseDependencyWalker(mod.Name);
}
}
toString()
{
return this.__modName;
}
}
function dependencyTree(modName)
{
return new dependencyWalker(modName);
}
function inverseDependencyTree(modName)
{
return new reverseDependencyWalker(modName);
}
================================================
FILE: stackCollector.js
================================================
"use strict";
function initializeScript()
{
return [new host.apiVersionSupport(1, 7)];
}
class StackEntry
{
constructor(name)
{
this.__name = name;
this.__count = 0;
}
getOrCreateChild(name)
{
if (!(name in this))
{
this[name] = new StackEntry(name);
}
return this[name];
}
toString()
{
return this.__name + " - " + this.__count;
}
}
var stackRoot = new StackEntry();
function onBreakpoint()
{
var node = stackRoot;
for (var frame of host.namespace.Debugger.State.DebuggerVariables.curstack.Frames)
{
var funcName = frame.toString().split("+")[0].trim();
node = node.getOrCreateChild(funcName);
node.__count++;
}
}
function resetStackTraces()
{
stackRoot = new StackEntry();
}
================================================
FILE: ttdUtil.js
================================================
"use strict";
function initializeScript()
{
return [new host.apiVersionSupport(1, 7)];
}
function AllExportCalls(mod)
{
var TTD = host.currentSession.TTD;
var funcs = host.currentProcess.Modules.getValueAt(mod).Contents.Exports;
var funcNames = funcs.Select(x => mod + "!" + x.Name);
// funcNames is an iterable, and we need to convert to an array for .apply
var funcNamesCopy = [...funcNames];
return TTD.Calls.apply(TTD, funcNamesCopy);
}
function AllExternalExportCalls(mod)
{
var calls = AllExportCalls(mod);
var exportModule = host.currentProcess.Modules.getValueAt(mod);
var start = exportModule.BaseAddress;
var end = exportModule.BaseAddress.add(exportModule.Size);
return calls.Where(x => x.ReturnAddress.compareTo(start) < 0 ||
x.ReturnAddress.compareTo(end) > 0);
}
================================================
FILE: watchForStackCorruption.js
================================================
"use strict";
// Usage: Load this script by ".scriptload" or with the WinDbg script window.
// Then run dx @$scriptContents.watchFunctionForStackCorruption("FuncName")
// Continue execution and the debugger will break in when the specified function has its return
// address overwritten.
// Note: This will script will not work if the watched function is called from more than 4 threads
// at the same time, since it uses a hardware breakpoint on each invocation of the watched func.
function initializeScript()
{
return [new host.apiVersionSupport(1, 7)];
}
function watchFunctionForStackCorruption(functionName)
{
var bp = host.namespace.Debugger.Utility.Control.SetBreakpointAtOffset(functionName, 0);
bp.Condition = "@$scriptContents.onWatchedFunctionEntry()";
}
function onWatchedFunctionEntry()
{
var stackPtr = host.namespace.Debugger.State.PseudoRegisters.General.csp;
var corruptionBP = host.namespace.Debugger.Utility.Control.SetBreakpointForReadWrite(stackPtr, "w", 8);
corruptionBP.Command = ".echo Stack corruption detected!";
var returnAddr = host.namespace.Debugger.State.PseudoRegisters.General.ra;
// This is a bit ugly, but I don't think there's a way to set "one shot" breakpoints
// from Debugger.Utility.Control or the Breakpoint object.
var addrString = returnAddr.address.toString(16);
host.namespace.Debugger.Utility.Control.ExecuteCommand("bp /1 " + addrString + '"bc ' + corruptionBP.Id + '; g"');
return false;
}
gitextract_r9j2lm4a/ ├── LICENSE ├── README.md ├── dependencyTree.js ├── stackCollector.js ├── ttdUtil.js └── watchForStackCorruption.js
SYMBOL INDEX (26 symbols across 4 files)
FILE: dependencyTree.js
function initializeScript (line 3) | function initializeScript()
function __getModByName (line 8) | function __getModByName(modName)
class dependencyWalker (line 23) | class dependencyWalker
method constructor (line 25) | constructor(modName)
method toString (line 45) | toString()
method [Symbol.iterator] (line 32) | *[Symbol.iterator]()
class reverseDependencyWalker (line 51) | class reverseDependencyWalker
method constructor (line 53) | constructor(modName)
method getModByName (line 58) | getModByName(modName)
method toString (line 102) | toString()
method [Symbol.iterator] (line 73) | *[Symbol.iterator]()
function dependencyTree (line 108) | function dependencyTree(modName)
function inverseDependencyTree (line 113) | function inverseDependencyTree(modName)
FILE: stackCollector.js
function initializeScript (line 3) | function initializeScript()
class StackEntry (line 8) | class StackEntry
method constructor (line 10) | constructor(name)
method getOrCreateChild (line 16) | getOrCreateChild(name)
method toString (line 25) | toString()
function onBreakpoint (line 33) | function onBreakpoint()
function resetStackTraces (line 44) | function resetStackTraces()
FILE: ttdUtil.js
function initializeScript (line 3) | function initializeScript()
function AllExportCalls (line 9) | function AllExportCalls(mod)
function AllExternalExportCalls (line 19) | function AllExternalExportCalls(mod)
FILE: watchForStackCorruption.js
function initializeScript (line 11) | function initializeScript()
function watchFunctionForStackCorruption (line 16) | function watchFunctionForStackCorruption(functionName)
function onWatchedFunctionEntry (line 22) | function onWatchedFunctionEntry()
Condensed preview — 6 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (15K chars).
[
{
"path": "LICENSE",
"chars": 1067,
"preview": "MIT License\n\nCopyright (c) 2022 Tim Misiak\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
},
{
"path": "README.md",
"chars": 7395,
"preview": "# WinDbgCookbook\nThis is a repo for small, useful scripts, extensions, and debugger data model \"dx\" queries.\n\nFeel free "
},
{
"path": "dependencyTree.js",
"chars": 2817,
"preview": "\"use strict\";\r\n\r\nfunction initializeScript()\r\n{\r\n return [new host.apiVersionSupport(1, 7)];\r\n}\r\n\r\nfunction __getMod"
},
{
"path": "stackCollector.js",
"chars": 882,
"preview": "\"use strict\";\r\n\r\nfunction initializeScript()\r\n{\r\n return [new host.apiVersionSupport(1, 7)];\r\n}\r\n\r\nclass StackEntry\r"
},
{
"path": "ttdUtil.js",
"chars": 857,
"preview": "\"use strict\";\n\nfunction initializeScript()\n{\n return [new host.apiVersionSupport(1, 7)];\n}\n\n\nfunction AllExportCalls("
},
{
"path": "watchForStackCorruption.js",
"chars": 1520,
"preview": "\"use strict\";\n\n// Usage: Load this script by \".scriptload\" or with the WinDbg script window.\n// Then run dx @$sc"
}
]
About this extraction
This page contains the full source code of the TimMisiak/WinDbgCookbook GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 6 files (14.2 KB), approximately 3.7k tokens, and a symbol index with 26 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.