CSAPP_BombLab實驗報告


Lab_2實驗報告

屏幕截圖

考察內容

本次lab主要考察的是對各種匯編指令的熟悉程度和對gdb的掌握程度。

各題答案

bomb1

Border relations with Canada have never been better.

該答案唯一。

bomb2

1 2 4 8 16 32

該答案唯一。

bomb3

6 682

該答案不唯一。

答案表:

x y
0 207(0xcf)
1 311(0x137)
2 707(0x2c3)
3 256(0x100)
4 389(0x185)
5 206(0xce)
6 682(0x2aa)
7 327(0x147)

bomb4

0 0

該答案不唯一。

答案表:

x y
0 0
1 0
3 0
7 0

bomb5

9/.567

該答案不唯一。

答案規律:

一個長度為6的字符串,其中從左到右每個字符的十六進制形式下ASCII碼的末位依次為:9、e、f、5、6、7。

bomb6

4 3 2 1 6 5

該答案唯一。

secret_phase

22

該答案唯一性不確定。

解題思路

bomb1

核心代碼部分只有一個:

  400ee4:	be 00 24 40 00       	mov    $0x402400,%esi
  400ee9:	e8 4a 04 00 00       	callq  401338 <strings_not_equal>
  400eee:	85 c0                	test   %eax,%eax
  400ef0:	74 05                	je     400ef7 <phase_1+0x17>
  400ef2:	e8 43 05 00 00       	callq  40143a <explode_bomb>
  400ef7:	48 83 c4 08          	add    $0x8,%rsp

查看函數<strings_not_equal>,發現其功能是比較以%rdi和%rsi為首地址的兩個字符串是否相等,如果相等返回0,不相等返回1。

因此結合bomb1中的情景可以發現,調用<explode_bomb>的條件是輸入的字符串和以%rsi為首地址的字符串不相等。通過gdb得知以%rsi為首地址的字符串為"Border relations with Canada have never been better.",得出答案。

bomb2

核心代碼以及翻譯:

  400f0a:	83 3c 24 01          	cmpl   $0x1,(%rsp)
  400f0e:	74 20                	je     400f30 <phase_2+0x34>
  400f10:	e8 25 05 00 00       	callq  40143a <explode_bomb>
  400f15:	eb 19                	jmp    400f30 <phase_2+0x34>
  400f17:	8b 43 fc             	mov    -0x4(%rbx),%eax
  400f1a:	01 c0                	add    %eax,%eax
  400f1c:	39 03                	cmp    %eax,(%rbx)
  400f1e:	74 05                	je     400f25 <phase_2+0x29>
  400f20:	e8 15 05 00 00       	callq  40143a <explode_bomb>
  400f25:	48 83 c3 04          	add    $0x4,%rbx
  400f29:	48 39 eb             	cmp    %rbp,%rbx
  400f2c:	75 e9                	jne    400f17 <phase_2+0x1b>
  400f2e:	eb 0c                	jmp    400f3c <phase_2+0x40>
  400f30:	48 8d 5c 24 04       	lea    0x4(%rsp),%rbx
  400f35:	48 8d 6c 24 18       	lea    0x18(%rsp),%rbp
  400f3a:	eb db                	jmp    400f17 <phase_2+0x1b>
if(*rsp!=1)explode_bomb;
rbx=rsp+4;
rbp=rsp+24;
do
  eax=rbx-4;
  eax*=2;
  if(eax!=(*rbx))explode_bomb;
  rbx+=4;
while(rbp!=rbx);

phase_2在調用<read_six_numbers>,讀入六個數存放在rsp至rsp+24后,判斷第一個數是否為1,如果不是則調用<explode_bomb>。然后循環遍歷六個數,%eax為%rbx的前驅。如果%rbx不為%eax的兩倍,則調用<explode_bomb>。因此可以得出答案為長度為6,首項為1,公比為2的等比數列,即"1,2,4,8,16,32"。

bomb3

輸入部分

  400f51:	be cf 25 40 00       	mov    $0x4025cf,%esi
  400f56:	b8 00 00 00 00       	mov    $0x0,%eax
  400f5b:	e8 90 fc ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  400f60:	83 f8 01             	cmp    $0x1,%eax
  400f63:	7f 05                	jg     400f6a <phase_3+0x27>
  400f65:	e8 d0 04 00 00       	callq  40143a <explode_bomb>
  400f6a:	83 7c 24 08 07       	cmpl   $0x7,0x8(%rsp)
  400f6f:	77 3c                	ja     400fad <phase_3+0x6a>

通過gdb查看首地址為0x4025cf的字符串,結果為"%d %d",結合下文的__isoc99_sscanf@plt可知,要求輸入的數字個數為2,進一步通過0x400f63~0x400f65“判斷輸入個數是否大於1”也能得出相同的結論。最后,0x400f63~0x400f6f語句表示第一個輸入的數字為小於7的非負數。

分支部分

  400f71:	8b 44 24 08          	mov    0x8(%rsp),%eax
  400f75:	ff 24 c5 70 24 40 00 	jmpq   *0x402470(,%rax,8)
  400f7c:	b8 cf 00 00 00       	mov    $0xcf,%eax
  400f81:	eb 3b                	jmp    400fbe <phase_3+0x7b>
  ...
  400fad:	e8 88 04 00 00       	callq  40143a <explode_bomb>
  400fb2:	b8 00 00 00 00       	mov    $0x0,%eax
  400fb7:	eb 05                	jmp    400fbe <phase_3+0x7b>
  400fb9:	b8 37 01 00 00       	mov    $0x137,%eax
  400fbe:	3b 44 24 0c          	cmp    0xc(%rsp),%eax
  400fc2:	74 05                	je     400fc9 <phase_3+0x86>
  400fc4:	e8 71 04 00 00       	callq  40143a <explode_bomb>

該部分代碼較長,未完全展示。

通過觀察發現,該部分中有大量內容為"jmp 400fbe <phase_3+0x7b>"的語句,判斷應該是分支結構,對應到源代碼應該是一個switch語句。實現條件跳轉的關鍵在於0x400f75語句:“jmpq *0x402470(,%rax,8)”。這條語句的意思是跳轉到以0x402470+8*%rax指向的數為地址的語句處。通過gdb可得出上述答案表。

bomb4

遞歸部分

遞歸部分就是整個 函數。其實質是一個遞歸的二分查找。

確定中點
  400fd2:	89 d0                	mov    %edx,%eax
  400fd4:	29 f0                	sub    %esi,%eax
  400fd6:	89 c1                	mov    %eax,%ecx
  400fd8:	c1 e9 1f             	shr    $0x1f,%ecx
  400fdb:	01 c8                	add    %ecx,%eax
  400fdd:	d1 f8                	sar    %eax
  400fdf:	8d 0c 30             	lea    (%rax,%rsi,1),%ecx

在該部分中,%esi為閉區間左端點,%edx為閉區間右端點。語句0x400fd2~0x400fdb的本質即是%eax=%edx-%esi,隨后通過%ecx=%rsi+(%eax>>1)這條語句可以得知,%ecx為區間中點。

比較大小&縮小區間
  400fe2:	39 f9                	cmp    %edi,%ecx
  400fe4:	7e 0c                	jle    400ff2 <func4+0x24>
  400fe6:	8d 51 ff             	lea    -0x1(%rcx),%edx
  400fe9:	e8 e0 ff ff ff       	callq  400fce <func4>
  400fee:	01 c0                	add    %eax,%eax
  400ff0:	eb 15                	jmp    401007 <func4+0x39>
  400ff2:	b8 00 00 00 00       	mov    $0x0,%eax
  400ff7:	39 f9                	cmp    %edi,%ecx
  400ff9:	7d 0c                	jge    401007 <func4+0x39>
  400ffb:	8d 71 01             	lea    0x1(%rcx),%esi
  400ffe:	e8 cb ff ff ff       	callq  400fce <func4>
  401003:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax

%edi為要查找的數。比較%edi和%ecx的大小,如果%ecx>%edi,表示%edi落在左半區間。因此將右端點%edx修改為%rcx-1,向下一層遞歸,回溯時將%eax修改為2*%eax。否則,表示%edi落在右半區間,此時判斷%edi和%ecx是否相等,如果相等則直接退出該遞歸部分。如果不相等則將左端點%esi修改為%rcx+1,向下一層遞歸,回溯時將%eax修改為2*%eax+1

輸入&判斷部分

這部分主要在<phase_4>里。主要內容就是判斷是否讀入了兩個以上的數字,以及規定了第一個數字不能大於14,第二個數字必須為0。最關鍵的部分在於判斷調用 后%eax是否為0。由於%edi落在左半區間和右半區間遞歸時回溯的條件不同,結合%eax初值為0可以得出以下結論:%edi在任何遞歸層數下都不能大於%ecx,即落在區間的右半部分(不包括中點)。根據%rsi和%rdx初值為0和14,可以得出上述答案表。

bomb5

phase_5的本質是以輸入字符串的從左到右每個字符的ASCII碼的十六進制末位為索引,查表得到新字符串后與目標字符串匹配。

索引部分

  40108b:	0f b6 0c 03          	movzbl (%rbx,%rax,1),%ecx
  40108f:	88 0c 24             	mov    %cl,(%rsp)
  401092:	48 8b 14 24          	mov    (%rsp),%rdx
  401096:	83 e2 0f             	and    $0xf,%edx
  401099:	0f b6 92 b0 24 40 00 	movzbl 0x4024b0(%rdx),%edx
  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>

翻譯代碼:

do
  ecx=rax+rbx; //movzbl
  *rsp=cl;
  rdx=*rsp;
  edx&=0xf;
  edx=*(rdx+4024b0); //movzbl
  *(rsp+rax+4*4)=dl;
  rax++;
while(rax!=6);

該部分就是遍歷所有字符,%rbx是讀入字符串的首地址,%edx用來存放字符的ASCII碼的十六進制末位,隨后將%edx索引至%rdx+0x4024b0處,並存放在%rsp+%rax+16處。

通過gdb調試得知以0x4024b0為首地址的字符串為:"maduiersnfotvbylSo you think you can stop the bomb with ctrl-c, do you?",其中有效項(前16個)為"maduiersnfotvbyl"。

檢驗部分

檢驗部分就是判斷新字符串是否等於目標字符串,即以0x40245e為首地址的字符串。通過gdb調試得知目標字符串為"flyers",其中每個字符分別在表的第9、14、15、5、6、7位。因此倒推出輸入字符串的ASCII碼的十六進制末位也應該是9,e,f,5,6,7。

bomb6

PS:(這個phase真的是太太太太長了……里面jmp指令也是非常的多,不用紙打印出來真的沒辦法看啊QAQ)

phase_6的本質就是將輸入的排列取反后以此為基准重新排列一個序列,使其成降序。

判斷是否為排列

  401128:	41 83 c4 01          	add    $0x1,%r12d
  40112c:	41 83 fc 06          	cmp    $0x6,%r12d
  401130:	74 21                	je     401153 <phase_6+0x5f>
  401132:	44 89 e3             	mov    %r12d,%ebx
  401135:	48 63 c3             	movslq %ebx,%rax
  401138:	8b 04 84             	mov    (%rsp,%rax,4),%eax
  40113b:	39 45 00             	cmp    %eax,0x0(%rbp)
  40113e:	75 05                	jne    401145 <phase_6+0x51>
  401140:	e8 f5 02 00 00       	callq  40143a <explode_bomb>
  401145:	83 c3 01             	add    $0x1,%ebx
  401148:	83 fb 05             	cmp    $0x5,%ebx
  40114b:	7e e8                	jle    401135 <phase_6+0x41>

翻譯代碼:

do	
	r12d++;
    ebx=r12d;
    do
      rax=ebx; //movslq
      eax=rsp+4*rax;
      if(eax==*rbp)explode_bomb;
      ebx++;
    while(ebx<=5);
while(r12d!=6);

讀入6個數字后,首先規定每個數不大於6,否則調用<explode_bomb>,然后通過上述雙重循環規定元素兩兩不等。這樣就能夠保證讀入的6個數字為6的一個排列。

取反部分

  401153:	48 8d 74 24 18       	lea    0x18(%rsp),%rsi
  401158:	4c 89 f0             	mov    %r14,%rax
  40115b:	b9 07 00 00 00       	mov    $0x7,%ecx
  401160:	89 ca                	mov    %ecx,%edx
  401162:	2b 10                	sub    (%rax),%edx
  401164:	89 10                	mov    %edx,(%rax)
  401166:	48 83 c0 04          	add    $0x4,%rax
  40116a:	48 39 f0             	cmp    %rsi,%rax
  40116d:	75 f1                	jne    401160 <phase_6+0x6c>

翻譯代碼:

rsi=*(rsp+4*6);
rax=r14;
do
  ecx=7;
  edx=ecx;
  edx-=*rax;
  *rax=edx; //*rax=7-*rax
  rax+=4;
while(rax!=rsi);

該部分利用一個循環,將元素x轉變為7-x。

索引部分

PS:(這部分的條件跳轉指令特別多……所以這部分我是在紙上完成的,沒辦法貼出翻譯代碼了)

該部分以每個元素值x為索引,索引至0x6032d0+16*x處,將該值賦給%rsp+8*x+32。用gdb調試后發現,0x6032d0+16*x指向的值分別為332,168,924,691,477,443。

檢驗部分

  4011da:	bd 05 00 00 00       	mov    $0x5,%ebp
  4011df:	48 8b 43 08          	mov    0x8(%rbx),%rax
  4011e3:	8b 00                	mov    (%rax),%eax
  4011e5:	39 03                	cmp    %eax,(%rbx)
  4011e7:	7d 05                	jge    4011ee <phase_6+0xfa>
  4011e9:	e8 4c 02 00 00       	callq  40143a <explode_bomb>
  4011ee:	48 8b 5b 08          	mov    0x8(%rbx),%rbx
  4011f2:	83 ed 01             	sub    $0x1,%ebp
  4011f5:	75 e8                	jne    4011df <phase_6+0xeb>

翻譯代碼:

ebp=5;
do
	rax=*(rbx+8);
	eax=*rax;
	if(*rbx<eax)explode_bomb;
	rbx=*(rbx+8);
while(--ebp!=0);

該部分利用一個循環,判斷序列是否為降序,如果不是則調用<explode_bomb>。對照原表可知,符合條件的索引排列為3,4,5,6,1,2。考慮到這是經過取反后的排列,因此答案排列應為4,3,2,1,6,5。

secret_phase

入口部分

容易發現<secret_phase>在<bomb_defuse>處被調用。一路檢索過去可以發現,觸發<secret_phase>的條件在於讀入的字符串是否等於"DrEvil"。可是在哪里輸入該字符串呢?調用gdb調試,查看0x402619處字符串,發現等於"%d %d %s",則可以判斷應在之前輸入兩個數字的phase時在末尾輸入一個"DrEvil"觸發<secret_phase>。

fun7

該函數是一個遞歸調用的函數。%rdi初始值為0x6030f0,%esi初始值為%ebx,也就是讀入的整數。

整個函數的意思是將(%rdi)與%esi比較,如果(%rdi)>%esi,%rdi=0x8(%rdi),即%rdi被更新為%rdi+8指向的值,遞歸進入下一層,回溯時將%eax更新為原來的兩倍。

如果(%rdi)==%esi,返回%eax=0。

如果(%rdi)<=%esi,%rdi被更新為%rdi+16指向的值,回溯時將%eax更新為2*%eax+1。

返回<secret_phase>查看<explode_bomb>被調用的條件,發現是%eax!=2。那么反推回去,可以發現如果想要%eax=2,在進入fun7時,需要先使(%rdi)>%esi,再使(%rdi<%esi),最后使(%rdi==%esi)。這樣在回溯時,初值為0的%eax先變為2*0+1=1,再變成2*1=2。

調用gdb查看0x6030f0后的若干字節:

0x6030f0 <n1>:	0x0000000000000024	0x0000000000603110
0x603100 <n1+16>:	0x0000000000603130	0x0000000000000000
0x603110 <n21>:	0x0000000000000008	0x0000000000603190
0x603120 <n21+16>:	0x0000000000603150	0x0000000000000000
0x603130 <n22>:	0x0000000000000032	0x0000000000603170
0x603140 <n22+16>:	0x00000000006031b0	0x0000000000000000
0x603150 <n32>:	0x0000000000000016	0x0000000000603270

發現0x8(%rdi)=(0x603110)=8,0x18(%rdi)=(0x603150)=0x16=22。

將22作為%esi,反推回去,發現第一層0x24>0x16,第二層0x8<0x16,滿足條件。因此22為答案。

Reference

  1. CSAPP


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM