Manual decompilation of asm snippet - c

I've been trying to decompile the following asm snippet(that's all I have):
55 push %rbp
48 89 e5 mov %rsp,%rbp
48 81 ec d0 00 00 00 sub $0xd0,%rsp
64 48 8b 04 25 28 00 mov %fs:0x28,%rax
00 00
48 89 45 f8 mov %rax,-0x8(%rbp)
31 c0 xor %eax,%eax
48 c7 85 30 ff ff ff movq $0x0,-0xd0(%rbp)
00 00 00 00
48 8d b5 38 ff ff ff lea -0xc8(%rbp),%rsi
b8 00 00 00 00 mov $0x0,%eax
ba 18 00 00 00 mov $0x18,%edx
48 89 f7 mov %rsi,%rdi
48 89 d1 mov %rdx,%rcx
f3 48 ab rep stos %rax,%es:(%rdi)
48 8b 15 19 06 20 00 mov 0x200619(%rip),%rdx
48 8d 85 30 ff ff ff lea -0xd0(%rbp),%rax
be ce 0f 40 00 mov $0x400fce,%esi
48 89 c7 mov %rax,%rdi
b8 00 00 00 00 mov $0x0,%eax
e8 4e fc ff ff callq 4008a0 <sprintf#plt>
Here is my attempt:
char buf[192] = {0};
sprintf(buf, "hello %s", name);
I've compiled this with gcc 4.8.5, and it gave me:
55 push %rbp
48 89 e5 mov %rsp,%rbp
48 81 ec d0 00 00 00 sub $0xd0,%rsp
64 48 8b 04 25 28 00 mov %fs:0x28,%rax
00 00
48 89 45 f8 mov %rax,-0x8(%rbp)
31 c0 xor %eax,%eax
48 8d b5 30 ff ff ff lea -0xd0(%rbp),%rsi
b8 00 00 00 00 mov $0x0,%eax
ba 18 00 00 00 mov $0x18,%edx
48 89 f7 mov %rsi,%rdi
48 89 d1 mov %rdx,%rcx
f3 48 ab rep stos %rax,%es:(%rdi)
48 8b 15 14 14 20 00 mov 0x201414(%rip),%rdx
48 8d 85 30 ff ff ff lea -0xd0(%rbp),%rax
be 2e 10 40 00 mov $0x40102e,%esi
48 89 c7 mov %rax,%rdi
b8 00 00 00 00 mov $0x0,%eax
e8 cb fb ff ff callq 4008a0 <sprintf#plt>
I'm struggling to figure out why this exists:
movq $0x0,-0xd0(%rbp)
and also the subsequent usage of -0xd0(%rbp) as a pointer for the argument to sprintf. I'm puzzled because the rep stos begin at -0xc8(%rbp) and not -0xd0(%rbp).
This is probably compiler specific, but still I'm curious what could possibly be the original code that produced that asm.

I imagine something like:
char buf[192] = {0, 0, 0, 0, 0, 0, 0, 0};
sprintf(buf + 8, "hello %s", name);
... would give you that output.
The movq instruction you refer to stores 0 (an 8-byte quantity) at the beginning of an array. The -0xc8(%rbp) comes from copying a string to an offset within the array.

Related

Bomb Lab Phase 4 [duplicate]

This question already has answers here:
Binary Bomb - Phase 4
(1 answer)
having trouble with bomb lab phase 4 [closed]
(1 answer)
Closed 5 years ago.
I'm having a bit of trouble understanding the following assembly code for the bomb lab. Running through it so far, I've figured out that the answer is supposed to be two decimal values. If not it will explode the bomb. Then, function 4 is making sure that the first value inputted is between 0 and 30. (0x1e) Then it jumps to func4 where it does something to my number. I understand up to the
sub %esi,%eax
then I don't completely understand what is going on in the function. I've tried plugging in values and checking them in the registry but I still don't understand what is going in function 4.
My attempt at understanding it is that, first its setting registers equal to each other. Then its doing an arithmetic right shift by 31 (0x1f). Then its subtracting by 1 and adding it to eax.
So, from what I understand its taking a number. Subtracting it by 1 and then adding them together? Such that the simplified formula would be (x-1)*x ?
Func_4
00000000004010b2 <func4>:
4010b2: 55 push %rbp
4010b3: 48 89 e5 mov %rsp,%rbp
4010b6: 89 d0 mov %edx,%eax
4010b8: 29 f0 sub %esi,%eax
4010ba: 89 c1 mov %eax,%ecx
4010bc: c1 e9 1f shr $0x1f,%ecx
4010bf: 01 c8 add %ecx,%eax
4010c1: d1 f8 sar %eax
4010c3: 8d 0c 30 lea (%rax,%rsi,1),%ecx
4010c6: 39 f9 cmp %edi,%ecx
4010c8: 7e 0c jle 4010d6 <func4+0x24>
4010ca: 8d 51 ff lea -0x1(%rcx),%edx
4010cd: e8 e0 ff ff ff callq 4010b2 <func4>
4010d2: 01 c0 add %eax,%eax
4010d4: eb 15 jmp 4010eb <func4+0x39>
4010d6: b8 00 00 00 00 mov $0x0,%eax
4010db: 39 f9 cmp %edi,%ecx
4010dd: 7d 0c jge 4010eb <func4+0x39>
4010df: 8d 71 01 lea 0x1(%rcx),%esi
4010e2: e8 cb ff ff ff callq 4010b2 <func4>
4010e7: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
4010eb: 5d pop %rbp
4010ec: c3 retq
Phase_4
00000000004010ed <phase_4>:
4010ed: 55 push %rbp
4010ee: 48 89 e5 mov %rsp,%rbp
4010f1: 48 83 ec 10 sub $0x10,%rsp
4010f5: 48 8d 4d fc lea -0x4(%rbp),%rcx
4010f9: 48 8d 55 f8 lea -0x8(%rbp),%rdx
4010fd: be 6d 2a 40 00 mov $0x402a6d,%esi
401102: b8 00 00 00 00 mov $0x0,%eax
401107: e8 a4 fb ff ff callq 400cb0 <__isoc99_sscanf#plt>
40110c: 83 f8 02 cmp $0x2,%eax
40110f: 75 0b jne 40111c <phase_4+0x2f>
401111: 8b 45 f8 mov -0x8(%rbp),%eax
401114: 83 e8 20 sub $0x20,%eax
401117: 83 f8 1e cmp $0x1e,%eax
40111a: 76 05 jbe 401121 <phase_4+0x34>
40111c: e8 b4 05 00 00 callq 4016d5 <explode_bomb>
401121: ba 3e 00 00 00 mov $0x3e,%edx
401126: be 20 00 00 00 mov $0x20,%esi
40112b: 8b 7d f8 mov -0x8(%rbp),%edi
40112e: e8 7f ff ff ff callq 4010b2 <func4>
401133: 83 f8 0e cmp $0xe,%eax
401136: 75 06 jne 40113e <phase_4+0x51>
401138: 83 7d fc 0e cmpl $0xe,-0x4(%rbp)
40113c: 74 05 je 401143 <phase_4+0x56>
40113e: e8 92 05 00 00 callq 4016d5 <explode_bomb>
401143: c9 leaveq
401144: c3 retq

Bomb Lab Phase 4, Identifying formula

I'm not understanding what the function below does. From what I gather, function 4 does something like (x+x)*2 or it does something like (high-low)/2 if a condition is reached. (I might be wrong on this). From reading the code, I also understood that in order to "defuse" the bomb. I need two decimal inputs, and the second one should be 14.
I'm stuck trying to figure out the first value, and trying to identify the correct formula to use in order to figure out the first value.
Function_4
00000000004010b2 <func4>:
4010b2: 55 push %rbp
4010b3: 48 89 e5 mov %rsp,%rbp
4010b6: 89 d0 mov %edx,%eax
4010b8: 29 f0 sub %esi,%eax
4010ba: 89 c1 mov %eax,%ecx
4010bc: c1 e9 1f shr $0x1f,%ecx
4010bf: 01 c8 add %ecx,%eax
4010c1: d1 f8 sar %eax
4010c3: 8d 0c 30 lea (%rax,%rsi,1),%ecx
4010c6: 39 f9 cmp %edi,%ecx
4010c8: 7e 0c jle 4010d6 <func4+0x24>
4010ca: 8d 51 ff lea -0x1(%rcx),%edx
4010cd: e8 e0 ff ff ff callq 4010b2 <func4>
4010d2: 01 c0 add %eax,%eax
4010d4: eb 15 jmp 4010eb <func4+0x39>
4010d6: b8 00 00 00 00 mov $0x0,%eax
4010db: 39 f9 cmp %edi,%ecx
4010dd: 7d 0c jge 4010eb <func4+0x39>
4010df: 8d 71 01 lea 0x1(%rcx),%esi
4010e2: e8 cb ff ff ff callq 4010b2 <func4>
4010e7: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax
4010eb: 5d pop %rbp
4010ec: c3 retq
Phase_4
00000000004010ed <phase_4>:
4010ed: 55 push %rbp
4010ee: 48 89 e5 mov %rsp,%rbp
4010f1: 48 83 ec 10 sub $0x10,%rsp
4010f5: 48 8d 4d fc lea -0x4(%rbp),%rcx
4010f9: 48 8d 55 f8 lea -0x8(%rbp),%rdx
4010fd: be 6d 2a 40 00 mov $0x402a6d,%esi
401102: b8 00 00 00 00 mov $0x0,%eax
401107: e8 a4 fb ff ff callq 400cb0 <__isoc99_sscanf#plt>
40110c: 83 f8 02 cmp $0x2,%eax
40110f: 75 0b jne 40111c <phase_4+0x2f>
401111: 8b 45 f8 mov -0x8(%rbp),%eax
401114: 83 e8 20 sub $0x20,%eax
401117: 83 f8 1e cmp $0x1e,%eax
40111a: 76 05 jbe 401121 <phase_4+0x34>
40111c: e8 b4 05 00 00 callq 4016d5 <explode_bomb>
401121: ba 3e 00 00 00 mov $0x3e,%edx
401126: be 20 00 00 00 mov $0x20,%esi
40112b: 8b 7d f8 mov -0x8(%rbp),%edi
40112e: e8 7f ff ff ff callq 4010b2 <func4>
401133: 83 f8 0e cmp $0xe,%eax
401136: 75 06 jne 40113e <phase_4+0x51>
401138: 83 7d fc 0e cmpl $0xe,-0x4(%rbp)
40113c: 74 05 je 401143 <phase_4+0x56>
40113e: e8 92 05 00 00 callq 4016d5 <explode_bomb>
401143: c9 leaveq
401144: c3 retq

Parse number of bytes reserved for local variables on the stack from GNU objdump output?

Consider the code snippet below.
The entry point of the program is main as defined in C-source code. Now, normally a function starts by decreasing %rsp to reserve space for local variables. But here, the GCC compiler reserves this space in some of the added (initial) functions.
My question is, where do I look for the number of bytes of reserved variables in these GCC-specific initialization functions? In this case, the number of reserved bytes is 0x08.
Also, in what order are these initial functions called?
00000000004003c0 <_start>:
4003c0: 31 ed xor ebp,ebp
4003c2: 49 89 d1 mov r9,rdx
4003c5: 5e pop rsi
4003c6: 48 89 e2 mov rdx,rsp
4003c9: 48 83 e4 f0 and rsp,0xfffffffffffffff0
4003cd: 50 push rax
4003ce: 54 push rsp
4003cf: 49 c7 c0 a0 05 40 00 mov r8,0x4005a0
4003d6: 48 c7 c1 30 05 40 00 mov rcx,0x400530
4003dd: 48 c7 c7 c0 04 40 00 mov rdi,0x4004c0
4003e4: e8 b7 ff ff ff call 4003a0 <__libc_start_main#plt>
4003e9: f4 hlt
4003ea: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
00000000004003f0 <deregister_tm_clones>:
4003f0: b8 37 10 60 00 mov eax,0x601037
4003f5: 55 push rbp
4003f6: 48 2d 30 10 60 00 sub rax,0x601030
4003fc: 48 83 f8 0e cmp rax,0xe
400400: 48 89 e5 mov rbp,rsp
400403: 76 1b jbe 400420 <deregister_tm_clones+0x30>
400405: b8 00 00 00 00 mov eax,0x0
40040a: 48 85 c0 test rax,rax
40040d: 74 11 je 400420 <deregister_tm_clones+0x30>
40040f: 5d pop rbp
400410: bf 30 10 60 00 mov edi,0x601030
400415: ff e0 jmp rax
400417: 66 0f 1f 84 00 00 00 nop WORD PTR [rax+rax*1+0x0]
40041e: 00 00
400420: 5d pop rbp
400421: c3 ret
400422: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
400426: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
40042d: 00 00 00
0000000000400430 <register_tm_clones>:
400430: be 30 10 60 00 mov esi,0x601030
400435: 55 push rbp
400436: 48 81 ee 30 10 60 00 sub rsi,0x601030
40043d: 48 c1 fe 03 sar rsi,0x3
400441: 48 89 e5 mov rbp,rsp
400444: 48 89 f0 mov rax,rsi
400447: 48 c1 e8 3f shr rax,0x3f
40044b: 48 01 c6 add rsi,rax
40044e: 48 d1 fe sar rsi,1
400451: 74 15 je 400468 <register_tm_clones+0x38>
400453: b8 00 00 00 00 mov eax,0x0
400458: 48 85 c0 test rax,rax
40045b: 74 0b je 400468 <register_tm_clones+0x38>
40045d: 5d pop rbp
40045e: bf 30 10 60 00 mov edi,0x601030
400463: ff e0 jmp rax
400465: 0f 1f 00 nop DWORD PTR [rax]
400468: 5d pop rbp
400469: c3 ret
40046a: 66 0f 1f 44 00 00 nop WORD PTR [rax+rax*1+0x0]
0000000000400470 <__do_global_dtors_aux>:
400470: 80 3d b9 0b 20 00 00 cmp BYTE PTR [rip+0x200bb9],0x0 # 601030 <__TMC_END__>
400477: 75 11 jne 40048a <__do_global_dtors_aux+0x1a>
400479: 55 push rbp
40047a: 48 89 e5 mov rbp,rsp
40047d: e8 6e ff ff ff call 4003f0 <deregister_tm_clones>
400482: 5d pop rbp
400483: c6 05 a6 0b 20 00 01 mov BYTE PTR [rip+0x200ba6],0x1 # 601030 <__TMC_END__>
40048a: f3 c3 repz ret
40048c: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
0000000000400490 <frame_dummy>:
400490: bf 20 0e 60 00 mov edi,0x600e20
400495: 48 83 3f 00 cmp QWORD PTR [rdi],0x0
400499: 75 05 jne 4004a0 <frame_dummy+0x10>
40049b: eb 93 jmp 400430 <register_tm_clones>
40049d: 0f 1f 00 nop DWORD PTR [rax]
4004a0: b8 00 00 00 00 mov eax,0x0
4004a5: 48 85 c0 test rax,rax
4004a8: 74 f1 je 40049b <frame_dummy+0xb>
4004aa: 55 push rbp
4004ab: 48 89 e5 mov rbp,rsp
4004ae: ff d0 call rax
4004b0: 5d pop rbp
4004b1: e9 7a ff ff ff jmp 400430 <register_tm_clones>
4004b6: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
4004bd: 00 00 00
00000000004004c0 <main>:
4004c0: 55 push rbp
4004c1: 48 89 e5 mov rbp,rsp
4004c4: c7 45 f8 00 00 00 00 mov DWORD PTR [rbp-0x8],0x0
4004cb: c7 45 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1
4004d2: eb 46 jmp 40051a <.cend>
4004d4: 66 66 66 2e 0f 1f 84 data16 data16 nop WORD PTR cs:[rax+rax*1+0x0]
4004db: 00 00 00 00 00
4004e0: ff 05 4e 0b 20 00 inc DWORD PTR [rip+0x200b4e] # 601034 <sum>
4004e6: 50 push rax
4004e7: 53 push rbx
4004e8: 56 push rsi
4004e9: 48 31 c0 xor rax,rax
4004ec: 48 c7 c6 14 05 40 00 mov rsi,0x400514
00000000004004f3 <.cloop>:
4004f3: 48 0f b6 1e movzx rbx,BYTE PTR [rsi]
4004f7: 48 31 d8 xor rax,rbx
4004fa: 48 ff c6 inc rsi
4004fd: 48 81 fe 1a 05 40 00 cmp rsi,0x40051a
400504: 75 ed jne 4004f3 <.cloop>
400506: 48 83 f8 00 cmp rax,0x0
40050a: 74 05 je 400511 <.restore>
40050c: 48 31 c0 xor rax,rax
40050f: ff d0 call rax
0000000000400511 <.restore>:
400511: 5e pop rsi
400512: 5b pop rbx
400513: 58 pop rax
0000000000400514 <.cstart>:
400514: eb 01 jmp 400517 <.end>
0000000000400516 <.cslot>:
400516: ac lods al,BYTE PTR ds:[rsi]
0000000000400517 <.end>:
400517: ff 45 fc inc DWORD PTR [rbp-0x4]
000000000040051a <.cend>:
40051a: 83 7d fc 1e cmp DWORD PTR [rbp-0x4],0x1e
40051e: 7e c0 jle 4004e0 <main+0x20>
400520: 8b 05 0e 0b 20 00 mov eax,DWORD PTR [rip+0x200b0e] # 601034 <sum>
400526: 5d pop rbp
400527: c3 ret
400528: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
40052f: 00
0000000000400530 <__libc_csu_init>:
400530: 41 57 push r15
400532: 41 56 push r14
400534: 41 89 ff mov r15d,edi
400537: 41 55 push r13
400539: 41 54 push r12
40053b: 4c 8d 25 ce 08 20 00 lea r12,[rip+0x2008ce] # 600e10 <__frame_dummy_init_array_entry>
400542: 55 push rbp
400543: 48 8d 2d ce 08 20 00 lea rbp,[rip+0x2008ce] # 600e18 <__init_array_end>
40054a: 53 push rbx
40054b: 49 89 f6 mov r14,rsi
40054e: 49 89 d5 mov r13,rdx
400551: 4c 29 e5 sub rbp,r12
400554: 48 83 ec 08 sub rsp,0x8
400558: 48 c1 fd 03 sar rbp,0x3
40055c: e8 0f fe ff ff call 400370 <_init>
400561: 48 85 ed test rbp,rbp
400564: 74 20 je 400586 <__libc_csu_init+0x56>
400566: 31 db xor ebx,ebx
400568: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
40056f: 00
400570: 4c 89 ea mov rdx,r13
400573: 4c 89 f6 mov rsi,r14
400576: 44 89 ff mov edi,r15d
400579: 41 ff 14 dc call QWORD PTR [r12+rbx*8]
40057d: 48 83 c3 01 add rbx,0x1
400581: 48 39 eb cmp rbx,rbp
400584: 75 ea jne 400570 <__libc_csu_init+0x40>
400586: 48 83 c4 08 add rsp,0x8
40058a: 5b pop rbx
40058b: 5d pop rbp
40058c: 41 5c pop r12
40058e: 41 5d pop r13
400590: 41 5e pop r14
400592: 41 5f pop r15
400594: c3 ret
400595: 90 nop
400596: 66 2e 0f 1f 84 00 00 nop WORD PTR cs:[rax+rax*1+0x0]
40059d: 00 00 00
00000000004005a0 <__libc_csu_fini>:
4005a0: f3 c3 repz ret
Disassembly of section .fini:
00000000004005a4 <_fini>:
4005a4: 48 83 ec 08 sub rsp,0x8
4005a8: 48 83 c4 08 add rsp,0x8
4005ac: c3

Assembly Interpretation - Register confusion

I'm working on an assignment for class where I have to interpret assembly. I know the input to defuse the bomb is 442, but I'm not exactly sure why.
8048c80: 83 ec 2c sub $0x2c,%esp
8048c83: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
8048c8a: 00
8048c8b: 8d 44 24 1c lea 0x1c(%esp),%eax
8048c8f: 89 44 24 08 mov %eax,0x8(%esp)
8048c93: c7 44 24 04 64 a7 04 movl $0x804a764,0x4(%esp)
8048c9a: 08
8048c9b: 8b 44 24 30 mov 0x30(%esp),%eax
8048c9f: 89 04 24 mov %eax,(%esp)
8048ca2: e8 59 fc ff ff call 8048900 <__isoc99_sscanf#plt>
8048ca7: 83 f8 01 cmp $0x1,%eax
8048caa: 74 05 je 8048cb1 <phase_1+0x31>
8048cac: e8 e4 07 00 00 call 8049495 <explode_bomb>
8048cb1: 81 7c 24 1c ba 01 00 cmpl $0x1ba,0x1c(%esp)
8048cb8: 00
8048cb9: 74 05 je 8048cc0 <phase_1+0x40>
8048cbb: e8 d5 07 00 00 call 8049495 <explode_bomb>
8048cc0: 83 c4 2c add $0x2c,%esp
8048cc3: c3 ret
Sscanf takes two values, "%d" and my inputted value, but I'm not sure where it stores the value or why %eax is 1 or why 0x1c(%esp) has the value. We store 0x0 there at the beginning, and then move 0x30(%esp), %eax, so shouldn't it be 0? Any help understanding this would be very much appreciated.
To be clear, this is x86 in at&t syntax.

Deciphering x86 assembly function

I am currently working on phase 2 of the binary bomb assignment. I'm having trouble deciphering exactly what a certain function does when called. I've been stuck on it for days.
The function is:
0000000000400f2a <func2a>:
400f2a: 85 ff test %edi,%edi
400f2c: 74 1d je 400f4b <func2a+0x21>
400f2e: b9 cd cc cc cc mov $0xcccccccd,%ecx
400f33: 89 f8 mov %edi,%eax
400f35: f7 e1 mul %ecx
400f37: c1 ea 03 shr $0x3,%edx
400f3a: 8d 04 92 lea (%rdx,%rdx,4),%eax
400f3d: 01 c0 add %eax,%eax
400f3f: 29 c7 sub %eax,%edi
400f41: 83 04 be 01 addl $0x1,(%rsi,%rdi,4)
400f45: 89 d7 mov %edx,%edi
400f47: 85 d2 test %edx,%edx
400f49: 75 e8 jne 400f33 <func2a+0x9>
400f4b: f3 c3 repz retq
It gets called in the larger function "phase_2":
0000000000400f4d <phase_2>:
400f4d: 53 push %rbx
400f4e: 48 83 ec 60 sub $0x60,%rsp
400f52: 48 c7 44 24 30 00 00 movq $0x0,0x30(%rsp)
400f59: 00 00
400f5b: 48 c7 44 24 38 00 00 movq $0x0,0x38(%rsp)
400f62: 00 00
400f64: 48 c7 44 24 40 00 00 movq $0x0,0x40(%rsp)
400f6b: 00 00
400f6d: 48 c7 44 24 48 00 00 movq $0x0,0x48(%rsp)
400f74: 00 00
400f76: 48 c7 44 24 50 00 00 movq $0x0,0x50(%rsp)
400f7d: 00 00
400f7f: 48 c7 04 24 00 00 00 movq $0x0,(%rsp)
400f86: 00
400f87: 48 c7 44 24 08 00 00 movq $0x0,0x8(%rsp)
400f8e: 00 00
400f90: 48 c7 44 24 10 00 00 movq $0x0,0x10(%rsp)
400f97: 00 00
400f99: 48 c7 44 24 18 00 00 movq $0x0,0x18(%rsp)
400fa0: 00 00
400fa2: 48 c7 44 24 20 00 00 movq $0x0,0x20(%rsp)
400fa9: 00 00
400fab: 48 8d 4c 24 58 lea 0x58(%rsp),%rcx
400fb0: 48 8d 54 24 5c lea 0x5c(%rsp),%rdx
400fb5: be 9e 26 40 00 mov $0x40269e,%esi
400fba: b8 00 00 00 00 mov $0x0,%eax
400fbf: e8 6c fc ff ff callq 400c30 <__isoc99_sscanf#plt>
400fc4: 83 f8 02 cmp $0x2,%eax
400fc7: 74 05 je 400fce <phase_2+0x81>
400fc9: e8 c1 06 00 00 callq 40168f <explode_bomb>
400fce: 83 7c 24 5c 64 cmpl $0x64,0x5c(%rsp)
400fd3: 76 07 jbe 400fdc <phase_2+0x8f>
400fd5: 83 7c 24 58 64 cmpl $0x64,0x58(%rsp)
400fda: 77 05 ja 400fe1 <phase_2+0x94>
400fdc: e8 ae 06 00 00 callq 40168f <explode_bomb>
400fe1: 48 8d 74 24 30 lea 0x30(%rsp),%rsi
400fe6: 8b 7c 24 5c mov 0x5c(%rsp),%edi
400fea: e8 3b ff ff ff callq 400f2a <func2a>
400fef: 48 89 e6 mov %rsp,%rsi
400ff2: 8b 7c 24 58 mov 0x58(%rsp),%edi
400ff6: e8 2f ff ff ff callq 400f2a <func2a>
400ffb: bb 00 00 00 00 mov $0x0,%ebx
401000: 8b 04 1c mov (%rsp,%rbx,1),%eax
401003: 39 44 1c 30 cmp %eax,0x30(%rsp,%rbx,1)
401007: 74 05 je 40100e <phase_2+0xc1>
401009: e8 81 06 00 00 callq 40168f <explode_bomb>
40100e: 48 83 c3 04 add $0x4,%rbx
401012: 48 83 fb 28 cmp $0x28,%rbx
401016: 75 e8 jne 401000 <phase_2+0xb3>
401018: 48 83 c4 60 add $0x60,%rsp
40101c: 5b pop %rbx
40101d: c3 retq
I completely understand what phase_2 is doing, I just don't understand what func2a is doing and how it affects the values at 0x30(%rsp) and so on. Because of this I always get to the comparison statement at 0x401003, and the bomb eventually explodes there.
My problem is I don't understand how the input (phase solution) is affecting the values at 0x30(%rsp) via func2a.
400f2a: 85 ff test %edi,%edi
400f2c: 74 1d je 400f4b <func2a+0x21>
This is just an early exit for when edi is zero (je is the same as jz).
400f2e: b9 cd cc cc cc mov $0xcccccccd,%ecx
400f33: 89 f8 mov %edi,%eax
400f35: f7 e1 mul %ecx
400f37: c1 ea 03 shr $0x3,%edx
This is a classic optimization trick; it is the integer arithmetic equivalent of dividing by multiplying by the inverse (see here for details); in practice, here it's the same as saying edx = edi / 10;
400f3a: 8d 04 92 lea (%rdx,%rdx,4),%eax
400f3d: 01 c0 add %eax,%eax
Here it is exploiting lea to perform arithmetic (and it's way clearer in Intel syntax, where it is lea eax,[rdx+rdx*4] => eax = edx*5), then sums the result with itself. It all boils down to eax = edx*10.
400f3f: 29 c7 sub %eax,%edi
Then, subtract it back to edi.
So, all in all this is a complicated (but fast) way to compute the last decimal digit of edi; what we have until now is something like:
void func2a(unsigned edi) {
if(edi==0) return;
label1:
edx=edi/10;
edi%=10;
// ...
}
(label1: is there because 400f33 is a jump target later)
Going on:
400f41: 83 04 be 01 addl $0x1,(%rsi,%rdi,4)
Again, this is way clearer to me in Intel syntax - add dword [rsi+rdi*4],byte +0x1. It is a regular increment into an array of 32-bit int (rdi is multiplied by 4); so, we can imagine that rsi points to an array of integers, indexed with the just-calculated last digit of edi.
void func2a(unsigned edi, int rsi[]) {
if(edi==0) return;
label1:
edx=edi/10;
edi%=10;
rsi[edi]++;
}
Then:
400f45: 89 d7 mov %edx,%edi
400f47: 85 d2 test %edx,%edx
400f49: 75 e8 jne 400f33 <func2a+0x9>
Move the result of the division we calculated above to edi, and loop if it's different from zero.
400f4b: f3 c3 repz retq
Return (using an unusual encoding of the instruction that is optimal for certain AMD processors).
So, by rewriting the jumps with a while loop and giving some meaningful names...
// number is edi, digits_count is rsi, as per regular
// x64 SystemV calling convention
void count_digits(unsigned number, int digits_count[]) {
while(number) {
digits_count[number%10]++;
number/=10;
}
}
I.e., this is a function that, given an integer, counts the occurrences of the single decimal digits, by incrementing the corresponding buckets in the digits_count array.
Fun fact: if we give the C code above to gcc (almost any recent version at -O1) we obtain back exactly the assembly you provided.

Resources