?1 #include? < stdio.h >
?2 #include? < windows.h >
?3
?4 void ?main()
?5 {
?6 // 取得主模塊的模塊句柄(即進程模塊基地址)
?7 HMODULE?hMod? = ?GetModuleHandle(NULL);
?8
?9 // 把進程基址賦給pDosHeader,即起始基址就是PE的IMAGE_DOS_HEADER
10 IMAGE_DOS_HEADER * ?pDosHeader? = ?(IMAGE_DOS_HEADER * )hMod;
11
12 // 定位到PE?HEADER
13 // 基址hMod加上IMAGE_DOS_HEADER結構的e_lfanew成員到達IMAGE_NT_HEADERS
14 // NT文件頭的前4字節是文件簽名("PE00"?字符串),然后是20字節的IMAGE_FILE_HEADER結構
15 // 即到達IMAGE_OPTIONAL_HEADER結構的地址,獲取了一個指向IMAGE_OPTIONAL_HEADER結構體的指針
16 IMAGE_OPTIONAL_HEADER? * ?pOptHeader? =
17 (IMAGE_OPTIONAL_HEADER? * )((BYTE * )hMod? + ?pDosHeader -> e_lfanew? + ? 24 );
18
19 // 定位到導入表
20 // 通過IMAGE_OPTIONAL_HEADER結構中的DataDirectory結構數組中的第二個成員中的
21 // VirturalAddress字段定位到IMAGE_IMPORT_DESCRIPTOR結構的起始地址
22 // 即獲得導入表中第一個IMAGE_IMPORT_DESCRIPTOR結構的指針(導入表首地址)
23 IMAGE_IMPORT_DESCRIPTOR * ?pImportDesc? = ?(IMAGE_IMPORT_DESCRIPTOR * )
24 ((BYTE * )hMod? + ?pOptHeader -> DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
25
26 while (pImportDesc -> FirstThunk)
27 {
28 // 遍歷結構的OriginalFirstThunk字段所指向的IMAGE_IMPORT_BY_NAME結構得到導出函數名
29 // 遍歷IMAGE_IMPORT_DESCRIPTOR結構的FirstThunk數組得到每個函數的地址
30
31 // 導出模塊的名稱
32 char * ?pszDllName? = ?( char * )((BYTE * )hMod? + pImportDesc -> Name);
33 printf( " \n模塊名稱:%s?\n " ,?pszDllName);
34
35 // ?一個IMAGE_THUNK_DATA就是一個雙字,它指定了一個導入函數
36 IMAGE_THUNK_DATA * ?pThunk? = ?(IMAGE_THUNK_DATA * )
37 ((BYTE * )hMod? + ?pImportDesc -> OriginalFirstThunk);
38 int ?n? = ? 0 ;
39 while (pThunk -> u1.Function)
40 {
41 // ?取得函數名稱。hint/name表前兩個字節是函數的序號,后4個字節是函數名稱字符串的地址
42 char * ?pszFunName? = ?( char * )
43 ((BYTE * )hMod? + ?(DWORD)pThunk -> u1.AddressOfData? + ? 2 );
44 // ?取得函數地址。IAT表就是一個DWORD類型的數組,每個成員記錄一個函數的地址
45 PDWORD?lpAddr? = ?(DWORD * )((BYTE * )hMod? + ?pImportDesc -> FirstThunk)? + ?n;
46
47 // ?打印出函數名稱和地址
48 printf( " ???從此模塊導入的函數:%-25s, " ,?pszFunName);
49 printf( " 函數地址:%X?\n " ,?lpAddr);
50 n ++ ;?pThunk ++ ;
51 }

52
53 pImportDesc ++ ;
54 }

55 MessageBox(NULL, " Test " , " Test " , 0 );
56 }