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 }