前面在學習 Malware Analysis 的過程中接觸到的 debugger 主要是 OllyDbg 與 x64dbg。透過這些工具,我們可以暫停惡意程式、設定 breakpoint、single step 執行指令、觀察 register、stack 和 memory,甚至直接修改 instruction,進一步理解惡意程式實際執行時的行為。
但如果繼續往 Windows Malware Analysis、DFIR,甚至更底層的 Rootkit、Driver 分析前進,就會遇到另一個很重要的工具:WinDbg。
WinDbg 是 Microsoft 提供的 Windows debugger。相較於 OllyDbg 或 x64dbg,它最大的特色之一,就是除了能進行一般的 User Mode Debugging,還可以進行 Kernel Mode Debugging。
【聲明】由於時間問題本日文章由 AI 生成QQ
WinDbg 全名可以理解為 Windows Debugger,是 Microsoft Debugging Tools for Windows 中最重要的除錯工具之一。
一般 debugger 的核心概念其實都差不多:
程式原本會由 CPU 不斷執行 instruction,而 debugger 可以介入這個過程,讓我們:
因此,如果已經使用過 x64dbg 或 OllyDbg,WinDbg 並不是完全不同的世界,真正的差異主要在於它能夠觀察的層級更深。
例如使用 x64dbg 分析 malware.exe 時,我們通常是在觀察:
malware.exe
↓
Windows API
↓
Windows Kernel
我們主要待在 malware.exe 所在的 User Mode。
但有些問題並不能只從 User Mode 看出來。
例如:
Process
Thread
Virtual Memory
Handle
Driver
Kernel Object
System Call
Exception
這些東西都與 Windows 作業系統本身密切相關。
WinDbg 的價值就在這裡。
要理解 WinDbg,首先一定要理解 Windows 的:
User Mode 與 Kernel Mode。
Windows 不會讓一般程式直接擁有最高權限。
一般應用程式,例如:
Chrome
Discord
notepad.exe
malware.exe
基本上都執行在 User Mode。
而 Windows 核心以及大部分 Driver 則執行在:
Kernel Mode
可以簡化成:
User Mode
------------------------
malware.exe
notepad.exe
browser.exe
Windows DLL
------------------------
↓
System Call
↓
------------------------
Kernel Mode
------------------------
Windows Kernel
Device Driver
Kernel Objects
Memory Manager
Process Manager
------------------------
User Mode 的程式受到很多限制,例如一個普通程式不能隨便讀取 Kernel Memory,也不能直接控制硬體。
Kernel Mode 則具有非常高的權限,這也是為什麼 Kernel Malware / Rootkit / Malicious Driver 特別危險,如果攻擊者成功把惡意程式碼放到 Kernel Mode,它能做到的事情就比普通 User Mode Malware 多很多。
而 WinDbg 正是分析這一層的重要工具。
如果只看基本 debugging 功能,三者其實有不少重疊。
例如都可以:
Disassemble
Breakpoint
Step Into
Step Over
Inspect Registers
Inspect Memory
Inspect Stack
但是定位不同。
OllyDbg 是比較早期、經典的 Windows User Mode Debugger,PMA 使用它作為主要教學工具,x64dbg 則可以視為現在 Reverse Engineering / Malware Analysis 中非常常見的 User Mode Debugger,介面也相對直覺。
WinDbg 的特色則是:
它和 Windows 本身的整合程度非常高。
除了 User Mode Debugging,WinDbg 還能進一步處理:
Kernel Debugging
Crash Dump Analysis
Driver Debugging
Windows Internals
Memory Analysis
Exception Analysis
因此可以簡單理解成:
OllyDbg / x64dbg
↓
偏向程式本身的 Reverse Engineering
WinDbg
↓
程式 + Windows Operating System
這並不是說 WinDbg 一定比 x64dbg「高級」,而是它們適合的場景不同。
如果只是想快速分析一個普通 Windows Malware,可以先使用 x64dbg。
但如果研究開始碰到:
Windows Internals
Kernel
Driver
Crash Dump
Rootkit
Memory Forensics
WinDbg 的重要性就會快速增加。
第一次使用 WinDbg 時,很容易遇到一個問題:
為什麼畫面裡全部都是地址?
例如:
00007ffb`12345678
單看地址幾乎沒有意義。
我們真正希望看到的是:
kernel32!CreateFileW
ntdll!NtCreateFile
nt!NtCreateProcess
這就需要 Symbol。
Symbol 可以幫助 debugger 把:
Memory Address
轉換成:
Module
Function
Variable
之類比較有意義的名稱。
Microsoft 提供 Symbol Server,可以讓 WinDbg 下載 Windows 系統元件需要的 symbol。
WinDbg 常見的 symbol 設定方式是:
.symfix
.reload
.symfix 可以協助設定 Microsoft Symbol Server。
.reload 則重新載入 symbol。
如果 symbol 沒有正確載入,後續分析可能會變得非常痛苦。
所以看到:
*** WARNING: Unable to verify checksum
*** ERROR: Module load completed but symbols could not be loaded
這類訊息時,就要開始注意是不是 symbol 出問題了。
WinDbg 和 x64dbg 最大的使用體驗差異之一,就是:
WinDbg 非常依賴 Command。
x64dbg 很多事情可以透過 GUI 點擊完成。
WinDbg 雖然也有 GUI,但實際分析時,大量操作還是會直接輸入 command。
例如:
r
查看 registers。
k
查看 call stack。
u
反組譯程式碼。
g
繼續執行。
一開始會覺得很像在背指令,但熟悉之後其實非常快。
最基本的操作之一就是查看 CPU registers:
r
如果是 x64 process,可能會看到:
rax
rbx
rcx
rdx
rsp
rbp
rsi
rdi
rip
其中最重要的幾個概念包括:
RIP → 下一個要執行的 instruction
RSP → Stack Pointer
RBP → 常被用來協助管理 stack frame
RAX → 常用於 function return value
如果之前已經學過 x86 assembly,這裡的概念基本上是一樣的。
只是 64-bit Windows 會看到:
RAX
RBX
RCX
而不是:
EAX
EBX
ECX
要查看目前附近的 assembly,可以使用:
u
也就是 Unassemble。
例如:
u rip
代表從目前 RIP 指向的位置開始進行反組譯。
可能會看到:
mov rax,rcx
test rax,rax
je ...
call ...
這時候做的事情其實就跟 x64dbg 的 Disassembly Window 很像。
我們要觀察:
現在執行到哪裡?
接下來 call 哪個 function?
conditional jump 是否成立?
register 裡面裝了什麼?
Debugger 最基本的操作當然少不了 Single Step。
WinDbg 中常見:
t
代表 Trace。
可以理解成 Step Into。
如果目前 instruction 是:
call function
使用 t 就會進入 function。
另一個則是:
p
代表 Step。
它的效果比較接近 Step Over。
也就是遇到:
call function
時,不一定要進去 function 裡面一條一條看,而是讓 function 執行完,再停在下一條 instruction。
這和之前在 x64dbg 學到的:
Step Into
Step Over
概念完全相同。
分析 Malware 時,我們不可能從 Entry Point 開始一條一條執行到最後。
所以 breakpoint 非常重要。
WinDbg 可以使用:
bp address
設定 software breakpoint。
例如:
bp 00007ff6`12345678
但如果 symbol 已經正確載入,更方便的方法是:
bp kernel32!CreateFileW
這樣程式呼叫 CreateFileW 時就會停下來。
對 Malware Analysis 而言這非常有用。
例如懷疑 malware 正在建立檔案,就可以觀察:
CreateFile
WriteFile
DeleteFile
如果懷疑它修改 Registry,就可以進一步追蹤相關 API。
如果懷疑它建立 process,也可以針對 process creation 相關函式進行觀察。
列出目前 breakpoint:
bl
刪除 breakpoint:
bc
Disable breakpoint:
bd
Enable breakpoint:
be
因此可以記成:
bp → breakpoint
bl → breakpoint list
bc → breakpoint clear
bd → breakpoint disable
be → breakpoint enable
Malware Analysis 中另一個非常重要的能力就是:
看 Memory。
WinDbg 提供很多 d 開頭的 command。
例如:
db
以 byte 顯示。
dw
以 word 顯示。
dd
以 double word 顯示。
dq
以 quad word 顯示。
如果想看字串,也可以使用:
da
查看 ASCII string。
或者:
du
查看 Unicode string。
這在 Malware Analysis 特別實用。
例如 register 裡面出現一個 pointer:
RCX = 000001F234567890
單看地址沒有意義。
這時候可以:
du rcx
如果結果出現:
C:\Users\...\AppData\malware.exe
就知道 RCX 指向的是一段 Unicode string。
因此分析 assembly 時不要只看:
RCX = 0x000001F234567890
而要繼續追:
這個 address 指向什麼?
這就是 debugger 中非常重要的思考方式。
另一個非常重要的 command 是:
k
它會顯示目前 thread 的 Call Stack。
假設看到:
malware!FunctionC
malware!FunctionB
malware!FunctionA
kernel32!BaseThreadInitThunk
ntdll!RtlUserThreadStart
我們就可以大概理解:
FunctionA
↓
FunctionB
↓
FunctionC
↓
現在停在這裡
這比只看目前 RIP 有用很多。
因為 RIP 只能告訴我們:
「現在在哪。」
Call Stack 則可以幫助回答:
「我是怎麼走到這裡的?」
這對 Reverse Engineering 和 Malware Analysis 都非常重要。
Windows Process 通常不只有自己的 EXE。
還會載入大量 DLL,例如:
ntdll.dll
kernel32.dll
KernelBase.dll
user32.dll
advapi32.dll
WinDbg 可以使用:
lm
查看 Loaded Modules。
lm 可以理解成:
List Loaded Modules
如果只想看特定 module,也可以搭配其他參數進一步查詢。
在 Malware Analysis 中,module 資訊可以幫助我們理解:
程式載入了哪些 DLL?
目前 address 屬於哪個 module?
某個 function 位於哪裡?
是否出現可疑 module?
WinDbg 還有一個非常重要的用途:
Crash Analysis。
Windows 發生:
Access Violation
Blue Screen
Application Crash
Driver Crash
時,可以產生 dump file。
WinDbg 可以直接分析這些 dump。
其中最有名的 command 大概就是:
!analyze -v
它會針對目前的 crash 資訊進行分析,提供:
Exception
Faulting Module
Stack
可能的問題位置
這也是 WinDbg 在 Malware Analysis 之外,被 Windows Developer、Driver Developer、Incident Responder 使用的重要原因。
前面有些 WinDbg command 前面有:
!
例如:
!analyze
這些通常屬於 Extension Commands。
在 Kernel Debugging 中,會大量看到這類 command。
例如可以查詢:
Process
Thread
Handle
Virtual Memory
Kernel Object
這也是 WinDbg 真正開始展現威力的地方。
當分析不再只是:
這一條 MOV 在做什麼?
而開始變成:
這個 Process 的 Windows 結構是什麼?
這個 Thread 現在在哪?
這段 Virtual Memory 屬於誰?
這個 Driver 載入在哪?
就已經開始從單純的 Reverse Engineering,逐漸進入 Windows Internals 的領域。
學到這裡可能會有一個問題:
如果 x64dbg 已經可以分析 malware,為什麼還要學 WinDbg?
我的理解是,兩者並不是替代關係。
如果分析普通 User Mode Malware:
Static Analysis
↓
IDA / Ghidra
Dynamic Analysis
↓
x64dbg
其實已經可以完成大量工作。
但如果研究方向逐漸往:
Advanced Malware
Rootkit
Kernel Malware
Malicious Driver
EDR
Windows Internals
Memory Forensics
發展,就會越來越需要理解 Windows 底層。
例如 Malware 可能透過:
Process Injection
API Hooking
Direct System Call
Driver
Kernel Manipulation
來逃避偵測。
如果只停留在 Windows API 層,很容易只看到:
「Malware 呼叫了某個 API。」
但不知道這個 API 往下究竟發生了什麼事情。
WinDbg 則提供了一條繼續往下看的路。
WinDbg 和 Threat Hunting 看起來好像距離很遠。
Threat Hunter 通常不會每天開 WinDbg 分析 endpoint。
但是理解 WinDbg 背後的概念,對 Threat Hunting 仍然非常重要。
因為很多 endpoint telemetry 最後都與 Windows Internals 有關:
Process
Thread
Module
Handle
Memory
Token
Driver
Registry
System Call
如果不知道 Windows 怎麼管理這些東西,就容易只停留在:
看到 Event ID → 查 Event ID
看到 Alert → 查 Alert
而比較深入的 Threat Hunting,需要進一步理解:
這個 telemetry 為什麼會產生?
正常 Windows 行為應該長什麼樣子?
Malware 改變了哪個行為?
EDR 又是從哪一層看到這件事情?
從 x86/x64 Assembly 開始,到 Registers、Stack、Memory、Breakpoint、Single Step、Call Stack,這些概念全部都可以直接延續到 WinDbg。
從中增加的是:
我們開始不只分析一支程式,而是開始理解這支程式所在的 Windows。
前面的問題可能是:
這支 Malware 做了什麼?
但繼續深入之後,可以去探討:
它利用 Windows 的什麼機制做到這件事?
甚至進一步變成:
如果我是 Defender,我可以從 Windows 留下的哪些 artifacts 或 telemetry 發現這個行為?
