bomblab總結

趁熱打鐵先把phase6的破解過程記錄下來

   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
   0x0000000000401100 <+12>:    mov    %rsp,%r13
   0x0000000000401103 <+15>:    mov    %rsp,%rsi
   0x0000000000401106 <+18>:    callq  0x40145c <read_six_numbers>
   0x000000000040110b <+23>:    mov    %rsp,%r14
   0x000000000040110e <+26>:    mov    $0x0,%r12d
   0x0000000000401114 <+32>:    mov    %r13,%rbp
   0x0000000000401117 <+35>:    mov    0x0(%r13),%eax
   0x000000000040111b <+39>:    sub    $0x1,%eax
   0x000000000040111e <+42>:    cmp    $0x5,%eax
   0x0000000000401121 <+45>:    jbe    0x401128 <phase_6+52>
   0x0000000000401123 <+47>:    callq  0x40143a <explode_bomb>
   0x0000000000401128 <+52>:    add    $0x1,%r12d
   0x000000000040112c <+56>:    cmp    $0x6,%r12d
   0x0000000000401130 <+60>:    je     0x401153 <phase_6+95>
   0x0000000000401132 <+62>:    mov    %r12d,%ebx
   0x0000000000401135 <+65>:    movslq %ebx,%rax
   0x0000000000401138 <+68>:    mov    (%rsp,%rax,4),%eax
   0x000000000040113b <+71>:    cmp    %eax,0x0(%rbp)
   0x000000000040113e <+74>:    jne    0x401145 <phase_6+81>
   0x0000000000401140 <+76>:    callq  0x40143a <explode_bomb>
   0x0000000000401145 <+81>:    add    $0x1,%ebx
   0x0000000000401148 <+84>:    cmp    $0x5,%ebx
   0x000000000040114b <+87>:    jle    0x401135 <phase_6+65>
   0x000000000040114d <+89>:    add    $0x4,%r13
   0x0000000000401151 <+93>:    jmp    0x401114 <phase_6+32>
   0x0000000000401153 <+95>:    lea    0x18(%rsp),%rsi
   0x0000000000401158 <+100>:   mov    %r14,%rax
   0x000000000040115b <+103>:   mov    $0x7,%ecx
   0x0000000000401160 <+108>:   mov    %ecx,%edx
   0x0000000000401162 <+110>:   sub    (%rax),%edx
   0x0000000000401164 <+112>:   mov    %edx,(%rax)
   0x0000000000401166 <+114>:   add    $0x4,%rax
   0x000000000040116a <+118>:   cmp    %rsi,%rax
   0x000000000040116d <+121>:   jne    0x401160 <phase_6+108>
   0x000000000040116f <+123>:   mov    $0x0,%esi
   0x0000000000401174 <+128>:   jmp    0x401197 <phase_6+163>
   0x0000000000401176 <+130>:   mov    0x8(%rdx),%rdx
   0x000000000040117a <+134>:   add    $0x1,%eax
   0x000000000040117d <+137>:   cmp    %ecx,%eax
   0x000000000040117f <+139>:   jne    0x401176 <phase_6+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
   0x000000000040119d <+169>:   jle    0x401183 <phase_6+143>
   0x000000000040119f <+171>:   mov    $0x1,%eax
   0x00000000004011a4 <+176>:   mov    $0x6032d0,%edx
   0x00000000004011a9 <+181>:   jmp    0x401176 <phase_6+130>
   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
   0x00000000004011c0 <+204>:   mov    %rdx,0x8(%rcx)
   0x00000000004011c4 <+208>:   add    $0x8,%rax
   0x00000000004011c8 <+212>:   cmp    %rsi,%rax
   0x00000000004011cb <+215>:   je     0x4011d2 <phase_6+222>
   0x00000000004011cd <+217>:   mov    %rdx,%rcx
   0x00000000004011d0 <+220>:   jmp    0x4011bd <phase_6+201>
   0x00000000004011d2 <+222>:   movq   $0x0,0x8(%rdx)
   0x00000000004011da <+230>:   mov    $0x5,%ebp
   0x00000000004011df <+235>:   mov    0x8(%rbx),%rax
   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
   0x00000000004011f2 <+254>:   sub    $0x1,%ebp
   0x00000000004011f5 <+257>:   jne    0x4011df <phase_6+235>
   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

pop和push都是在維護寄存器,不用管

<+18> →輸入的是六個數字

<+39>~<+42>是一個編譯器的套路,把eax先減1,再和5做無符號比較,實際上是在判定1<=eax<=6。→6個數字必須介於1~6之間

<+26>但凡看到把0賦值給寄存器(r12),就要考慮它是不是下標。<+52>~<+60>印證了我們的猜想,此處有一個循環。<+60>指出了循環的結束位置在95行。

<+62> 把代表下標的寄存器(r12)賦值給另一個寄存器(ebx),說明多半ebx也是下標。<+81>~<+84>印證了我們的猜想,這是一個循環中的循環。

閱讀代碼可知,截止到<+92>,代碼要求輸入的六個數介於區間[1, 6], 並且互不相等

同構的僞代碼大概是這樣:

for (int i = 1; i < 6; ++i)
    int tmp = num[i-1];
    if(!(1 <= tmp && tmp <= 6)) explode_bomb();
    for (int j = i; j < 6; ++j)
        if(num[j] == tmp) explode_bomb();

下面進入代碼的第二部分,從<+95>開始

<+114>~<+121>注意到add、cmp、jX三人組,說明此處又有循環,<+121>的jne是往回跳,說明<+121>就是這段循環的結束位置。

閱讀代碼可知,<+92>~<+121>部分同構的僞代碼大概是這樣:

for (int i = 0; i < 6; ++i)
    num[i] = 7 - num[i];

下面進入代碼的第三部分,從<+123>開始

<+123>賦值0,猜測esi是下標

下面這一段跳來跳去的,我也猜不出原始的程序結構長啥樣了,就模擬一遍運行過程吧

首先跳轉到<+163>,把num[0]保存到了ecx中

<+166>把num[0]與1作比較,如果<=1,就跳轉到<+143>?這挺讓人費解的。我們觀察一下<+143>在什麼情況下會被運行到。注意到<+143>的前一句是jmp,跳轉到<+143>的後一句,因此正常情況下<+143>都不會被運行,除非直接跳轉到<+143>

接下來往哪看呢?我們的輸入是1~6,<=1是特殊情況,因此不管這個jmp,往下看纔是程序的主線

<+171>把1賦值給eax,猜測eax是下標

<+176>出現魔法地址0x6032d0,賦值給了edx,一般魔法地址都是重要線索!

跳回<+130>

<+134>~<+139>又見循環三人組,下標爲eax(代號爲j)

循環體的內容是把rdx偏置8字節地址處存放的8字節值賦值給rdx?這什麼鬼。rdx能這麼搞,他偏置8位地址處存放的8字節值也只能是地址,我們想到了鏈表。

打印一下試試

那這個鏈表節點的前8個字節是存啥的,試着打印一下

恰好是節點的編號!

所以節點的c風格聲明應該長這樣:

struct node {
    int32_t still_dont_know;
    int id;
    node* nxt
};

至此,我們發現了魔法地址的驚天祕密!

再看循環結束條件是j != num[i],也就是說,num[i]是幾,鏈表就往後走幾步,rdx保存了節點的地址

跳轉到<+148>

先看<+153>~<+163>又見循環三人組,下標是rsi(代號爲i),記得我們在<+123>給rsi賦值爲0,說明這一帶是一個i爲下標的大循環

再看回<+148>把rdx的值賦值給p[i]。

因此在<+123>~<+181>這一部分,如果把鏈表中編號爲id的節點地址叫做L[id],那麼這一部分乾的事情就是P[i] = L[num[i]];

同構的僞代碼大概是這樣:

for (int i = 0; i < 6; ++i)
    node* p;
    if (num[i] <= 1) p = head;
    else
        p = head;
        for (int j = 1; j < num[i]; ++j)
            p = p->nxt;
    P[i] = p;

下面進入代碼的第四部分,從<+183>開始

這部分指針非常亂,最好自己畫張圖

<+193>注意到0x50這個數,0x50 = 0x20 + 6 * 8,因此代表循環結束位置

<+208>~<+215>又見循環三人組,下標爲rax(代號爲i),由<+215>的跳轉地址得知,循環結束位置是<+222>的前一行

在<+183>~<+222>這一部分,所做的事情是按照L[num[0]]->L[num[1]]->...->L[num[5]]的順序重排鏈表(此前的順序是L[0]->L[1]->...->L[5])

同構的僞代碼:

for (int i = 1; i < 6; ++i)
    P[i-1]->nxt = P[i]; // P[i]即L[num[i]]
P[5]->nxt = NULL;

下面進入代碼的第五部分,從<+230>開始

指針同樣非常亂,最好自己畫圖

分析方法沒啥特殊的,發現它訪問了node前4字節的值,就叫它val吧

這一部分,所做的事情是檢查是否滿足P[0]->val > ... > P[5]->val

同構的僞代碼:

for (int i = 0; i < 6; ++i)
    if(P[i-1]->val < P[i]->val) explode_bomb();

因此我們打印看一下各個節點的val值:

因此當num[i]值爲3, 4, 5, 6, 1, 2時,相應的P[i]->val是924, 691, 477, 443, 332, 168,只有這樣才滿足要求

別忘了之前num的值反轉過,因此正確輸入爲4, 3, 2, 1, 6, 5

 

最後,完結撒花!

(當然secret_phase還沒做

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章