Debug Fundamentals #4 : Spoiler

Debug Fundamentals #4 : Spoiler

  • Comments 2

We’re posting the answers to Debug Fundamentals #4 in this blog. Additionally we posted all of your answers that trickled into the original blog. We deferred the posting of your answers to prevent spoiling it for the others but you should find them up there now. Stay tuned for Debug Fundamentals #5!

 

 

Part One – Debugging

 

1.       What caused the access violation?

Code tried to execute with an invalid EIP address.

0:000> !address @eip

 ProcessParameters 00280f20 in range 00280000 00284000

 Environment 00280808 in range 00280000 00284000

    00ac5000 : 00ac5000 - 7513b000

                    Type     00000000

                    Protect  00000001 PAGE_NOACCESS

                    State    00010000 MEM_FREE

                    Usage    RegionUsageFree

 

2.       Examine the registers at the time of the crash.  Is there anything interesting about the contents?

There are ASCII values in 3 of the registers.

0:000> .formats @eax

  Chars:   SEGP  (little endian would be PGES)

0:000> .formats @eip

Evaluate expression:

  Chars:   GAME

0:000> .formats @ebp

  Chars:   OVER

 

3.       How did the registers get into this state?

The saved EIP and EBP values on the stack were corrupt and the boom() function executed a leave and ret instruction, loading the corrupt values into the registers.

4.       Find the offending data structure which caused this state to occur. What are its contents?

“GAMEOVER Happy debugging courtesy of Platforms GES!” backwards

0:000> dc @esp-38 l34/4

001bfdc8  45532180 6d732047 74666f72 20506c61  .!SEG smroftalP

001bfdd8  79206f66 72746573 20636f75 67696e67  fo ysetruoc gnig

001bfde8  65627567 70792064 20486170 4f564552  gubed yppaH REVO

001bfdf8  47414d45                             EMAG


 

5.       Are there security concerns with this access violation? Why?

A malicious user could potentially manipulate EIP to execute arbitrary code and compromise the system.

6.        Why is this class of crashes not seen in the wild much anymore?

This exercise was explicitly compiled with the /GS- flag.  The Microsoft compiler appropriately enables buffer overrun security checks by default using the /GS compiler switch. This is a randomized “cookie” value placed on the stack during the function prolog right before the saved EIP and EBP. During the function epilog this value is asserted before executing the ret instruction. If it is not correct the program is terminated.

More info : http://msdn.microsoft.com/en-us/library/8dbf701c.aspx

Part Two – Reverse Engineering

 

Examine the functions main(), snap(), crack(), pop(), and boom().

1.       Describe with a sentence or two what each one is doing.  (There is no need to comment on every assembly instruction or re-write the code in C here unless you really feel you need to.)

main() – Allocates a buffer on the stack and makes a call to snap() passing it the buffer.

//

// Allocate a buffer on the stack

//

int

main()

{

      char buf[sizeof(string) + 13];           

      return snap ((char *)buf);

}

snap() – Does a strcpy() like operation from a global buffer into the buffer parameter and passes it to crack().

//

// Copy static string to stack

//

int

snap(char * buf)

{

      for (int i = 0; string[i]; i++)

      {

            buf[i] = string[i];

      }

     

      return crack (buf);

}

 

crack() – Does a string reverse operation on the buffer parameter then counts the number of characters before finding a special delimiting character (0xC3) and passes the buffer and character count to pop().

//

// Reverse the string

//

int

crack(char * buf)

{

      char * s = buf;

      char * p = s;

     

      while (*p) p++;

      p--;

 

      while (p > s)

      {

            char t = *s;

            *s++ = *p;

            *p-- = t;

      }

 

      // strlen of the secret

      char * len = buf;

      unsigned i = 0;

           

      while (*len != '\xc3')

      {

            len++;

            i++;

      }

     

      i++;

           

      return pop (buf, i);

}


 

pop() – Does a memmove() like operation removing the character count parameter from the start of the string buffer and passes it to boom().

//

// Do a memory move on the string, hiding the secret

//

int pop(char * buf, unsigned size)

{

      volatile char * a = buf;

      char * b = buf + size;

     

      while (*b)

            *a++ = *b++;

     

      *a = '\0';

     

      return boom (buf);     

}

 

boom() – Allocates a stack buffer and does a strcpy() operation from the parameter into it. Takes each char of the new stack buffer and swaps the nibbles of each character so that 0y1101 1001 is 0y1001 1101. Then returns ‘SEGP’; or PGES as a DWORD.

//

// Copy string to our local buf, decrypt and boom!!!

//

int

boom(char * buf)

{

      char new_buf[sizeof(string) - 0x14];

      register unsigned int i;     

     

      for (i = 0; buf[i]; i++)

      {

            new_buf[i+1] = buf[i];

      }

     

            while (*buf)

            *buf ++ = *buf << 4 | *buf >> 4;

 

      return (int)'SEGP';

}


Bonus:

 

1.       If this access violation occurred while the program was running without a debugger present, would there be anything different about the crashing register state or the data structure which caused it? If so what is it and why?

When a debugger is present, an unhandled exception is immediately trapped and the pristine state of the process can be examined. When a debugger is not present, an unhandled exception handler is executed in the context of the original exception before the JIT debug handling takes effect and a debugger is attached. Since the offending corruption was in stack memory which has been popped off the stack before the access violation occurred, the unhandled exception handler reused and overwrote the offending stack memory.

More Info on debugging and unhandled exception filters:

Debugging a custom unhandled exception filter  

Don’t perform complicated tasks in your unhandled exception filter

 

2.       The functions from “Part Two – Reverse Engineering” perform operations on a set of data. During this manipulation some data is lost. Find this data and decode its “secret” message.

                “<DBGNINJA>”

 

Share this post :
Leave a Comment
  • Please add 6 and 8 and type the answer here:
  • Post
  • Thank you for submitting this cool story - Trackback from DotNetShoutout

  • Nice and fun!

    When there will be #5? :)

    Just a little note regarding the reversing of the function boom.

    By looking a the disassembly:

    .text:010011E8                 lea     eax, [ebp+new_buf]

    .text:010011EB                 jmp     short loc_1001204

    .text:010011ED ; ---------------------------------------------------------------------------

    .text:010011ED

    .text:010011ED loc_10011ED:                            ; CODE XREF: boom(char *)+41j

    .text:010011ED                 mov     cl, [eax]

    .text:010011EF                 mov     dl, [eax]

    It seems it should be more:

    while(*new_buf)

    *new_buf++ = *new_buf >> 4 | *new_buf << 4;

    rather than:

               while (*buf)

               *buf ++ = *buf << 4 | *buf >> 4;

     <DIV class=commentowner>[Very Soon:) ^ronsto.]</DIV>

Page 1 of 1 (2 items)