x86 Assembly
Reverse
sicc
Outline
-
reverse
-
x86 assembly
Reverse
- 將執行檔盡可能地還原成程式碼,以利我們去分析程式的演算法與 function
Reverse
- 將執行檔盡可能地還原成程式碼,以利我們去分析程式的演算法與 function
那如果你問 ChatGPT 他會怎麼回答
Reverse
- 將執行檔盡可能地還原成程式碼,以利我們去分析程式的演算法與 function
那如果你問 ChatGPT 他會怎麼回答
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10278680/pasted-from-clipboard.png)
Reverse
- 將執行檔盡可能地還原成程式碼,以利我們去分析程式的演算法與 function
那如果你問 ChatGPT 他會怎麼回答
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10278683/pasted-from-clipboard.png)
Reverse
機器語言
組合語言
高階語言
C,C++,python
難懂,接近硬體
01 01 10 11 01 00
好懂!
組譯器
編譯器
Reverse
- 編譯 Compile
- 將原始碼轉換成電腦能執行的程式
- 組譯 Assembly
- 將組語組譯成執行檔
原始碼
編譯
組譯
執行檔
Reverse
- 反編譯 Decompile
- 把程式翻譯成虛擬碼 Pseudocode
- 反組譯 Disassembly
- 將執行檔轉為組合語言
原始碼
反編譯
反組譯
執行檔
x86 Assembly
Assembly
-
機器語言
- 00 01 10 11
-
組合語言
- mov eax,16
Assembly
-
x86
- 32 位元暫存器
- Intel 以前的處理器大多以 86 為其產品編號的末兩碼
-
x64
- 64 位元暫存器
Assembly - Registers
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279055/pasted-from-clipboard.png)
Assembly - Registers
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279056/pasted-from-clipboard.png)
此圖擷取自網路
Assembly - Flags
- 也是 Register 的一種
- 用來儲存指令運算完的結果
-
Zero flag (ZF)
- 運算結果為0 : ZF = 1
- 運算結果為1 : ZF = 0
-
Sign flag (SF)
- 正數 : 0 負數 : 1
- 數字在二進位表示法的第一個 bit
Assembly - Flags
- Carry flag (CF)
- 無號數運算溢位時 CF = 1 反之為 0
- Overflow flag (OF)
- 有號數運算溢位時 OF = 1 反之為 0
Assembly - Instructions
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279142/pasted-from-clipboard.png)
Assembly - Instructions
- add
- add dest, source
- source : 來源
- dest : destination 目標
- add dest, source
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279159/pasted-from-clipboard.png)
Assembly - Instructions
- sub
- sub dest, source
- source : 來源
- dest : destination 目標
- sub dest, source
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279164/pasted-from-clipboard.png)
Assembly - Instructions
- sub
- sub dest, source
- source : 來源
- dest : destination 目標
- sub dest, source
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279164/pasted-from-clipboard.png)
Assembly - Instructions
- inc
- inc dest
- dest : destination 目標
- inc dest
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279173/pasted-from-clipboard.png)
Assembly - Instructions
- dec
- dec dest
- dest : destination 目標
- dec dest
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279220/pasted-from-clipboard.png)
Assembly - Instructions
- Label
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279287/pasted-from-clipboard.png)
Assembly - Instructions
- cmp
- cmp a, b : 看 a - b 的結果,但a b 值不會被重寫
- 比較兩數值的大小
- 前面減後面但結果不會寫回暫存器
- 會影響 flag 的數值,搭配 jmp 等跳轉指令
- 例如:
- a = 1 & b =1
- cmp a, b
- 因為 a - b = 0
- Zero flag (ZF) 被設定
Assembly - Jump
- JMP
- JMP label
- 直接跳到 label (不需要任何條件)
- JZ, JE
- jump if ZF = 1/ equal
- JNZ, JNE
- jump if ZF = 0/ not equal
Assembly - Jump
- JG
- jump if greater (>)
- JGE
- jump if greater or equal (>=)
- JA (無號數運算)
- jump if above
- JAE (無號數運算)
- jump if above or equal (>=)
Assembly - Jump
- JB (無號數)
- jump if below (<)
- JBE (無號數)
- jump if below or equal (<=)
- JL
- jump if less (<)
- JLE
- jump if less or equal (<=)
Lab 0x0
L1:
mov eax, 3
mov ebx, 5
add eax, 1
dec ebx
cmp eax, ebx
jg equal
jmp not_equal
equal:
add ebx, 7
jmp end
not_equal:
add eax, 10
inc ebx
end:
Lab 0x0 solution
L1:
mov eax, 3 ; eax = 3 ebx = 0
mov ebx, 5 ; eax = 3 ebx = 5
add eax, 1 ; eax = 4 ebx = 5
dec ebx ; eax = 4 ebx = 4
cmp eax, ebx
jg equal ; 因為 eax = ebx 所以不跳轉
jmp not_equal ; 跳轉到 not_equal
equal:
add ebx, 7
jmp end
not_equal:
add eax, 10 ; eax = 14 ebx = 4
inc ebx ; eax = 14 ebx = 5
end:
Lab 0x1
L1:
mov eax, 3
mov ebx, 5
add eax, 1
dec ebx
cmp eax, ebx
jg L3
L2:
add eax, 10
inc ebx
L3:
add ebx, 7
嘗試把它寫成我們的高階語言
Lab 0x1
#include <bits/stdc++.h>
using namespace std;
int main(){
int eax = 3;
int ebx = 5;
eax +=1;
ebx--;
if(eax <= ebx){
eax += 10;
ebx ++;
}
ebx +=7;
}
Lab 0x1
L1:
mov eax, 3 ; eax = 3 ebx = 0
mov ebx, 5 ; eax = 3 ebx = 5
add eax, 1 ; eax = 4 ebx = 5
dec ebx ; eax = 4 ebx = 4
cmp eax, ebx
jg L3 ; eax = ebx 所以不跳轉
L2:
add eax, 10 ; eax = 14 ebx = 4
inc ebx ; eax = 14 ebx = 5
L3:
add ebx, 7 ;eax = 14 ebx = 12
Assembly - call & ret
- 概念類似 C 語言的 function
int main(){
int a = 1 , b = 2;
function(a,b);
}
但要怎麼在記憶體中實作呢?
Assembly - call & ret
- 概念類似 C 語言的 function
int main(){
int a = 1 , b = 2;
function(a,b);
}
但要怎麼在記憶體中實作呢?
Assembly - Stack
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/10279441/pasted-from-clipboard.png)
Assembly - Stack
1
2
3
Assembly - Stack
1
2
3
Assembly - Stack
1
2
3
Assembly - Stack
1
2
Assembly - Stack
1
Assembly - Stack
- 一段連續的記憶體空間由高位址長向低位址
- 由 esp,ebp 兩個暫存器,指向位置之間的記憶體空間
- 只對 top 做操作
C Calling Convention
C Calling Convertion
High address
Low address
ebp
esp
stack
frame
- 對 Top 做操作
- 插入或刪除元素時
只能在 esp 插入或刪除
- 插入或刪除元素時
C Calling Convertion
High address
Low address
ebp
esp
- push
- 把值放入 stack 中 (esp)
- push eax
- eax 的值會被放入 esp
0x12345678
0x97658364
push 0x87654321
C Calling Convertion
High address
Low address
ebp
esp
- push
- 把值放入 stack 中 (esp)
- push eax
- eax 的值會被放入 esp
0x12345678
0x97658364
push 0x87654321
0x87654321
C Calling Convertion
High address
Low address
ebp
esp
- pop
- 把 stack 中 top 的值取出
- pop
- 將 stack 最頂的值放入 eax
0x12345678
0x97658364
pop
0x87654321
C Calling Convertion
High address
Low address
ebp
esp
- pop
- 把 stack 中 top 的值取出
- pop
- 將 stack 最頂的值放入 eax
0x12345678
0x97658364
pop
eax : 0x87654321
Text
Assembly - Stack
void add(int a,int b){
a = a + b;
}
int main(){
int a = 1, b = 2;
add(a,b);
cout << a << " " << b << endl;
}
Assembly - Stack
void add(int a,int b){
a = a + b;
}
由右至左 push 參數
push b
push a
call add
Assembly - Stack
void add(int a,int b){
a = a + b;
}
mov eax , b
add eax ,a
mov a, eax
ret
Big/Little Endian
Big/Little Endian
- 假設有一個資料為 0x12345678
Big
Endian
Little
Endian
High address
Low address
0x78
0x56
0x34
0x12
0x12
0x34
0x56
0x78
Big/Little Endian
- 假設有一個資料為 0x12345678
-
Big Endian
- 0x12345678
-
Little Endian
- 0x78563412
Reverse
-
動態分析
-
靜態分析
Reverse - 動態分析
- 在程式執行的時候一邊分析程式當下運行的情況
- 分析暫存器、記憶體等元件的變化
- gdb
- GNU Debugger
- 只有文字
- 有 peda 插件
Reverse - gdb
-
gdb filename 用 gdb 開啟 file
-
r
un使程式跑起來,跑到第一個中斷點
或程式結束
-
b
reak 設立新斷點
- break *address
- break *function_name
-
Info function
- 顯示所有的 function
Reverse - gdb
-
ni
nexti 執行下一行指令
-
si
stepi 進入 function call
-
c
ontinue 繼續執行到下一個斷點或結束
-
disas
semble function 反組譯某函式
- Info register 顯示所有暫存器
Reverse - gdb
-
set * address = value
-
set $register = value
- info break ( i b ) 下過的中斷點訊息
- delete ( del )清除所有中斷點
- del num 刪除特定中斷點
- num 依據 i b 的號碼為準
- del num 刪除特定中斷點
- quit (q) 離開 gdb
Lab 0x2
![](https://s3.amazonaws.com/media-p.slid.es/uploads/2146226/images/11202184/1710831987969.png)
Reverse - 靜態分析
- 分析時沒有執行
- 單純從程式碼、組合語言、static data 分析
- ghidra
- 免費的最讚
- IDA
- 要錢錢
x86 Assembly
By sicc
x86 Assembly
- 137