這一篇算是 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
 InInitializationOrderModuleListInLoadOrderModuleListInMemoryOrderModuleList這三個彼此是一個串一個
!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
