---
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 權限就多高

> 把 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