1. 程式人生 > >PE結構學習02-導出表

PE結構學習02-導出表

ges 需要 printf res time 調用 clas 開始 lang

導出表:

  • 上篇文章,我們學習了各種頭,Dos,NT,節表頭,我們知道,OptionalHeader指向的DataDirectory[]數組一共有16個:

技術分享

  • 我們接下來要學習的有:
  1. IMAGE_DIRECTORY_ENTRY_IMPORT 導入表
  2. IMAGE_DIRECTORY_ENTRY_BASERELOC 基址重定位表
  3. IMAGE_DIRECTORY_ENTRY_EXPORT 導出表
  4. IMAGE_DIRECTORY_ENTRY_RESOURCE 資源表

  • 今天我們學習導出表:
  1. 我們知道dll文件,是動態鏈接庫,裏面有許多函數給別人調用,但是別人怎麽知道裏面有什麽函數呢?就需要導出表清單給人家看,就如同你去餐廳點餐,卻不知道餐廳有什麽菜,這時服務生會拿出菜單來,這個菜單就如同導出表。
  2. 所有PE文件都可以有導出表,只是大部分情況下,exe不提供導出表而已。
  • 我們知道OptionalHeader指向的DataDirectory[]數組一共有16個,每個都是一樣的結構:
  1. VirtualAddress 虛擬偏移地址
  2. size 大小
  • NtHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT ],這個數據目錄表VirtualAddress指向的是導出表的地址:
typedef struct _IMAGE_EXPORT_DIRECTORY 
{
DWORD Characteristics;//未使用,總是定義為0
DWORD TimeDateStamp;//文件生成時間
WORD MajorVersion;//未使用,總是定義為0
WORD MinorVersion;//未使用,總是定義為0
DWORD Name; //模塊的真實名稱的RVA
DWORD Base; //基數,加上序數就是函數地址數組的索引值
DWORD NumberOfFunctions;//導出函數的總數
DWORD NumberOfNames; //以名稱方式導出的函數的總數
DWORD AddressOfFunctions; // RVA from base of image指向輸出函數地址的RVA
DWORD AddressOfNames; // RVA from base of image指向輸出函數名字的RVA
DWORD AddressOfNameOrdinals; // RVA from base of image向輸出函數序號的RVA

} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY
  1. Characteristics:現在沒有用到,一般為0。
  2. TimeDateStamp:導出表生成的時間戳,由連接器生成。
  3. MajorVersion,MinorVersion:看名字是版本,實際貌似沒有用,都是0。
  4. Name:模塊的名字,就是dll的名稱。
  5. Base:序號的基數,按序號導出函數的序號值從Base開始遞增。
  6. NumberOfFunctions:所有導出函數的數量。
  7. NumberOfNames:按名字導出函數的數量。
  8. AddressOfFunctions:一個RVA,指向一個DWORD數組,數組中的每一項是一個導出函數的RVA,順序與導出序號相同。
  9. AddressOfNames:一個RVA,依然指向一個DWORD數組,數組中的每一項仍然是一個RVA,指向一個表示函數名字。
  10. AddressOfNameOrdinals:一個RVA,還是指向一個WORD數組,數組中的每一項與AddressOfNames中的每一項對應,表示該名字的函數在AddressOfFunctions中的序號。
typedef struct _IMAGE_IMPORT_BY_NAME 
{
WORD Hint;
CHAR Name[1];
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
技術分享

技術分享

  • AddressOfFunctions 指向所有函數的地址。
  • AddressOfNames 指向名字的地址。
  • AddressOfNameOrdinals 指向一個序號。

  • 查找導出表代碼(c/c++):
int main(int argc, char *argv[])
{
 PIMAGE_DOS_HEADER Pdos = (PIMAGE_DOS_HEADER)GetModuleHandle(L"user32.dll");


 PIMAGE_NT_HEADERS Pnt = (PIMAGE_NT_HEADERS)((int)Pdos->e_lfanew + (int)Pdos);

 IMAGE_OPTIONAL_HEADER32 Popt = Pnt->OptionalHeader;

 IMAGE_EXPORT_DIRECTORY * Export;
 Export = (IMAGE_EXPORT_DIRECTORY*)(Popt.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)Pdos);

 DWORD * AllAddress;
 DWORD * AllName;
 USHORT * AllOrg;

 AllAddress = (DWORD*)((int)Export->AddressOfFunctions + (int)Pdos);//函數地址數組
 AllName = (DWORD*)((int)Export->AddressOfNames + (int)Pdos);//函數名稱數組
 AllOrg = (USHORT *)((int)Export->AddressOfNameOrdinals + (int)Pdos);//序號數組


 int OneAddress;
 char * OneName;
 USHORT OneOrg;
 char * Buf = new char[500];
 int ListId = NULL;

 for (int i = 0; i < (int)Export->NumberOfNames; i++)
 {

 OneName = (char*)((BYTE*)Pdos + AllName[i]);
 OneOrg = (USHORT)AllOrg[i];
 OneAddress = (int)((int)Pdos + AllAddress[OneOrg]);

 printf("Name: %s, Org :%d,Address :%x\n", OneName, OneOrg, OneAddress);
 }

 return 0;
}

技術分享

PE結構學習02-導出表