Sunday, June 30, 2013

Heap Debugging Tricks

On Windows, the LFH (Low Fragmentation Heap) is commonly used to dynamically allocate small chunks of memory (<16KB in size). Many programs use the LFH as it is intended for high performance allocation/free of small objects, even in a multithreaded environment. Debugging memory corruptions on the heap can often be complex, but the following Windbg tricks may help:
  • !heap -p -a MEMORY_ADDRESS
This command is extremely useful when tracking down Use-After-Free vulnerabilities in applications. When run on a memory address, there are 2 relevant scenarios:

1) The memory address is inside a current allocation- Windbg displays the call stack that led to the allocation.


2) The memory address is inside an allocation that was freed- Windbg displays the call stack that led to the free.



Using this command requires the page heap to be enabled. Page heap can be enabled per application using the gflags.exe utility that is distributed in the Windbg package.


  • Caller Based Conditional Breakpoint

This Caller Based Conditional Breakpoint is very useful when one is interested in the place where the object gets allocated/freed, especially when the allocation/free codepath is very “hot” (meaning it is executed very often). The idea behind this breakpoint is to only break when there is a certain function (MemberFunction in the example below) on the call stack (ie only break if a certain function called this function directly or indirectly). If a breakpoint is placed on the constructor/destructor of the object’s class, and the object is allocated/freed very often, this could result in the breakpoint getting hit many more times that a human can reasonably look at. For this reason, placing a Caller Based Conditional Breakpoint in the constructor/destructor usually greatly reduces the number of times the breakpoint is hit, allowing a human to reasonably be able to investigate each time the breakpoint is hit. The Caller Based Conditional Breakpoint is of the following format:
bp Module!MyFunctionWithConditionalBreakpoint "r $t0 = 0;.foreach (v { k }) { .if ($spat(\"v\", \"*Module!ClassA:MemberFunction*\")) { r $t0 = 1;.break } }; .if($t0 = 0) { gc }"


  • Register Watching Breakpoint

The Register Watching Breakpoint is a slight variation on the Caller Based Conditional Breakpoint. In the Register Watching Breakpoint, instead of actually breaking when the appropriate caller is on the call stack, the command in Caller Based Conditional Breakpoint is modified to just print the CPU registers (using the ‘r’ command). Very often, in destructors, the address of the object that is being destroyed is in one of the CPU registers. The end result would be that each time the Register Watching Breakpoint is hit, the CPU registers will be printed rather than breaking execution. Since computers are very deterministic machines, if there is no entropy introduced in the program’s execution, one can count the number of times the breakpoint was hit before the object of interest was freed, and predict it the next time the program is run, and eventually get a live debugging session which is watching the object as it is being freed. The Register Watching Breakpoint is of the following format:

bp Module!MyFunctionWithConditionalBreakpoint "r $t0 = 0;.foreach (v { k }) { .if ($spat(\"v\", \"* Module!ClassA:MemberFunction *\")) { r; r $t0 = 1; gc; } }; .if($t0 = 0) { gc }"


References:


2 comments:

  1. very useful one as lot of use after free these days.

    ReplyDelete
  2. @an_animal asks:

    @neilsikka can you explain in more details the last 2 commands for windbg breakpoints? thanks!

    Caller Based Conditional Breakpoint:
    Only break at a certain instruction if this instruction is executed AND another specified function is on the call stack. For example, if funcA and funcB call funcC, this breakpoint allows the user to break in funcC only if funcC was directly/indirectly called by funcA. This is useful if funcB calls funcC 100,000,000 times and funcA calls funcC 1 time, and funcC is only of interest when it is called directly/indirectly by funcA. Instead of dealing with the breakpoint in funcC being hit 100,000,000 times, this type of breakpoint only breaks 1 time. This is an often scenario when breaking in constructors/destructors when analyzing Use After Free vulnerabilities.

    Register Watching Breakpoint:
    In this scenario, breakpoints are usually useful on entering a destructor or exiting a constructor because in both cases, it is very likely for the Use After Freed object to be pointed to by one of the registers. Every time the breakpoint is hit, print the CPU registers with the 'r' command, and automatically continue execution. If there is too much output, log windbg output to a file. At crash time, the offending memory dereference will be displayed in the Access Violation message. Go through the log and search for this address, and it should be in one of the registers on entry/exit of the destructor/constructor. The number of times this breakpoint was hit before the offending object was destroyed/allocated should be constant across multiple runs (assuming the program crashes the same way every time). The next time the program is run, it is known how many times the breakpoint has to be hit before it destroys/constructs the offending object, allowing the analyst to predict and get a live debugging session with the object being freed/allocated in real time.

    ReplyDelete