This level gets a little rough. We?ve decided to use r2 for good, so patching is not an option.
Previous posts:
CMU Bomb Lab with Radare2 ? Phase 1
Hello world. In the interests of putting more Radare2 content out there, here?s a noob friendly intro to r2, for those?
medium.com
CMU Bomb Lab with Radare2 ? Phase 2
Reverse Engineering with r2
medium.com
CMU Bomb Lab with Radare2 ? Phase 3
Welcome back! This series would get boring if all we did was patch instructions, so let?s try actually doing this?
medium.com
CMU Bomb Lab with Radare2 ? Phase 4
Phase 4 is my least favourite phase, but it?s not so bad when your goal is cheating.
medium.com
CMU Bomb Lab with Radare2 ? Phase 5
I lied about cheating through everything in this challenge. We will 100% do Phase 5 properly since it focuses on basic?
medium.com
Load the binary, perform analysis, seek to Phase 6, and have a look at your task.
Pull up the function in Graph mode with VV, press p to cycle between views, and select the minigraph. Now you can see there are a few loops.
Let?s start with when it calls sym.read_six_numbers
0x00401100 4989e5 mov r13, rsp0x00401103 4889e6 mov rsi, rsp0x00401106 e851030000 call sym.read_six_numbers0x0040110b 4989e6 mov r14, rsp0x0040110e 41bc00000000 mov r12d, 0
rsp is copied into both r13 and rsi. rsi doesn?t get used again until later, but r13 is used for comparison in the loop.
0x00401106 e851030000 call sym.read_six_numbers0x0040110b 4989e6 mov r14, rsp 0x0040110e 41bc00000000 mov r12d, 0
The result of sym.read_six_numbers goes into rsp, which is then copied into r14. rsp, then r12d is set to zero. Since this happens just before a loop, this means r12d is might a loop counter.
Skip to the end of the loop, and notice that it adds 4 to r13 every time the loop runs. This suggests r13 is being used to cycle through the numbers.
Knowing this, let?s start the loop itself
0x00401114 4c89ed mov rbp, r13 0x00401117 418b4500 mov eax, dword [r13]0x0040111b 83e801 sub eax, 10x0040111e 83f805 cmp eax, 50×00401121 7605 jbe 0x4011280x00401123 e812030000 call sym.explode_bomb:
As the loop increments, each number is compared to 6 (well, technically 5 since 1 is first subtracted from 6), and if that number is greater than 6, boom.
0x00401128 4183c401 add r12d, 10x0040112c 4183fc06 cmp r12d, 6 0x00401130 7421 je 0x401153
Next we check if we?ve read the last digit. If not, continue the loop.
0x00401132 4489e3 mov ebx, r12d 0x00401135 4863c3 movsxd rax, ebx 0x00401138 8b0484 mov eax, dword [rsp + rax*4]0x0040113b 394500 cmp dword [rbp], eax0x0040113e 7505 jne 0x4011450x00401140 e8f5020000 call sym.explode_bomb;[2] 0x00401145 83c301 add ebx, 1 0x00401148 83fb05 cmp ebx, 5 0x0040114b 7ee8 jle 0x401135
Following the flow, the next section compare each digit from our input against the next. If any number appears more than once, boom.
As pseudocode, it looks something like this:
input = stdinfor digit in input:for i in range(0, 6): if (input[i] < 1) || (input[i] > 6): fail() for j in range(i , 6): if (input[i] == input[j]: fail()
First loop done. Onto the next.
0x00401153 488d742418 lea rsi, [var_18h] 0x00401158 4c89f0 mov rax, r14 0x0040115b b907000000 mov ecx, 7 .-> 0x00401160 89ca mov edx, ecx : 0x00401162 2b10 sub edx, dword [rax]: 0x00401164 8910 mov dword [rax], edx: 0x00401166 4883c004 add rax, 4 : 0x0040116a 4839f0 cmp rax, rsi `=< 0x0040116d 75f1 jne 0x401160
rax is set to the first digit from our input, and as the loop progresses, each digit is subtracted from 7, transforming the input. Something like this:
input = stdinfor i in range(0,6): input[i] = 7 – input[i]Loops like this area easy to spot in Graph mode
Try using the cursor to follow conditional statements to help wrap your head around code. In Visual mode move the cursor to a conditional statement, press ENTER and it will always jump.
You can also add comments in Visual/Graph mode with the semi colon ; command.
Linked Lists
As you?ve probably noticed, there?s a obj.node in the disasssembly. Whenever I see something interesting, I try printing the hexdump. Type px @ obj.node, then TAB completion to reveal node1?6.
You can also use pxa ? (P)rint he(X) (D)ump (A)nnotated ? to label the information.
At each offset, you can see the numbers 1?6 at at +0x4. At +0x8 you can see another address, which is a pointer to the offset of the next item in the list. This is a classic linked list, and in C looks something like:
struct node { int value; int index; struct node *next};
We will use r2?s pf ? (P)rint (F)ormatted data ? to define and print these structures. The syntax is:
pf.[name of new object] [assign data types] [assign data names]
To get a list of all data types for pf, check the help by running pf??.We will use i for ints, and *? for the pointer to the next item.
pf.node ii*? value index (node)next
Shoutout to Unlogic for his awesome writeup that covered this.
Now print the node with:
pf.node @ obj.node1
r2 will not only print out the node, it will get the address from next, then print that node too, until it finally reaches a null.
Neat! Now what?
Let?s add 1 2 3 4 5 6 to our answers.txt, load r2 in Debug mode, seek to sym.phase_6 and set a breakpoint after the second loop which transformed our input. Place another breakpoint after mov qword [rdx + 8], 0 , which is terminates the linked list by placing a NULL in the next address offset.
Continue to the first breakpoint. Verify the transform has been applied by printing the stack with px 32 @ rsp. You can also see this information in Visual mode?s debug view
As long as you?ve been paying attention, the final loop is a piece of cake.
0x004011da bd05000000 mov ebp, 5.-> 0x004011df 488b4308 mov rax, qword [rbx + 8] : 0x004011e3 8b00 mov eax, dword [rax] : 0x004011e5 3903 cmp dword [rbx], eax,==< 0x004011e7 7d05 jge 0x4011ee|: 0x004011e9 e84c020000 call sym.explode_bomb`–> 0x004011ee 488b5b08 mov rbx, qword [rbx + 8] : 0x004011f2 83ed01 sub ebp, 1 `=< 0x004011f5 75e8 jne 0x4011df
The loop counter is ebp, counting down from 5 and ending the loop when it hits 0. rbx is a pointer to the current node.
.-> 0x004011df 488b4308 mov rax, qword [rbx + 8] : 0x004011e3 8b00 mov eax, dword [rax]
By setting rax to be the pointer to rbx+8, we?re creating pointer to the next item in the linked list. This allows us to compare each item to the next.
: 0x004011e5 3903 cmp dword [rbx], eax,==< 0x004011e7 7d05 jge 0x4011ee|: 0x004011e9 e84c020000 call sym.explode_bomb`–> 0x004011ee 488b5b08 mov rbx, qword [rbx + 8] : 0x004011f2 83ed01 sub ebp, 1 `=< 0x004011f5 75e8 jne 0x4011df
This checks to make sure the current node?s value is greater than the next one?s. If not, boom. Since we control the order of the indexes with our stdin, we need to put the nodes in descending order to beat this level, based on their value, not index.
Once again, here is our linked list.
:> pf.node @ obj.node6 value : 0x00603320 = 443 index : 0x00603324 = 6 next : (*0x603310) struct<node> value : 0x00603310 = 477 index : 0x00603314 = 5 next : (*0x603300) struct<node> value : 0x00603300 = 691 index : 0x00603304 = 4 next : (*0x6032f0) struct<node> value : 0x006032f0 = 924 index : 0x006032f4 = 3 next : (*0x6032e0) struct<node> value : 0x006032e0 = 168 index : 0x006032e4 = 2 next : (*0x6032d0) struct<node> value : 0x006032d0 = 332 index : 0x006032d4 = 1 next : (*0x0) NULL
If we want these in descending order based on value, we need:
3 4 5 6 1 2
Fail. Did you forget about the transform? You need to take each number and subtract it from 7. I wrote it out in pseudo code earlier, but I would hope you can do this in your head. I believe in you!
New commands:
pxa # Hex dump with annotationspf.[struct name] # Define a formatpf?? # View format optionspf @ [struct.name] # Use a format template to print
Well that was a bit more intense. I guess despite our best efforts, we?ve gotten sucked into a few of these challenges.
One more to go, and it?s a doozy.
Next: CMU Binary Bomb with Radare2 ? Secret Phase
Links
Linked Lists ? Computerphile