主頁 >  其他 > 深入理解計算機系統bomb實驗

深入理解計算機系統bomb實驗

2021-04-12 12:18:55 其他

深入理解計算機系統Bomb實驗

  • 前言
  • 準備階段
    • 上傳bomb.c檔案
    • 生成匯編代碼
    • 進入gdb除錯模式
    • 獲取主要函式的匯編代碼
  • 實驗階段
    • Phase1
      • 實驗探究
      • 輸入字串首地址的保存
      • 繼續phase1的研究
      • 通關密鑰
    • Phase2
      • 實驗探究
      • 通關密鑰
    • Phase3
      • 實驗探究
      • sscanf陳述句
      • swith-case陳述句
      • 通關密鑰
    • Phase4
      • 實驗探究
      • 通關密鑰
    • Phase5
      • 實驗探究
      • 通關密鑰
    • Phase6
      • 實驗探究
      • 通關密鑰
    • 秘密關卡
      • 實驗探究
        • 找到隱藏關卡入口
        • secret_phase探究
  • 小結

前言

最近我在學計算機系統時,做到了一個蠻有趣的實驗游戲——bomb實驗(其實就是一個c程式),這個實驗有六關,每一關需要輸入一個字串(可以稱之為密鑰),每一關只有輸入正確的密鑰才能通過,否則“炸彈“將會爆炸,因此,我們需要通過匯編c代碼找出匯編檔案中藏有的密鑰的資訊,通過這個實驗,我的匯編語言能力獲得了極好的鍛煉,因此紀錄程序以供大家分享并作為紀念,

準備階段

上傳bomb.c檔案

首先,據實驗的要求,我們需要一臺linux機器進行gdb除錯,我們可以使用linux虛擬機或者租一臺linux云主機,在這里我使用的是騰訊云的云主機,在這臺主機上,我新建一個檔案夾,并將實驗所需要的bomb.c檔案進行上傳,
使用工具:xftp
復制bomb.c檔案

生成匯編代碼

在上傳完成后,我們打開已連接上服務器的xshell或者虛擬機的teminal應用,使用cd命令進入到剛才上傳到的檔案夾中,之后,我們使用objdump -d bomb > bomb_assembly.S命令生成一個名為bomb_assembly.S的匯編代碼檔案
生成匯編代碼

進入gdb除錯模式

使用gdb bomb命令進入bomb.c檔案的除錯模式
進入gdb除錯

獲取主要函式的匯編代碼

首先,我們打開已經生成好的匯編語言檔案(可以在linux的檔案管理器中打開或者通過xftp打開),找到main函式,將其復制下來,單獨保存至一個檔案中,方便查看,

0000000000400da0 <main>:
  # ...省略了以上的部分匯編代碼
  400e32:	e8 67 06 00 00       	callq  40149e <read_line>
  400e37:	48 89 c7             	mov    %rax,%rdi
  400e3a:	e8 a1 00 00 00       	callq  400ee0 <phase_1>
  400e3f:	e8 80 07 00 00       	callq  4015c4 <phase_defused>
  400e44:	bf a8 23 40 00       	mov    $0x4023a8,%edi
  400e49:	e8 c2 fc ff ff       	callq  400b10 <puts@plt>
  400e4e:	e8 4b 06 00 00       	callq  40149e <read_line>
  400e53:	48 89 c7             	mov    %rax,%rdi
  400e56:	e8 a1 00 00 00       	callq  400efc <phase_2>
  400e5b:	e8 64 07 00 00       	callq  4015c4 <phase_defused>
    400e60:	bf ed 22 40 00       	mov    $0x4022ed,%edi
  400e65:	e8 a6 fc ff ff       	callq  400b10 <puts@plt>
  400e6a:	e8 2f 06 00 00       	callq  40149e <read_line>
  400e6f:	48 89 c7             	mov    %rax,%rdi
  400e72:	e8 cc 00 00 00       	callq  400f43 <phase_3>
  400e77:	e8 48 07 00 00       	callq  4015c4 <phase_defused>
  400e7c:	bf 0b 23 40 00       	mov    $0x40230b,%edi
  400e81:	e8 8a fc ff ff       	callq  400b10 <puts@plt>
  400e86:	e8 13 06 00 00       	callq  40149e <read_line>
  400e8b:	48 89 c7             	mov    %rax,%rdi
  400e8e:	e8 79 01 00 00       	callq  40100c <phase_4>
  400e93:	e8 2c 07 00 00       	callq  4015c4 <phase_defused>
  400e98:	bf d8 23 40 00       	mov    $0x4023d8,%edi
  400e9d:	e8 6e fc ff ff       	callq  400b10 <puts@plt>
  400ea2:	e8 f7 05 00 00       	callq  40149e <read_line>
  400ea7:	48 89 c7             	mov    %rax,%rdi
  400eaa:	e8 b3 01 00 00       	callq  401062 <phase_5>
  400eaf:	e8 10 07 00 00       	callq  4015c4 <phase_defused>
  400eb4:	bf 1a 23 40 00       	mov    $0x40231a,%edi
  400eb9:	e8 52 fc ff ff       	callq  400b10 <puts@plt>
  400ebe:	e8 db 05 00 00       	callq  40149e <read_line>
  400ec3:	48 89 c7             	mov    %rax,%rdi
  400ec6:	e8 29 02 00 00       	callq  4010f4 <phase_6>
  400ecb:	e8 f4 06 00 00       	callq  4015c4 <phase_defused>
  400ed0:	b8 00 00 00 00       	mov    $0x0,%eax
  400ed5:	5b                   	pop    %rbx
  400ed6:	c3                   	retq   
  400ed7:	90                   	nop
  400ed8:	90                   	nop
  400ed9:	90                   	nop
  400eda:	90                   	nop
  400edb:	90                   	nop
  400edc:	90                   	nop
  400edd:	90                   	nop
  400ede:	90                   	nop
  400edf:	90                   	nop
  # ...省略了以下phase3-phase6的匯編代碼

我們發現,phase1-phase6函式似乎就恰好對應題目中給出的第一關到第六關,于是,在gdb中,我們可以快速地使用disas命令進入這些函式的匯編代碼中一探究竟,

  400e3a:	e8 a1 00 00 00       	callq  400ee0 <phase_1>  #找到函式名前的函式開始指令的地址
  400e3f:	e8 80 07 00 00       	callq  4015c4 <phase_defused>

進入gdb模式,使用disas 0x400ee0進入phase1的匯編代碼,
disas 命令
重復上述步驟,依次快速復制phase1到phase6的代碼,將代碼分別復制到不同檔案中,

實驗階段

Phase1

實驗探究

打開復制下來的phase1的代碼檔案
關于每一步的解釋以# 的注釋標在代碼后

   0x0000000000400ee0 <+0>:	sub    $0x8,%rsp  # 在堆疊中開辟一個8位元組的臨時空間
   0x0000000000400ee4 <+4>:	mov    $0x402400,%esi  # 將0x402400的值作為<string not equal>的引數傳入
   0x0000000000400ee9 <+9>:	callq  0x401338 <strings_not_equal>
   0x0000000000400eee <+14>:	test   %eax,%eax   # 測驗該函式回傳值
   0x0000000000400ef0 <+16>:	je     0x400ef7 <phase_1+23>   # 若回傳值為0則跳過炸彈爆炸函式
   0x0000000000400ef2 <+18>:	callq  0x40143a <explode_bomb>  # 回傳值為1,炸
   0x0000000000400ef7 <+23>:	add    $0x8,%rsp  # 恢復堆疊
   0x0000000000400efb <+27>:	retq  

由字面意義可知,<string_no_equal>函式起到了一個比較字串是否相等的作用,于是,猜測該函式具有兩個引數——一個是我們輸入的字串的首地址,另一個是待比較的字串的首地址

輸入字串首地址的保存

回傳main函式保存的檔案中,查看呼叫phase1函式之前的幾句代碼,發現確實如此,引數暫存器%rdi被<read_line>函式的回傳值賦值,因此,猜測<read_line>函式用于讀取一行字串,將回傳值保存于%rax,而被賦值的%rdi中存盤的就是輸入的字串的首地址

  400e32:	e8 67 06 00 00       	callq  40149e <read_line>
  400e37:	48 89 c7             	mov    %rax,%rdi
  400e3a:	e8 a1 00 00 00       	callq  400ee0 <phase_1>

再觀察其他的phase函式呼叫前的陳述句,我們都可以發現類似情況,因此,我們認為這些%rdi暫存器在phase函式的一開始,起到的是存盤輸入字串首地址的作用

  400e4e:	e8 4b 06 00 00       	callq  40149e <read_line>
  400e53:	48 89 c7             	mov    %rax,%rdi
  400e56:	e8 a1 00 00 00       	callq  400efc <phase_2>

繼續phase1的研究

于是,我們可以繼續猜想,在呼叫<string_no_equal>函式之前的%esi暫存器中是否也存盤了一個待比較的字串首地址,

  0x0000000000400ee4 <+4>:	mov    $0x402400,%esi  # 將0x402400的值作為<string not equal>的引數傳入

使用,x/s命令將0x402400中存盤的字串匯出,答案如我們所愿,
x/s 0x402400
因此,phase1函式的作用只是單純的讓我們輸入一個字串,再將我們輸入的字串和存盤的字串進行比較而已,

通關密鑰

密鑰即為“Border relations with Canada have never been better.”,輸入即可通關,

使用run命令執行bomb.c程式,再輸入第一關密鑰
run

Phase2

實驗探究

打開phase2匯編代碼被保存的檔案

   0x0000000000400efc <+0>:	push   %rbp
   0x0000000000400efd <+1>:	push   %rbx
   0x0000000000400efe <+2>:	sub    $0x28,%rsp  # 產生一塊40位元組大小的臨時空間
   0x0000000000400f02 <+6>:	mov    %rsp,%rsi  # 將堆疊指標賦值給引數暫存器
   0x0000000000400f05 <+9>:	callq  0x40145c <read_six_numbers>
   0x0000000000400f0a <+14>:	cmpl   $0x1,(%rsp)  # 比較1和堆疊頂元素的大小
   0x0000000000400f0e <+18>:	je     0x400f30 <phase_2+52>  
   0x0000000000400f10 <+20>:	callq  0x40143a <explode_bomb>  # 若不相等則炸
   0x0000000000400f15 <+25>:	jmp    0x400f30 <phase_2+52>
   0x0000000000400f17 <+27>:	mov    -0x4(%rbx),%eax  # 將堆疊中的上一個元素值賦值
   0x0000000000400f1a <+30>:	add    %eax,%eax  # 堆疊中的上一個元素值*2后保存
   0x0000000000400f1c <+32>:	cmp    %eax,(%rbx)  # 將上一個元素值的2倍與%rbx對應的值(現元素值)進行比較
   0x0000000000400f1e <+34>:	je     0x400f25 <phase_2+41>
   0x0000000000400f20 <+36>:	callq  0x40143a <explode_bomb>
   0x0000000000400f25 <+41>:	add    $0x4,%rbx   # 將%rbx的+=4
   0x0000000000400f29 <+45>:	cmp    %rbp,%rbx  # 比較是否等于尾指標
   0x0000000000400f2c <+48>:	jne    0x400f17 <phase_2+27>
   0x0000000000400f2e <+50>:	jmp    0x400f3c <phase_2+64>
   0x0000000000400f30 <+52>:	lea    0x4(%rsp),%rbx  # 將堆疊指標加4的賦值
   0x0000000000400f35 <+57>:	lea    0x18(%rsp),%rbp  # 將堆疊的尾指標賦值
   0x0000000000400f3a <+62>:	jmp    0x400f17 <phase_2+27>
   0x0000000000400f3c <+64>:	add    $0x28,%rsp
   0x0000000000400f40 <+68>:	pop    %rbx
   0x0000000000400f41 <+69>:	pop    %rbp
   0x0000000000400f42 <+70>:	retq 

首先函式將堆疊指標傳入引數暫存器,考慮到緊挨的read_six_number函式,猜測堆疊指標作為引數用于保存數字,而另一引數%rdi(上文提到)給出輸入字串地址,因此,函式read_six_number函式用于將輸入的字串轉換為6個數字, 得知,本輪需要輸入6個數字作為密鑰,

接下來從<+14>陳述句中得知,第一個輸入的數字是1,


<+41>(偏移量++)
<+57>(尾指標的賦值)
<+45> (偏移量等于尾值)
判斷出,這函式當中存在一個回圈,回圈中%rbx依次保存堆疊中的所有元素的地址,而又由<+27>-<+32>陳述句中可知,堆疊中元素滿足這樣的排列:堆疊中每一元素是它上一元素的兩倍 ,即需輸入一個首項為1,公比為2,項數為6的等比數列,

通關密鑰

在這里插入圖片描述

Phase3

實驗探究

   0x0000000000400f43 <+0>:	sub    $0x18,%rsp  #堆疊指標減24用來存放3個臨時變數(看大小決定個數)
   0x0000000000400f47 <+4>:	lea    0xc(%rsp),%rcx  #%rcx=堆疊指標+12(引數)
   0x0000000000400f4c <+9>:	lea    0x8(%rsp),%rdx  #%rdx=堆疊指標+8(引數)
   0x0000000000400f51 <+14>:	mov    $0x4025cf,%esi  #某個引數的傳遞
   0x0000000000400f56 <+19>:	mov    $0x0,%eax  #對回傳值賦值0,為sscanf陳述句做準備
   0x0000000000400f5b <+24>:	callq  0x400bf0 <__isoc99_sscanf@plt>#按格式讀入輸入
   0x0000000000400f60 <+29>:	cmp    $0x1,%eax    #將回傳值與1進行比較
   0x0000000000400f63 <+32>:	jg     0x400f6a <phase_3+39>  #若回傳值大于1(說明scanf的引數大于1),jump39
   0x0000000000400f65 <+34>:	callq  0x40143a <explode_bomb>   #否則炸
   0x0000000000400f6a <+39>:	cmpl   $0x7,0x8(%rsp)  #比較第一個數字與7的大小
   0x0000000000400f6f <+44>:	ja     0x400fad <phase_3+106>  #若>7,跳轉106,炸;并且是無符號數的比較,
   0x0000000000400f71 <+46>:	mov    0x8(%rsp),%eax    #把第一個數字的值給%eax
   0x0000000000400f75 <+50>:	jmpq   *0x402470(,%rax,8)   #這是屬于跳轉表的形式,
   0x0000000000400f7c <+57>:	mov    $0xcf,%eax   #以下就是把某一個值放到%eax中在做<+123>的程序,就是switch-case陳述句
   0x0000000000400f81 <+62>:	jmp    0x400fbe <phase_3+123>  
   0x0000000000400f83 <+64>:	mov    $0x2c3,%eax
   0x0000000000400f88 <+69>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400f8a <+71>:	mov    $0x100,%eax  
   0x0000000000400f8f <+76>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400f91 <+78>:	mov    $0x185,%eax
   0x0000000000400f96 <+83>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400f98 <+85>:	mov    $0xce,%eax
   0x0000000000400f9d <+90>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400f9f <+92>:	mov    $0x2aa,%eax
   0x0000000000400fa4 <+97>:	jmp    0x400fbe <phase_3+123>
0x0000000000400fa6 <+99>:	mov    $0x147,%eax
   0x0000000000400fab <+104>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400fad <+106>:	callq  0x40143a <explode_bomb>
   0x0000000000400fb2 <+111>:	mov    $0x0,%eax
   0x0000000000400fb7 <+116>:	jmp    0x400fbe <phase_3+123>
   0x0000000000400fb9 <+118>:	mov    $0x137,%eax
   0x0000000000400fbe <+123>:	cmp    0xc(%rsp),%eax #都是在拿rsp+12的地址對應的值與eax進行比較
   0x0000000000400fc2 <+127>:	je     0x400fc9 <phase_3+134>  #若等就會結束,成功;不等,就會炸
   0x0000000000400fc4 <+129>:	callq  0x40143a <explode_bomb>
   0x0000000000400fc9 <+134>:	add    $0x18,%rsp
   0x0000000000400fcd <+138>:	retq

sscanf陳述句

在該匯編語言中,使用了sscanf格式化輸入,sscanf的陳述句同read_six_number函式類似,只是具有了更靈活的形式,引數有需要規定的輸入形式 ,本陳述句中以%esi引數暫存器傳入,通過該引數,函式可以將輸入的合法字串轉換為規定的數字或者字串,

使用x/s 命令查看,得知是“%d %d”,即需要輸入兩個整數,
%d %d

而另外兩個引數,分別是堆疊的+12地址,堆疊的+8地址,這兩個引數用作保存轉換的數字,回傳值是輸入成功的值的個數,這里是兩個%d,所以若正常按格式輸入兩個數字,回傳值應大于1,據<+32>得,若不大于1,則炸彈爆炸,

swith-case陳述句

接著是一個典型的swith-case陳述句,首先在<+44>中,將第一個數字與7進行無符號的小于比較,這是在規定輸入的第一個數字必須是0-6之間的第一個數(包含0,6),然后,是一個經典的跳轉表形式,
在這里插入圖片描述
通過<+46>陳述句,第一個數字成為了跳轉表的引數<+50>,<+57><+64>等陳述句,分別對應的輸入第一個數字為0-6情況的不同跳轉,

在跳轉后,將某個值(每個跳轉對應的值均不同)存入%eax暫存器中,接著統一跳轉至<+123>,0-6對應的不同的%eax的結果與第二個數字進行比較,若相等,方可通過,

第一個數字對應的case陳述句下取出的值
00xcf=207
10x137=311
20x2c3=707
30x100=256
40x185=389
50xce=206
60x2aa

通關密鑰

因此,本局關卡需要輸入兩個數字,第一個數字必須是0-6中的一個,而第二個數字通過swith-case陳述句對應0-6,需輸入不同數字,

通關實體 (以第一個數字0為例)
在這里插入圖片描述

Phase4

實驗探究

   0x000000000040100c <+0>:	sub    $0x18,%rsp     
   0x0000000000401010 <+4>:	lea    0xc(%rsp),%rcx  //要用的引數,放入引數暫存器中給scanf存
   0x0000000000401015 <+9>:	lea    0x8(%rsp),%rdx  //要用的引數
   0x000000000040101a <+14>:	mov    $0x4025cf,%esi    //這個也是“%d %d”
   0x000000000040101f <+19>:	mov    $0x0,%eax
   0x0000000000401024 <+24>:	callq  0x400bf0 <__isoc99_sscanf@plt>
   0x0000000000401029 <+29>:	cmp    $0x2,%eax  //不是正常的兩個引數就炸
   0x000000000040102c <+32>:	jne    0x401035 <phase_4+41> 
   0x000000000040102e <+34>:	cmpl   $0xe,0x8(%rsp)  //這個值和14
   0x0000000000401033 <+39>:	jbe    0x40103a <phase_4+46>  //低于或者相等
   0x0000000000401035 <+41>:	callq  0x40143a <explode_bomb>
   0x000000000040103a <+46>:	mov    $0xe,%edx
   0x000000000040103f <+51>:	mov    $0x0,%esi
   0x0000000000401044 <+56>:	mov    0x8(%rsp),%edi
   0x0000000000401048 <+60>:	callq  0x400fce <func4>
   0x000000000040104d <+65>:	test   %eax,%eax  //回傳0才是正確做法
   0x000000000040104f <+67>:	jne    0x401058 <phase_4+76>
   0x0000000000401051 <+69>:	cmpl   $0x0,0xc(%rsp)   //再比較第二個輸入值和0的關系
   0x0000000000401056 <+74>:	je     0x40105d <phase_4+81>  //需等于0,否則炸
   0x0000000000401058 <+76>:	callq  0x40143a <explode_bomb>
   0x000000000040105d <+81>:	add    $0x18,%rsp
   0x0000000000401061 <+85>:	retq   

該函式簡單明了,同Phase3,同樣使用了一個sscanf陳述句,同樣是"%d %d"格式輸入,因此,密鑰仍為兩個數字,其次,0x8(%rsp)作為第一個數字,應該滿足<+34>陳述句,即低于或者小于14,最后,func4的回傳值必須是0,而func4的引數在<+46>-<+56>中給出,

于是,我們通過disas 命令獲取func4的匯編代碼,(這里不再示例gdb的使用)

   0x0000000000400fce <+0>:	sub    $0x8,%rsp
   0x0000000000400fd2 <+4>:	mov    %edx,%eax   # result=14
   0x0000000000400fd4 <+6>:	sub    %esi,%eax # result-=0,不變
   0x0000000000400fd6 <+8>:	mov    %eax,%ecx  
   0x0000000000400fd8 <+10>:	shr    $0x1f,%ecx  # %ecx邏輯右移31位,補0,取最高位之意
   0x0000000000400fdb <+13>:	add    %ecx,%eax  # 拿自己的最高位加上result;(負數加1正數加0)14+0=0
   0x0000000000400fdd <+15>:	sar    %eax  # 算術右移,單運算元是只移動一位的意思  7
   0x0000000000400fdf <+17>:	lea    (%rax,%rsi,1),%ecx  # 7+0=%ecx
   0x0000000000400fe2 <+20>:	cmp    %edi,%ecx  # 比較第一個輸入值和%ecx的關系
   0x0000000000400fe4 <+22>:	jle    0x400ff2 <func4+36>
   0x0000000000400fe6 <+24>:	lea    -0x1(%rcx),%edx  
   0x0000000000400fe9 <+27>:	callq  0x400fce <func4>
   0x0000000000400fee <+32>:	add    %eax,%eax
   0x0000000000400ff0 <+34>:	jmp    0x401007 <func4+57>
   0x0000000000400ff2 <+36>:	mov    $0x0,%eax  # 給出0
   0x0000000000400ff7 <+41>:	cmp    %edi,%ecx  # 再比較一次
   0x0000000000400ff9 <+43>:	jge    0x401007 <func4+57> #  大于等于
   0x0000000000400ffb <+45>:	lea    0x1(%rcx),%esi
   0x0000000000400ffe <+48>:	callq  0x400fce <func4>
   0x0000000000401003 <+53>:	lea    0x1(%rax,%rax,1),%eax
   0x0000000000401007 <+57>:	add    $0x8,%rsp
   0x000000000040100b <+61>:	retq   

根據注釋,我們可以得出:當回傳值為0時,第一個數字需為7, 再回到函式phase4中來,我們看到有<+69>陳述句,該陳述句規定了第二個數字需為0這一輸入

通關密鑰

在這里插入圖片描述

Phase5

實驗探究

   0x0000000000401062 <+0>:	push   %rbx
   0x0000000000401063 <+1>:	sub    $0x20,%rsp  //開辟一個32位元組的空間
   0x0000000000401067 <+5>:	mov    %rdi,%rbx    //rdi是輸入字串陣列地址 
   0x000000000040106a <+8>:	mov    %fs:0x28,%rax  //  堆疊溢位保護
   0x0000000000401073 <+17>:	mov    %rax,0x18(%rsp)  //把回傳值存盤到堆疊臨時記憶體中
   0x0000000000401078 <+22>:	xor    %eax,%eax  //異或自己,置零
   0x000000000040107a <+24>:	callq  0x40131b <string_length>  
   0x000000000040107f <+29>:	cmp    $0x6,%eax  //字串長度與6比較
   0x0000000000401082 <+32>:	je     0x4010d2 <phase_5+112>  //等于的話跳轉,否則炸
   0x0000000000401084 <+34>:	callq  0x40143a <explode_bomb>
   0x0000000000401089 <+39>:	jmp    0x4010d2 <phase_5+112>
   0x000000000040108b <+41>:	movzbl (%rbx,%rax,1),%ecx  //將字符依次賦值
   0x000000000040108f <+45>:	mov    %cl,(%rsp)   //%rcx的最低位元組(依次的元素的值)給堆疊頂記憶體存盤
   0x0000000000401092 <+48>:	mov    (%rsp),%rdx  //將這個字符賦值給%rdx
   0x0000000000401096 <+52>:	and    $0xf,%edx   //使得%edx高位的值被0覆寫掉,只剩0-15
   0x0000000000401099 <+55>:	movzbl 0x4024b0(%rdx),%edx  // 將(0x4024b0+%rdx)對應記憶體的值給了%edx
   0x00000000004010a0 <+62>:	mov    %dl,0x10(%rsp,%rax,1)   //再將%edx的低位保存在堆疊中
   0x00000000004010a4 <+66>:	add    $0x1,%rax  
   0x00000000004010a8 <+70>:	cmp    $0x6,%rax
   0x00000000004010ac <+74>:	jne    0x40108b <phase_5+41>//似乎是一個回圈
   0x00000000004010ae <+76>:	movb   $0x0,0x16(%rsp)  //把0的值改寫到這個字串對應的結尾字串,所以最后有'\0'做結尾
   0x00000000004010b3 <+81>:	mov    $0x40245e,%esi  //這個是需要比較的字串地址
   0x00000000004010b8 <+86>:	lea    0x10(%rsp),%rdi  //這個是輸入字串地址
   0x00000000004010bd <+91>:	callq  0x401338 <strings_not_equal>  
   0x00000000004010c2 <+96>:	test   %eax,%eax  //是0就是兩字串相等
   0x00000000004010c4 <+98>:	je     0x4010d9 <phase_5+119>
   0x00000000004010c6 <+100>:	callq  0x40143a <explode_bomb>
   0x00000000004010cb <+105>:	nopl   0x0(%rax,%rax,1) //對齊作用
   0x00000000004010d0 <+110>:	jmp    0x4010d9 <phase_5+119>
   0x00000000004010d2 <+112>:	mov    $0x0,%eax  //回傳值后32位置0
   0x00000000004010d7 <+117>:	jmp    0x40108b <phase_5+41> 
   0x00000000004010d9 <+119>:	mov    0x18(%rsp),%rax
   0x00000000004010de <+124>:	xor    %fs:0x28,%rax  //看是否被改寫,否則出現大問題,這可不是炸的問題了
   0x00000000004010e7 <+133>:	je     0x4010ee <phase_5+140>
   0x00000000004010e9 <+135>:	callq  0x400b30 <__stack_chk_fail@plt>
   0x00000000004010ee <+140>:	add    $0x20,%rsp
   0x00000000004010f2 <+144>:	pop    %rbx
   0x00000000004010f3 <+145>:	retq   

首先,根據<+29>陳述句,<string_length>函式的回傳值,即輸入字串的長度必須等于6, 緊接著,跳轉至<+112>陳述句將%eax置0,然后才回傳<+41>陳述句繼續進行,<+41>陳述句將字符依次賦值給%ecx ,我們注意到,%rax在<+66>處++,并且在<+74>處跳轉回去形成一個回圈,而在這個回圈中%rax是每次都改變的,因此每一次回圈都使得%ecx獲得到的是下一個的新字符,因此,稱之為依次

之后通過一系列的操作:%ecx->堆疊頂->%rdx,將這個元素的值賦給%rdx,接著對%rdx使用0xf掩碼,使其只剩低4位有效,(注意,這使得后面可以免去輸入低位ASCLL碼的麻煩

我們接著看到<+55>陳述句,這是關鍵;這一陳述句將不同的%rbx值作為偏移量,對0x4024b0的地址進行偏移,從而獲得不同的字符放入%edx暫存器中,然后再將%edx暫存器中的值放如堆疊中保存,在回圈陳述句退出后(回圈執行6次,我們可以得知應輸入6個字符),將第7個字符設為/0標志字串的結尾,然后是一個簡單字串比較函式(看保存在堆疊中的字串與0x40245e作為首地址的字串是否相等——<+81>中給出引數),

所以,Phase5的接題關鍵是,輸入的字符作為偏移量,可以剛好使得0x4024b0作為首地址偏移所對應得新的字符與0x40245e對應得字符依次相等

因此,我們分別使用x/s 0x4024b0以及x/s 0x40245e命令查看兩個字串,
在這里插入圖片描述
在這里插入圖片描述
得到,偏移量應該為 9 15 14 5 6 7 ,才能依次對應“f l y e r s”,
由于前面使用了0xf作為掩碼,所以可以使用字串“9?>567”代替低ascll碼得輸入,

通關密鑰

在這里插入圖片描述

Phase6

實驗探究

Section1 準備作業

  0x00000000004010f4 <+0>:	push   %r14
   0x00000000004010f6 <+2>:	push   %r13
   0x00000000004010f8 <+4>:	push   %r12
   0x00000000004010fa <+6>:	push   %rbp
   0x00000000004010fb <+7>:	push   %rbx
   0x00000000004010fc <+8>:	sub    $0x50,%rsp   //開辟80位元組的臨時空間
   0x0000000000401100 <+12>:	mov    %rsp,%r13  //將堆疊指標保存到被呼叫者暫存器r13
   0x0000000000401103 <+15>:	mov    %rsp,%rsi   //將堆疊指標傳入引數,用于接受那6個數字
   0x0000000000401106 <+18>:	callq  0x40145c <read_six_numbers>
   0x000000000040110b <+23>:	mov    %rsp,%r14   //r14同樣用來保存堆疊指標
   0x000000000040110e <+26>:	mov    $0x0,%r12d  

由上述代碼可知,需要輸入6個數字作為密鑰,

Section2


   0x0000000000401114 <+32>:	mov    %r13,%rbp   //將堆疊指標的值賦給%rbp保存(這里,每一次回圈都會+4%r13)
   0x0000000000401117 <+35>:	mov    0x0(%r13),%eax  //將堆疊指標指向的數字(%eax也是32位的)賦給%eax
   0x000000000040111b <+39>:	sub    $0x1,%eax  //數字的值--
   0x000000000040111e <+42>:	cmp    $0x5,%eax  //減完以后和5進行比較
   0x0000000000401121 <+45>:	jbe    0x401128 <phase_6+52>   //低于或者相等才可(也就是說,每一個數字都是要低于等于5的才行)(也不能是負數)
   0x0000000000401123 <+47>:	callq  0x40143a <explode_bomb>//否則炸
   0x0000000000401128 <+52>:	add    $0x1,%r12d  //0+1
   0x000000000040112c <+56>:	cmp    $0x6,%r12d  //比較和6比較大小,因此猜測是在一個回圈中
   0x0000000000401130 <+60>:	je     0x401153 <phase_6+95>//這是跳出外層回圈
   0x0000000000401132 <+62>:	mov    %r12d,%ebx   //將這個會變化的值(第一次是1)賦值給一個被呼叫者暫存器
   0x0000000000401135 <+65>:	movslq %ebx,%rax  //有符號數的低位元組到高位元組賦值,%rax被改變
   0x0000000000401138 <+68>:	mov    (%rsp,%rax,4),%eax  //將這個值對應的元素(每一次回圈給一個)賦值給%eax
   0x000000000040113b <+71>:	cmp    %eax,0x0(%rbp)  //將這些數字與(%rbp進行比較)%rbp在外面其實一直在被遞增(所以比較的始終是這個元素和它的上一個元素)
   0x000000000040113e <+74>:	jne    0x401145 <phase_6+81>  //不等于才是對的
   0x0000000000401140 <+76>:	callq  0x40143a <explode_bomb>
   0x0000000000401145 <+81>:	add    $0x1,%ebx  //再將這個計數器值加1
   0x0000000000401148 <+84>:	cmp    $0x5,%ebx  //將這個值與5進行比較
   0x000000000040114b <+87>:	jle    0x401135 <phase_6+65>  //這是一個嵌套回圈
   0x000000000040114d <+89>:	add    $0x4,%r13                  //將%r13+4
   0x0000000000401151 <+93>:	jmp    0x401114 <phase_6+32>  

在這一部分,由注釋可以得出,這一部分是一個嵌套回圈,該嵌套回圈有兩層,外層回圈作用是,確定輸入這幾個數字均在1-6之間(包含1,6)(見<+45>),內層回圈作用是,確定這幾個數字互不相等(見<+71>),

Section3

   0x0000000000401153 <+95>:	lea    0x18(%rsp),%rsi   //將指標+0x18地址對應的值賦值給%rsi引數
   0x0000000000401158 <+100>:	mov    %r14,%rax  //將堆疊指標的值傳遞給回傳值暫存器
   0x000000000040115b <+103>:	mov    $0x7,%ecx  //將7賦值給第二個引數
   0x0000000000401160 <+108>:	mov    %ecx,%edx  //將第二個引數賦值給第三個引數    發現,第一個回圈后%ecx不受影響,這是一個定值
   0x0000000000401162 <+110>:	sub    (%rax),%edx  //讓7-%rax指向的數字
   0x0000000000401164 <+112>:	mov    %edx,(%rax)  //將這個結果賦值給這個數字
   0x0000000000401166 <+114>:	add    $0x4,%rax //讓它指向第二個數字
   0x000000000040116a <+118>:	cmp    %rsi,%rax  //比較%rsi尾指標地址是否不同,這應該是最后一個數字,說明這是一個回圈
---Type <return> to continue, or q <return> to quit---
   0x000000000040116d <+121>:	jne    0x401160 <phase_6+108>

該部分的作用即,將輸入的數字分別轉換為7-該數字,如1變為6…,其中堆疊指標對應的是堆疊頂元素,堆疊指標+8對應的是堆疊中的第二個元素,即堆疊中的每一個元素之間的地址間隔8個位元組,

Section4

   0x000000000040116f <+123>:	mov    $0x0,%esi  //賦值0給%esi
   0x0000000000401174 <+128>:	jmp    0x401197 <phase_6+163>
   0x0000000000401176 <+130>:	mov    0x8(%rdx),%rdx   //將某個值給取出來賦值給%rdx==6304480
   0x000000000040117a <+134>:	add    $0x1,%eax  //將這個值+1
   0x000000000040117d <+137>:	cmp    %ecx,%eax  //這里是比較%ecx(每一個數字)和%eax(第一次是2)
   0x000000000040117f <+139>:	jne    0x401176 <phase_6+130>  //若不等,跳轉回到130,這是一個回圈
   0x0000000000401181 <+141>:	jmp    0x401188 <phase_6+148> 
   0x0000000000401183 <+143>:	mov    $0x6032d0,%edx            
   0x0000000000401188 <+148>:	mov    %rdx,0x20(%rsp,%rsi,2)  //將這個值存起來
   0x000000000040118d <+153>:	add    $0x4,%rsi   //將計數器++
   0x0000000000401191 <+157>:	cmp    $0x18,%rsi  //計數器退出條件
   0x0000000000401195 <+161>:	je     0x4011ab <phase_6+183>
   0x0000000000401197 <+163>:	mov    (%rsp,%rsi,1),%ecx   //這一看又是一個回圈,目的,將不同的數字給依次取出
   0x000000000040119a <+166>:	cmp    $0x1,%ecx   //比較這些數字和1的大小關系     
   0x000000000040119d <+169>:	jle    0x401183 <phase_6+143>  //如果是小于等于1就直接到143
   0x000000000040119f <+171>:	mov    $0x1,%eax  //繼續執行  將1賦值給%eax
   0x00000000004011a4 <+176>:	mov    $0x6032d0,%edx  //將這個值賦值給%edx(復原)
   0x00000000004011a9 <+181>:	jmp    0x401176 <phase_6+130>

這一部分起到了關鍵作用,首先將堆疊中元素取出<+163>(這里同樣是依次取出),置于%ecx,接著是一個判斷陳述句<+143>,我們首先考慮堆疊頂元素等于1(這是經過了section3后的,原值是6)的情況——這時,堆疊頂元素被覆寫為0x6032d0 <+148>,

那么,我們繼續考慮堆疊中元素大于1的情況,此時均會跳轉至<+130>處,在<+130>到<+141>之間是一個回圈,若堆疊頂元素是2,則只執行一次<+130>陳述句后退出,若是3,則執行兩次,依此類推,

而<+130>陳述句,實際上是對%rdx+8這一地址取值后,賦值給%rbx自己(可以看成是一個鏈表:p=p->next)

因此,不同的值對應的不同結果如下,堆疊中最后會按照原來對應的數字來保存不同的地址
在這里插入圖片描述
Section5
在這里,我們為方便敘述,我們將堆疊中存的地址稱為地址元素

   0x00000000004011ab <+183>:	mov    0x20(%rsp),%rbx   //給定開始地址元素
   0x00000000004011b0 <+188>:	lea    0x28(%rsp),%rax     //這是下一元素的堆疊地址
   0x00000000004011b5 <+193>:	lea    0x50(%rsp),%rsi   //這個是末尾元素的堆疊地址
   0x00000000004011ba <+198>:	mov    %rbx,%rcx    //開始地址元素的賦值
   0x00000000004011bd <+201>:	mov    (%rax),%rdx       //將堆疊中的下一個地址元素賦值給%rdx(中轉站)
   0x00000000004011c0 <+204>:	mov    %rdx,0x8(%rcx)   //這是將堆疊中的下一個地址元素賦值給(上一地址元素+8)對應的記憶體中
   0x00000000004011c4 <+208>:	add    $0x8,%rax  //將%rax+8(下一堆疊地址)
   0x00000000004011c8 <+212>:	cmp    %rsi,%rax  //退出條件:下一堆疊地址等于末尾元素堆疊地址(所以只回圈五次)此時%rdx為第五個地址元素
   0x00000000004011cb <+215>:	je     0x4011d2 <phase_6+222>
   0x00000000004011cd <+217>:	mov    %rdx,%rcx   //中轉站中的值賦值給%rcx(這里是把第二個地址元素賦給(原來的開始元素),副本間的賦值)
   0x00000000004011d0 <+220>:	jmp    0x4011bd <phase_6+201>

該部分的作用:把堆疊中所有的下一個地址元素賦值給,其上一個地址元素+8對應的記憶體中,見<+204>,但是,堆疊本身存的地址元素并沒有被改變,而且,這些地址元素指向的值確實也沒有被改變,因為改變的是地址元素+8對應的記憶體值,而我們不是地址元素對應的記憶體值,(注:地址元素所對應的值的大小只占8位元組的大小

Section6

   0x00000000004011d2 <+222>:	movq   $0x0,0x8(%rdx)   //將0值賦給(最后一個地址元素+8)對應記憶體中
   0x00000000004011da <+230>:	mov    $0x5,%ebp
   0x00000000004011df <+235>:	mov    0x8(%rbx),%rax  //這里是(現地址元素+8對應的記憶體值)對應的記憶體(注意,即下一個地址元素)
   0x00000000004011e3 <+239>:	mov    (%rax),%eax   //將這個地址元素再解參考得到(就是下一個地址元素指向的值!!注意,這個值是沒有被改變的!)
   0x00000000004011e5 <+241>:	cmp    %eax,(%rbx)   //將這個值與上一個元素地址對應的記憶體(均沒有被改變!)進行比較
   0x00000000004011e7 <+243>:	jge    0x4011ee <phase_6+250>  上一個元素地址對應的值需要大于等于下一個的
   0x00000000004011e9 <+245>:	callq  0x40143a <explode_bomb>
   0x00000000004011ee <+250>:	mov    0x8(%rbx),%rbx  //將%rbx++
   0x00000000004011f2 <+254>:	sub    $0x1,%ebp  //計數器,五次回圈,比較只需要五次就可以比完
   0x00000000004011f5 <+257>:	jne    0x4011df <phase_6+235>  //若不等于則回去
---Type <return> to continue, or q <return> to quit---
   0x00000000004011f7 <+259>:	add    $0x50,%rsp
   0x00000000004011fb <+263>:	pop    %rbx
   0x00000000004011fc <+264>:	pop    %rbp
   0x00000000004011fd <+265>:	pop    %r12
   0x00000000004011ff <+267>:	pop    %r13
   0x0000000000401201 <+269>:	pop    %r14
   0x0000000000401203 <+271>:	retq   

在這部分,我們使用一個回圈將堆疊中所有的地址元素對應的值,和它的下一個地址元素(見<+235><+239>)對應的值進行比較(見<+241>),而比較的目的是,讓下一個元素地址對應的值均大于現地址元素對應的值,

因此,我們使用x/g 陳述句,對于0x6032d0-0x603320對應的值查詢,

地址
0x6032d0332
0x6032e0168
0x6032f0924
0x603300691
0x603310477
0x603320443

再對應上一張表,我們可以得出使得對應元素值從大到小數字串是"4 3 2 1 6 5"

通關密鑰

在這里插入圖片描述

秘密關卡

實驗探究

我們注意到,每一個函式后面都存在一個phase_defused函式,而當我們使用disas命令匯編這一代碼時,卻意外的發現位于代碼<+108>陳述句下的secret_phase關卡

   0x00000000004015c4 <+0>:	sub    $0x78,%rsp
   0x00000000004015c8 <+4>:	mov    %fs:0x28,%rax  
   0x00000000004015d1 <+13>:	mov    %rax,0x68(%rsp) #將phase函式的回傳值放入堆疊中保存
   0x00000000004015d6 <+18>:	xor    %eax,%eax  # 置0
   0x00000000004015d8 <+20>:	cmpl   $0x6,0x202181(%rip)        # 0x603760 <num_input_strings>
   0x00000000004015df <+27>:	jne    0x40163f <phase_defused+123>
   0x00000000004015e1 <+29>:	lea    0x10(%rsp),%r8 # sscanf引數,下同
   0x00000000004015e6 <+34>:	lea    0xc(%rsp),%rcx
   0x00000000004015eb <+39>:	lea    0x8(%rsp),%rdx
   0x00000000004015f0 <+44>:	mov    $0x402619,%esi  # “%d %d %s”
   0x00000000004015f5 <+49>:	mov    $0x603870,%edi
   0x00000000004015fa <+54>:	callq  0x400bf0 <__isoc99_sscanf@plt>
   0x00000000004015ff <+59>:	cmp    $0x3,%eax  # 引數有3
   0x0000000000401602 <+62>:	jne    0x401635 <phase_defused+113>
   0x0000000000401604 <+64>:	mov    $0x402622,%esi
   0x0000000000401609 <+69>:	lea    0x10(%rsp),%rdi  # %rdi中存盤的是字串
   0x000000000040160e <+74>:	callq  0x401338 <strings_not_equal> # 比較兩字串
   0x0000000000401613 <+79>:	test   %eax,%eax
   0x0000000000401615 <+81>:	jne    0x401635 <phase_defused+113>
   0x0000000000401617 <+83>:	mov    $0x4024f8,%edi   # 輸出函式提示
   0x000000000040161c <+88>:	callq  0x400b10 <puts@plt>
   0x0000000000401621 <+93>:	mov    $0x402520,%edi
   0x0000000000401626 <+98>:	callq  0x400b10 <puts@plt>
   0x000000000040162b <+103>:	mov    $0x0,%eax  # 將回傳值置0
---Type <return> to continue, or q <return> to quit---
   0x0000000000401630 <+108>:	callq  0x401242 <secret_phase>
   0x0000000000401635 <+113>:	mov    $0x402558,%edi
   0x000000000040163a <+118>:	callq  0x400b10 <puts@plt>
   0x000000000040163f <+123>:	mov    0x68(%rsp),%rax
   0x0000000000401644 <+128>:	xor    %fs:0x28,%rax
   0x000000000040164d <+137>:	je     0x401654 <phase_defused+144>
   0x000000000040164f <+139>:	callq  0x400b30 <__stack_chk_fail@plt>
   0x0000000000401654 <+144>:	add    $0x78,%rsp
   0x0000000000401658 <+148>:	retq   

找到隱藏關卡入口

  • 首先,在<+20><+27>陳述句中,使用了一個 0x202181(%rip) 的值,這個值從匯編代碼自帶的提示中可以猜想得到,是一個當前已經輸入的關卡數,即字串數,而該比較陳述句的含義是,只有在已完成關卡6的情況下才能進入到secret_phase,否則,將會直接跳到<+123>陳述句,失去進入<+108>秘密關卡函式的機會,
  • 其次,是一個sscanf陳述句,然而,sscanf語言的引數相比于前面的引數要多了一個,通過x/s陳述句查看,輸入格式為"%d %d %s",那么照理而言除了三個地址作為引數外,不應該有0x603870作為引數,
  • 于是,我們想到sscanf陳述句與scanf陳述句的不同之處,sscanf陳述句可以有一個字串引數,用于指定sscanf所需輸入的字串的源,(默認源是標準輸入)
  • 而這個字串應當由我們輸入觸發隱藏關卡才對,為什么會由匯編語言給出?這就說明應該是我們前面的輸入,保存到了這個地方,使得隱藏函式的以觸發,

于是,我們嘗試使用gdb進行端點的除錯,查看0x603870處的這個字串的值,我們在phase6的最后一條陳述句中設定斷點,
在這里插入圖片描述
接著,我們開始按照剛剛的答案一步步運行程式,到了斷點處,程式將自動停止,
在這里插入圖片描述
接著,我們使用x/s命令查看0x603870處字串的值
在這里插入圖片描述
我們可以通過之前6關輸入的字串得知,**第4關的字串就是觸發隱藏關卡的入口,**但是,在第四關處,我們還應該輸入某個字串在"7 0"之后,于是,我們開始對這個字串進行尋找,

我們發現,<+74>陳述句對兩個字串進行了比較,而其中一個字串就是sscanf輸入地址引數所指向的字串,因此,我們了解到需要將與其作比較字串作為輸入,

使用x/s命令查看,我們知道可以通過在第4關輸入"7 0 DrEvil"作為通關密鑰的同時,開啟隱藏關卡,
在這里插入圖片描述

secret_phase探究

   0x0000000000401242 <+0>:	push   %rbx
   0x0000000000401243 <+1>:	callq  0x40149e <read_line>
   0x0000000000401248 <+6>:	mov    $0xa,%edx  # 按十進制轉換
   0x000000000040124d <+11>:	mov    $0x0,%esi  # 將字串要保存到的地址設定為空地址
   0x0000000000401252 <+16>:	mov    %rax,%rdi  # 要轉換的字串是標準輸入進來的
   0x0000000000401255 <+19>:	callq  0x400bd0 <strtol@plt>
   0x000000000040125a <+24>:	mov    %rax,%rbx  # 保存該轉換后的數字
   0x000000000040125d <+27>:	lea    -0x1(%rax),%eax  # 將該數字-=1
   0x0000000000401260 <+30>:	cmp    $0x3e8,%eax # 將已經減過1的數字與0x3e8進行比較
   0x0000000000401265 <+35>:	jbe    0x40126c <secret_phase+42> # 若低于或者等于則跳轉
   0x0000000000401267 <+37>:	callq  0x40143a <explode_bomb>
   0x000000000040126c <+42>:	mov    %ebx,%esi  # 將原數字賦值給該引數
   0x000000000040126e <+44>:	mov    $0x6030f0,%edi
   0x0000000000401273 <+49>:	callq  0x401204 <fun7>
   0x0000000000401278 <+54>:	cmp    $0x2,%eax  # 若回傳值為2,那么該函式拆彈成功
   0x000000000040127b <+57>:	je     0x401282 <secret_phase+64>
   0x000000000040127d <+59>:	callq  0x40143a <explode_bomb>
   0x0000000000401282 <+64>:	mov    $0x402438,%edi
   0x0000000000401287 <+69>:	callq  0x400b10 <puts@plt>
   0x000000000040128c <+74>:	callq  0x4015c4 <phase_defused>
   0x0000000000401291 <+79>:	pop    %rbx
   0x0000000000401292 <+80>:	retq   

  • 根據C庫函式strtol的定義,我們得知這是一個轉換字串為數字的字串,所以,我們需要輸入一個數字,
  • 根據<+27><+30>,該數字需要低于0x3e8,
  • 在進入到func7函式后,若回傳值為2,則跳轉到<+64>列印出拆彈成功的字串,

因此,關鍵在于func7函式,注意,初次呼叫func7時,我們的引數分別是輸入的數字(%esi),以及0x6030f0(%rdi),

fun7函式

   0x0000000000401204 <+0>:	sub    $0x8,%rsp
   0x0000000000401208 <+4>:	test   %rdi,%rdi  # 測驗rdi
   0x000000000040120b <+7>:	je     0x401238 <fun7+52> # 若為%rdi為0則跳轉,回傳0xffffffff,無法獲得回傳值為2的正確結果
   0x000000000040120d <+9>:	mov    (%rdi),%edx  # 獲取該地址對應的值
   0x000000000040120f <+11>:	cmp    %esi,%edx  # 與輸入數字進行比較,
   0x0000000000401211 <+13>:	jle    0x401220 <fun7+28>
   0x0000000000401213 <+15>:	mov    0x8(%rdi),%rdi
   0x0000000000401217 <+19>:	callq  0x401204 <fun7>
   0x000000000040121c <+24>:	add    %eax,%eax
   0x000000000040121e <+26>:	jmp    0x40123d <fun7+57>
   0x0000000000401220 <+28>:	mov    $0x0,%eax
   0x0000000000401225 <+33>:	cmp    %esi,%edx
   0x0000000000401227 <+35>:	je     0x40123d <fun7+57>
   0x0000000000401229 <+37>:	mov    0x10(%rdi),%rdi
   0x000000000040122d <+41>:	callq  0x401204 <fun7>
   0x0000000000401232 <+46>:	lea    0x1(%rax,%rax,1),%eax
   0x0000000000401236 <+50>:	jmp    0x40123d <fun7+57>
   0x0000000000401238 <+52>:	mov    $0xffffffff,%eax
   0x000000000040123d <+57>:	add    $0x8,%rsp
   0x0000000000401241 <+61>:	retq   

這一部分的代碼比較短,也比較好讀,下面呼叫了兩次fun7說明這也是一個遞回程式,而且觀察得到%rsi的值在整個遞回的程序中沒有變化過,起到的只是一個比較的作用,
一開始還檢測了一下%rdi是否為0,后面設定遞回引數的時候用mov 0x8(%rdi),%rdi,自身加上一個偏移量的間接尋址代替自身,基本可以確定%rdi是一個指標,%rdi+0x8和%rdi+0x10同樣也是一個指標,看到這里基本已經猜出這個資料結構就是二叉樹了,之后的尋找答案也就不難了,順著左右兒子找一下就得到答案了:

答案是0x16,也就是22,

小結

這一次的bomb實驗,包含了計算機系統中第三章匯編語言的幾乎所有知識點,通過本次的練習,我的匯編語言能力獲得了很好的鍛煉,對于一些重要知識點(如跳轉表,回圈)的知識點,掌握的更加牢靠,而本實驗中包含的許多有趣實用的匯編語言技巧(如一些精巧的中間變數的使用、靈活的jump跳轉指令的運用)使我更加注意編程技巧的學習,匯編語言的學習無疑是一件重中之重的學習任務,學習之途任重而道遠,今發此文,與諸君共勉,

——ECNU 楊政 (轉載請宣告)

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/275148.html

標籤:其他

上一篇:CV學習:李宏毅2021機器學習(2)

下一篇:只有懦夫才會畏懼選擇!

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more