July 24, 2012

Detecting Read Access to Uninitialized Stack Memory

As I mentioned in the previous post I developed a program that is able to trace when the stack memory is being accessed. This time, I improved this program so if there is a read access to the portion of the stack memory that was not written before it issues a read-before-write notification. This happens when for example an uninitialized variable is being read.

Here is one of the erroneous C program I tested my test tool with. The C program reads uninitialized variable both in process and process2 functions from the CONTEXT structure. Highlighted the lines accessing uninitialized memory.
// TestRBW.cpp : Example file to test read-before-write bugs.
// Compile with optimization disabled.

#include "stdafx.h"
#include <string.h>

#define MAX 16

typedef struct _CONTEXT
{
    int arr[MAX];
    int a;
    int b;
    int c;
} CONTEXT;

void init(CONTEXT* ctx)
{
    memset(ctx->arr, 0, sizeof(ctx->arr[0]) * (MAX-1));
    ctx->a = 1;
}

void process(CONTEXT* ctx)

{
    int trash;

    for (int i = 0; i < MAX; i++)

    {
        trash = ctx->arr[i];
    }
}

void process2(CONTEXT* ctx)

{
    ctx->b = ctx->c;
}

void process3(int num)

{
    int trash;

    if (num)

        trash = num;
}

int _tmain(int argc, _TCHAR* argv[])

{
    CONTEXT ctx;

    // Erroneously initializes context. The last element of arr member remains unitialized.

    // b and c members remain uninitialized, too.
    init(&ctx);

    // Accesses to each element of the array. Read-before-write error should be reported in this function.

    process(&ctx);

    // Copies c to b but c is uninitialized. Read-before-write error should be reported in this function.

    process2(&ctx);

    // This contains no read-before-write bug.

    process3(ctx.a);
}
And here is the result of the test. In the log you can see both of the bugs were detected.
0:000> !region 18 18f000 1000
[Data Access] Data at 0018ff28 is read before it is written
[Data Access] EIP=00401044 Data=0018ff28 R
[Data Access] 00401044 8b048a          mov     eax,dword ptr [edx+ecx*4]
[Data Access] Data at 0018ff34 is read before it is written
[Data Access] EIP=00401059 Data=0018ff34 R
[Data Access] 00401059 8b5148          mov     edx,dword ptr [ecx+48h]
Break reason: 00000010
Looking the functions of the two EIPs. Highlighted the lines accessing uninitialized memory.
TestRBW!process:
00401020 55              push    ebp
00401021 8bec            mov     ebp,esp
00401023 83ec08          sub     esp,8
00401026 c745f800000000  mov     dword ptr [ebp-8],0
0040102d eb09            jmp     TestRBW!process+0x18 (00401038)
0040102f 8b45f8          mov     eax,dword ptr [ebp-8]
00401032 83c001          add     eax,1
00401035 8945f8          mov     dword ptr [ebp-8],eax
00401038 837df810        cmp     dword ptr [ebp-8],10h
0040103c 7d0e            jge     TestRBW!process+0x2c (0040104c)
0040103e 8b4df8          mov     ecx,dword ptr [ebp-8]
00401041 8b5508          mov     edx,dword ptr [ebp+8]
00401044 8b048a          mov     eax,dword ptr [edx+ecx*4]
00401047 8945fc          mov     dword ptr [ebp-4],eax
0040104a ebe3            jmp     TestRBW!process+0xf (0040102f)
0040104c 8be5            mov     esp,ebp
0040104e 5d              pop     ebp
0040104f c3              ret
TestRBW!process2:
00401050 55              push    ebp
00401051 8bec            mov     ebp,esp
00401053 8b4508          mov     eax,dword ptr [ebp+8]
00401056 8b4d08          mov     ecx,dword ptr [ebp+8]
00401059 8b5148          mov     edx,dword ptr [ecx+48h]
0040105c 895044          mov     dword ptr [eax+44h],edx
0040105f 5d              pop     ebp
00401060 c3              ret
I built this new functionality on the top of one mentioned in the previous post. The additions are the followings:
  • We trace both read and write memory accesses to the stack memory.
  • We maintain a structure to flag what memory addresses on the stack have been written.
  • Before the program starts to trace the memory it considers that memory addresses greater or equal than ESP have been written and maintain the structure according to this.
  • If a write memory access occurs we maintain the structure to flag the memory region has been written.
  • If an element is popped from the stack (read access to stack memory) we maintain the structure to remove addresses belongs to the unused portion of the stack memory.
  • If a read access memory occurs we read the structure and check if the memory at the address has been written. Giving notification according to results.

July 8, 2012

Tracing access to stack memory

In the previous post I wrote about a concept to intercept when arbitrary region of the memory is being accessed.

Below is an example output of the Windbg extension. I set it to monitor when the stack memory of the current thread (Address: 18d000 Size: 3000) is being accessed, and to break in when there is a call to other module (Break reason: 2).

In the log you can see the address where the memory access occurred and the instruction caused the memory access. Also, you can see the address of the data being accessed, and the type of the data access (R for read, W for write).

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.