phase_1
We can see the memory with x/s
x/s 0x402400
So the first phase we input is:
Border relations with Canada have never been better.
phase_2
Read_six_numbers function description
In the phase_2, we will input 6 numbers first. The first number will be stored in rdx , second will be stored in rcx,third will be stored r8, the fourth will be stored in r9 ,the fifth will be stored in rsp, the sixth will be stored in rsp+0x8. When the program run to 0x40148f, it will compare the eax with 5, which means whether we have inputed the 6 numbers, if not it will jump to explode_bomb.
phase_2 function description
First of all, the program will check the first number whether is 1 which means the first number we input must be 1 or it will trigger the explode_bomb. After the comparsion, we get into the loop, the process of checking the right number.
The loop asm code description:
add rbx,0x4 # the cur will be the next
cmp rbx,rbp # determine the end of the loop
mov eax, DWORD PTR [rbx-0x4] # the before value moves to eax
add eax, eax # double eax
cmp DWORD PTR [rbx],eax # the next number must be twice previous number
So the answer is
1 2 4 8 16 32
phase_3
When we get into the phase_3, the code of swich function in asm which make me stuck for a while.
The first number must be lower than 7, or it will trigger the explode_bomb. The second number is variable because of the switch statement. The second number will be stored in rsp+0xc, when the program run to 0x400fc2, the eax will compare with your second input.
My answer is:
1 313
phase_4
func_4 description
edx = a
esi = b
eax = a, eax = a - b
ecx = a - b
ecx = ecx >> 31
eax = ecx + eax = (a-b) >> 31 + (a-b)
eax = ((a-b)>>31+(a-b))>>1
We don’t have to know the func_4 code meaning. The argument we can’t control, it always sets as 0xe automatically. Obviously, the function is recursive function. When ecx is bigger than edi, the function will return.
phase_4 descirption
Obviously, the first number will be stored in rsp+0x8, the second one will be stored in rsp+0xc.
If we the first number bigger than 0xe, it will jump to explode_bomb. So we have to choose the one which lower than 0xe.
Whatever the first number we input, it will be changed to 0xe finally and get into the func4 with 0xe
phase_5
To the better understanding, I divided the phase_5 into three parts.
First part, the length of string must be equal to six.
The second part, also is the most difficult and important.
mov rdx, QWORD PTR [rsp] # move the first character of the string to rsp from rdx
and edx,0xf
# get the lower 4 digits.
# For example 1100 1111 -> 1111, 1001 1101 -> 1101
# 1100 1111 & 0000 1111 -> 1111
movzx edx, BYTE PTR[rdx + 0x4024b0]
# 0x4024b0 is the array address, maduiersnfotvbyl
# we should take the index to get the character of string.
# for example
# 1111 -> 15+0x4024b0 -> l
# 1001 -> 9+0x4024b0 -> f
mov BYTE PTR [rsp+rax*1+0x10], dl # store the modified character in new address of stack
add rax, 0x1 # move the cur
cmp rax, 0x6 # the end of the loop
After we get the new string in rsp+0x10, we have to be equal to the value in 0x40245e which means the new stirng have to be equal to “flyers”
gdb-peda$ x/s 0x40245e
0x40245e: "flyers"
The enumerate available character python script as follows:
flyers
f = 9 = 1001 , l = 15 = 1111, y = 14 = 1110 , e = 5 = 0100, r = 6 = 0101, s = 7 = 0110
# CSAPP Bomb Lab Phase5
# Enumerate available characters
# Author: Kelpie
# Date: 2023-2-27
char_list = [9,15,14,5,6,7]
cur1 = []
cur2 = []
cur3 = []
cur4 = []
cur5 = []
cur6 = []
# what is upper?
# 1 << 4 = 0001 0000
# 2 << 4 = 0010 0000
for i in range(1,8):
upper = i << 4
for j in char_list:
char = upper | j
str = chr(char)
# The python switch statement is not available until 3.10 :-(
if j == 9 :
cur1.append(str)
elif j == 15 :
cur2.append(str)
elif j == 14 :
cur3.append(str)
elif j == 5 :
cur4.append(str)
elif j == 6 :
cur5.append(str)
elif j == 7 :
cur6.append(str)
print("cur1: " , cur1)
print("cur2: " , cur2)
print("cur3: " , cur3)
print("cur4: " , cur4)
print("cur5: " , cur5)
print("cur6: " , cur6)
cur1: [')', '9', 'I', 'Y', 'i', 'y']
cur2: ['/', '?', 'O', '_', 'o']
cur3: ['.', '>', 'N', '^', 'n', '~']
cur4: ['%', '5', 'E', 'U', 'e', 'u']
cur5: ['&', '6', 'F', 'V', 'f', 'v']
cur6: ["'", '7', 'G', 'W', 'g', 'w']
phase_6
The most challenging phase is undoubtedly at the end. But when you finish this part, when you review it. I will find this phase is not so difficult.
I sorted out the idea of doing the problem and write the comment in the asm code.
For the better understanding, I divided asm code into 6 part, each part is the different function in this phase.
The most puzzling part is Part 4. When you get what is ecx, 0x6032d0 meaning and know this part is the double loop, you will get clearer understanding.
0x00000000004010f4 <+0>: push r14
0x00000000004010f6 <+2>: push r13
0x00000000004010f8 <+4>: push r12
0x00000000004010fa <+6>: push rbp
0x00000000004010fb <+7>: push rbx
0x00000000004010fc <+8>: sub rsp,0x50
0x0000000000401100 <+12>: mov r13,rsp
0x0000000000401103 <+15>: mov rsi,rsp
0x0000000000401106 <+18>: call 0x40145c <read_six_numbers>
0x000000000040110b <+23>: mov r14,rsp
0x000000000040110e <+26>: mov r12d,0x0
0x0000000000401114 <+32>: mov rbp,r13
0x0000000000401117 <+35>: mov eax,DWORD PTR [r13+0x0]
0x000000000040111b <+39>: sub eax,0x1
0x000000000040111e <+42>: cmp eax,0x5
0x0000000000401121 <+45>: jbe 0x401128 <phase_6+52>
0x0000000000401123 <+47>: call 0x40143a <explode_bomb>
# if the numbers of input is enough to 6, it will trigger the explode_bomb
------------ ------------ ---------- part 1 ---------- ------------ ------------
0x0000000000401128 <+52>: add r12d,0x1
0x000000000040112c <+56>: cmp r12d,0x6
0x0000000000401130 <+60>: je 0x401153 <phase_6+95>
0x0000000000401132 <+62>: mov ebx,r12d
0x0000000000401135 <+65>: movsxd rax,ebx
0x0000000000401138 <+68>: mov eax,DWORD PTR [rsp+rax*4]
# We input the number will be stored in RSP
# rsp+rax*4
0x000000000040113b <+71>: cmp DWORD PTR [rbp+0x0],eax
0x000000000040113e <+74>: jne 0x401145 <phase_6+81>
0x0000000000401140 <+76>: call 0x40143a <explode_bomb>
# check if exist the same number in we input or trigger the bomb
------------ ------------ ---------- part 2 ---------- ------------ ------------
0x0000000000401145 <+81>: add ebx,0x1
0x0000000000401148 <+84>: cmp ebx,0x5
0x000000000040114b <+87>: jle 0x401135 <phase_6+65>
0x000000000040114d <+89>: add r13,0x4
0x0000000000401151 <+93>: jmp 0x401114 <phase_6+32>
0x0000000000401153 <+95>: lea rsi,[rsp+0x18]
-----------
0x0000000000401158 <+100>: mov rax,r14
0x000000000040115b <+103>: mov ecx,0x7
0x0000000000401160 <+108>: mov edx,ecx
0x0000000000401162 <+110>: sub edx,DWORD PTR [rax]
0x0000000000401164 <+112>: mov DWORD PTR [rax],edx
0x0000000000401166 <+114>: add rax,0x4
0x000000000040116a <+118>: cmp rax,rsi
0x000000000040116d <+121>: jne 0x401160 <phase_6+108>
# each number will be sub by 7
------------ ------------ ---------- part 3 ---------- ------------ ------------
----------------------------------------------------------------------------------------
# double loop in this section
# This section get the index from rsp+rsi*1 and stored the node[index] to rsp+rsi*2+0x20
----------------------------------------------------------------------------------------
0x000000000040116f <+123>: mov esi,0x0
0x000000000040116f <+123>: mov esi,0x0
0x0000000000401174 <+128>: jmp 0x401197 <phase_6+163>
0x0000000000401176 <+130>: mov rdx,QWORD PTR [rdx+0x8] # rdx = node.next
0x000000000040117a <+134>: add eax,0x1
0x000000000040117d <+137>: cmp eax,ecx
0x000000000040117f <+139>: jne 0x401176 <phase_6+130>
0x0000000000401181 <+141>: jmp 0x401188 <phase_6+148>
0x0000000000401183 <+143>: mov edx,0x6032d0
0x0000000000401188 <+148>: mov QWORD PTR [rsp+rsi*2+0x20],rdx
0x000000000040118d <+153>: add rsi,0x4
0x0000000000401191 <+157>: cmp rsi,0x18
0x0000000000401195 <+161>: je 0x4011ab <phase_6+183>
0x0000000000401197 <+163>: mov ecx,DWORD PTR [rsp+rsi*1]
0x000000000040119a <+166>: cmp ecx,0x1
0x000000000040119d <+169>: jle 0x401183 <phase_6+143>
0x000000000040119f <+171>: mov eax,0x1
0x00000000004011a4 <+176>: mov edx,0x6032d0
0x00000000004011a9 <+181>: jmp 0x401176 <phase_6+130>
------------ ------------ ---------- part 4 ---------- ------------ ------------
0x00000000004011ab <+183>: mov rbx,QWORD PTR [rsp+0x20]
0x00000000004011b0 <+188>: lea rax,[rsp+0x28]
0x00000000004011b5 <+193>: lea rsi,[rsp+0x50]
0x00000000004011ba <+198>: mov rcx,rbx
0x00000000004011bd <+201>: mov rdx,QWORD PTR [rax]
0x00000000004011c0 <+204>: mov QWORD PTR [rcx+0x8],rdx
0x00000000004011c4 <+208>: add rax,0x8
0x00000000004011c8 <+212>: cmp rax,rsi
0x00000000004011cb <+215>: je 0x4011d2 <phase_6+222>
0x00000000004011cd <+217>: mov rcx,rdx
0x00000000004011d0 <+220>: jmp 0x4011bd <phase_6+201>
# connect the node
------------ ------------ ---------- part 5 ---------- ------------ ------------
0x00000000004011d2 <+222>: mov QWORD PTR [rdx+0x8],0x0
0x00000000004011da <+230>: mov ebp,0x5
0x00000000004011df <+235>: mov rax,QWORD PTR [rbx+0x8]
0x00000000004011e3 <+239>: mov eax,DWORD PTR [rax]
0x00000000004011e5 <+241>: cmp DWORD PTR [rbx],eax
# compare the node value
0x00000000004011e7 <+243>: jge 0x4011ee <phase_6+250>
0x00000000004011e9 <+245>: call 0x40143a <explode_bomb>
0x00000000004011ee <+250>: mov rbx,QWORD PTR [rbx+0x8]
0x00000000004011f2 <+254>: sub ebp,0x1
0x00000000004011f5 <+257>: jne 0x4011df <phase_6+235>
0x00000000004011f7 <+259>: add rsp,0x50
0x00000000004011fb <+263>: pop rbx
0x00000000004011fc <+264>: pop rbp
0x00000000004011fd <+265>: pop r12
0x00000000004011ff <+267>: pop r13
0x0000000000401201 <+269>: pop r14
0x0000000000401203 <+271>: ret
------------ ------------ ---------- part 6 ---------- ------------ ------------
The all modified input by Part 3 will be stored in $rsp.
The 0x6032d0 is the node.
struct node{
int nodeVal; // 4 bytes
int Weinput; // 4 bytes
node* next; // 8 bytes
}
sizeof(node) = 16 bytes
The answer is:
4 3 2 1 6 5
All phases had been finished :-)