Lattice
629 words
3 minutes
Reversing Simple Calculations

Here i will reverse a simple c++ program that does basic math calculations

0000000000001149 <_Z5printv>:
    1149:       55                      push   rbp
    114a:       48 89 e5                mov    rbp,rsp
    114d:       48 83 ec 10             sub    rsp,0x10
    1151:       c7 45 f8 02 00 00 00    mov    DWORD PTR [rbp-0x8],0x2
    1158:       c7 45 fc 04 00 00 00    mov    DWORD PTR [rbp-0x4],0x4
    115f:       8b 55 f8                mov    edx,DWORD PTR [rbp-0x8]
    1162:       8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
    1165:       01 d0                   add    eax,edx
    1167:       89 c6                   mov    esi,eax
    1169:       48 8d 05 d0 2e 00 00    lea    rax,[rip+0x2ed0]        # 4040 <_ZSt4cout@GLIBCXX_3.4>
    1170:       48 89 c7                mov    rdi,rax
    1173:       e8 c8 fe ff ff          call   1040 <_ZNSolsEi@plt>
    1178:       be 0a 00 00 00          mov    esi,0xa
    117d:       48 89 c7                mov    rdi,rax
    1180:       e8 ab fe ff ff          call   1030 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c@plt>
    1185:       90                      nop
    1186:       c9                      leave
    1187:       c3                      ret

0000000000001188 <main>:
    1188:       55                      push   rbp
    1189:       48 89 e5                mov    rbp,rsp
    118c:       e8 b8 ff ff ff          call   1149 <_Z5printv>
    1191:       b8 00 00 00 00          mov    eax,0x0
    1196:       5d                      pop    rbp
    1197:       c3                      ret

main()#

starting off with the main function we see push rbp which puts the rbp register onto the stack

then we move the rsp register into rbp to be a reference point to the beginning of a function

next it makes a function call to print

print()#

on the print function we start off just like the main function with pushing the rbp register to the stack and moving rsp to rbp

The program then subtracts 0x10 which is 16 bytes to allocate space for local variables.

Now for the interesting part, on address 1151 we move the number 0x2 into the address value of [rbp-0x8]. this is most likely to initialize a variable in the function.

we do the same with 0x4 but at [rbp-0x4].

Notice how the offset is going down by -4 each time? This should indicate that we are initializing a int data type

At this point the registers look like so:

[rbp-0x8] = 2

[rbp-0x4] = 4

Going forward we move both of those values into a new register. 2 into edx and 4 into eax

115f:  mov    edx,DWORD PTR [rbp-0x8] ; move 2 into edx
1162:  mov    eax,DWORD PTR [rbp-0x4] ; move 4 into eax

This will be used for calculation purposes between the registers like below

1165:  add    eax,edx ; add 2 + 4 = 6

here we added the two registers so that the eax register will equal 2 + 4

next we move eax(6) into the esi register. The esi register is the second argument whenever a function call is being made.

System V ABI Calling Convention:

Argument #Register
1stRDI
2ndRSI
3rdRDX
4thRCX
5thR8
6thR9
1167:  mov    esi,eax ; move eax into esi

For the final set of operations we load the address lea of cout , which is a function used to print to the console, into the rdi register which is the first argument to a function.

1169:  lea    rax,[rip+0x2ed0]    ; 4040 <_ZSt4cout@GLIBCXX_3.4> get std::cout << address
1170:  mov    rdi,rax

Now we can make a function call with the arguments in place rdi = std::cout << rsi = 6

1173:  call   1040 <_ZNSolsEi@plt>  ; std::cout << 6;

The final set of instruction are making a new function call and we can see that it is using another set of arguments esi,rdi moving 0xa = \n into esi, which will be the second argument and rax = std::cout << into rdi.

Finally we make another function call to the << operator which will print a newline character to the end of the cout statement and end the program.

1178:  mov    esi,0xa
117d:  mov    rdi,rax
1180:  call   1030 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c@plt>
1185:  nop
1186:  leave
1187:  ret

Program reveal#

#include <iostream>

void print()
{
  int num1{2};
  int num2{4};
  std::cout << num1 + num2 << '\n';
}

int main(){
  print();
}

As we can see, the program initialized two int variables with 2 and 4 then proceeded to add them, with a newline ending.