Reverse Engineering a Compiled C++ Binary part 3

Table of Contents

DISCLAIMER

Through this paper I am not encouraging people to hack, destroy or steal anything, you must comply with laws and you shall take entire responsibility if you use this knowledge for bad behavior. With great power comes great responsibilities. Reverse engineering is not always legal, check EULA/laws in your country.

THE CODE

Alright I think this will be the last of my "Reverse Engineering a Compiled C++ Binary" papers as there is only so many very simple examples we can go through.

Below is the source code for the binary we will attempt to reverse engineer.

$ cat sample.c++ 
#include <iostream>
int main() {
using namespace std;

 int a;
 int b;
 int c;
 int d;
 int e;

 b = 24;
 c = 10;
 d = 12;
 e = b - c + d;
 
 cout << "Please enter your code: ";
 cin >> a;
 
if ( a == e )
 {
       cout << "Correct!\n";
    } else {
       cout << "Incorrect...\n";
    }
    return 0;
  }

Just like last time this binary has all symbols in place.

$ file sample
sample: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped

REVERSING

Like always lets check this binary for anything promising in the binary.

$ strings sample
/lib64/ld-linux-x86-64.so.2
"+xO
CyIk
libstdc++.so.6
__gmon_start__
_Jv_RegisterClasses
_ZNSt8ios_base4InitD1Ev
__gxx_personality_v0
_ZSt3cin
_ZNSirsERi
_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
_ZSt4cout
_ZNSt8ios_base4InitC1Ev
libm.so.6
libgcc_s.so.1
libc.so.6
__cxa_atexit
__libc_start_main
GLIBC_2.2.5
CXXABI_1.3
GLIBCXX_3.4
fff.
fffff.
l$ L
t$(L
|$0H
Please enter your code: 
Correct!
Incorrect...

Lets get down to it and start by disassembling the main portion.

$ gdb -q sample
Reading symbols from /home/jness/tm/sample...done.
(gdb) disass main
Dump of assembler code for function main:
0x0000000000400844 <main+0>:  push   %rbp
0x0000000000400845 <main+1>:  mov    %rsp,%rbp
0x0000000000400848 <main+4>:  sub    $0x20,%rsp
0x000000000040084c <main+8>:  movl   $0x18,-0x8(%rbp)
0x0000000000400853 <main+15>: movl   $0xa,-0xc(%rbp)
0x000000000040085a <main+22>: movl   $0xc,-0x10(%rbp)
0x0000000000400861 <main+29>: mov    -0xc(%rbp),%eax
0x0000000000400864 <main+32>: mov    -0x8(%rbp),%edx
0x0000000000400867 <main+35>: mov    %edx,%ecx
0x0000000000400869 <main+37>: sub    %eax,%ecx
0x000000000040086b <main+39>: mov    %ecx,%eax
0x000000000040086d <main+41>: add    -0x10(%rbp),%eax
0x0000000000400870 <main+44>: mov    %eax,-0x14(%rbp)
0x0000000000400873 <main+47>: mov    $0x400a0c,%esi
0x0000000000400878 <main+52>: mov    $0x601180,%edi
0x000000000040087d <main+57>: callq  0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x0000000000400882 <main+62>: lea    -0x4(%rbp),%rax
0x0000000000400886 <main+66>: mov    %rax,%rsi
0x0000000000400889 <main+69>: mov    $0x601060,%edi
0x000000000040088e <main+74>: callq  0x400740 <_ZNSirsERi@plt>
0x0000000000400893 <main+79>: mov    -0x4(%rbp),%eax
0x0000000000400896 <main+82>: cmp    -0x14(%rbp),%eax
0x0000000000400899 <main+85>: jne    0x4008ac <main+104>
0x000000000040089b <main+87>: mov    $0x400a25,%esi
0x00000000004008a0 <main+92>: mov    $0x601180,%edi
0x00000000004008a5 <main+97>: callq  0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00000000004008aa <main+102>:        jmp    0x4008bb <main+119>
0x00000000004008ac <main+104>:        mov    $0x400a2f,%esi
0x00000000004008b1 <main+109>:        mov    $0x601180,%edi
0x00000000004008b6 <main+114>:        callq  0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00000000004008bb <main+119>:        mov    $0x0,%eax
0x00000000004008c0 <main+124>:        leaveq 
0x00000000004008c1 <main+125>:        retq   
End of assembler dump.

Right off the bat we see what appears to be some hex values being added to a portion of memory, and then below we can see a cmp which leads to our jne. Lets take a better look at this cmp.

0x0000000000400896 <main+82>: cmp    -0x14(%rbp),%eax

Looking at this snippet above we notice two new function which we havent went over before, sub and add, we can look these up at http://flip-edesign.com/basics_of_assembler.pdf

*SUB* is the opposite of the ADD command. It subtracts the value of src from the value of
dest and stores the result in dest.

*ADD* instruction adds a value to a register or a memory address. It can be used in
these ways

Alright we have to do some basic math.

0x000000000040084c <main+8>:  movl   $0x18,-0x8(%rbp)   ; value = 24
0x0000000000400853 <main+15>: movl   $0xa,-0xc(%rbp)    ; value = 10
0x000000000040085a <main+22>: movl   $0xc,-0x10(%rbp)   ; value = 12
0x0000000000400861 <main+29>: mov    -0xc(%rbp),%eax    ; move int 10 to %eax
0x0000000000400864 <main+32>: mov    -0x8(%rbp),%edx    ; move int 24 to %edx
0x0000000000400867 <main+35>: mov    %edx,%ecx          ; move %edx to %ecx (int 24)
0x0000000000400869 <main+37>: sub    %eax,%ecx          ; subtract %ecx (24) from %eax (10)
0x000000000040086b <main+39>: mov    %ecx,%eax          ; move result of subtraction (int 14) to %eax
0x000000000040086d <main+41>: add    -0x10(%rbp),%eax   ; add -0x10(%rbp) (int 12) to %eax (int 14)

So if our theroy is correct the "code" should be 26, lets give this a try.

$ ./sample 
Please enter your code: 26
Correct!

Author: Jeffrey Ness <jness@flip-edesign.com>

Date: 2010-03-23 15:40:57 CDT

HTML generated by org-mode 6.21b in emacs 23