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:
1) The memory address is inside a current allocation- Windbg displays the call stack that led to the allocation.
- !heap -p -a MEMORY_ADDRESS
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:
very useful one as lot of use after free these days.
ReplyDelete@an_animal asks:
ReplyDelete@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.
Many of the magazines provide great working opportunity to the writers of various different levels. Also to other people connected with that media.
ReplyDelete