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