滴水逆向——PE导出表

本文详细介绍了PE文件的导出表结构,包括如何定位导出表、导出表的各个组成部分如AddressOfFunctions和AddressOfNames的解释,以及如何根据函数名获取地址。文章还讨论了为何要将导出表分成三部分,并提供了打印导出表和根据导出序号获取函数地址的实践操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Ⅰ.知识点:

1.如何定位导出表:    
    数据目录项的第一个结构,就是导出表.   
    typedef struct _IMAGE_DATA_DIRECTORY {  
    DWORD   VirtualAddress;   
    DWORD   Size;     
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;  
    VirtualAddress  导出表的RVA   
    Size 导出表大小      

2.导出表结构     
    上面的结构,只是说明导出表在哪里,有多大,并不是真正的导出表.
    如何在FileBuffer中找到这个结构呢?在VirtualAddress中存储的是RVA,如果想在FileBuffer中定位
    必须要先将该RVA转换成FOA.    
    真正的导出表结构如下:    

3.AddressOfFunctions说明:   
    该表中元素宽度为4个字节    
    该表中存储所有导出函数的地址   
    该表中个数由NumberOfFunctions决定   
    该表项中的值是RVA, 加上ImageBase才是函数真正的地址  
    定位:      
    IMAGE_EXPORT_DIRECTORY->AddressOfFunctions 中存储的是该表的RVA 需要先转换成FOA

4.AddressOfNames说明:    
    该表中元素宽度为4个字节    
    该表中存储所有以名字导出函数的名字的RVA  
    该表项中的值是RVA, 指向函数真正的名称  

5.AddressOfNameOrdinals

Ⅱ.关键点:       
       为什么要分成3张表?     
       1、函数导出的个数与函数名的个数未必一样.所以要将函数地址表和函数名称表分开.
       2、函数地址表是不是一定大于函数名称表?   
       未必,一个相同的函数地址,可能有多个不同的名字.  
       3、如何根据函数的名字获取一个函数的地址?   

Ⅲ.问题描述:

  打印导出表

  根据函数的导出序号获取一个函数的地址

Ⅳ.代码实现:

#include<stdio.h>
#include<stdlib.h>
#include<windows.h>

#define test 1
#define ordianl 3

DWORD ToLoaderPE(LPSTR file_path, PVOID* pFileBuffer);
BOOL MemoryToFile(PVOID pMemBuffer, DWORD size, LPSTR lpszFile);
DWORD FoaToImageOffset(PVOID pBuffer, DWORD dwFoa);
DWORD RvaToFileOffset(PVOID pBuffer, DWORD dwRva);
DWORD GetSctionEmptySpace(PVOID pFileBuffer, DWORD SectionOrdinal);
DWORD Alignment(DWORD alignment_value, DWORD addend, DWORD address);
DWORD GetFunctionAddrByName(PVOID pFileBuffer, LPSTR fun_name);
DWORD GetFunctionAddrByOrdinals(PVOID pFileBuffer, DWORD fun_ordinal);
VOID LogExportTable(PVOID pFileBuffer);

//char file_path[] = "c:\\users\\desktop\\notepad.exe";
char file_path[] = "c:\\users\\desktop\\dll1test.dll";
//char file_path[] = "c:\\users\\desktop\\ipmsg2007.exe";
char fun_name[] = "Mul";
char write_file_path[] = "D:\\Lib\\cp_XX.exe";
char write_adddata_file_path[] = "D:\\Lib\\cp_adddata_XX.exe";
char write_addsec_file_path[] = "D:\\Lib\\cp_addsec_XX.exe";
char write_enlargersec_file_path[] = "D:\\Lib\\cp_enlargersec_XX.exe";
char write_mergesec_file_path[] = "D:\\Lib\\cp_mergesec_XX.exe";

//返回PE文件大小
DWORD ToLoaderPE(LPSTR file_path, PVOID* pFileBuffer)
{
	FILE *pFile = NULL;
	DWORD FileSize = 0;
	PVOID pFileBufferTemp = NULL;

	pFile = fopen(file_path, "rb");

	if (!pFile)
	{
		printf("(ToLoaderPE)Can't open file!\n");
		return 0;
	}

	fseek(pFile, 0, SEEK_END);
	FileSize = ftell(pFile);
	printf("FileBuffer: %#x\n", FileSize);
	fseek(pFile, 0, SEEK_SET);
	pFileBufferTemp = malloc(FileSize);

	if (!pFileBufferTemp)
	{
		printf("(ToLoaderPE)Allocate dynamic memory failed!\n");
		fclose(pFile);
		return 0;
	}

	DWORD n = fread(pFileBufferTemp, FileSize, 1, pFile);

	if (!n)
	{
		printf("(ToLoaderPE)Read file failed!\n");
		free(pFileBufferTemp);
		fclose(pFile);
		return 0;
	}
	*pFileBuffer = pFileBufferTemp;
	pFileBufferTemp = NULL;
	fclose(pFile);
	return FileSize;
}

BOOL MemoryToFile(PVOID pMemBuffer, DWORD size, LPSTR lpszFile)
{
	FILE *fp;
	fp = fopen(lpszFile, "wb");
	if (fp != NULL)
	{
		fwrite(pMemBuffer, size, 1, fp);
	}
	fclose(fp);
	printf("Store file success!\n");
	return 1;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值