2

I am relatively new to assembly and am trying to understand the following assembler dump (this is from the common 'binary bomb' exercise which I am attempting in order to get more familiar with assembly). The basic premise is that you have to find the right input needed to exit the program successfully without "triggering the bomb" (calling the explode_bomb function) by inspecting the assembly and setting breakpoints. It is a common exercise used to teach GDB debugging and assembly syntax.

From what I can understand, this program first checks string input using scanf and checks whether 1 argument is provided. Upon setting a breakpoint and inspecting the value of the eax register, I am able to see the input value I enter so it seems as though I should be looking for this to be compared with something else. The program then moves some things around and compares the value of the eax register to the binary value 0x52b = 1323. However, I have tried using this value as my input and it does not work so I am wondering whether I am misunderstanding the logic behind this program.

I would greatly appreciate any help/advise!

Updated (I am not sure whether this is correct):

  • The program takes 1 input argument, stores in eax register. Explodes if not 1 argument input.
  • The program then does mov 0x1c(%esp),%eax which essentially does eax = [esp + 0x1c] (wouldn't this overwrite the program's input?)
  • The program then does lea (%eax,%eax,2),%eax which essentially does eax = eax + eax * 2
  • Finally, the program does cmp $0x52b,%eax which compares the value in the eax register to 0x52b.
0x08048bd0 <+0>:     sub    $0x2c,%esp
0x08048bd3 <+3>:     movl   $0x0,0x1c(%esp)
0x08048bdb <+11>:    lea    0x1c(%esp),%eax
0x08048bdf <+15>:    mov    %eax,0x8(%esp)
0x08048be3 <+19>:    movl   $0x804a644,0x4(%esp)
0x08048beb <+27>:    mov    0x30(%esp),%eax
0x08048bef <+31>:    mov    %eax,(%esp)
0x08048bf2 <+34>:    call   0x8048870 <__isoc99_sscanf@plt>
0x08048bf7 <+39>:    cmp    $0x1,%eax
0x08048bfa <+42>:    je     0x8048c01 <phase_1+49>
0x08048bfc <+44>:    call   0x8049363 <explode_bomb>
0x08048c01 <+49>:    mov    0x1c(%esp),%eax
0x08048c05 <+53>:    lea    (%eax,%eax,2),%eax
0x08048c08 <+56>:    cmp    $0x52b,%eax
0x08048c0d <+61>:    je     0x8048c14 <phase_1+68>
0x08048c0f <+63>:    call   0x8049363 <explode_bomb>
0x08048c14 <+68>:    add    $0x2c,%esp
0x08048c17 <+71>:    ret  
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
mlz7
  • 2,067
  • 3
  • 27
  • 51
  • what is the goal of this 'binary bomb' exercise? – Ackdari Apr 06 '20 at 17:05
  • @Ackdari i updated the description, it is basically a binary which expects user input and if this input is valid, you pass onto the next level and if it is invalid, the "bomb" explodes. The goal is to determine what the necessary input is without triggering the "bomb" – mlz7 Apr 06 '20 at 17:08
  • What is the value of `eax` at position `<+53>` and `<+56>`? Or other question at which point does it currently explode `<+44>` or `<+63>`? – Ackdari Apr 06 '20 at 17:12
  • You might want to check out [this](https://stackoverflow.com/questions/9153282/lea-assembly-instruction) to understand what the `lea` instruction does to the value in `eax` before it is compared to `0x52` – Ackdari Apr 06 '20 at 17:17
  • lea (%eax, %eax, 2), %eax sets %eax to %eax + %eax * 2, so it just multiplies %eax by 3. So you need to enter 0x52b / 3 = 441 – Alex Sveshnikov Apr 06 '20 at 17:27
  • @Alex thank you, thats what I figured (I added an update which I am not sure is correct or not) but what I don't understand is how the input is still in eax at this point, wouldn't `mov 0x1c(%esp),%eax` overwrite the input stored in eax? – mlz7 Apr 06 '20 at 17:29
  • @mlz7 _"The program then does `lea (%eax,%eax,2),%eax` which essentially does `eax = [eax + eax * 2]`"_ no lea does not load a value from memory it does only arithmetic in the registers – Ackdari Apr 06 '20 at 17:29
  • @Ackdari thank you very much for the link, I added an update with what I understand from what you sent – mlz7 Apr 06 '20 at 17:29
  • @mlz7 if what you said in your update is true then there is *no way* of avoiding `explode_bomb`, since you do not control `eax` anymore once it is overwritten by the contents of `esp + 0x1c`. You either have another input or the `eax` register gets saved somewhere. Post the code of the function ***as text***, not as an image. – Marco Bonelli Apr 06 '20 at 17:30
  • 1
    You pass to scanf the address in memory where to store your input (line 11). After scanf completes in eax there is a result how many entries have been parsed (should be 1). The actual result is stored at that memory location esp + 0x1c, that's where you get it from on line 49. – Alex Sveshnikov Apr 06 '20 at 17:31
  • @Alex Oh ok I think I understand. Is scanf input always stored in this specific offset ( esp + 0x1c) or is that something specific to this program? – mlz7 Apr 06 '20 at 17:36
  • 2
    scanf("%d", &int_var) - in this specific case the int_var was stored at stack at position 1c. It can be any address. For example, the location of this variable on stack depends on whether you define other variables before it or not. – Alex Sveshnikov Apr 06 '20 at 17:38

1 Answers1

2

In x86 32bit, arguments are passed on the stack according to the IA32 cdecl calling convention (see this wiki page for more info).

Your phase_1 function is calling sscanf(), passing the arguments here:

0x08048bdb <+11>:    lea    0x1c(%esp),%eax
0x08048bdf <+15>:    mov    %eax,0x8(%esp)
0x08048be3 <+19>:    movl   $0x804a644,0x4(%esp)
0x08048beb <+27>:    mov    0x30(%esp),%eax
0x08048bef <+31>:    mov    %eax,(%esp)

This is, in short:

sscanf(esp + 0x30, 0x804a644, esp + 0x1c);

Which should be something like:

int var_on_stack;
sscanf(user_input, "%d", &var_on_stack); 
// user_input starts at esp + 0x30
// &var_on_stack == esp + 0x1c

The first argument (user_input) was probably passed as argument to the phase_1 function, and it probably contains data that was previously read.

The value 0x804a644 is the address of the format string that is being passed to scanf(), I assume it's something like "%d" because the value is treated like an integer afterwards. You can check what's at address 0x804a644 with x/s 0x804a644 to see exactly what the format string is (and also understand the type of the variable that is being read).

After that, these two instructions:

0x08048c01 <+49>:    mov    0x1c(%esp),%eax
0x08048c05 <+53>:    lea    (%eax,%eax,2),%eax

Get the scanned value from the stack into eax, and then multiply it by 3 (that lea ends up doing eax = eax*2 + eax).

After this is done, the value is compared with 0x52b. Therefore you need to input 0x52b/3, which is 1323/3, which is 441.

Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128