# Reverse :::danger 請愛惜共筆,勿進行惡意刪減 ::: [Slides](https://docs.google.com/presentation/d/1pnMSRhfC9tMg5CoRofIiF0VUH57Y47YF/edit?usp=sharing&ouid=101320963245090047568&rtpof=true&sd=true) [NISRA CTF](https://class.enlightened.nisra.net/) --- :::spoiler Table of Content [TOC] ::: > 虛擬機器 VirtualBox 全家桶 > 建議預留 40GB+ 硬碟空間 ~內附安裝說明~ > - [主載點](https://drive.google.com/drive/folders/14Qh5CmGSDODujndOMRWsL_LvdaCTrV-A?usp=sharing) > - [備用載點](https://drive.google.com/drive/folders/1OLpE-aaW7gVXrlfXjL_qEe1grPZ9iysC?usp=sharing) ## Intro -Reverse * 逆向工程 Reverse Engineering * 分析程式邏輯 * 修改程式邏輯 * E.g. * 破解付費軟體(Crack) * 遊戲外掛 ### 何謂逆向 * 跟著箭頭就會產生程式 ![程式產生](https://i.imgur.com/GwjBEWa.png) * 而從下逆向上去就是Reverse ### 需要先備知識/工具 * 基礎程式概念 * 程式邏輯 * 組合語言 * 工具 * PC * decompiler * 堅持下去的心 * 眼睛 ## 組合語言 Assembly * 看懂它 * 沒了 ![](https://i.imgur.com/9S9fgED.png) - 機器語言 - 組合語言 - 剩下的語言 ~C++,\ Java,\ Fortran...~ <!--hackmd 截圖上傳真的方便OuOb--> <!--同意。真香。--> - Assembly language - 副檔名: `.asm` `.s` ### 位元 bit > **B**inary Dig**it**s ### x86 vs x64 * x86 * 32位元暫存器 * Intel以前的處理器多以86作為產品編號末兩碼 ~例如8086~ * x64 * 64位元暫存器 ### 派系 Syntax * ==Intel== * `mov eax,16` * 主流 ==範例以此為主== * AT&T * `mov $16, %eax` ## Stack * 用來放資料的容器 * **L**ast **I**n **F**irst **O**ut ![](https://i.imgur.com/uG7Vazz.png) - Memory Layout - `system` 命令列參數、環境參數 - `stack` 區域變數 - ... - `heap` 動態配置變數 - `bss` 未初始化靜態變數 - `data` 已初始化資料變數 - `text` 程式原始碼 > 由高位址長到低位址 ### 副函式 [link : replit.com](https://replit.com/languages/c) ```c= #include <stdio.h> // 參數 Parameter // ↓ ↓ int plus(int a, int b){ int temp = a + b; // ↑區域變數 Local Variable return temp; } int main() { int result = plus(87, 87); printf("%d\n", result); return 0; } ``` <!--為甚麼這個筆可以這麼大xDD--> <!--資安女捷思不是我們可以質疑的(X--> | EBP -> | 內容 | |:------:|:------:| | | ... | | | 內容 | | ESP | 最下端 | - 呼叫慣例 Calling Convention ~的其中一種~ ```c= // 傳參數方向 // ← ← ← ← ← ← ← ← ← ← ← ← func(int a, int b, int c){ int local_var1; int local_var2; } ``` ↓轉成組語↓ ```asm= push c, b, a push return address push ebp_old ``` 拉出新空間 分配空間給`local _var1, local_var2` | Register | stack | |:---------------------------:|:--------:| | ^原^==**EBP**== >_ | main | | ↓ | c | | ↓ | b | | ↓ | a | | ↓ | ... | | ↓ | ret addr | | ^新^EBP, ^原^==**ESP**== >_ | ebp_old | | ↓ | ... | | ↓ | | | ^新^ESP >_ | | <!--ㄟ不是這個有點難表示--> <!--小畫家搞不好會比較快ww--> ![Imgur](https://imgur.com/o6fATFr.gif) <!--大概是這樣ㄇ--> ### 暫存器 * `EAX`, `EBX`, `ECX`, `EDX` * 32 bits > 今天以這編為主 * `Rxx` * 64 bits - `EBP` - base pointer - 指向第一個被push進stack的東西 - `ESP` - stack pointer - 指向最後一個被push 進stack的東西 - stack 頂端 - `EIP` - instruction pointer - 指向下一行要執行的程式碼 ### 基本指令 - `MOV` - `mov eax, tmp` - 把`tmp`放到`eax`裡 - `eax = tmp` - `eax`和`tmp`兩個size要一樣 ex. 32bit ⇆ 32bit , 64bit ⇆ 64bit - `MOVZX` - `movzx eax, tmp` - 把`tmp`放到`eax`裡 - `eax = tmp` - `eax`和`tmp`兩個size可以不一樣 ex. 64bit ← 32bit - `add eax, ebx` - 相當於`eax = eax + ebx` - `sub eax, ebx` - 相當於`eax = eax - ebx` ### Array |Array Elements→| 29 | 17 | 42 | 13 | 56 | |-|:---:|:---:|:---:|:---:|:---:| |Array Indices→| 0 | 1 | 2 | 3 | 4 | ### 組合語言-定址模式 - addressing mode定址模式 - `mov esi,offset arrA` - `[esi]` - arrA[0] - `[esi + 4]` - arrA[1] ~32\ bits~ ### 進階指令 - `push` - `push eax` - 把 eax push 到 stack 的頂端 - `pop` - `pop ebx` - 把 stack 頂端的東西 `pop` 到 `ebx` 裡 - 呼叫副程式 - `call <label>` - `push eip + 4` + `jmp <label>` - 存回來的位置 + 跳到副程式 - `ret` - `pop eip` 後跳到 eip 的位址 - `return` - `cmp` - `cmp eax, ebx` - eax-ebx的值去調整flag - Flags - Zero flag `ZF` - 當前指定進行計算後結果為0 - 則ZF=1 - Sign flag `SF` - 當前指令進行計算後結果為負 - 則SF=1 - Overflow flag `OF` - OF = 1 當前指令計算後 overflow - Carry Flag `CF` - 如果carry - 跳轉指令 - JZ, JE - jump if ZF=1/equal - JNZ, JNE - jump if ZF = 0/not equal - JG > - jump if greater - JGE >= - jump if greater or equal - JL < - jump if smaller - JLE <= - jump if smaller or equal ### Lab 0x2 (? ```asm= mov eax, 1 mov ebx, 2 cmp eax, ebx jz L1 ; je L1 add eax, 2 jmp after_L1 L1: add ebx, 2 after_L1 inc eax ``` 求`eax`、`ebx`的值? > tips : `inc eax` => eax + 1 ### Lab 0x3 ```asm= mov eax, 1 mov ebx, 2 cmp eax, ebx jz L1 ; je L1 add eax, 2 L1 : add ebx, 2 after_L1: inc eax ``` 求`eax`、`ebx`的值? > tips : Line 5 做完接著做 L1 > 以此類推 ### Lab 0x4 ```asm= ; 預設 esi 裡 ; 已經放了 arr 的開頭位址 ; arr[0] = 0 mov eax, 0 cmp eax, [esi] jz L1 ; je L1 add eax, 2 jmp after_L1 L1: inc [esi] after_L1: ... ``` 求`eax`、`[esi]`的值? > tips : \[esi\] = arr\[0\] <!----> ## Reverse - `file <Filename>` - 32 / 64 bit - dynamic / static linked - stripped / not stripped - 靜態分析 - 分析時沒有執行 - 分析程式碼、組合語言、static data - Patch instruction - Tools - objdump - `objdump -M Intel -d <File>` - IDA Pro - 貴鬆鬆 - ghidra - National Security Agency - JAVA - **免費** - 動態分析 - 邊執行邊分析 - 分析當下的 register 和 memory - Tools - gdb - **G**NU **D**e**b**ugger - peda ~~讓人生變彩色的~~ ###### tags: `Enlightened` `NISRA` `2021` <style> .navbar-brand::after { content: " × NISRA"; } </style>