x86 Assembly

Reverse

sicc

Outline

  • reverse

  • x86 assembly

Reverse

  • 將執行檔盡可能地還原成程式碼,以利我們去分析程式的演算法與 function

Reverse

  • 將執行檔盡可能地還原成程式碼,以利我們去分析程式的演算法與 function

那如果你問 ChatGPT 他會怎麼回答

Reverse

  • 將執行檔盡可能地還原成程式碼,以利我們去分析程式的演算法與 function

那如果你問 ChatGPT 他會怎麼回答

Reverse

  • 將執行檔盡可能地還原成程式碼,以利我們去分析程式的演算法與 function

那如果你問 ChatGPT 他會怎麼回答

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

Assembly - Registers

此圖擷取自網路

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

Assembly - Instructions

  • add
    • add dest, source
      • source : 來源
      • dest : destination 目標

Assembly - Instructions

  • sub
    • sub dest, source
      • source : 來源
      • dest : destination 目標

Assembly - Instructions

  • sub
    • sub dest, source
      • source : 來源
      • dest : destination 目標

Assembly - Instructions

  • inc
    • inc dest
      • dest : destination 目標

Assembly - Instructions

  • dec
    • dec dest
      • dest : destination 目標

Assembly - Instructions

  • Label

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

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 的號碼為準
  • quit (q) 離開 gdb

Lab 0x2

Reverse - 靜態分析

  • 分析時沒有執行
  • 單純從程式碼、組合語言、static data 分析
  • ghidra
    • 免費的最讚
  • IDA
    • 要錢錢

x86 Assembly

By sicc

x86 Assembly

  • 134