Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
逆向工程實務 極入門篇
Search
LJP-TW
February 20, 2021
Technology
1
730
逆向工程實務 極入門篇
2021/2/20 AIS3 Club 東部資安社群新春推廣 東華大學
LJP-TW
February 20, 2021
Tweet
Share
More Decks by LJP-TW
See All by LJP-TW
Reverse Engineering - 1
ljptw
0
1.2k
Reverse Engineering - 2
ljptw
0
540
Reverse Engineering - 3
ljptw
0
440
Re:0 從零開始的逆向工程
ljptw
1
740
Linux 極入門篇
ljptw
1
270
Fuzzing 101
ljptw
1
150
Binary Exploitation - File Structure
ljptw
1
250
Binary Exploitation - Basic 補充篇
ljptw
1
38
Binary Exploitation - Heap
ljptw
1
120
Other Decks in Technology
See All in Technology
AIを駆使したゲーム開発戦略: 新設AI組織の取り組み / sge-ai-strategy
cyberagentdevelopers
PRO
1
130
AWS CodePipelineでコンテナアプリをデプロイした際に、古いイメージを自動で削除する
smt7174
1
110
ガチ勢によるPipeCD運用大全〜滑らかなCI/CDを添えて〜 / ai-pipecd-encyclopedia
cyberagentdevelopers
PRO
3
210
大規模データ基盤チームのオンプレTiDB運用への挑戦 / dpu-tidb
cyberagentdevelopers
PRO
1
110
急成長中のWINTICKETにおける品質と開発スピードと向き合ったQA戦略と今後の展望 / winticket-autify
cyberagentdevelopers
PRO
1
160
新卒1年目が挑む!生成AI × マルチエージェントで実現する次世代オンボーディング / operation-ai-onboarding
cyberagentdevelopers
PRO
1
170
ExaDB-D dbaascli で出来ること
oracle4engineer
PRO
0
3.6k
MAMを軸とした動画ハンドリングにおけるAI活用前提の整備と次世代ビジョン / abema-ai-mam
cyberagentdevelopers
PRO
1
120
「 SharePoint 難しい」ってよく聞くけど、そんなに言うなら8歳の息子に試してもらった
taichinakamura
1
630
プロダクト成長に対応するプラットフォーム戦略:Authleteによる共通認証基盤の移行事例 / Building an authentication platform using Authlete and AWS
kakehashi
1
150
Autify Company Deck
autifyhq
1
39k
リンクアンドモチベーション ソフトウェアエンジニア向け紹介資料 / Introduction to Link and Motivation for Software Engineers
lmi
4
290k
Featured
See All Featured
Keith and Marios Guide to Fast Websites
keithpitt
408
22k
Docker and Python
trallard
40
3.1k
Done Done
chrislema
181
16k
Raft: Consensus for Rubyists
vanstee
136
6.6k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.6k
A Tale of Four Properties
chriscoyier
156
23k
Music & Morning Musume
bryan
46
6.1k
Documentation Writing (for coders)
carmenintech
65
4.4k
The Invisible Side of Design
smashingmag
297
50k
Making the Leap to Tech Lead
cromwellryan
132
8.9k
Statistics for Hackers
jakevdp
796
220k
Imperfection Machines: The Place of Print at Facebook
scottboms
264
13k
Transcript
2021/02/20 逆向工程實務 LJP
Outline 1 基礎知識篇 • 簡介逆向工程 • 程式如何變成程序 • 簡介 CPU
暫存器 • Runtime Architecture • 簡介 x86_64 • 逆向工程方式 • 靜態分析 • 動態分析 • Endian • ASLR 簡易實務篇 • x86_64 組合語言 • 函式庫 • 加速逆向工程 • 阻止逆向工程
工具安裝篇 2
JDK • Jdk-15.0.2_windows-x64_bin.exe • 一直按下一步就對了 • 設置環境變數 3 https://www.oracle.com/java/technologies/javase-jdk15-downloads.html
JDK 4
Ghidra • ghidra_9.2.2_PUBLIC_20201229.zip • 解壓縮 • JDK 環境變數有設定好, 就能成功運行 ghidraRun.bat
5 https://ghidra-sre.org/
x64dbg • Snapshot_2021-02-09_17-28.zip • 解壓縮 • 執行 release/x96dbg.exe • 一開始初始化選項
全部選確定 • 桌面就會出現 x32dbg 和 x64dbg 的捷徑 6 https://sourceforge.net/projects/x64dbg/
什麼是逆向工程? 7
順向工程 8 程式碼 程式 程序 運行 組譯 編譯
順向工程 9 程式碼 程式 程序 運行 組譯 編譯 C、C++、RustC x86
asm .exe、 Linux ELF Java Java Bytecode .class Python Python Bytecode .pyc Smali Dalvik Bytecode .dex
逆向工程 10 程式碼 程式 程序 組譯 編譯 運行 反組譯 反編譯
C、C++、RustC x86 asm .exe、 Linux ELF Java Java Bytecode .class Python Python Bytecode .pyc Smali Dalvik Bytecode .dex
為何要逆向工程? 11
為何要逆向工程? • 了解程式內部邏輯在做什麼 • 是否有惡意行為 • 尋找程式漏洞 • 修改內部邏輯 12
從哪開始逆向 13 main 的第一行就是程序的第一道指令嗎?
程式怎麼跑起來的? 14 程式碼 程式 程序 組譯 編譯 運行 反組譯 反編譯
程式 to 程序 • 程式檔案的頭部會存放資訊 告訴 OS 怎麼把它放到記憶體裡 程式進入點在哪 •
頭部結構 • Windows: PE (Portable Executable) Header • Linux: ELF (Executable and Linkable Format) • 接著以大家熟悉的 exe 舉例 15
程式 to 程序 • 實際拆一隻 exe • DOS Header •
Magic number • MZ 開頭 • 用來快速簡易辨識格式 • File address of new exe header • PE Header 所在的 offset 16
程式 to 程序 • PE Header • Magic number •
PE 開頭 • 又細分成幾個 Header • File Header • Optional Header 17
程式 to 程序 • Optional Header • Entry Point •
程式進入點 • Image Base • 整個程式的基址 • 第一道指令位址 • Image Base + Entry Point • 0x4014E0 18
程式 to 程序 • 第一道指令位址 • Image Base + Entry
Point • 0x4014E0 • 偷瞄一下 0x4014E0 • 被工具自動標示成 entry 19
程式 to 程序 • Section Header • Raw Address •
在檔案中的 offset • Virtual Address • 放到記憶體中的位址 (要再加 Image Base) • 有許多 section • .text • 可執行的機械碼 主程式通常放在這 • .data • 放資料的區域 20
程式 to 程序 21
程式 to 程序 22 程式檔案 記憶體 Header .text section .data
section … Header 0x400000 (Image Base) .text section .data section … 0x401000 0x403000 0x0 0x400 0x1c00
程式 to 程序 23 記憶體 Header 0x400000 (Image Base) .text
section .data section … 0x401000 0x403000
程式 to 程序 Linux 的 ELF 格式雖然和 PE 不同 但目的也是一樣,
要讓 OS 知道怎麼 load 他 所以 ELF 很多欄位都可以在 PE 中找到類似功能的對應欄位 24
程式檔案放上記憶體了 阿然後勒 程序是怎麼執行的? 25 程式碼 程式 程序 組譯 編譯 運行
反組譯 反編譯
先講講 CPU 暫存器 26
CPU 暫存器 • CPU 實現了不同指令集架構 (Instruction Set Architecture) • WIKI
支援 • 不同指令集架構有不同的暫存器、指令格式 • 暫存器 (Register) • x86_64: rax rbx rcx rdx rdi rsi rbp rsp rip … • ARM: SP LR PC R0 R1 R2 R3 R4 … • MIPS: r0 r1 r2 r3 ... • 接下來都以 x86_64 / x86 來講 27
x86_64 暫存器 28 al ah rax (8 Bytes) eax (4
Bytes) ax (2 Bytes) bl bh rbx (8 Bytes) ebx (4 Bytes) bx (2 Bytes) cl ch rcx (8 Bytes) ecx (4 Bytes) cx (2 Bytes) dl dh rdx (8 Bytes) edx (4 Bytes) dx (2 Bytes) si (2 Bytes) rsi (8 Bytes) esi (4 Bytes) di (2 Bytes) rdi (8 Bytes) edi (4 Bytes) bp (2 Bytes) rbp (8 Bytes) ebp (4 Bytes) sp (2 Bytes) rsp (8 Bytes) esp (4 Bytes)
x86 暫存器 29 al ah eax (4 Bytes) ax (2
Bytes) bl bh ebx (4 Bytes) bx (2 Bytes) cl ch ecx (4 Bytes) cx (2 Bytes) dl dh edx (4 Bytes) dx (2 Bytes) si (2 Bytes) esi (4 Bytes) di (2 Bytes) edi (4 Bytes) bp (2 Bytes) ebp (4 Bytes) sp (2 Bytes) esp (4 Bytes)
x86_64 暫存器 • 還有更多暫存器, 例如 r8 ~ r15、rip、segment 暫存器 …
• 有幾個重要的暫存器 • rsp: stack 頂部位址 (Stack Pointer) • rbp: stack 底部位址 (Base Pointer) • rip: 下一條要執行的指令位址 (Instruction Pointer) 30
現在可以來講講程序怎麼執行的了 31
程式 to 程序 32 記憶體 Header 0x400000 (Image Base) .text
section .data section … 0x401000 0x403000
程序 33 記憶體 .text section 0x00401000 CPU EAX EBX ECX
EDX EDI ESI EBP 0x0128FF94 ESP 0x0128FF8C EIP 0x004014e0 0x4014E0 stack 0x0128FF8C 0x0128FF94 EIP -> <-EBP <-ESP
程序 34 記憶體 .text section 0x00401000 CPU EAX EBX ECX
EDX EDI ESI EBP 0x0128FF94 ESP 0x0128FF80 EIP 0x004014e3 0x4014E0 stack 0x0128FF80 0x0128FF94 EIP -> <-EBP <-ESP
等等 那個指令是什麼 35
x86_64 指令 • 一種機械碼對應一種組合語言指令 • 像是 83 ec 0c 對應
sub esp, 0xc • 加 add • 減 sub • 乘 mul • 除 div • 呼叫 call • 返回 ret • 跳 jmp • 遇到沒看過的就查 36
x86_64 指令 37 mov rax, 1 add rax, 5 mov
rbx, 7 sub rbx, rax inc rax ASM rax = 1 rax = rax + 5 rbx = 7 rbx = rbx – rax rax++ C ✕ ✕
38
程式分析 39
程式分析 • 如果你只看組語來分析 這個叫做 靜態分析 40
程式分析 • 如果你用工具來讓程序跑跑停停,在這過程中分析程序內部邏輯, 這叫做動態分析 41
程式分析 • 實務上為兩者交叉使用,看個人喜好方式 • 靜態分析工具 (反組譯, 反編譯, 分析函數) • IDA
• Ghidra • 動態分析工具 (設定中斷點, 觀察 Registers、 Memory) • x64dbg • windbg • gdb 42
來試試看用 Ghidra 進行靜態分析 43
靜態分析: Ghidra 44 創好新的 Project 後 介面類似這樣 File > Import
File 或按 I 或直接把程式拖進來 對程式按兩下即可開始分析
靜態分析: Ghidra 版面類似這樣, 可以通過 Window 自己調整喜歡的樣子 第一次進入會問要不要跑分析, 就給他跑 45
靜態分析: Ghidra 各種快捷鍵 : Ghidra cheatsheet 46 Ref: https://ghidra-sre.org/CheatSheet.html
靜態分析: Ghidra 前往程式進入點 47 Ref: https://ghidra-sre.org/CheatSheet.html
靜態分析: Ghidra Entry: 第一道指令位址 (Image Base + Entry Point) 48
靜態分析: Ghidra • 在進入 main 前會執行一些初始化工作 • 找長得像是 main(int argc,
char *argv[], char *envp[]) 的 function call 49 Ref: https://hackmd.io/@sysprog/c-runtime?type=view
靜態分析: Ghidra 50 成功找到 main
靜態分析: Ghidra • 把函數改名, 對著函數名稱按 L • 修改參數名稱, 對著參數按 L,
改成 argc argv … • 修改參數型別, 對著參數按 ctrl+L, 改成 int、 char **… • 修改這些的意義是幫助你理解程式 51
靜態分析: Ghidra 52 從組語介面可以看到 main 的起始位址為 0x140001060
Demo 53
接著來試試用 x64dbg 進行動態分析 54
動態分析: x64dbg • 把程式拖進去 • 按一下組語指令的視窗 • Ctrl + g
移動到指定記憶體位址 • 設定中斷點: 按一下要設中斷點的指令後按 F2 • 繼續執行: 按 F9 讓程序繼續執行,一直按 F9 直到剛剛設定的中斷 點為止 55
動態分析: x64dbg • F8 單步步過一條指令 • 步過步過… • 即將執行 mov
qword ptr ss:[rsp+90], rax • 看一下 rax 和 rsp 現在是多少 • rax 為 0x0000F95351A401E4 • 看一下位址為 rsp + 90 的記憶體內容現在是什麼 56
動態分析: x64dbg • 點一下資料視窗, 按 Ctrl + g 移動到 rsp
+ 90 • 內容是 0 • 步過這行指令後, 將 rax 寫入到此 • rax 為 0x0000F95351A401E4, 但寫入記憶體順序卻反了 • WHY? 57
在講原因之前先讓我來個 Demo 58
Endian 59 Memory 0x34 0x56 0x78 0x12 a+1 a+2 a+3
a Memory 0x56 0x34 0x12 0x78 a+1 a+2 a+3 a Big-Endian Little-Endian 0x12345678 32-bits Integer
Endian • Little-Endian 好處: • 型別轉換 (e.g. int to short
int) 時不用換記憶體位址 60 Memory 0x56 0x34 0x12 0x78 a+1 a+2 a+3 a Little-Endian 0x12345678 32-bits Integer 0x5678 16-bits short Integer 0x78 8-bits char
動態分析: x64dbg • 點一下資料視窗, 按 Ctrl + g 移動到 rsp
+ 90 • 內容是 0 • 步過這行指令後, 將 rax 寫入到此 • rax 為 0x0000F95351A401E4, 但寫入記憶體順序卻反了 • WHY? Answer: Little-Endian 61
ASLR • Address Space Layout Randomization • 以上的例子中, 靜態分析和動態分析時, 組語指令的位址都相同
• 就是沒有使用 ASLR 62 Visual studio project property PE-Bear
ASLR • 使用 ASLR 每次加載程式時會隨機化 Base Address 63 Visual studio
project property PE-Bear
ASLR • 在 PE Header 中以 DLL can move bit
是否為 1 來決定要不要使 用 ASLR • IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE • 利用 PE-Bear 修改 binary, 把 ASLR 關閉 64
Lab: observe_c.exe 65 任務目標 • 在 Ghidra 中找到 main 函數
• 關閉執行檔的 ASLR • 以 x64dbg 動態觀察 main 函數 • 熟悉工具
Challenge: ezGiveUflag.exe 66 任務目標: 獲取 Flag (Flag 格式為 FLAG{…})
組合語言 Assembly 67 人類讀高階程式語言比直接讀組合語言快 若能知道對應的高階程式語言會變成什麼樣的組語 就能更快速的讀組語
if 68
if 69
if 70
if 71
for 72
for 73
for 74
for 75
for 76
for 77
條件 jmp • 配合 cmp / test • 迴圈會往回跳 /
IF 只會往前跳 78 Ref: http://www.unixwiz.net/techtips/x86-jumps.html je / jz 相同 / 為 0 jne / jnz 不同 / 不為 0 jb / jl 無符號 / 有符號 小於 ja / jg 無符號 / 有符號 大於 jnb / jnl 無符號 / 有符號 不小於 Jna / jng 無符號 / 有符號 不大於
array 79
array 80 sizeof int index assign
array 81 sizeof int index assign array 超出範圍, 依然照常編/組譯
struct 82 10
struct 83 10 Stack RSP -> int user[4] int room
info_struct local_info RSP+0x48 -> …
struct 84 10 Stack int local_info.id RSP+0x48 -> char local_info.name[10]
RSP+0x4C -> char *local_info.data RSP+0x58 ->
struct 85 10 Stack int local_info.id RSP+0x48 -> char local_info.name[10]
RSP+0x4C -> char *local_info.data RSP+0x58 -> Q: 為何不是 RSP + 0x56 呢 2 Bytes
struct • Struct alignment 86
Call function 87
x86 Calling Convention • 規定了呼叫函數時如何傳遞參數 • Windows • Function(rcx, rdx,
r8, r9) • Linux • Function(rdi, rsi, rdx, rcx, r8, r9) • 超過的參數會放到 stack 上 88
區域變數 vs 全域變數 89
區域變數 vs 全域變數 90 • 區域變數: 以 RSP 來定位 •
全域變數: 直接寫到特定位址
Lab: observe_c.exe 91 任務目標 • 觀察高階語言的各種語法轉換成 什麼樣的組合語言
Stack Frame • 函數都是以 RSP 來定位區域變數 • Q: 怎麼區別不同函數的區域變數? •
呼叫函數後, RIP 就從 A 函數跑到 B 函數了 • Q: 要怎麼 return 回 A 函數? 92
Stack Frame 93 Stack RSP RBP Stack[0]
Stack Frame 94 Stack RBP Stack[0] RSP
Stack Frame 95 Stack RBP Stack[0] RSP Stack[0]
Stack Frame 96 Stack RBP Stack[-0x8] RSP Stack[0]
Stack Frame 97 Stack RSP Stack of main RBP Stack[-0x8]
Stack[0]
Stack Frame 98 Stack RSP Stack of main RBP Stack[-0x8]
Stack[0] 快轉一下
Stack Frame 99 Stack RSP Stack of main RBP Stack[-0x8]
Stack[0]
Stack Frame 100 Stack RSP Stack of main RBP Stack[-0x8]
00000000 004015de Stack[0]
Stack Frame 101 Stack RSP Stack of main RBP Stack[-0x8]
00000000 004015de Stack[0]
Stack Frame 102 Stack RSP Stack of main RBP Stack[-0x8]
00000000 004015de Stack[0] Stack[-0x8]
Stack Frame 103 Stack RSP Stack of main RBP Stack[-0x48]
00000000 004015de Stack[0] Stack[-0x8]
Stack Frame 104 Stack RSP Stack of main RBP Stack[-0x48]
00000000 004015de Stack[0] Stack[-0x8] Stack of function_B
Stack Frame 105 Stack RSP Stack of main RBP Stack[-0x48]
00000000 004015de Stack[0] Stack[-0x8] Stack of function_B 快轉一下
Stack Frame 106 Stack RSP Stack of main RBP Stack[-0x48]
00000000 004015de Stack[0] Stack[-0x8] Stack of function_B
Stack Frame 107 Stack RSP Stack of main RBP Stack[-0x48]
00000000 004015de Stack[0] Stack[-0x8] Stack of function_B
Stack Frame 108 Stack RSP Stack of main RBP Stack[-0x8]
00000000 004015de Stack[0] Stack[-0x8] Stack of function_B
Stack Frame 109 Stack RSP Stack of main RBP Stack[-0x8]
00000000 004015de Stack[0] Stack[-0x8] Stack of function_B
Stack Frame 110 Stack RSP Stack of main RBP Stack[-0x8]
00000000 004015de Stack[0] Stack[-0x8] Stack of function_B
Stack Frame 111 Stack Stack of main Stack[0] RSP 比較一下
call 之前與 call 之後 RBP Stack[-0x8]
Stack Frame • 函數都是以 RSP 來定位區域變數 • Q: 怎麼區別不同函數的區域變數? •
呼叫函數後, RIP 就從 A 函數跑到 B 函數了 • Q: 要怎麼 return 回 A 函數? 112
Stack Frame • 函數都是以 RSP 來定位區域變數 • Q: 怎麼區別不同函數的區域變數? •A:
想辦法讓不同函數的 stack 區域不同 • 呼叫函數後, RIP 就從 A 函數跑到 B 函數了 • Q: 要怎麼 return 回 A 函數? •A: 在呼叫 B 函數前把下一條指令 push 進 stack B 函數以 ret 把 A 函數下一條指令從 stack pop 回 rip 進而回到 A 函數 113
Stack Frame 114 Stack RSP Stack of old function RBP
Return Address … Old RBP Stack of current function Old RBP
Lab: stack_frame.exe 115 任務目標 • 觀察 Stack frame 的變化 •
觀察遞迴函數 Stack frame 的 變化
動態分析 x64dbg/x32dbg Part2 溫馨提醒: 你看得到的東西幾乎都能強行修改 Register、Memory、Instruction … 116
Challenge: ezCrackme.exe 117 任務目標: 獲取 Flag (Flag 格式為 FLAG{…})
函式庫 Library 118
函式庫 Library • 把一堆函式打包在一起變成函式庫 • 程式可以用兩種方式連結函式庫 • Static Link 將程式用到的函式庫函數一起包到程式中
• Dynamic Link 將程式哪邊有用到函式庫函數記錄下來, 並且在執行階段時才把外部函式 庫加載進記憶體, 並進行連結 119
函式庫 Library 120 • Static Link 將程式用到的函式庫函數一起包到程式中
函式庫 Library • Dynamic Link 將程式哪邊有用到函式庫函數記錄下來, 並且在執行階段時才把外 部函式庫加載進記憶體, 並進行連結 121
函式庫 Library • Dynamic Link 將程式哪邊有用到函式庫函數記錄下來, 並且在執行階段時才把外 部函式庫加載進記憶體, 並進行連結 •
不同 OS 大同小異 • Windows: .dll (Dynamic-Link Library) kernel32.dll ntdll.dll msvcrt.dll • Linux: .so (Shared Object) libc-2.31.so libcrypto.so libssl.so 122
靜態分析 DLL • DLL 沒有 main, 但是有 DllMain (可有可無) •
看 export 哪些 functions • 看 exe 用到什麼 functions 123
靜態分析 DLL • 比如說這支 useDll.exe • Imports 了 HIDLL.DLL •
使用了此 DLL 的 YoDllFunc1 函數 124
靜態分析 DLL • 那就在把 HIDLL.DLL 拖進來分析 • 看 Exports 了哪些函數,
追蹤想追的函數 • DLL DLL, HIDLL.DLL OTHERDLL.DLL 125
動態分析 DLL • 把用到 DLL 的 exe 拉進工具裡 • 1.
斷點下在 exe 呼叫到 DLL 函數的位址 126
動態分析 DLL • 把用到 DLL 的 exe 拉進工具裡 • 2.
直接下在 DLL 函數位址 127
Challenge: useDll.exe 128 任務目標: 獲取 Flag (Flag 格式為 FLAG{…})
如何更快的進行逆向工程? 129
加快逆向工程 • 更快的找到關鍵程式碼 = 加快逆向工程, but HOW? • 1. 動態分析
call 函數, 觀察輸入輸出直接猜函數在做什麼 • 2. 若呼叫到特定函數, 則猜測為關鍵程式碼 • 3. 搜尋特定字串在哪邊有使用到 130
靜態分析: Ghidra Part2 搜尋字串: Search > For Strings … 131
靜態分析: Ghidra Part2 觀察字串在哪用到 132
Lab: DuRaRaRa 133 Lab 敘述: 此題為今年 AIS3 EOF 初賽的 Reverse
題目 PE 中還有一個 PE Lab 目標: 通過追蹤特定函數, 加快逆向工程, 最終把 PE 裡面的 PE 抓出來
Lab: DuRaRaRa 題目內容: - Cracked_IDA_PRO_7_5_SP3_installer.exe - secret.txt 134
Lab: DuRaRaRa 把題目拖進 Ghidra 後… 135
Lab: DuRaRaRa 找是哪邊呼叫到 VirtualAlloc • 對著 VirtualAlloc 右鍵 • Show
References to 136
Lab: DuRaRaRa 137
Lab: DuRaRaRa 138 在 0x403020 開始, 長度 0x5a492, 是另一個 PE
原程式用 VirtualAlloc + memcpy 把此 PE 複製到新位址 CreateThread 把新位址的 PE 給跑起來
Lab: DuRaRaRa 把從 0x403020 開始, 長度 0x5a492 的 Bytes 取出來
先 goto 0x403020, 用上面選單 Select > Bytes 選 Select Forward 139
Lab: DuRaRaRa 找到真正要 Reverse 的程式 此函數有用到 secret.txt 字串, 判斷為關鍵程式碼 140
阻止逆向工程? 141
Anti-Reverse Engineering • 加殼 • https://en.wikipedia.org/wiki/Executable_compression#DOS_executable • 加密 / 編碼
• Anti-Debug • https://github.com/LordNoteworthy/al-khaser • Self-modifying • https://en.wikipedia.org/wiki/Self-modifying_code • Manual Symbol Resolution • https://blog.christophetd.fr/hiding-windows-api-imports-with-a-customer-loader/ • https://www.ired.team/miscellaneous-reversing-forensics/windows-kernel-internals/exploring- process-environment-block • … 142
加殼 Pack • 把原本程式的機械碼壓縮, 並在 Entry Point 寫上解壓縮程式 • 原程式在執行時期才會被解壓縮並且運行
• 讓靜態分析變困難 • 著名的加殼器 (Packer): UPX • 需要脫殼 143 UPX 加殼後 Ghidra 認不出是 PE UPX 加殼前
Anti-Debug • 有一些方式能知道現在程式有沒有被 Debugger 監視著 • 方式很多, 簡報放不下 • 偵測到被
Debugger 監視, 那就不要執行特定行為 144
Self-modifying • 修改自己的機械碼 • 脫殼也是 self-modifying • 增加靜態分析難度 145
Manual Symbol Resolution • Windows 有一個酷酷的結構: PEB (Process Environment Block)
• 通過 PEB, 能找出所有已加載的 DLL 位址 • 通過爬 DLL 的 export table, 能找到此 DLL 支援的函數的位址 • 達到了 不在程式原始碼中呼叫 API 卻能呼叫 API 的目標 • 靜態分析工具自然解析不出呼叫了什麼 API 146
Manual Symbol Resolution 147
Manual Symbol Resolution 148 WinDbg 畫面
149
Manual Symbol Resolution • 怎麼拿到 PEB ? • https://en.wikipedia.org/wiki/Win32_Thread_Information_Block 150
Manual Symbol Resolution 151 PEB +0x018 Ldr _PEB_LDR_DATA +0x010 InLoadOrderModuleList
+0x020 InLoadOrderModuleList +0x000 Flink +0x008 Blink
_LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks +0x030 DllBase +0x058 BaseDllName _PEB_LDR_DATA Manual Symbol
Resolution 152 +0x010 InLoadOrderModuleList +0x020 InLoadOrderModuleList _LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks …… +0x030 DllBase +0x058 BaseDllName
Manual Symbol Resolution 153
Manual Symbol Resolution 154 _LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks +0x030 DllBase +0x058
BaseDllName DOS Header PE Header +0x03c e_lfanew DllBase + e_lfanew +0x088 Export Directory RVA Export Directory DllBase + Export Directory RVA +0x00c NAME +0x014 NumberOfFunctions +0x01c AddressOfFunctions +0x020 AddressOfNames
Manual Symbol Resolution 155 Export Directory +0x00c NAME +0x014 NumberOfFunctions
+0x01c AddressOfFunctions +0x020 AddressOfNames
Challenge: giveUflag.exe 156 任務目標: 獲取 Flag (Flag 格式為 FLAG{…})