The most detailed analysis of bomb_lab phase5!

bomb_lab phase5’s most detailed analysis!

1. Preliminarily beautify the disassembly code

phase5:
  401062: 53 push %rbx
  401063: 48 83 ec 20 sub $0x20,%rsp
  401067: 48 89 fb mov %rdi,%rbx
  40106a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
  401071: 00 00
  401073: 48 89 44 24 18 mov %rax,0x18(%rsp)
  401078: 31 c0 xor ?x,?x
  40107a: e8 9c 02 00 00 callq 40131b <string_length>
  40107f: 83 f8 06 cmp $0x6,?x //Check whether the read length is 6
  401082: 74 4e je 4010d2 <phase_5 + 0x70>
  401084: e8 b1 03 00 00 callq 40143a <explode_bomb>
  401089: eb 47 jmp 4010d2 <phase_5 + 0x70>
  //eax = 6char
  
real start:
  40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),?x
  40108f: 88 0c 24 mov %cl,(%rsp)
  401092: 48 8b 14 24 mov (%rsp),%rdx
  401096: 83 e2 0f and $0xf,?x
  401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),?x // maduiersnfotvby
  4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1)
  4010b3: be 5e 24 40 00 mov $0x40245e,%esi //flyers
  4010b8: 48 8d 7c 24 10lea 0x10(%rsp),%rdi
  4010bd: e8 76 02 00 00 callq 401338 <strings_not_equal>
  4010c2: 85 c0 test ?x,?x
  4010c4: 74 13 je 4010d9 <phase_5 + 0x77> //work out
  4010c6: e8 6f 03 00 00 callq 40143a <explode_bomb>
  4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
  4010d0: eb 07 jmp 4010d9 <phase_5 + 0x77>


end:
  4010d2: b8 00 00 00 00 mov $0x0,?x
  int eax = 0;
  4010d7: eb b2 jmp 40108b <phase_5 + 0x29>
  4010d9: 48 8b 44 24 18 mov 0x18(%rsp),%rax
  4010de: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
  4010e5: 00 00
  4010e7: 74 05 je 4010ee <phase_5 + 0x8c>
  4010e9: e8 42 fa ff ff callq 400b30 <__stack_chk_fail@plt> // in case overflow
  
real_end:
  4010ee: 48 83 c4 20 add $0x20,%rsp
  4010f2: 5b pop %rbx
  4010f3: c3 retq

2. It is not difficult to see that the part that we really need to decrypt is the realstart part. The front of realstart is to detect whether the length of the read string is equal to six

Next we see that realstart can be divided into two parts. The first part processes the string. The second part checks whether the result is within 0x40245e.

real start:

part1:
  40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),?x
  40108f: 88 0c 24 mov %cl,(%rsp)
  401092: 48 8b 14 24 mov (%rsp),%rdx
  401096: 83 e2 0f and $0xf,?x
  401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),?x // maduiersnfotvby
  4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1)

part2:
  4010b3: be 5e 24 40 00 mov $0x40245e,%esi //flyers
  4010b8: 48 8d 7c 24 10lea 0x10(%rsp),%rdi
  4010bd: e8 76 02 00 00 callq 401338 <strings_not_equal>
  4010c2: 85 c0 test ?x,?x
  4010c4: 74 13 je 4010d9 <phase_5 + 0x77> //work out
  4010c6: e8 6f 03 00 00 callq 40143a <explode_bomb>
  4010cb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
  4010d0: eb 07 jmp 4010d9 <phase_5 + 0x77>

3.gdb bomb

x/s 0x40245e got flyers

That is, part2 can be equivalent to

if(0x10(%rsp!)=="flyers")
    work_out();
else
 explore_bomb();

4. Next we focus on part1. The most difficult part to understand is movzbl and %cl, which we will explain later

 40108b: 0f b6 0c 03 movzbl (%rbx,%rax,1),?x
  40108f: 88 0c 24 mov %cl,(%rsp)
  401092: 48 8b 14 24 mov (%rsp),%rdx
  401096: 83 e2 0f and $0xf,?x
  401099: 0f b6 92 b0 24 40 00 movzbl 0x4024b0(%rdx),?x // maduiersnfotvby
  4010a0: 88 54 04 10 mov %dl,0x10(%rsp,%rax,1)
  4010a4: 48 83 c0 01 add $0x1,%rax
  4010a8: 48 83 f8 06 cmp $0x6,%rax
  4010ac: 75 dd jne 40108b <phase_5 + 0x29>

5. From the last add $0x1,%rax and cmp $0x6,%rax, we can see that each time %rax adds 1 to 6 to exit, which is exactly equal to our characters

It is inferred that this is a for loop used to traverse each character

So the code written in c-like style is

for(int rax=1;rax<=6;rax + + )
{<!-- -->
movzbl (%rbx,%rax,1),?x
      mov %cl,(%rsp)
  mov (%rsp),%rdx
 and $0xf,?x
 movzbl 0x4024b0(%rdx),?x // maduiersnfotvby
  mov %dl,0x10(%rsp,%rax,1)
}

6. Here movzbl is equivalent to using forced type conversion because char is a 4-bit byte and int is an 8-bit byte. After using mov, you need to add zeros to the front

movzb1(%rbx,%rax,1),?x = (int)mov(%rbx,%rax,1),?x

Equivalent to ecx = rbx + rax*1

Equivalent to ecx = rbx[rax]

Continue to beautify the code

for(int rax=1;rax<=6;rax + + )
{<!-- -->
      ecx = rbx[rax];
      rsp=cl
      rdx=rsp
      edx &= 0xf
      edx = 0x4024b0[rdx]
      0x10rsp[rax] = dl
}

in

rbx = ?nput
0x4024b0 = “maduiersnfotvby”;

%cl: %cl is an 8-bit register and is part of %rcx (the low 8 bits of %rcx)

In other words, cl and ecx are the same thing, and dl and edx are the same thing, which are the intermediate products in forced type conversion.

7. Merge ecx and cl

for(int rax=1;rax<=6;rax + + )
{<!-- -->
      rdx = (int)rbx[rax];
      edx &= 0xf
      edx = 0x4024b0[rdx]
      0x10rsp[rax] = edx
}

Finally got

 char *s = "maduiersnfotvby";
for(int i = 1;i<=6;i + + )
{<!-- -->
char a = input[i];
a&= 0xf;
edx = s[a];
ans[i] = edx;
}
if(ans == "flyers")
    return;

8. Corresponding character query

That is to say, after each character is forced to type conversion through ascii, the lowest four digits are taken and the corresponding position of “maduiersnfotvby” is the letter.

Purpose f l y e r s
At the s position (hexadecimal) 9 f e 5 6 7
Corresponding letters (multiple) i o n e f g
#include<stdio.h>

int main()
{<!-- -->
for(int i=97;i<=122;i + + )
{<!-- -->
char a = (char)i;
printf("%c = %x\\
" , a, (i & amp;0xf));
}
return 0;
}
//Check the s position corresponding to each letter
a = 1
b = 2
c=3
d = 4
e = 5
f=6
g=7
h = 8
i=9
j = a
k = b
l = c
m=d
n = e
o = f
p = 0
q=1
r=2
s = 3
t=4
u=5
v = 6
w = 7
x = 8
y=9
z = a

phase5 cracked successfully!