---
# System prepended metadata

title: Malware Analysis
tags: [security]

---

---
title: Malware Analysis
description: AIS3 寒假課程，由 adr 主講
tags: security
lang: zh_tw
---

# Malware Analysis
[TOC]

# Tools
- PEview
    - 開 COFF file
- PEbear (v0.3.9.7)
    - 開 exe
- PEstudio
    - 打包疑似惡意程式會用到
- AutoRuns
    - 可簡單檢查 Windows 註冊表
- Process Monitor
    - 紀錄以及查看所有讀寫註冊表、File system、創造子程序的活動
- 火絨劍
    - 前幾個的合體
    - 雖然是中國製造就是ㄌ

# Compiler
- .rdata
    像是字串這種 const 會放在此
- .idata
    Import Address Table, 引用的外部函數會存在此表
    組語中用 ds(data segment register) 指向此表
- .text
    程式碼部分存放在此
- .data
    可修改的全域變數


## gcc
- `gcc -S gg.c -masm=intel`
    Compile only
    生出 assembly code
- `gcc -c gg.s`
    Compile and assemble, but don't link
    生出 object file

### look into assembly code
- `.section .rdata,"dr"`
    設定 .rdata 為唯讀

- `FLAT:LC1`
    TBD. 這 FLAT 是啥

## COFF Obj File
可以用 PEview 觀察 COFF object file
- IMAGE_FILE_HEADER
    Machine: 014c 表示 32bits
    NumberOfSections: 保存著有幾個 SECTION
- IMAGE_SECTION_HEADER
    是一個 IMAGE_SECTION_HEADER 陣列
    用 IMAGE_FILE_HEADER 保存的幾個 SECTION 的資訊
    可以簡單列舉所有 SECTION
    若沒有此 SECTION (e.g. 沒有 .data 段)
    則會 mapping address 0
- SECTION
- IMAGE SYMBOL TABLE
    可從此找到引用的外部函數

## exe file
- DOS Header
    MZ 字串開頭
- DOS stub
- NT Headers
    - Signature
        - PE 字串開頭
    - File Header
        - 就像 COFF 的 IMAGE_FILE_HEADER
        - Misc(VirtualSize): 要申請多大虛擬記憶體
        - VirtualAddress: 預期擺放到哪個記憶體地址
        - SizeOfRawData: 要擺多少資料上去記憶體
        - PointerToRawData: 要從這 exe file 的哪裡把資料擺上記憶體
        - 擺上記憶體的行為有個專有名詞 **`File Mapping`**
    - Optional Header
        - PE 結構特有欄位
        - entry pointer, 32bits/64bits, Image base 都放在此
- Section Header Array
    - 就像 COFF 的 IMAGE_SECTION_HEADER

## Windows Process
- [推薦閱讀1](https://www.cnblogs.com/qyun/p/6675062.html)
- [推薦閱讀2](https://forcemz.net/windows/2018/12/01/PrivexecNew/)
- Parent Process 權限多高, Child Process 權限就多高

![](https://blog-10039692.file.myqcloud.com/1490956886477_3643_1490956887033.jpg)

> 把 Process 當成挫冰碗 
> [name=adr]

- (B.) Child Process Created
    剛創出執行緒, 並將 entry pointer 指向 RtlUserThreadStart
    目的是修正 import function table
    
- (C.) RtlUserThreadStart
    - LdrInitializeThunk
        - LdrpInitializeProcess
    這些 function 不只修 import function table, 也有跟 **windows shim** 有關的機制
    - [shim 衍生閱讀](https://www.freebuf.com/articles/system/114287.html)
- (D.) Jmp to program

### Threads
- TEB
    - 用 fs:[0x18] 存取 TEB
    - 一個 process 中可多個 threads, threads 資訊由 TEB 紀錄
- PEB
    - fs:[0x30]

### Process Hollowing
創好 process 後, 把 text 段替換為惡意程式

```
CreateProcessA(path, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)
```
- 創造 Process 但先不執行
- 任何 memory mapping 操作都還沒做

```
VirtualAllocEx
```
分配虛擬記憶體

```
WriteProcessMemory
```
寫入 Memory

### IFEO (Image File Execution Options)
改註冊表 AeDebug 讓在 cmd 原本執行 a.exe 實際上變成執行 b.exe

# IDA trick
## main / WinMain
- [WinMain](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-winmain)
    - Bonus Keyword: WinExec
    - nShowcmd: 是否有視窗

:::info
main: 跳出小黑窗 terminal
WinMain: 跳出現代視窗 or 什麼視窗都沒有
:::

一開始入口點 start 會執行 CRTStartup
接著用 `cmdln` 獲取指令列
會執行 msvcrt.dll 提供的 `__getmainargs`
此 function 用來 parse 餵給 main 的三參數: argc argv envp
若是 WinMain 則會有四參數(請閱 M$ Manual)

找 main / WinMain 方式:
從 CRTStartup 追進去, 找到一個 function 符合以下
- 吃三個參數 (合理懷疑是 argc argv envp)(或四個)
- 回傳值會丟給 exit

他八成是 main

## Info
- 若看到 TlsCallback_0 TlsCallback_1 start
    => MinGW 編的
    - main 中第一個 function 不用逆
       第一個 function 是對 tlsCallback 做初始化
       實際上是有張 tls 表存放 8 個 function pointer, 都是初始化
       這 function 把 tls 表的 init functions 執行過一遍後就 return
       若沒有 strip 掉, 則此 function 會叫做 `_main`
- 只有 start
    => MS VS 編的
    
## 挑重點看
> 你該不會要一行一行看吧
> [name=adr]
> 

惡意程式一定會有一些惡意行為
惡意行為一定要 call 外部函數 e.g. VirtualAlloc
從高風險的外部函數往回追

## IDA Hot keys
- About ASLR
    Edit -> Segments -> Rebase program
    重新定義 IMAGE BASE
    
- `x`: jump to xref to operand
    跳到使用此變數的 code 段

- C Pseudocode to Asm
    在 C Pseudocode 頁面空白處右鍵並按 Copy to asm
    
- `y`: 修正函數、變數定義
    
- `alt+a`: set ASCII string style
    若是寬字節字串, 卻被 IDA 已 byte char 形式表示, 可用 `alt+a` 調整

## 動態模擬
> 建議使用 windows 10
> [name=adr]
> 

因為 windows 10 內建 Local Win32 debugger
adr 習慣還會有 Windbg

接著就能動態 debug

**靜態分析會出錯的部分, 跑過一次動態分析後就會修好ㄌ**

## Enum
比如說解出 OpenProcess 這 API
第一個參數, 根據 MSDN, 可以是幾個 flag 的 and
這些 FLAG 是個 enum, 取名規則前面都有 PROCESS
只要在 IDA 中把此參數的 Type 設定為 MACRO_PROCESS
就能在 decompiler 畫面看到 enum name, 而不是冷冰冰的數字

## recon shellcode
Hot key `d` 先改變結構長度
Hot key `u` 回到 undefined 狀態
Hot key `c` 當作指令解碼
Hot key `p` 從當下位址當作一個 code block 試圖反組譯
Hot key `f` 試圖將 code block 作為 function

## Plugin
- Light in house
    - 將有執行到 code block 的高亮起來

# Patch
## Rellocation
符合以下條件則 99% 有開 ASLR
1. 有 .reloc 區段
2. 有個 Base Relocation Table

複習一下 File mapping
從躺在 Disk 的 program 變成躺在 ram 上的 process
記憶體轉換公式:
**ImageBase + Virtual Address(VA) + offset = 實際躺在 ram 上的位址**

relocation table 存放哪個 text 段用到什麼 function
import function | text address (VA + offset)
--- | ---

**當程式 load 進 memory 後, 若有啟用 ASLR, 則會再從 relocation table 中將 text 段程式碼做替換, 換成正確的、加過 ASLR base 的 import function address**

小知識
1. x32/x64dbg 中有畫底線的就是由 relocation table 決定的地址
2. WinMain 吃的第一個參數就是 ImageBase

patch 時注意這點, 不能 patch 到會被 relocate 的部分

整個過程是:
- 躺在 disk 中的 program, text 段中用到外部函數的部分會先寫著 Origin ImgaeBase + VA + offset
- Application loader 做 file mapping 時, 從 relocation table 中找到要修改的 text 段
- 將 text 段中原本的 Origin ImgaeBase + VA + offset 減去 Origin ImgaeBase 加上 ASLR ImageBase
- 修改完畢

## IDA
再來就是實際 patch
在 IDA 中, Edit > Patch Program > Assemble
Patch 好後, Edit > Patch Program > Apply patches to input file


## x64dbg
按 space 修組合語言
之後 ctrl+P 修補程式即可

# 特殊 calling convention
- __declspec(naked) 
- __fastcall
- __cdecl
    - 由呼叫的函數收拾記憶體空間
    - gcc 函數預設是這種類型
- ret 10
    - 被呼叫的函數收拾記憶體空間, 此例是 ret 前 add esp, 0x10
    - e.g. Win32 許多種 API 都屬於這類型

# 編譯器優化產生的指令
- [_mm_cvtsi32_si128](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_si128&expand=1879)
- [_mm_cmpistrz](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpistrz&expand=960)

# SEH
Structured Exception Handling
Visual Studio 關於 SEH 的參數
- EHsc: 編譯器時期就解決一些咚咚
- SEH: Windows 特有的解法

若 SEH 中找不到 Handler 就呼叫 SetUnhandledExceptionFilter 這 API 設定的 Callback
- VS 中的 "錯誤報告" 這變數就是設定相關的參數

看到兩次 push
第二次 push 還是 push fs:[0]
就肯定是在註冊 SEH chain

x64dbg 忽略例外要拔掉
配合單步步入(忽略例外) 單步步過(忽略例外)
才能 debug exception

IDA 中的圖形看到兩個並排的 code block 沒有連線
就是 Try 跟對應的 catch exception


# Others
- x32dbg TLS Callbacks
- IDA Local Win32 Debugger
- Valut7
- 函數中 push ecx 之類的等同於 sub esp, 0x4 申請區域變數空間
- lea edx, dword ptr ds:[edx+ecx-0x30]
    - 等校於 edx = edx + ecx - 0x30
    - 一種優化, 速度加快 4 倍
- PATHEXT
    只要副檔名有在此環境變數被設定, 都是可執行ㄉ
    - .vbs/.js 會用 wscript.exe 執行
    - .msc 會用 microsoft management console 執行
- 可以用 cheatengine hook dll ?!?!?!
- [unicode 202e](https://isvincent.pixnet.net/blog/post/47138941-windows-%E7%94%B1%E5%8F%B3%E5%90%91%E5%B7%A6%E9%A1%AF%E7%A4%BA%E5%AD%97%E5%85%83%28%E9%97%9C%E6%96%BCunicode%E7%9A%84202e%E5%AD%97%E5%85%83%29)
    - os.rename('a.exe', u'a\u202etpp.exe')
    - 副檔名騙你
- [amsi.dll](https://tyranidslair.blogspot.com/2018/06/disabling-amsi-in-jscript-with-one.html)
    - 把 powershell 複製出來, 改名成 amsi.dll
    - 執行此 amsi.dll
    - 用這 powershell(名字已經變成 amsi.dll) 執行的 command 不會被 defender 防護
- SetUnhandled
    - https://github.com/x64dbg/x64dbg/issues/1685

- ZwQueryInformationProcess
- Self-delete
    - http://www.delphitop.com/html/chengxu/1762.html
- control flow guard

# DLL
入口函數有兩種 
- DllEntryPoint
- DllMain

LoadLibrary 時會執行一次 DLLMain

## Debug dll
IDA 中動態 debug dll 設定
IDA 先開 dll, 之後將
Debugger > Process options > Application 改為 exe 路徑
即可

## entrypoint 之前
在執行 exe 的 entrypoint 前, 會先執行其使用的 dll 的 entrypoint

# 0xcc int3
Debugger 下斷點的方式

若先下斷點之後再 copy paste 過去, 會被影響到
要注意下斷點的時機, 先讓他 copy paste 完再斷點

# Windows Programming
- SetWindowsHookExW
    - 註冊 hook
- UnhookWindowsHookEx
    - 註銷 hook
- ShellExecuteA
    - 執行 command
- WinExec
    - 執行 process
- CreateMutexA
    - ?
- GetLastError
    - 獲取 error number
- MessageBoxA
    - 創造 messagebox
- GetTempPathA
    - 獲取 temp path
- ExitProcess
    - 離開
- GetTickCount
    - 取得系統 counter
- LoadLibraryA
- LoadLibraryW
    - 載入 dll
- GetProcAddress
    - 獲取 dll 中的特定 function address
- CallNextHookEx
- GetModuleFileNameW
- VirtualAlloc
- VirtualAllocEx
- WriteProcessMemory
- NtUnmapViewOfSection
- CreateProcessA
- GetThreadContext
- SetThreadContext
- ResumeThread

