Peb(Process Environment Block)
獲取Peb,也就是進程環境塊的一種方法
一句彙編指令
代碼
mov eax,fs:[30h]
獲得當前peb
peb是個結構體。
{
BYTE bInheritedAddressSpace;
BYTE bReadImageFileExecOptions;
BYTE bBeingDebugged;
BYTE bSpareBool;
LPVOID lpMutant;
LPVOID lpImageBaseAddress;
PPEB_LDR_DATA pLdr; <------------ 0C字節
········· 目前只需要這些
} _PEB, * _PPEB; ```
獲得PPEB_LDR_DATA pLdr 的指針 所指向的地址是一個PEB_LDR_DATA數據類型的結構體。
typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes
{
DWORD dwLength;
DWORD dwInitialized;
LPVOID lpSsHandle;
LIST_ENTRY InLoadOrderModuleList; <-------0C字節
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
LPVOID lpEntryInProgress;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
取出LIST_ENTRY類型的結構體InLoadPrderModuleList(按照加載順序排列的模塊表)
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;
LIST_ENTRY是個雙向鏈表,其中Flink指向下一個模塊中的地址
在這個時候我們就不得不介紹一下其他的結構體了LDR_DATA_TABLE_ENTRY
typedef struct _LDR_DATA_TABLE_ENTRY
{
//LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry.
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STR FullDllName;
UNICODE_STR BaseDllName; <----------2C字節
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
這個結構體和PEB_LDR_DATA結構體的地址關係是如下圖一樣的關係
而在LDR_DATA_TABLE_ENTRY這個結構體中有我們想要的成員UNICODE_STR類型的BASEDLLNAME
UNICODE_STR也是一個結構體
typedef struct _UNICODE_STRING_
{
UINT16 Length;
UINT16 MaximumLength;
WCHAR* Buffer;
}UNICODE_STRING, *PUNICODE_STRING;
BASEDLLNAME 中的 WCHAR* Buffer 是我們想要的存有模塊名稱的數據。
因此
我們要把LIST_ENTRY類型的Flink中的數據,也就是Flink指向的地址強轉成LDR_DATA_TABLE_ENTRY來獲取我們想要的Buffer。
若
找到想要找的庫則取LDR_DATA_TABLE_ENTRY的 DLLBASE (當前模塊Dos頭)
typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
WORD e_magic; // Magic number<---MZ
WORD e_cblp; // Bytes on last page of file
WORD e_cp; // Pages in file
WORD e_crlc; // Relocations
WORD e_cparhdr; // Size of header in paragraphs
WORD e_minalloc; // Minimum extra paragraphs needed
WORD e_maxalloc; // Maximum extra paragraphs needed
WORD e_ss; // Initial (relative) SS value
WORD e_sp; // Initial SP value
WORD e_csum; // Checksum
WORD e_ip; // Initial IP value
WORD e_cs; // Initial (relative) CS value
WORD e_lfarlc; // File address of relocation table
WORD e_ovno; // Overlay number
WORD e_res[4]; // Reserved words
WORD e_oemid; // OEM identifier (for e_oeminfo)
WORD e_oeminfo; // OEM information; e_oemid specific
WORD e_res2[10]; // Reserved words
LONG e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
在DOS頭中最重要的兩個成員就是 WORD e_magic(存放dos的標誌MZ)和 LONG e_lfanew(指向pe文件 NT頭的偏移)
IMAGE_NT_HEADERS =(PIMAGE_NT_HEADERS)( IMAGE_DOS_HEADER -> e_lfanew +(ULONG_PTR) IMAGE_DOS_HEADER)
#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; //Signature字段被設置爲00004550h, ASCI|| 字符碼是:PE00
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
NT頭裏有兩個重要的成員 一個FileHeader (文件頭)和Optional Header(選項頭)
FileHeader
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
IMAGE_FILE_HEADER STRUCT
+04h WORD Machine; // 運行平臺
+06h WORD NumberOfSections; // 文件的區塊數目
+08h DWORD TimeDateStamp; // 文件創建日期和時間
+0Ch DWORD PointerToSymbolTable; // 指向符號表(主要用於調試)
+10h DWORD NumberOfSymbols; // 符號表中符號個數(同上)
+14h WORD SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32 結構大小
+16h WORD Characteristics; // 文件屬性
IMAGE_FILE_HEADER ENDS
Optional Header
typedef struct _IMAGE_OPTIONAL_HEADER {
//
// Standard fields.
//
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
//
// NT additional fields.
//
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;
IMAGE_OPTIONAL_HEADER32 STRUCT
+18h WORD Magic; // 標誌字, ROM 映像(0107h),普通可執行文件(010Bh)
+1Ah BYTE MajorLinkerVersion; // 鏈接程序的主版本號
+1Bh BYTE MinorLinkerVersion; // 鏈接程序的次版本號
+1Ch DWORD SizeOfCode; // 所有含代碼的節的總大小
+20h DWORD SizeOfInitializedData; // 所有含已初始化數據的節的總大小
+24h DWORD SizeOfUninitializedData; // 所有含未初始化數據的節的大小
+28h DWORD AddressOfEntryPoint; // 程序執行入口RVA
+2Ch DWORD BaseOfCode; // 代碼的區塊的起始RVA
+30h DWORD BaseOfData; // 數據的區塊的起始RVA
+34h DWORD ImageBase; // 程序的首選裝載地址
+38h DWORD SectionAlignment; // 內存中的區塊的對齊大小
+3Ch DWORD FileAlignment; // 文件中的區塊的對齊大小
+40h WORD MajorOperatingSystemVersion; // 要求操作系統最低版本號的主版本號
+42h WORD MinorOperatingSystemVersion; // 要求操作系統最低版本號的副版本號
+44h WORD MajorImageVersion; // 可運行於操作系統的主版本號
+46h WORD MinorImageVersion; // 可運行於操作系統的次版本號
+48h WORD MajorSubsystemVersion; // 要求最低子系統版本的主版本號
+4Ah WORD MinorSubsystemVersion; // 要求最低子系統版本的次版本號
+4Ch DWORD Win32VersionValue; // 莫須有字段,不被病毒利用的話一般爲0
+50h DWORD SizeOfImage; // 映像裝入內存後的總尺寸
+54h DWORD SizeOfHeaders; // 所有頭 + 區塊表的尺寸大小
+58h DWORD CheckSum; // 映像的校檢和
+5Ch WORD Subsystem; // 可執行文件期望的子系統
+5Eh WORD DllCharacteristics; // DllMain()函數何時被調用,默認爲 0
+60h DWORD SizeOfStackReserve; // 初始化時的棧大小
+64h DWORD SizeOfStackCommit; // 初始化時實際提交的棧大小
+68h DWORD SizeOfHeapReserve; // 初始化時保留的堆大小
+6Ch DWORD SizeOfHeapCommit; // 初始化時實際提交的堆大小
+70h DWORD LoaderFlags; // 與調試有關,默認爲 0
+74h DWORD NumberOfRvaAndSizes; // 下邊數據目錄的項數,這個字段自Windows NT 發佈以來一直是16
+78h IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; // 數據目錄表
IMAGE_OPTIONAL_HEADER32 ENDS
對我們找出導出表有用的就是Optional Header中的最後一個成員 [IMAGE_NUMBEROF_DIRECTORY_ENTRIES]
這個成員是數據目錄表 放着下圖數據
我們取出第一號元素 也就是導出表 來找我們的函數地址
那首先我們得知道導出表結構體中的成員
在這個結構體中我們首先取出NumberOfNames成員(存有以函數名導出的函數個數),然後取出AddressOfNames(函數名地址表RVA)
AddressOfNames + IMAGE_DOS_HEADER = TrueAddressOfNames
//存有函數名字的數組首地址
TrueAddressOfNames[1,2,3,4····]就是dll中以函數名字導出的函數名字,
若找到函數名字
則記錄下來對應的TrueAddressOfNames[i]中的 i
然後取出AddressOfNameOrdinals(函數序號地址表,它本身是個RVA)
AddressOfNameOrdinals + IMAGE_DOS_HEADER = TrueAddressOfNameOrdinals
//存有目標函數序號的數組首地址
TrueAddressOfNameOrdinals[i] = OrdinalsOfFunctionRva 可以得出存有函數地址RVA的數組中的序號
AddressOfFunctions + IMAGE_DOS_HEADER = RvaAddressOfFunctions
//存有函數地址RVA的數組首地址
TrueAddressOfFunctions =
RvaAddressOfFunctions[OrdinalsOfFunctionRva] + IMAGE_DOS_HEADER
//目標函數在進程的地址
這樣子TrueAddressOfFunctions就是我們最後要的目標函數地址。