---
# System prepended metadata

title: Day14 - 史上最強Debugger - 人體肉眼 Debugger

---

# Day14 - 史上最強Debugger - 人體肉眼 Debugger
{%hackmd theme-dark %}

今天，準備要開始逆向程式碼。在介紹工具之前，先來解說逆向工程的邏輯。基本上，對於逆向，有很多現成的工具可以直接套用，但許多有其極限(當然，有工具可以提升效率，我沒有說要完全摒棄工具)。但就對於想透過組合語言來解釋程式碼而言，不仰賴工具仍可以練習自己的組合語言語感。因此，很多時候透過交叉比對，更可以解釋狀況。以下，我將講解如何將程式碼一步步拼湊回來。

我會先提供一份已經逆向過的程式碼截圖，讀者可以挑戰可否在不使用工具下，理解程式碼的運作邏輯？接著會提供透過 GDB 輔助動態追蹤的過程與解答，讓讀者比較是否與自己的理解相同。
## 路上撿到程式碼
情境引導：在通往偉大的航道，你撿到一支程式碼，執行後發現它是一支會驗證使用者輸入的程式(如下圖)。到底驗證過後能獲得什麼秘辛呢？好奇的你，真的好想知道。於是，你隨意輸入一段內文(LET ME IN)，發現錯誤。果然沒那那麼簡單就可以拿到擁有世界上的一切的「海賊王」哥爾·D·羅傑的寶藏。你忽然想到，最近不是有學過逆向嗎？何不來逆逆看？

![](https://i.imgur.com/fvQetlq.png)


## 被逆向的程式碼
下圖是透過 GDB 逆向的程式碼，想請問讀者這段程式碼到底在做什麼？
讀者可以拿出紙與筆，畫出以下程式碼的運作流程圖。花一點時間，消化這幾天所看到的知識，若忘記可以往回翻，或查閱相關資料。重點是，若想提升組合語言的識別能力，不要輕易的直接看解答，先讓大腦思考一下。我去成大上課的時候，聽到 Jserv 大大的名言，跟大家分享：
>「如果你把游泳池當作浴缸泡著，再泡幾年還是不會游泳」 
>– jserv



![](https://i.imgur.com/sVkitLj.png)

## 拼湊程式碼
經過與海軍奮鬥的一番掙扎後，我們現在來講解一下如何肉眼識別程式碼。
先看下圖，其實我們看到組合語言密密麻麻，也不是每一個都是重點。我把重點用紅筆標示起來於下圖。讀者可能會問，那什麼是重點？重點就在每次的比較、跳躍與呼叫其他函式。比方說記憶體結尾是 5cc 的地方，有一個 cmp 指令，接著 5d0 的 jne；還有 5ea 的地方，有一個 call 的指令，後面還寫著 \<printf@plt>。這些都是重點，因為我們逆向的時候，想知道到底什麼條件下會觸發這些事情？觸發後做了什麼事？

![](https://i.imgur.com/jt93z0S.jpg)

於是，透過上述方法，就可以簡略畫出程式運作圖(如下圖)。可以知道，總共有三個區域，分別是白色、紅色、綠色的區塊。分別對應三種情況。首先，白色區塊代表的就是驗證全部通過後的結果(找到寶藏)，而紅色代表的是第一個驗證沒過的下場，綠色表的是第二個驗證沒過的下場。簡單來說，就是要走在白色這條主線上，才能通關成功！

![](https://i.imgur.com/XSPXSI9.png)

透過與 GDB 的動態追蹤，可以得到下圖結果。紅色的 1 代表，沒通過參數個數驗證，綠色的 2 代表通過參數個數驗證，卻沒通過驗證碼的驗證，紫色的 3 代表驗證全部，安全達陣！

![](https://i.imgur.com/83I9352.jpg)


## 原始程式碼
以下是哥爾·D·羅傑的寶藏。解答公布：
```c=
#include <string.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
        if(argc==2) {
        printf("Checking License: %s\n", argv[1]);
        if(strcmp(argv[1], "APTX-4869")==0) {
            printf("Access Granted!\n");
        } else {
            printf("WRONG!\n");
        }
    } else {
        printf("Usage: <key>\n");
    }
    return 0;
}
```

## 結論
恭喜找到 ONE PIECE！動態追蹤程式程式碼蠻有趣的，雖然有點累、甚至有很多看不懂的情況，但了解背後邏輯94爽。明天，將會講解如何透過工具解讀程式碼。