---
# System prepended metadata

title: 2020 程安 Reverse筆記2
tags: [程式安全]

---

---
breaks: true
---

# 2020 程安 Reverse筆記2
###### tags: `程式安全`

## 如何恢復struct的member
### struct
- C用`malloc`來分配struct的空間
C++則是用`new`,差別是<font color='red'>`new`會自動幫你call constructor</font>

- 如果strip過後(指令`$ strip <binary>`),在c下面看起來就只是`malloc`了一個空間,但看不出來實際長甚麼樣子
![](https://i.imgur.com/pFuqwxI.png =500x)
    - 可在`v3`上按右鍵`reset pointer type`之後,再右鍵`create new struct type`,就可以變成下面這樣
    ![](https://i.imgur.com/6Mil92C.png =500x)
    - 這時`shift + F1`可以看到多出一個struct
    ```c=
    struct __attribute__((packed)) __attribute__((aligned(2))) struct_v3
    {
      char char0;     //1byte
      _BYTE gap1[3];  //下面dword 4byte對齊: +3byte
                      //把這個gap拔掉也不影響
      _DWORD dword4;  //4byte
      _WORD word8;    //2byte
                      //struct本身對齊2byte
    };                //共佔0xc=12byte
    ```

## 基礎分析技巧
1. `file <binary>`
    - base on `magic`
        - `man file`
        ![](https://i.imgur.com/yf7OiMf.png)
      
          > The information identifying these files is read from /etc/magic and the compiled magic file usr/share/misc/magic.mgc, or the files in the directory /usr/share/misc/magic if the compiled file does not exist.

        - `/usr/share/misc/magic.mgc`裡面定義了各種file的檢驗規則,用來判斷檔案型別
    - `man magic` : 定義了怎麼檢查
        - ex 
        ```!
         0             string  MZ
         >0x18         leshort <0x40
         >>(4.s*512)   leshort !0x014c MZ executable (MS-DOS)
         # if it's not COFF, go back 512 bytes and add the offset taken
         # from byte 2/3, which is yet another way of finding the start
         # of the extended executable
         >>>&(2.s-514) string  LE      LE executable (MS Windows VxD driver)
        ```
        > 檢查offset 0,為MZ
        > 繼續看offset 0x0 + 0x18 檢查一個short是否小於0x40,如果是繼續往下走,不是就找別的檢查規則

2. gdb
    - `gcc -g`會帶上symbol,debug時會有行號
    ![](https://i.imgur.com/qN2PcE8.png =500x)
    - 不小心`si`進到不想進的function,可以`fin`直接到結束的地方
    - 逆symbol strip掉的binary,如果已經恢復struct,但需要動態debug,如果member有linklist會很可怕
        - 可以先自己寫好struct,然後`gcc -g -c -o <name>.o`編譯起來
        `Note: -c表不要link`
        ```c!=
        #include <stdint.h>

        struct ss{
            char aChar; //1 byte
            int aInt;   //4 byte
            int16_t aInt16;//2 byte 4+4+2= 10, true= 12
        };

        struct ss any; //隨便宣告即可,重點是要讓type留著
        ```
        - 此時`objdump -t -M intel <file>.o`可以看到symbol table
        `Note: -t表顯示symbol table, -T表顯示動態dynamic symbol table`
        ![](https://i.imgur.com/T3QAbyh.png =500x)

        - gdb跑起來要逆的binary,在gdb cmd輸入`add-symbol-file <file>.o 0`
        `Note: 0代表從offset 0開始載`
            > `set $var1 = ...`可以自己設定值
            > `p $var1`可以印出值
            > - 假設在malloc之後`set $var1=$rax`,設定成malloc的空間ptr
            > 然後繼續執行直到要Print出時想看一下struct的值
            > 這時`p *(struct ss*)$var1`,
            > 該struct的所有值就會以struct的方式顯示
            ![](https://i.imgur.com/0F9FRCz.png =300x)

        - 

3. x64dbg
    - 想要監控某個memory位址甚麼時候會被存取
        - `右鍵->中斷點`: 可以設定記憶體被讀/寫/執行時中斷
        `Note: 原理是將該memory page設為不可讀/寫/執行,戳到時就會error,就可以被debugger抓到`
        ![](https://i.imgur.com/z19YPL6.png =500x)
        
    - 對應到gdb的 `watch(寫)`及`rwatch(讀)`
        - ex.此時已`malloc`完,回傳值放在`rax=0x80052a0`,我們要監控這個記憶體位址何時被寫
        ![](https://i.imgur.com/ZyZ1qbZ.png)
        `Note: Hardware point會斷在執行完之後`


## Anti-debug
### software斷點跟hardware斷點的差別
- Software斷點
    - 用x64dbg隨意下幾個斷點,然後用<font color='red'>Cheat Engine</font>打開, Memory View
    - 可以看到用x64dbg直接下software斷點的在memory上直接被改成`int3`
![](https://i.imgur.com/MIQFPJe.png)

- Hardware斷點
    - 若是在指令上`右鍵->中斷點->設定硬體執行中斷點`,則不會變成`int3`
    - 但硬體斷點最多只能下4個
        - x86提供DR0-DR7以及2個MSR暫存器用於hardware debug,其中只有DR0-DR3為硬體斷點暫存器
![](https://i.imgur.com/rUYk2wU.png)

:::info
- 惡意程式利用檢查自己.text段的memory是否有被修改就可以判斷是否在被debug
    - ex.把所有opcode相加,跟原本不一樣
- 因為硬體斷點不會修改,因此可以改用硬體斷點
:::

## 逆向的分析策略
1. 套用已知模型
    - ex.知道malware有哪些分類(fileless, 銀行木馬, keylogger, etc)
        - 就可以大概知道他可能會做什麼事

2. Magic Number
    - 有些常用算法有固定Magic Number
        - md5的狀態變量
            > A=0x67452301,
            > B=0xefcdab89,
            > C=0x98badcfe,
            > D=0x10325476
        - AES的s-box
        ![](https://i.imgur.com/KWQONkS.png)
        - DES的s-box
        ![](https://i.imgur.com/qioaPJu.png)

3. 預測程式碼 : 猜測程式可能在幹嘛
    - ex. 前面做了`md5_init`,又有輸入的地方,後面可能就是拿輸入做md5 hash

4. 抽象化

## PE format
- Windows使用PE(Portable Executable)做為執行檔格式
 Mac OS使用Mach-O
 Unix及Linux使用ELF(Executable Linkable Format)
 
- 可以用`010 editor`或`PE Bear`等PE viewer查看PE格式

- PE file = `DOS Header + DOS stub + NT Header + Section Headers + Sections` 
    ![](https://i.imgur.com/a66hK4O.png)

    ![](https://i.imgur.com/qE4snIP.png =300x)
    
### Dos Header
- 0x0 : 'MZ' 
- 最尾端4byte(`e_lfanew`) : 指向'PE'所在的offset
    ![](https://i.imgur.com/hxL9H8t.png)

### Dos Stub
- 裡面有一個'This program cannot run in DOS mode'的字串
![](https://i.imgur.com/KqRoGFW.png)
- 如果用dosbox開debug mode執行PE檔,會執行這邊的code,裡面真的是assembly code

### NT Header('PE' Signature + File Hdr + Optional Hdr)
- 從這邊開始才是給現在電腦在看的東西

- 如果有在Linux上裝`mingw-w64`,可以在`/usr/i686-w64-mingw32/include`下的`winnt.h`中看到`_IMAGE_NT_HEADER`的struct

#### File Header
![](https://i.imgur.com/4bDAdZN.png =500x)
- `Machine`: 記錄這個file在什麼樣的機器上跑
- `NumberOfSection`: 有幾個section
- `SizeOfOptionalHeader`: 紀錄Optional Header的size,
    - 正常來說,Optiona Header是一個c的struct,應該已經知道size,所以這個entry的存在意義(?
    - 結果變成可以利用的點,有些惡意程式會把Optional Header改大,然後在Optional Header的後面塞惡意code,但是這些code<font color='red'>並不會在parse header時被執行到</font>,還是要透過控制執行流程才能跳到這邊的code

#### Optional Header: 雖然是option但還是必選RRR
- `Magic`: 標誌位,但這邊指的是他是32還是64bit
- `AddressOfEntryPoint`: 程式進入點在文件中的offset
- `ImageBase`: mapping到記憶體上要從哪裡開始放
    - `ImageBase` + `AddressOfEntryPoint`才是程式執行起來之後的entry point 
- `FileAlignment`跟`SectionAlignment`
    1. `FileAlignment`:代表在file中,每個section要以`FileAlignment`對齊,不夠的地方會用`00 = NULL`補滿
        - ex 通常`FileAlignment` = 0x200
        ![](https://i.imgur.com/lqBrhWb.png =200x)

    2. `SectionAlignment`:mapping到記憶體上之後,每個section要`SectionAlignment`對齊
        - 為了方便設定每個section的`rwx`權限,通常會把同一個section放在一個page上,而一個page通常為4096byte = 0x1000,因此`SectionAlignment`通常設為0x1000
        ![](https://i.imgur.com/At91uaR.png)
        
- `SizeOfHeader`: Headers+NULL的大小,通常是0x400
- `NumberOfRvaAndSizes`: 通常是固定值 = 0x10
	- RVA是一個array,總共有0x10=16個值(其中第16個是reserved, 第15個是.NET header)
	![](https://i.imgur.com/SnjgXYx.png =400x)
	- ex. 想要找<font color='red'>import table</font>,在file offset 0x100的地方找到Import Directory的RVA=0x9000, <font color='blue'>加上`ImageBase`</font>之後就是memory中import table的位置


### Section Headers
有幾個section就有幾個section header,這些section header用一個array串起來
![](https://i.imgur.com/y5Utlb8.png =500x)

- `Raw Address` = `PointerToRawData`: section在file中的offset,為`FileAlignment`的倍數
- `Raw Size` = `SizeOfRawData`: 該section在file中的大小(`FileAlignment的倍數`)
- `Virtual Address`: 加上`ImageBase`就是section在memory中的address,為`SectionAligmnment`的倍數
- `Virtual Size`: 不包含NULL的section size

	![](https://i.imgur.com/tBhCj3e.png =600x)


### Section
:::info
1. `.text`
2. `.data`
3. `.rdata` : read only data 
	- ex. print出的字串
4. `.bss` : 沒初始化的全域或靜態變數
	- ex. `int i;`
5. `.idata` : import相關的
6. `.edata` : export相關的
`Note: 如果沒有.idata或.edata,可能被併在.data中`
7. `.rsrc` : 存放GUI相關的資源,定義在`winuser.h`中
8. `.reloc` : 重定位相關
9. `.pdata` : 跟例外處理相關
`Note: PE(32bit)沒有,PE+(64bit)才有`
:::

- 找Import在file中的位置
	- ex. 找KERNEL32.dll的位置
		`NameRVA` - `.idata`的`Virtual Addr` + `.idata`的`
PointerToRawData`
= 9994 - 9000 + 4E00 = 5794
	
		![](https://i.imgur.com/1qq5Oz1.png =400x)
		
		![](https://i.imgur.com/TGWOXY9.png =400x)

		可以`ctrl+G`跳到0x5794
		
		![](https://i.imgur.com/lbsdBwH.png =500x)
		
#### IAT(Import Address Table)
- 每個DLL都是一個`IMAGE_IMPORT_DESCRIPTOR`結構
`Note: 64bit的DLL放在System32, 32bit的DLL放在SysWOW64`
```c=
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
      __C89_NAMELESS union {
	DWORD Characteristics;
	DWORD OriginalFirstThunk; //指向INT
      } DUMMYUNIONNAME;
      DWORD TimeDateStamp;

      DWORD ForwarderChain;
      DWORD Name;
      DWORD FirstThunk; //指向IAT
    } IMAGE_IMPORT_DESCRIPTOR;
```

- `OriginalFirstThunk`: 指向`INT`,是一個array
	每個entry是一個`IMAGE_THUNK_DATA`結構
	其中的`AddressOfData`再指向一個`IMAGE_IMPORT_BY_NAME`結構
- `FirstThunk`: 指向`IAT`,每個entry也是`IMAGE_THUNK_DATA`結構,
<font color='blue'>初始化</font>時,`IAT`跟`INT`中的`AddressOfData`指向相同的`IMAGE_IMPORT_BY_NAME`結構
```c=
 typedef struct _IMAGE_THUNK_DATA32 {
      union {
	DWORD ForwarderString;
	DWORD Function;
	DWORD Ordinal;
	DWORD AddressOfData; //指向IMAGE_IMPORT_BY_NAME
      } u1;
    } IMAGE_THUNK_DATA32;
	
 typedef struct _IMAGE_IMPORT_BY_NAME {
      WORD Hint;     //函數編號
      CHAR Name[1];  //函數名稱
    } IMAGE_IMPORT_BY_NAME,*PIMAGE_IMPORT_BY_NAME;
```
 ![](https://i.imgur.com/zL65a1Z.png =500x)


