Reverse-Engineering Training Part 3

Reverse-Engineering Training Part 3

Hello! Welcome back to part 3 of my reverse-engineering challenge walkthrough.

Today we will begin investigating the curious functions we found in the Assembly dump. This can get overwhelming pretty quickly, so I will be splitting this section up into three posts.

So, the curious functions we found in the main function were called “check_argcount”, “check_argv”, and “check_key”.

No alt text provided for this image

This function is mercifully short. The first two instructions can be safely ignored. “Push %rbp” and “mov %rsp,%rbp” are more advanced programming concepts that basically tell your processor to bookmark where it was before we jumped to this function. When the function ends, the program will look at the bookmark to return in its normal execution flow.

The next two instructions are where this function get interesting. “mov %edi,-0x4(%rbp)” translates to “move the contents of the ‘edi’ register into the location that is 4 bytes from the memory address that the ‘rbp’ register points to”. That’s a little complicated, but you can think of registers as short term variables that are constantly changed depending on the needs of the program.

The next instruction, “compl $0x3,-0x4(%rbp)” will compare the value of 3 to the value that we moved in the last instruction. Considering that the function is named “check_argcount” we will hazard a guess that we need a total of 3 arguments on the command line. The first is the name of the program being called (./a.out), the second is the email value, and the third is the key. Any fewer or more arguments should result in this function failing. Let’s check just to make sure.

We will now view the program using the GNU Debugger tool (GDB)! Debuggers are useful for slowing down a program to see how it executes instructions that a normally performed thousands of times in the blink of an eye. We will be setting something called a “breakpoint” at the memory address of the instruction we want to examine. A breakpoint is a little pause button that tells the program to halt its current execution so the analyst can examine how the program is running at that exact instance.

First, we open up our program with GDB. The syntax for this is "gdb <name of the program you want to debug>.

No alt text provided for this image

Then we set our break point. Remembering that “check_argcount” started at the address “0x401223”, we set our first breakpoint. GDB syntax for setting breakpoints looks like “b* <memory address goes here>”.

No alt text provided for this image

Then we run our program with some dummy arguments. The GDB syntax for running a program from the start looks like “<run <argument 1 goes here> <argument 2 goes here> <so on and so forth with arguments>”.

No alt text provided for this image

And there we go! The output “Breakpoint 1, 0x0000000000401223 in check_argcount ()” is exactly what we want to see. The program executed normally until it hit the instructions inside “check_argcount” at the address of 0x401223. Let’s take a look at the next few instructions to make sure they are what we expect. We will do that with the GDB syntax of “disassemble $rip”. This translates to “turn the machine code (disassemble) into human readable mnemonics at the location of the instruction pointer ($rip)”. The instruction pointer is exactly what it sounds like. It points at a memory address of the current instruction being executed in the program.

No alt text provided for this image

Great! That sure looks like our “check_argcount” function! Next we will skip down past the “bookmarking” instructions until we hit 0x401227, the location of the first instructions that are unique to the function. We will do this with the GDB syntax “stepi 2”. This tells GDB to “step” two instructions, or to execute two more instructions. We do this, then disassemble again.

No alt text provided for this image

Ok! Now we have our first mystery to solve. What’s in %edi? What’s currently at -0x4(%rbp)? We can use GDB to examine these values. The syntax “info registers $edi” translates to “tell me the value of the ‘edi’ register”. We follow this with “x/x $rbp-0x4”, which translates to “examine (x) the byte (/x) at the location 4 bytes from the address stored in ‘rbp’ ($rbp-0x4)”.

No alt text provided for this image

Nice. So, there’s nothing in that location now. But, after our current instruction executes…

No alt text provided for this image

…we should see that the value of the ‘edi’ register has been loaded into -0x4(%rbp)…

No alt text provided for this image

Nice. We know that the next instruction “compl” compares the value of 3 against the value that is stored at -0x4(%rbp). It might be safe to assume that the program here is definitely checking that we have the right amount of arguments on the command line, but let’s try it with more arguments, just to make sure. We restart our program with one more command line argument of “toomanyarguments!!”

No alt text provided for this image

And, as my grandfather used to say, “vee-ola”. The program now has the value 4 stored at -0x4($rbp). I think it’s safe to say that this function performs exactly how it’s named.

That’s all for this entry. In the next article, we will dive into the “check_argv” function. That should be a different check.



To view or add a comment, sign in

More articles by Christopher Campbell

  • Reverse-Engineering Training Part 2

    Hello! Welcome back to part 2 of my reverse-engineering challenge walkthrough. Before we dive further into the…

    1 Comment
  • Reverse Engineering Training

    Hello. My company conducted some internal training recently on reverse-engineering.

    4 Comments

Explore content categories