Reverse Engineering a Binary 2

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

In this example we have a bit more complicated program which assigns two integers to varibles then performs a multiplication on them to get our code :

#include < iostream>
int main() {
using namespace std;

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

 b = 10;
 c = 24;
 d = b * c;

 cout << "Please enter your code: ";
 cin >> a;

if ( a == d )
 {
       cout << "Correct!\n";
    } else {
       cout << "Incorrect...\n";
    }
    return 0;
  }

Again this binary is not stripped of its symbols so we can easily debug:

$ 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

Lets go ahead and see if strings offers any hide secrets:

$ strings sample
/lib64/ld-linux-x86-64.so.2
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...

So we know a bit about this application, it ask for a “code” and depending on your answer will give one an answer “Correct!” or “Incorrect…”

Alright lets go ahead and start disassembling with GDB :

$ 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    $0x10,%rsp
0x000000000040084c <main+8>:  movl   $0xa,-0x8(%rbp)
0x0000000000400853 <main+15>: movl   $0x18,-0xc(%rbp)
0x000000000040085a <main+22>: mov    -0x8(%rbp),%eax
0x000000000040085d <main+25>: imul   -0xc(%rbp),%eax
0x0000000000400861 <main+29>: mov    %eax,-0x10(%rbp)
0x0000000000400864 <main+32>: mov    $0x4009fc,%esi
0x0000000000400869 <main+37>: mov    $0x601180,%edi
0x000000000040086e <main+42>: callq  0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x0000000000400873 <main+47>: lea    -0x4(%rbp),%rax
0x0000000000400877 <main+51>: mov    %rax,%rsi
0x000000000040087a <main+54>: mov    $0x601060,%edi
0x000000000040087f <main+59>: callq  0x400740 <_ZNSirsERi@plt>
0x0000000000400884 <main+64>: mov    -0x4(%rbp),%eax
0x0000000000400887 <main+67>: cmp    -0x10(%rbp),%eax
0x000000000040088a <main+70>: jne    0x40089d <main+89>
0x000000000040088c <main+72>: mov    $0x400a15,%esi
0x0000000000400891 <main+77>: mov    $0x601180,%edi
0x0000000000400896 <main+82>: callq  0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x000000000040089b <main+87>: jmp    0x4008ac <main+104>
0x000000000040089d <main+89>: mov    $0x400a1f,%esi
0x00000000004008a2 <main+94>: mov    $0x601180,%edi
0x00000000004008a7 <main+99>: callq  0x400730 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x00000000004008ac <main+104>:        mov    $0x0,%eax
0x00000000004008b1 <main+109>:        leaveq
0x00000000004008b2 <main+110>:        retq
End of assembler dump.

Looking at the above output I find the cmp to stand out as it appears to lead to the jne which decides our fate in this program:

0x0000000000400887 <main+67>: cmp    -0x10(%rbp),%eax

We can see something is being compared against %eax register, lets go ahead and see where -0x10(%rbp) leads:

0x0000000000400845 <main+1>:  mov    %rsp,%rbp
###
0x000000000040084c <main+8>:  movl   $0xa,-0x8(%rbp)
0x0000000000400853 <main+15>: movl   $0x18,-0xc(%rbp)
0x000000000040085a <main+22>: mov    -0x8(%rbp),%eax
0x000000000040085d <main+25>: imul   -0xc(%rbp),%eax
0x0000000000400861 <main+29>: mov    %eax,-0x10(%rbp)
###
0x0000000000400887 <main+67>: cmp    -0x10(%rbp),%eax

Ok so it seems we are moving some what appears to be hex values to some of our registers, lets go ahead and see if we can find out the values in a interger:

(gdb) print 0xa
$1 = 10
(gdb) print 0x18
$2 = 24

This is starting to look promising. Lets contiune on and see what happens with this data:

0x000000000040085a <main+22>:mov    -0x8(%rbp),%eax

Alright so first the value in the register (which we know to be 10) is moved to %eax , lets contiune on:

0x000000000040085d <main+25>:imul   -0xc(%rbp),%eax

Ok so the funtion imul is taking our data in the next register, lets go ahead and look that function on at basics_of_assembler.pdf

IMUL multiplies either EAX with value (IMUL value) or it multiplies two values and puts
them into a destination register (IMUL dest, value, value) or it multiplies a register
with a value (IMUL dest, value).

So now that we now that IMUL will perform multiplication all that is left is to try our theory out (10 * 24 = 240):

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