前言
CSAPP对我个人的影响很大所以想自己写一份相关lab的答案,以供交流讨论。
概念辨析
lea dest [from] //把from的地址赋给dest
mov dest from //把from的值赋给dest
mov dest [from] //把from指向的地址的值赋给dest
jz //jump if zero(zero 指 zero flag 所以jz可以理解为相等时跳转)
ds //数据开始的段地址
phase_1 answer: Border relations with Canada have never been better.
public phase_1
phase_1 proc near
; __unwind {
sub rsp, 8
mov esi, offset aBorderRelation ; "Border relations with Canada have never"...
call strings_not_equal
test eax, eax
jz short loc_400EF7
call explode_bomb
栈指针减8,开辟空间,esi为第二个接收函数第二个参数,调用strings_not_equal,推测第一个存储在rdi的参数为string 。当相同的时候跳转到 loc_400EF7 。否则就引爆炸弹。
loc_400EF7:
add rsp, 8
retn
; } // starts at 400EE0
phase_1 endp
栈指针加8恢复之前的状态函数结束。
查看 内存中字符串的值:Border relations with Canada have never been better.
输入即可
phase_2 answer: 1 2 4 8 16 32
public phase_2
phase_2 proc near
var_38= dword ptr -38h
var_34= byte ptr -34h
var_20= byte ptr -20h
; __unwind {
push rbp
push rbx
sub rsp, 28h
mov rsi, rsp
call read_six_numbers
cmp [rsp+38h+var_38], 1
jz short loc_400F30
栈指针减 40,开辟空间,将rsp中值放到rsi中。调用函数read_six_numbers,比较[rsp+38h+var_38] ( a[0] )的值和1,如果相等就跳转到loc_400F30,否则引爆炸弹。
loc_400F30:
lea rbx, [rsp+38h+var_34]
lea rbp, [rsp+38h+var_20]
jmp short loc_400F17
将[rsp+38h+var_34] (a[1])中的地址放入rbx ,[rsp+38h+var_20] (尾部)中的地址放入rbp。跳转到loc_400F17。
loc_400F17:
mov eax, [rbx-4]
add eax, eax
cmp [rbx], eax
jz short loc_400F25
将[rbx-4] (a[0])地址的值放到eax中 ,将eax的值加倍,后比较a[1]和2*a[0]的值如果相等跳转到loc_400F25,不相等就引爆炸弹。
loc_400F25:
add rbx, 4
cmp rbx, rbp
jnz short loc_400F17
把rbx(a[1])中的地址值加4得到a[2],比较rbx与rbp的值如果不相等就跳回loc_400F17(do while 循环 每次比较 2*a[i]==a[i+1]),所以最终输入的数字应该为1,2,4,8,16,32。
read_six_numbers
public read_six_numbers
read_six_numbers proc near
var_18= qword ptr -18h
var_10= qword ptr -10h
; __unwind {
sub rsp, 18h
mov rdx, rsi
lea rcx, [sri+4]
lea rax, [rsi+14h]
mov [rsp+18h+var_10], rax
lea rax, [rsi+10h]
mov [rsp+18h+var_18], rax
lea r9, [rsi+0Ch]
lea r8, [rsi+8]
mov esi, offset unk_4025C3
mov eax, 0
call ___isoc99_sscanf
cmp eax, 5
jg short loc_401499
栈指针减24,又由函数名,推测为6个int。 分别存放在 (值:)rsi(rsi中为rsp中的值即为函数调用前栈底的地址),(地址:)[rsi+4],[rsi+8],[rsi+0Ch],[rsi+10h] ,[rsi+14h],又将上述内容(或地址)移动到rdx,rcx,r8,r9,rax,[rsp+18h+var_18],[rsp+18h+var_10],offset unk_4025C3 中内容为 %d %d %d %d %d %d,保存在rsi中,后调用___isoc99_sscanf函数(查看函数原型)之后比较eax中的值(读入int的个数)和5,如果大于就跳转到 short loc_401499,小于等于就引爆炸弹。为了下面叙述方便直接记各个寄存器的值分别为a[0],a[1],a[2],a[3],a[4],a[5]。
call explode_bomb
loc_401499:
add rsp, 18h
retn
; } // starts at 40145C
read_six_numbers endp
结束读入。
phase_3 answer:(输入一组即可) 0 207 或 1 311 或 2 707 或 3 256 或 4 389 或 5 206 或 6 682 或 7 327
public phase_3
phase_3 proc near
var_10= dword ptr -10h
var_C= dword ptr -0Ch
; __unwind {
sub rsp, 18h
lea rcx, [rsp+18h+var_C]
lea rdx, [rsp+18h+var_10]
mov esi, offset aDD ; "%d %d"
mov eax, 0
call ___isoc99_sscanf
cmp eax, 1
jg short loc_400F6A
栈指针减24,开辟空间,将[rsp+18h+var_C]的地址赋给rcx,将[rsp+18h+var_10]的地址赋给rdx,将offset 中值赋给 esi,和前面相同是调用___isoc99_sscanf读入整数,查看内存可以看到"%d %d"读入两个,如果eax的值大于1就跳转(即输入两个整数),否则引爆炸弹。为了叙述方便记 [rsp+18h+var_10]地址处存放的值为first,[rsp+18h+var_C]为second。
loc_400F6A: ; switch 8 cases
cmp [rsp+18h+var_10], 7
ja short def_400F75 ; jumptable 0000000000400F75 default case
如果first大于7就引爆炸弹,所以first<=7。
mov eax, [rsp+18h+var_10]
jmp ds:jpt_400F75[rax*8] ; switch jump
将second的值放到eax跳转到jpt_400F75对应的地址加8*first(switch语句)下面列出各种情况:
loc_400F7C: ; jumptable 0000000000400F75 case 0
mov eax, 0CFh
jmp short loc_400FBE
loc_400FB9: ; jumptable 0000000000400F75 case 1
mov eax, 137h
loc_400F83: ; jumptable 0000000000400F75 case 2
mov eax, 2C3h
jmp short loc_400FBE
loc_400F8A: ; jumptable 0000000000400F75 case 3
mov eax, 100h
jmp short loc_400FBE
loc_400F91: ; jumptable 0000000000400F75 case 4
mov eax, 185h
jmp short loc_400FBE
loc_400F98: ; jumptable 0000000000400F75 case 5
mov eax, 0CEh
jmp short loc_400FBE
loc_400F9F: ; jumptable 0000000000400F75 case 6
mov eax, 2AAh
jmp short loc_400FBE
loc_400FA6: ; jumptable 0000000000400F75 case 7
mov eax, 147h
jmp short loc_400FBE
mov eax, 0
jmp short loc_400FBE
loc_400FBE:
cmp eax, [rsp+18h+var_C]
jz short loc_400FC9
跳转到loc_400FBE比较eax和second,如果相等就跳转到loc_400FC9,否则引爆炸弹。
loc_400FC9:
add rsp, 18h
retn
; } // starts at 400F43
phase_3 endp
函数结束。