---
# System prepended metadata

title: 0x01. Windows Internal Basics & Assembly
tags: [Malware Analysis, Reverse Engineering, tutorials]

---

# 0x01. Windows Internal Basics & Assembly
 
[TOC]
 
## Virtual Memory

一般我們看到的Windows操作系統，都是在User Mode底下的
- 滑鼠/鍵盤
- 瀏覽器
- Office
- 遊戲
- ....

相對的，在我們看不到的底層系統運作稱為Kernel Mode

如下，每個程式可以稱之為Process，Process範圍包含User Mode/Kernel Mode
- 小算盤
- 瀏覽器
- 資料夾

當每個Process執行時，以32位元系統來說會被分配4GB的Ram給Porcess (User/Kernel 各2GB) 

64位元則是分配8/248 TB



|     | 32位元                    | 64位元                                      |
| --- | ------------------------- | ------------------------------------------- |
| User Mode Address  | 0 - 0x7fff ffff           | 0 - 0x7ff ffff ffff                         |
| Kernel Mode Address  | 0x8000 0000 - 0xffff ffff | 0xffff 0800 0000 0000 - 0xffff ffff ffff ffff |

<br>

電腦真的有這麼大的 RAM????


沒有，32位元為例，User Mode中的這2GB是虛擬的，並不會真正佔用這麼多，而Kernel mode是所有processes共用2GB的記憶體

![](https://i.imgur.com/krI4E8c.jpg)


....

<br>

主要提的會以User Mode為主

<br>

## PE Intro
### PE Structure

PE: Portable Executable，常見的exe檔案是PE, DLL(待會會提到)也是PE的一種
有自己特別一套架構，跟依照的規範

既然目標是做逆向工程，所以得了解一下PE檔案的架構

針對PE檔案，可以用PE View/CFF Exploror等工具來觀測裡面的資料

### Magic Bytes

在惡意程式分析的時候，常常會遇到一種狀況
攻擊者在一個PE檔案裏面嵌入了另一個PE檔案，等待主檔案執行後釋放出內嵌的exe檔案

下列的特殊字元能幫助識別是否有新的內嵌PE檔案出現在Memory/檔案之中，稱之為Magic byte

DOS Header: 0 -> 5A 4D (MZ - Little Endian)
PE Offset: 0x3C -> 0xF0 

**再強調一次，這些是微軟定義的**

![](https://i.imgur.com/flb3arQ.png)

----

### PE Signature

0xF0的Offset -> 45 50 (PE - little endian)

![](https://i.imgur.com/fAthLIX.png)

----

### Sections

PE檔案當然會帶有更多的東西，包含以下，我們用section來區隔，每個section有不同的功用

.text:  程式碼
.idata: import library列表
.edata: export library列表
.data:  Global variable
.rsrc:  程式需要的額外資源

![](https://i.imgur.com/a9maP8q.png)

----

### Example
來看看人家WannaCry的資源放了什麼

MZ?? PE????(圖中A4 A5, 19C 19D)
裡頭塞個PE檔

![](https://i.imgur.com/W5jDZqU.png)



---
### PE Map to Memory

承一開始所說的虛擬位址概念(User Mode 2GB)，PE檔案裡面也會標示Sections對應到Virtual Memory的位址


![](https://i.imgur.com/JaW0VbO.png)


大概是這樣子
![](https://i.imgur.com/yKNj1aV.png)

再對照一次
Virtual Size: 程式執行放到memory大小，在Debugger裡面也會看到一樣大小
Virtual Address: 在Debugger中，距離Base Address的Offset 
Raw Size: PE檔案該Section真實大小
Raw Address: PE檔案該Section的Offset
![](https://i.imgur.com/a9maP8q.png)


**[大神PE詳細講解](https://ithelp.ithome.com.tw/articles/10187490)**

<br>

## DLL vs EXE

DLL: 純Library，無法點兩下就自己跑
EXE: 執行檔，會需要DLL的幫忙來執行各種功能

<br>


## 初探程式執行的方式

一般想要執行程式如小算盤，通常就是點兩下然後小算盤就出現了

你可以做加加減減，可是，實際到底做了些甚麼事情呢?

一開始的小算盤可能是用C++編寫，經過compile(編譯)之後，會變成shellcode(機械碼)的形式，其實就是hex number

剛剛看到了每個程式，包含小算盤都會有`.text` section，儲存程式碼的section，裡面儲存就是很多的Hex number format

當程式開始執行後，CPU會解讀`.text`的這些Hex number，搭配對應的指令集去做運算

但是人類無法看懂Hex number，所以需要使用Disassembly等工具，將Hex number轉譯成看得懂的assembly code(組合語言)

<br>

## Registers

為何需要Register?

程式執行時，假設2+3
2跟3都要存在某個地方，讓CPU來相加，暫存2,3的地方就是暫存器

```
R開頭: 64位元
E開頭: 32位元

R(E) IP: 指到下一個即將被執行的指令

R(E) AX：加減乘除 - 尾 / Function return
R(E) BX：用於陣列的某Offset
R(E) CX：計數器
R(E) DX：加減乘除 - 頭

R(E) SI：陣列Copy - Source
R(E) DI：陣列Copy - Destination

R(E) BP：Stack Base
R(E) SP：Stack Top

R8 - R15: 64位元獨有，提供額外空間
```

<br>

長度 (RBX/RCX/RDX也可套用)
```
                   RAX       
0000 0000 0000 00 0  0

                   EAX
          0000 00 0  0
          
                    AX
               00 0  0
               
                    AH
                  0 
                    AL
                     0 
```

---

### Flag

在程式執行時，除了Register之外，還有一個叫Flag的東西紀錄程式的狀態

```
Set: 1
Not set/clear: 0

ZF (Zero Flag) : 剛剛做的Assembly運算後為0?
CF (Carry Flag): 在進行加法或減法運算時，如果產生了進位或借位，有就Set
SF (Sign Flag) : 運算結果是否為負數？
```

[這邊有大神對Flag的介紹](https://godleon.blogspot.com/2008/02/comparisons-assembly-cmp-cmp-cmp-vleft.html)

<br>

## Stack

單純依賴Register做程式計算資料的暫存是不夠的
Windows引進了Stack的概念，stack其實只是一塊記憶體，供程式隨時取用

他的特性以其取用方法如下

1. 後進先出
2. Function 變數 **(32位元 Only)**
3. push 向上增長(位值變小)
4. pop  向下增長(為值變大)
5. Pop/Push 才能改變
6. pop eax = copy esp value to eax, and esp - 4 

<br>

## Assembly

雖然假設看本系列的人有一定組合語言基礎，但還是介紹一下常見到的指令以及概念

程式透過編譯器，變成機械碼(真正儲存在執行黨內的東西)
分析師透過反彙編器(IDA/GDB..)打開，看到的是組合語言

```
           Compiler   EXE    Disassembler
C code        ->     機械碼      ->    逆向時所看到的組合語言
int a;         |   55           |     push ebp
printf('bla'); |   8B EC        |     mov ebp, esp    
return 0;      |   ........     |     .....
```

機械碼 VS 組合語言
```
B9       42 00 00 00  ; little endian
mov ecx, 0x42
```

一些常見組合語言，以32位元，intel架構為例
```
mov eax, 0x20 ;  rax = 0x20
mov eax, [0x11223344]  ; 將存在0x11223344的東西 copy到rax

add eax, 1    ; eax += 1
inc eax       ; eax += 1 比上面的好，因為機械碼會比較短
dec eax       ; eax -= 1
sub eax, 0x10 ; eax -= 10
add eax, ebx  ; eax = eax + ebx

mul 0x50      ; eax = eax * 0x50  結果會以 edx:eax格式儲存
div 0x50      ; edx:eax / 0x50    eax = 商, edx = 餘數

and eax, ebx  ; eax = eax && ebx
xor eax, eax  ; eax = eax (xor) eax, 一種快速將eax設為0的方法
xor eax, 0x20 ; eax = eax (xor) 0x20, 常用於加密字串避免被在靜態分析時被發現
or eax, 0x20  ; eax = eax || 0x20

shl eax, 1    ; 10110001 左移變成 01100010, CF set
shr eax, 1    ; 10110001 右移變成 01011000, CF set
              ; 根據被移除位是否為1來規範CF flag

rol eax, 1    ; 10110001 轉圈左移變成 01100011, CF set
ror eax, 1    ; 10110001 轉圈右移變成 11011000, CF set

jz            ; 如果 Zero Flag（ZF）設置（即為1），則跳轉到指定的程式碼位置。ZF通常在前一個指令比較或測試兩個值並且結果為零時設置。
jnz           ; 如果 Zero Flag（ZF）未設置（即為0），則跳轉到指定的程式碼位置。
je            ; 與 jz 指令相同，如果 Zero Flag（ZF）設置（即為1），則跳轉到指定的程式碼位置。
jg            ; 如果前一個 cmp 或 sub 指令的結果顯示第一個操作數大於第二個操作數（並且沒有發生溢出），則跳轉到指定的程式碼位置。

cmp eax, ebx  ; eax - ebx, 用flag保留運算結果, eax值不會更改 
              ; if eax == ebx -> ZF set 1 
              ; if eax != ebx -> ZF set 0


push eax      ; push eax's data to top stack,   esp = esp - 4
pop eax       ; pop data from top stack to eax, esp = esp + 4

pushad        ; 將 eax,ecx,edx,ebx,esp,ebp,esi,edi 依序push進去stack
popad         ; 將 stack 依序pop回edi,esi,ebp,esp,ebx,edx,ecx,eax 
              ; 常常用在 packer 上面，保存原本程式暫存器的數值

ret           ; pop eip(there's no such instruction)
nop           ; do nothing, good for padding
```
<br>

## Calling Convention ( _stdcall )

在組合語言中，與一般寫程式無異，都需要有function的存在來幫助程式做重複性的工作
有function就必定會有argument要傳進子function，但是32/64位元的方法有點不一樣

32位元：利用Stack保存進入Function
64位元：主要利用Register保存 RCX, RDX, R8, R9, Stack

return value: RAX/EAX

下列是個32位元小程式，以及他對應的assembly
```
int test(int a, int b)
{
  int x, y
  x = a;
  y = b;
  return 0;
}

int main()
{
  test(2,3);
  return 0;
}
```

```
main:

101 push 3
102 push 2
103 Call test     ; 偷偷做push 104 (return address)
104 add esp, 0x08 ; 恢復先前因push而被減掉的stack
105 xor eax, eax  ; main's return 0

test:

200 push ebp               ; 保存Main EBP值
201 mov ebp, esp           ; 創造新的Stack, EBP 變小 往上跑
202 sub esp, 0x08          ; 為新的Stack開 Local buffer

203 mov eax, [ebp+0x08]    ; eax = 3
204 mov [ebp-0x04], eax    ; store to local variable
205 mov eax, [ebp+0x0c]    ; eax = 2
206 mov [ebp-0x08], eax    ; store to local variable

207 xor eax, eax           ; eax = 0, test's return 0
208 mov esp, ebp           ; 還原原本 ESP
209 pop ebp                ; 還原原本EBP
20A ret 8                  ; return 2個參數下面存的return address

```
<br>

Example stack layout
```
After execution to 206, what stack looks like

|Address|      Value     |
--------------------------
|  10   |        2       |<- EBP - 0x08 / New ESP ; 202 sub esp, 0x08 ; 206 mov [ebp-0x08], eax
|  14   |        3       |<- EBP - 0x04           ; 204 mov [ebp-0x04], eax 
|  18   |     old rbp    |<- EBP                  ; 200 push ebp      ; 201 mov ebp, esp
|  1c   | return address |              ; 103 Call test 
|  20   |        2       |<- EBP + 0x04 ; 102 push 2
|  24   |        3       |<- EBP + 0x08 ; 101 push 3

```
<br>

**重點：**
確保Stack用完後，ESP/EBP回到原本值
Stack被使用後並不需要清除成0
```
EBP + 0x08 : Main's argument
EBP - 0x04 : test's local variable
```

64位元的傳值方法不是透過push/pop，而是透過register

還是沒有看懂？
沒關係，這邊有30cm大神的文章 [更多資源](https://speakerdeck.com/aaaddress1/binary-ninja-101-windows-binary-reversing-from-zero-to-master)

<br>



更多資訊可以從[秋聲大神的書](https://www.books.com.tw/products/0010750587)找到，相當推薦

至於識別一些常見的C語言結構，也可以參考 [惡意代碼分析實戰](https://www.books.com.tw/products/CN11109741) 第六章


---

上述的大概就是要進入逆向工程的一些前置知識，下一篇會介紹在開始分析惡意程式之前所需要的環境

<br>

[-0xbc](https://hackmd.io/@0xbc000)
###### tags: `Malware Analysis` `Reverse Engineering` `tutorials`



