README.md
Rendering markdown...
'use strict'
var allocations = Object();
function toString(out, opt = "")
{
var str = "";
for(var line of out)
{
str += line + opt
}
return str;
}
function readValue(str)
{
var out = host.namespace.Debugger.Utility.Control.ExecuteCommand("dd poi("+ str +") L1");
var str = toString(out);
return str.split(" ")[0];
}
function dumpObjectTree (o, recurse, compress, level)
{
var s = "";
var pfx = "";
if (typeof recurse == "undefined")
recurse = 0;
if (typeof level == "undefined")
level = 0;
if (typeof compress == "undefined")
compress = true;
for (var i = 0; i < level; i++)
pfx += (compress) ? "| " : "| ";
var tee = (compress) ? "+ " : "+- ";
for (i in o)
{
var t, ex;
try
{
t = typeof o[i];
}
catch (ex)
{
t = "ERROR";
}
switch (t)
{
case "function":
var sfunc = String(o[i]).split("\n");
if (sfunc[2] == " [native code]")
sfunc = "[native code]";
else
if (sfunc.length == 1)
sfunc = String(sfunc);
else
sfunc = sfunc.length + " lines";
s += pfx + tee + i + " (function) " + sfunc + "\n";
break;
case "object":
s += pfx + tee + i + " (object)";
if (o[i] == null)
{
s += " null\n";
break;
}
s += "\n";
if (!compress)
s += pfx + "|\n";
if ((i != "parent") && (recurse))
s += dumpObjectTree (o[i], recurse - 1,
compress, level + 1);
break;
case "string":
if (o[i].length > 200)
s += pfx + tee + i + " (" + t + ") " +
o[i].length + " chars\n";
else
s += pfx + tee + i + " (" + t + ") '" + o[i] + "'\n";
break;
case "ERROR":
s += pfx + tee + i + " (" + t + ") ?\n";
break;
default:
s += pfx + tee + i + " (" + t + ") " + o[i] + "\n";
}
if (!compress)
s += pfx + "|\n";
}
s += pfx + "*\n";
return s;
}
function getMethods(obj)
{
host.diagnostics.debugLog("inside getMethods");
var result = [];
for (var id in obj) {
try {
if (typeof(obj[id]) == "function") {
result.push(id + ": " + obj[id].toString());
}
} catch (err) {
result.push(id + ": inaccessible");
}
}
return result;
}
function initializeScript()
{
host.diagnostics.debugLog("[+] HeapInspector loaded!s\n");
}
function getAllocation(addr)
{
return allocations[addr];
}
function showStackTrace(addr)
{
host.diagnostics.debugLog(allocations[addr].stack);
}
function dumpAllocations()
{
var addresses = Object.keys(allocations);
for(var addr of addresses)
{
host.diagnostics.debugLog("Address : " + allocations[addr].addr + "\n");
host.diagnostics.debugLog("Size : " + allocations[addr].size + "\n");
host.diagnostics.debugLog("Stack : " + allocations[addr].stack + "\n");
}
}
function getStackTrace()
{
var out = host.namespace.Debugger.Utility.Control.ExecuteCommand("kc");
return toString(out,"\n");
}
function handleRtlHeapAlloc()
{
var heapHandle = readValue("esp+4");
var flags = readValue("esp+8");
var size = readValue("esp+C");
var addr = Number(host.namespace.Debugger.State.DebuggerVariables.curthread.Registers.User.eax).toString(16);
host.diagnostics.debugLog("RtlHeapAlloc("+heapHandle+","+flags + ","+size+") = " + addr + "\n");
allocations[addr] = {"addr" : addr, "size" : size, "heap" : heapHandle, "stack": getStackTrace()};
}
function handleRtlFreeHeap()
{
var heapHandle = readValue("esp+4");
var flags = readValue("esp+8");
var addr = readValue("esp+C");
host.diagnostics.debugLog("RtlFreeHeap("+heapHandle+","+flags + ","+addr+"\n");
}
function handleRtlReAllocateHeap()
{
var heapHandle = readValue("esp+4");
var flags = readValue("esp+8");
var memPtr = readValue("esp+C");
var size = readValue("esp+0x10");
var addr = Number(host.namespace.Debugger.State.DebuggerVariables.curthread.Registers.User.eax).toString(16);
host.diagnostics.debugLog("RtlReAllocateHeap("+heapHandle+","+flags + ","+memPtr+","+size+") = " + addr + "\n");
allocations[addr] = {"addr" : addr, "size" : size, "heap" : heapHandle, "stack": 0};
}
function showHeap(heapHandle)
{
/*
To be able to use this function you need to collect stack trace. Set the following breakpoint at the beginning of your application:
bp ntdll!RtlAllocateHeap "pt \"dx Debugger.State.Scripts.heap.Contents.handleRtlHeapAlloc();g\""
Next you can use it in that way :
0:000> !heap -x 0x003a9bb0
Entry User Heap Segment Size PrevSize Unused Flags
-----------------------------------------------------------------------------
003a9ba8 003a9bb0 00340000 00340000 10028 d8 18 busy extra fill
dx Debugger.State.Scripts.heap.Contents.showHeap("00340000")
*/
var blackList = ["RtlAllocateHeap","RtlDebugAllocateHeap","RtlpAllocateHeap","malloc","7z!operator","7z_exe!operator","ChildEBP","WARNING"," #"];
var heap = host.namespace.Debugger.Utility.Control.ExecuteCommand("!heap -p -h " + heapHandle);
var addr = "";
for(var chunk of heap)
{
try
{
addr = chunk.split(" ")[3];
addr = (parseInt(addr,16)).toString(16);
}
catch(exc)
{
addr = "";
}
try
{
var stack = allocations[addr]["stack"].split("\n");
var flag = false;
var finalFrame;
for(var frame of stack)
{
finalFrame = frame;
for( var entry of blackList )
{
if(frame.includes(entry))
{
flag = true;
break;
}
}
if(!flag)
break;
flag = false;
}
host.diagnostics.debugLog(chunk + " - " + finalFrame + "\n");
}
catch(exc){
//print line without changes
host.diagnostics.debugLog(chunk + "\n");
}
}
}
function showObjects(heapHandle)
{
/*
This function won't work without turning on gflag +ust
WARNING :
line : var callStack = host.namespace.Debugger.Utility.Control.ExecuteCommand("!heap -p -a " + previous);
cause windbg DoS at least under Win7x86 Windbg 6.1 (7610)
*/
var heap = host.namespace.Debugger.Utility.Control.ExecuteCommand("!heap -p -h " + heapHandle);
var previous = "";
var previousChunk = "";
var addr = "";
for(var chunk of heap)
{
try
{
try
{
addr = chunk.split(" ")[3];
addr = (parseInt(addr,16)).toString(16);
}
catch(exc)
{
addr = "";
}
if( chunk.includes("vftable") )
{
//object with vftable found. previous point on its address. print stack trace
host.diagnostics.debugLog(previousChunk);
host.diagnostics.debugLog(chunk);
host.diagnostics.debugLog("\n");
//var callStack = host.namespace.Debugger.Utility.Control.ExecuteCommand("!heap -p -a " + previous);
//host.diagnostics.debugLog( toString(callStack) );
showStackTrace(previous)
host.diagnostics.debugLog("\n===============================================================\n");
}
previous = addr
previousChunk = chunk
}
catch(exc)
{
}
}
}