目錄

動態調試是什麼

先説一些基礎概念

為什麼要動態調試

怎麼動態調試

1.動態調試代替思考

2.動態調試劫持控制


動態調試是什麼

簡單説,就是運行程序,運行中監控程序的運行流程,數據變化,和靜態分析的對比如下

場景

動態調試(推薦)

靜態分析(推薦)

確認參數寄存器 / 調用約定

✅ 直接觀察寄存器值變化

❌ 容易因編譯器差異判斷錯誤

提取解密後的中間數據

✅ 內存中直接追蹤字符串

❌ 需逆向所有加密步驟,易出錯

繞過校驗 / 觸發 flag

✅ 改內存 / 寄存器直接滿足條件

❌ 可能需要 patch 二進制,步驟繁瑣

理解整體代碼結構

❌ 太細節,容易陷入指令級泥潭

✅ 快速看函數調用、邏輯分支

先説一些基礎概念

  • 斷點:程序執行到此處會停下
  • 單步(F8):程序執行一步
  • 運行(F9):運行程序,到斷點停下

為什麼要動態調試

  • 快速觀察程序運行流程,變量流向。
  • 程序有加密流程,追蹤字符串,觀察加密方法
  • 需要控制程序走向

怎麼動態調試

今天我們只講IDA的動態調試。首先我們要先明確一點,動態調試本質是要讓程序運行,不同車保程序的運行平台也是不一樣的,因此,IDA動態調試分為本地調試遠程調試兩種。具體怎麼遠程調試這裏不展開,網上教程很多

1.動態調試代替思考

對於動態調試,我想用一題簡單的例題來引入,這是一道十分基礎的XOR

逆向ctf_2020湖湘杯Re_02_GTZ_寄存器

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_02

那麼已知主函數如下,密文已經顯示,且只存在XOR計算,如何最快解出flag。因為這個XOR函數計算比較簡單,大多數人會選擇用python寫一個反推腳本(flag+1=x⬅️flag=x-1),這很好理解

如果從另一個角度來想,XOR運算是可逆運算(a異或b=c,a異或c=b),我們用動態調試會怎麼樣

這裏為了方便大家觀察,因此我下了兩個斷點,正常來説只要在圖一的if判斷處下一個就可以了

逆向ctf_2020湖湘杯Re_02_GTZ_寄存器_03

逆向ctf_2020湖湘杯Re_02_GTZ_寄存器_04

選擇Local Window debugger後點擊綠色小箭頭(F9)執行程序

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_05

接着在彈出的命令窗輸入主函數看到的密文回車,此時程序停止在我們的第一個斷點,我們可以打開字符串表(Locals)更方便看變化的字符串。(菜單欄Debugger➡️debugger windows➡️Locals)此時我們可以看到Str1Str2內的值都是一樣的,而下一步就是進行異或運算

逆向ctf_2020湖湘杯Re_02_GTZ_寄存器_06

此時我們點擊F8,程序會執行下一步,邊執行邊觀察Locals窗口,發現Str1的值變紅,證明發生了變化,觀察就是flag

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_07

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_08

此時,你是否意識到,我們根本沒有看XOR中的加密流程,而是直接利用動態調試繞過計算幫我們輸出了結果,這就是動態調試最大的好處之一。回憶一下,自己品味一下為什麼可以這樣

2.動態調試劫持控制

接下來我們來看第二題,一道利用動態調試實現非預期解的題目,不過由於這題的base64加密沒有魔改,因此直接解會更快,但是我們學習重點是如何用動態調試的方法來幫我們跳過加密的步驟。

看主函數,可以發現是base64加密,密文也擺在眼前了,但是注意到只執行了encode函數,還有一個decode的函數並沒有被執行

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_09

那麼,我們可不可以讓這個decode函數幫我們解密呢,當然。那我們需要什麼

1.decode函數地址

2.密文地址(打開shift+F12找)

提前準備好,準備開始劫持!

首先,我們在call encode函數處下個斷點,先不讓程序執行加密函數

逆向ctf_2020湖湘杯Re_02_GTZ_寄存器_10

逆向ctf_2020湖湘杯Re_02_GTZ_動態調試_11

接下來,來到decode函數,在其將解密的值傳回處,下個斷點,先不讓程序結束

逆向ctf_2020湖湘杯Re_02_GTZ_寄存器_12

逆向ctf_2020湖湘杯Re_02_GTZ_動態調試_13

接下來觀察,輸入encode函數Str的哪個寄存器,一般來説是RDI,不過這裏是RCX

逆向ctf_2020湖湘杯Re_02_GTZ_動態調試_14

逆向ctf_2020湖湘杯Re_02_GTZ_動態調試_15

F9運行程序,隨便輸點東西。程序停在call encode前,這時候我們要讓它執行call decode。在register窗口找到RIP,(儲存程序要跳轉的下一個地址)雙擊並修改地址為decode的地址

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_16

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_17

此時成功就會跳轉到decode函數,記得剛剛説過RCX是要輸入到Str的寄存器嗎,雙擊它,將地址改成密文的地址

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_18

逆向ctf_2020湖湘杯Re_02_GTZ_寄存器_19

F9執行程序,我們就會發現,RDX寄存器的內容已經發生變化,這就是我們要的結果。看起來不像flag是因為,題目還有一步調換字符,這裏就不展示了。

逆向ctf_2020湖湘杯Re_02_GTZ_動態調試_20

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_21

至此,我們又能發現動態調試一個強大的功能,就是控制流劫持。我們可以構造有利於我們解題的條件。

逆向ctf_2020湖湘杯Re_02_GTZ_字符串_22

動態調試是 “讓程序‘説話’” 的工具 —— 它將靜態代碼轉化為可交互的運行過程,既能驗證分析結論,又能直接獲取關鍵數據繞過複雜邏輯,是逆向中 “從理論到實操” 的核心橋樑,尤其在靜態分析陷入困境時,動態調試往往是破局的關鍵