遍历导出表

1.通过DOS头部找到PE头部

    DOS头部的数据结构如下:
_IMAGE_DOS_HEADER
+0x000 e_magic : Uint2B
+0x002 e_cblp : Uint2B
+0x004 e_cp : Uint2B
+0x006 e_crlc : Uint2B
+0x008 e_cparhdr : Uint2B
+0x00a e_minalloc : Uint2B
+0x00c e_maxalloc : Uint2B
+0x00e e_ss : Uint2B
+0x010 e_sp : Uint2B
+0x012 e_csum : Uint2B
+0x014 e_ip : Uint2B
+0x016 e_cs : Uint2B
+0x018 e_lfarlc : Uint2B
+0x01a e_ovno : Uint2B
+0x01c e_res : [4] Uint2B
+0x024 e_oemid : Uint2B
+0x026 e_oeminfo : Uint2B
+0x028 e_res2 : [10] Uint2B
+0x03c e_lfanew : Int4B

    偏移0x3c处是PE头部的相对虚拟地址。

2.通过PE头部找到数据目录项

    PE头部的数据结构如下:

typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature;
    IMAGE_FILE_HEADER FileHeader;
    IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

_IMAGE_FILE_HEADER
+0x000 Machine : Uint2B
+0x002 NumberOfSections : Uint2B
+0x004 TimeDateStamp : Uint4B
+0x008 PointerToSymbolTable : Uint4B
+0x00c NumberOfSymbols : Uint4B
+0x010 SizeOfOptionalHeader : Uint2B
+0x012 Characteristics : Uint2B
_IMAGE_OPTIONAL_HEADER
+0x000 Magic : Uint2B
+0x002 MajorLinkerVersion : UChar
+0x003 MinorLinkerVersion : UChar
+0x004 SizeOfCode : Uint4B
+0x008 SizeOfInitializedData : Uint4B
+0x00c SizeOfUninitializedData : Uint4B
+0x010 AddressOfEntryPoint : Uint4B
+0x014 BaseOfCode : Uint4B
+0x018 BaseOfData : Uint4B
+0x01c ImageBase : Uint4B
+0x020 SectionAlignment : Uint4B
+0x024 FileAlignment : Uint4B
+0x028 MajorOperatingSystemVersion : Uint2B
+0x02a MinorOperatingSystemVersion : Uint2B
+0x02c MajorImageVersion : Uint2B
+0x02e MinorImageVersion : Uint2B
+0x030 MajorSubsystemVersion : Uint2B
+0x032 MinorSubsystemVersion : Uint2B
+0x034 Win32VersionValue : Uint4B
+0x038 SizeOfImage : Uint4B
+0x03c SizeOfHeaders : Uint4B
+0x040 CheckSum : Uint4B
+0x044 Subsystem : Uint2B
+0x046 DllCharacteristics : Uint2B
+0x048 SizeOfStackReserve : Uint4B
+0x04c SizeOfStackCommit : Uint4B
+0x050 SizeOfHeapReserve : Uint4B
+0x054 SizeOfHeapCommit : Uint4B
+0x058 LoaderFlags : Uint4B
+0x05c NumberOfRvaAndSizes : Uint4B
+0x060 DataDirectory : [16] _IMAGE_DATA_DIRECTORY


    PE头部的DataDirectory相对于PE头部的偏移为0x78。
    DataDirectory的第一项为导出表目录。
_IMAGE_DATA_DIRECTORY
+0x000 VirtualAddress : Uint4B
+0x004 Size : Uint4B
     可以根据第一个字段寻找到导出表。

3.导出表数据结构

typedef 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
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

    NumberOfFunctions字段是总的导出函数个数;NumberOfNames字段是有名字的函数个数;AddressOfNames是函数的名称字符串相对虚拟地址;AddressOfNameOrdinals是与AddressOfNames一一对应的此函数在AddressOfFunctions里的索引;AddressOfFunctions存的函数的相对虚拟地址。

4.遍历导出表

    遍历导出表中NumberOfNames个有名称的函数,并根据AddressOfNameOrdinals里的索引找到其在AddressOfFunctions里存放的地址。

以遍历user32.dll的导出表为例:

#include <stdio.h>

#include <Windows.h>

int main()
{
	HMODULE hDll = LoadLibraryA("user32.dll");
	if (!hDll)
		return 0;


	IMAGE_EXPORT_DIRECTORY* exportDir;

	int baseAddr = (int)hDll;
	int RVA, VA;

	RVA = *((int*)(baseAddr + 0x3c)); 
	VA = baseAddr + RVA; // File address of new exe header
	VA += 0x78; //DataDirectory
	RVA = *((int*)VA);
	exportDir = (IMAGE_EXPORT_DIRECTORY*)(baseAddr + RVA);

	int* RVAFunctions = (int*)(baseAddr + exportDir->AddressOfFunctions);
	int* RVANames = (int*)(baseAddr + exportDir->AddressOfNames);
	short* Ordinals = (short*)(baseAddr + exportDir->AddressOfNameOrdinals);

	int i, VAFunction, ordinal;
	int numName = exportDir->NumberOfNames;
	for (i = 0; i < numName; i++)
	{
		ordinal = *(Ordinals + i);
		RVA = *(RVAFunctions + ordinal);
		VAFunction = baseAddr + RVA;

		RVA = *(RVANames + i);
		VA = baseAddr + RVA;

		printf("%d: %s - 0x%x\n", ordinal, (char*)VA, VAFunction);
	}
	
	return 0;
}

验证正确性:
    在代码语句最后调用MessageBoxA函数。控制台中打印的关于MessageBoxA的地址为0x775b7e60:
在这里插入图片描述
    再调试进入MessageBoxA函数,起始地址也为0x775b7e60:
在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值