這一篇算是 Windows10 x64 shellcode 的前哨站,在寫 shellcode 之前發現有太多知識需要先科普,先在這邊整理一些知識後進去 windows shellcode 的領域會比較懂
首先要先知道一隻 windows 程式進入記憶體會是長怎麼樣
TEB
- Thread Environment Block
- 每個 Thread 都會有一個
- NtTIB 被包含在裡面 (從 TEB 的開頭最一開始就是 NtTIB 的內容,後面才開始接其他內容)
- TEB + 0x60 = PEB address
- 32 位元 : FS[0x18] 固定存放 TEB 位址
- 64 位元 : GS[0x30] 固定存放 TEB 位址
!_TEB
dt !_TEB
(資訊太多了,可以自己 trace,這邊就不貼完整的了)dt !_NT_TIB
- https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-teb
- https://en.wikipedia.org/wiki/Win32_Thread_Information_Block
- 就我自己 Trace 的結果,我自己覺得 TIB 不等於 TEB 就是了
PEB
- Process Environment Block
- 每個 Process 都有一個
ImageBaseAddress
- program base address_PEB_LDR_DATA
(Ldr) - DLL 相關- ProcessHeap
- 32 位元 : FS[0x30] 固定存放 PEB 位址
- 64 位元 : GS[0x60] 固定存放 PEB 位址
!peb
dt !_PEB
(資訊太多了,可以自己 trace,這邊就不貼完整)- https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
- https://en.wikipedia.org/wiki/Process_Environment_Block
Ldr
- 串接所有會用到的 DLL 位址
- Link list
- Ldr.InInitializationOrderModuleList
- Ldr.InLoadOrderModuleList
- Ldr.InMemoryOrderModuleList
- DLL name
- DLL Base address
- 串接順序有固定,前三個是 binary 本身 -> ntdll -> kernel32
InInitializationOrderModuleList
InLoadOrderModuleList
InMemoryOrderModuleList
這三個彼此是一個串一個!peb
dt ntdll!_LDR_DATA_TABLE_ENTRY
整理下來的流程圖大概是這樣 (這是 x86 的,x64 要乘以2)
https://blog.the-playground.dk/2012/06/understanding-windows-shellcode.html
看一下 DLL base 可以看到是熟悉的 MZ Header,下面開始介紹 PE Structure
https://www.slideshare.net/Hexxx/pe-format
- DOS Header (_IMAGE_DOS_HEADER)
- Structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; /* 00: MZ Header signature */
WORD e_cblp; /* 02: Bytes on last page of file */
WORD e_cp; /* 04: Pages in file */
WORD e_crlc; /* 06: Relocations */
WORD e_cparhdr; /* 08: Size of header in paragraphs */
WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */
WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */
WORD e_ss; /* 0e: Initial (relative) SS value */
WORD e_sp; /* 10: Initial SP value */
WORD e_csum; /* 12: Checksum */
WORD e_ip; /* 14: Initial IP value */
WORD e_cs; /* 16: Initial (relative) CS value */
WORD e_lfarlc; /* 18: File address of relocation table */
WORD e_ovno; /* 1a: Overlay number */
WORD e_res[4]; /* 1c: Reserved words */
WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */
WORD e_oeminfo; /* 26: OEM information; e_oemid specific */
WORD e_res2[10]; /* 28: Reserved words */
DWORD e_lfanew; /* 3c: Offset to extended header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; - RVA (Relative Virtual Address)
- 在記憶體中,相對於 Binary Base 之間的 offset
- 如果 RVA 為 0x3000, 代表實際位置在 Binary Base + 0x3000
e_magic
通常是 File Header 也就是 0x5a4d (MZ)e_lfanew
是 NT header 的 RVAdt !_IMAGE_DOS_HEADER
- https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
- Structure
- NT Header (_IMAGE_NT_HEADERS64)
- Structure
1
2
3
4
5typedef struct _IMAGE_NT_HEADERS64 {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;- Signature
- File Header
- 通常為 0x4550 (PE)
- FileHeader (_IMAGE_FILE_HEADER)
- Machine
- 表示該執行檔的architecture
Machine Value Meaning 0x014c / IMAGE_FILE_MACHINE_I386 x86 0x0200 / IMAGE_FILE_MACHINE_IA64 Intel Itanium 0x8664 / IMAGE_FILE_MACHINE_AMD64 x64
- 表示該執行檔的architecture
- NumberofSection
- 表示該執行檔的 Section 數量,可以透過
!dh
取得更詳細的資訊
- 表示該執行檔的 Section 數量,可以透過
dt !_IMAGE_FILE_HEADER
- Structure
OptionalHeader (_IMAGE_OPTIONAL_HEADER)
- Structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; - Magic
- PE32 : 0x10b
- PE32+ : 0x20b
- AddressOfEntryPoint
- 程式進入點的 RVA (以ImageBaseAddress 為起點)
- NumberOfRvaAndSizes : DataDirectory 的數量
- DataDirectory (_IMAGE_DATA_DIRECTORY)
- 依序記錄每個 Export Directory 的 RVA (VirtualAddress) 及 Size
- 各 DataDirectory 之間的間隔為 0x8 (x64)
- 陣列呈現的資訊是有順序的,詳情可以看官方
https://docs.microsoft.com/zh-tw/windows/win32/api/winnt/ns-winnt-image_data_directory
- 依序記錄每個 Export Directory 的 RVA (VirtualAddress) 及 Size
dt _IMAGE_OPTIONAL_HEADER64
- https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64
- https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32
- Structure
Export Directory
- 透過上面 DataDirectory 的第0個陣列的 VirtualAddress 可以到達
- windbg 沒有他的
display type
所以直接貼官方的圖 - Structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
}; - NumberOfFunctions
- 紀錄內部 function 的數量,與 NumberOfName 數量相等 (表示 dll 內有幾個 function)
- NumberOfName
- Name pointer(array) 的數量,與 ordinal table 數量相等 (表示 dll 內有幾個 function name)
- AddressOfFunctions
- Export function 的
RVA
- Export function 的
- AddressOfNames
- 存放 Name pointer(array) 的
RVA
,這邊存放有所有 Export function 的名稱
- 存放 Name pointer(array) 的
- AddressOfNameOrdinals
- 存放 ordinal table(array) 的相對位置
- 與 Name Pointer array 是一對一 mapping 的,也就是說如果
WinExec
在 Name[x] ,那麼 WinExec 在 Ordinal table 的 index 就是 x - ordinal table
- 其元素內容每個為 2 bytes
- 表示在 Export Address Table 中的 index
- 這邊不是 RVA, 直接就是 index value
- https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#export-directory-table
- https://sites.google.com/site/peofcns/win32forth/pe-header-f/02-image_directory/01-entry_export
- https://ghidra.re/ghidra_docs/api/ghidra/app/util/bin/format/pe/ExportDataDirectory.html
該介紹的都介紹差不多了
這邊會示範如何 trace 出 WinExec
來當 example
複習一下 Export Table
的 RVA
把 Export Table
拿出來看
照著上面針對 Export Table
介紹的 Structure 進行排列
1 | Characteristics = 0x00000000 # Reserved, must be 0. |
整個找 function RVA 的 flow 大概是這樣
來源: https://www.programmersought.com/article/19694281094/
接著取得 AddressOfFunctions (0x1c)
的內容
簡單來說如果 Export function 如果在自己的 dll 的話就會直接給出 function 位置 (jmp),若 Export function 在其他 dll 的話就會給出 Name pointer 的位置,這邊解釋了為什麼上面的圖沒有將每個函數地址表做對應
再來看 AddressOfNames (0x20)
的內容
AddressOfNameOrdinals (0x24)
直接用 windbg
在 AddressOfNames 尋找 WinExec
的字串
相關 command 請看
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/s--search-memory-
長度部分使用該 Export Directory 的總大小,在這個 memory range 裡面尋找 WinExec
的 ASCII code00007ff82e170000+0008f8fc
是 AddressOfNames
的 base addresss -a (00007ff82e170000+0008f8fc) l 0xdb48 "WinExec"
我們知道 AddressOfNames 裡面放的都是以 4byte 為一個單位的陣列,需要找到是第幾個陣列存放 WinExec
首先我們先取得 WinExec 的 Name pointer RVAs -d (00007ff82e170000+0008f8fc) l 0xdb48 0009b59b
得知 00007ff82e201114
存放 WinExec 的 Name pointer RVA,那是第幾個陣列呢 ?
把 Array 的位置扣除 AddressOfNames 的 base address 再除以 4 就是我們要的答案
第 0x606 個陣列,把這個數字拿去看 ordinal table,記得 0x606 要乘以 2, 因為 ordinal table 的陣列是以 2 bytes 為一個單位的陣列00007ff82e170000+00091250
是 AddressOfNameOrdinals
的 base addressdw (00007ff82e170000+00091250+(0x606*4))
可以看到一樣是 0x606, 現在把這個數字拿去 AddressOfFunctions
就能求出 WinExec 的 RVA0008dfa8+00007ff82e170000
是 AddressOfFunctions
的 base address
一樣記得要把 0x606 乘以 4, 因為 AddressOfFunctions
是以 4 bytes 為一個單位的陣列
放上整個 flow
至此文章就告一段落了,這篇文章主要就是在學習 windows shellcode 需要惡補的內容
這篇文章真的幫我很多
http://bufferoverflow123.blogspot.com/2018/06/bufferoverflow-3-4-kernel32dl.html
https://bsodtutorials.wordpress.com/2014/03/02/import-address-tables-and-export-address-tables/
https://docs.microsoft.com/en-us/previous-versions/ms809762(v=msdn.10)?redirectedfrom=MSDN