iT邦幫忙

2021 iThome 鐵人賽

DAY 15
0
Security

現實主義勇者的 Windows 攻防記系列 第 15

【Day 15】從零開始的 Debug 生活 - Debugger 原理

  • 分享至 

  • xImage
  •  

環境

  • Windows 10 21H1
  • x64dbg Aug 2 2020, 13:56:14
  • IDA 7.5

前情提要

【Day 05】你逆 - 逆向工程工具介紹有提過逆向工程所需要的工具,其中包含我常用的 Debugger x64dbg。我們也逆過小算盤,認識基本的 Debugger 使用方法,這篇文章也會拿小算盤下手認識 Debugger。

這篇會介紹 Debugger 究竟是怎麼運作的,為什麼可以停在某個斷點,讓使用者可以慢慢的觀察程式的運行流程。由於不同的 Debugger 在處理同個事件上可能會有不同的實作方式,這篇文會以 x64dbg 為例講解 Debugger 的行為。

下面介紹與實際測試的部分都是在 64-bit 的環境,但是 32-bit 其實大同小異。

Debugger 機制

Debug Flag

介紹

這是 PEB 結構中的一個成員 BeingDebugged,顧名思義它就是用來判斷目前這個 Process 是否正在被 Deubg。開發者在程式中可以利用這個 Flag 判斷是否被 Debug,而做出不同的行為。

Windows API 有相對應的 IsDebuggerPresentCheckRemoteDebuggerPresent 函數檢查這個 Flag 的值,回傳為 TRUE 代表程式正在被 Debug。

實際測試

用 x64dbg 可以看到 PEB 的第三個 Byte 是 1,也就是正在 Debug。

Software Breakpoint

介紹

Software Breakpoint(軟體斷點)有三種實作方式,分別是 INT3、Long INT3、UD2,在 x64dbg 可以點選 Options => Preferences => Engine => Default Breakpoint Type 設定。

x64dbg 預設是使用 int3,Opcode 為 cc,執行後觸發 EXCEPTION_BREAKPOINT,然後 Debugger 再去處理這個 Exception,達到斷點的效果。

Debugger 會把下斷點的位址的指令改成 int3,所以當程式執行到這個位址時,就會觸發上面所提到的 EXCEPTION_BREAKPOINT。執行完 int3 後,因為 Instruction Pointer(RIP/EIP)指向的位址是 int3 的下一個 Byte,所以 Debugger 在處理 Exception 時會把 Instruction Pointer 減 1,並且把原本要執行的指令填回去。

實際測試

用 IDA 打開 calc.exe,可以看到最後有執行 ShellExecuteW

這邊我們針對 ShellExecuteW 下斷點。因為 Debugger 不會把它做的改變顯示在 Debugger,方便使用者使用,所以我使用了另一個工具觀察。下圖左邊是 x64dbg 在 ShellExecuteW 函數的位址,並且下了斷點;右邊是開源的工具 HookHunter
HookHunter 會自動比對檔案與記憶體,看函數有沒有被改動。下圖可以發現,下了斷點後,原本執行的是 push rbp,機械碼是 40 55。但是因為下斷點的關係,其中的 40 被改成 cc。而原本的值 40 會被 Debugger 存起來等等用來復原。

在抵達斷點後可以注意到 HookHunter 已經沒有偵測到檔案和記憶體的不同,因為這時 Debugger 已經把原本被改掉的機械碼 40 填回去了。

之後在執行斷點位址的下一個指令後,斷點的位址又被設回去 int3,機械碼為 cc

Trap Flag

介紹

Trap Flag(陷阱標誌)是 CPU 中的其中一個 Flag,當 Flag 為 1(set) 時會觸發 EXCEPTION_SINGLE_STEP,其他還有 OF(Overflow Flag)、DF(Direction Flag)、IF(Interrupt Flag)、SF(Sign Flag)、ZF(Zero Flag)、AF(Auxiliary Flag)、PF(Parity Flag)、CF(Carry Flag)。

這邊只說明 Trap Flag 的運作原理。在上面介紹 Software Breakpoint 時,最後一個步驟有說明斷點的位址會在執行完後再填回 int3,讓斷點繼續發揮作用。因此這邊需要有個機制讓 int3 再被填回去,Debugger 就是利用 Trap Flag。

由於 Trap Flag 為 1(set) 時會觸發 EXCEPTION_SINGLE_STEP,Debugger 就可以透過處理這個 Exception 來達到把 int3 填回原本程式的效果。在觸發 Exception 之後,Trap Flag 則會被 CPU 設為 0(unset)。

實際測試

一樣在 ShellExecuteW 下斷點並停在這個位址後,可以觀察到右邊視窗有個 TF,代表著 Trap Flag,目前的值為 1(set)。

這時會觸發 EXCEPTION_SINGLE_STEP,而 TF 會被重設為 0(reset)。

Hardware Breakpoint

介紹

Hardware Breakpoint(硬體斷點) 是透過 Debug Register DR0~DR7 來實作的。其中 DR0~DR3 四個暫存器存放下硬體斷點的位址;DR4、DR5 保留;DR6 存放 Debug Status,用來判斷是踩到哪個斷點;DR7 是 Debug Control,用來設定斷點,其中包含要在對 DR0~DR3 做什麼操作才會觸發斷點,例如讀、寫、執行。

實際測試

使用方法很簡單,就在目標位址按右鍵 => Breakpoint => Hardware,設定斷點。接著就可以在右邊視窗中看到 Debug Register 的改變。

參考資料


上一篇
【Day 14】Explorer 你怎麼沒感覺 - Ring3 Rootkit 隱藏檔案
下一篇
【Day 16】從一開始的 Anti-Debug 生活 - Anti-Debug
系列文
現實主義勇者的 Windows 攻防記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言