July 1, 2012

Data Access Breakpoint Using Memory Protection

When debugging data formats I sometimes think about how cool would be to have a debugger command that would allow me to place data access breakpoint on arbitrary region of the memory. Certainly, I can put hardware breakpoint on memory region with the restrictions that the size of the region is either 1, 2 or 4 bytes on IA32 architecture.

But what if I want to place a breakpoint on a data dump that has a size of greater than 4 bytes. For example, I want to do this to see what location within the region would be first accessed. Normally, there is no way to do this because of the lack of the support IA32 architecture provides. Software solution is possible but not implemented in debuggers such as in Ollydbg and in Windbg.

What you could do in these circumstances is to guess where the code parsing the data starts, and place a breakpoint on the execution flow, so when you break in the debugger you can trace the code from that point and watch the data flow. This is likely to be tedious process because you spend time stepping through code you are not interested. The other ideas tend to be even more tedious, and require prepration work (hooking etc.) We shouldn't forget that the reason we want to place breakpoint on memory region is usually to narrow down the scope of total debugging.

Some time ago I've seen how Armadillo protection uses debugge/debugger process to mark encrypted pages and when there is an access to the page it gets decrypted and executed on-the-fly. Also, EMET (Enhanced Mitigation Experience Toolkit) in the heap spray mitigation function uses to mark certain pages as unaccessible so the system cannot allocate memory to that address. This has inspired me how to write a plugin that allows me to place data breakpoint on arbitrary memory region. Yay!

Using VirtualProtect it's possible to disable all access to the memory page in the process address space. I however don't use VirtualProtect in the plugin but use VirtualProtectEx instead because the extended version allows me to disable all access to the memory in specified process rather than the current process.

The prototype has been developed as an extension command for Windbg. It requires two parameters describing the breakpoint: the address and the size of the region. When data is accessed within this region the we break in the debugger.

When the extension command runs it locates the base address of the memory page the specified region belongs to. Next, PAGE_NOACCESS protection flag is set for the memory page. This allows us to filter any access to the memory page via exception handling.

When the target runs in the debugger, and if there is an attempt to read from the protected page it results in an access violation. Due to this, the exception event callback implemented in the Windbg extension is executed. This callback verifies if the address of inaccessible data is within the region of the data breakpoint. If it is we restore the original protection flags for the page and break in the debugger - breakpoint hit. Otherwise, we restore the original protection flag to execute the single instruction previously generated the exception. Then we restore the protection flags do disable all access and continue to run the application until there is an attempt to read from the protected page resulting in an access violation.

The exception information is stored in EXCEPTION_RECORD structure which is available in the exception even callback function. Exception->ExceptionAddress is the address where the exception occurred. Exception->ExceptionInformation[1] is the address of the inaccessible data. More information on exception is available here.

Before I run the plugin command I also run sxn av so if access violation occurs we don't break in the debugger but get notification of the exception. Thus we let the event callback handle the exception.

When the memory page is too big - irrespectively of the breakpoint size - it might be possible it's being accessed too many times. In this case, the debugging tends to be extremely slow because of the frequent context switches between the target process and the debugger.

An enhancement of this plugin would be to let the execution continue when a data is accessed but to record each address being accessed so we can trace the memory access for certain memory regions.
  This blog is written and maintained by Attila Suszter. Read in Feed Reader.