丁同亚的博客
夺朱非正色

1.数据目录里存的地址都是RVA内存相对地址,需要转换成文件地址 才能在 fileBuffer中找到
2.windows定义了 _IMAGE_EXPORT_DIRECTORY 这么一个结构体来描述导出表
3.

typedef struct _IMAGE_EXPORT_DIRECTORY {
	DWORD Characteristics;       // 保留,总是为0x00000000
	DWORD TimeDateStamp;         // 文件的时间戳,这个和PE头应该是一样的
	WORD MajorVersion;           // 主版本号,通常未使用
	WORD MinorVersion;           // 次版本号,通常未使用
	DWORD Name;                  // 指向模块名称字符串的RVA(需要转换成FOA才能在fileBuffer找到对应的字符串)
	DWORD Base;                  // 导出函数序号的起始值
	DWORD NumberOfFunctions;     // 导出函数总数
	DWORD NumberOfNames;         // 以名称方式导出的函数数
	DWORD AddressOfFunctions;    // 指向输出函数地址数组的RVA (指向的是函数指针 类型的数组,数组里存的都是RVA)
	DWORD AddressOfNames;        // 指向输出函数名字数组的RVA (指向的是字符串指针 类型的数组,数组里存的都是RVA)
	DWORD AddressOfNameOrdinals; // 指向输出函数序号数组的RVA (指向的是short类型的数组,数组里存的都是函数序号,这个序号是减过base的,可以直接用)
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

void* exportTableResolve(void* exportTableAddress,PE pe,void* fileBuffer){

	int numberOfTable = pe.NumberOfRvaAndSizes.value;
	int tmp;
	tmp = *((int*)exportTableAddress);
	int faddress = (int)VA2FA(fileBuffer, tmp);
	IMAGE_EXPORT_DIRECTORY* pExportTable = (IMAGE_EXPORT_DIRECTORY*)(faddress + (int)fileBuffer);
	int nameaddress = (int)VA2FA(fileBuffer, pExportTable->Name) +(int)fileBuffer;
	int TimeDateStamp = pExportTable->TimeDateStamp;
	int Base = pExportTable->Base;
	int* AddressOfFunction = (int*)(VA2FA(fileBuffer, pExportTable->AddressOfFunctions) + (int)fileBuffer);
	int* AddressOfNames = (int*)(VA2FA(fileBuffer, pExportTable->AddressOfNames) + (int)fileBuffer);
	unsigned short* AddressOfNameOrdinals = (unsigned short*)(VA2FA(fileBuffer, pExportTable->AddressOfNameOrdinals) + (int)fileBuffer);
	int NumberOfNames = pExportTable->NumberOfNames;

	 char* tmpName;
	for (size_t i = 0; i < NumberOfNames; i++)
	{
		tmpName = (char*)(VA2FA(fileBuffer, AddressOfNames[i]) + (int)fileBuffer);
		printf(tmpName);
		printf("---%04d---", AddressOfNameOrdinals[i]);
		printf("---%08X---", AddressOfFunction[AddressOfNameOrdinals[i]]);
		printf("---%08X---", (VA2FA(fileBuffer, AddressOfFunction[AddressOfNameOrdinals[i]]) + (int)fileBuffer));
		printf("\n");
	}

	for (size_t i = 0; i < pExportTable->NumberOfFunctions; i++)
	{
		printf("---%08X---", (VA2FA(fileBuffer, AddressOfFunction[i]) + (int)fileBuffer));
		printf("\n");
	}


	return NULL;
}

4.通过比对名称表 获得索引 根据索引取出 名称序号表存的函数序号 根距序号(这个序号是减过base的直接当索引用就行)到函数地址表获取函数地址(RVA)
5.根据序号获取函数地址 减去 base 之后 去函数地址表索引出来 取出的是RVA
5.RVA转FOA:

int VA2FA(void* fileBuffer,int virtualAddress_source){
	PE pe = resolvePE(fileBuffer);


	unsigned short numberOfSections = *(unsigned short*)((int)fileBuffer + pe.NumberOfSections.address);
	int virtualAddress;
	int sectionSize;
	int fileAddress;
	int virtualSize;
	for (size_t i = 0; i < numberOfSections; i++)
	{
		virtualAddress = *(int*)((int)fileBuffer + pe.sectionTable[i].VirtualAddress.address);
		virtualSize = *(int*)((int)fileBuffer + pe.sectionTable[i].VirtualSize.address);
		sectionSize = *(int*)((int)fileBuffer + pe.sectionTable[i].SizeOfRawData.address);
		fileAddress = *(int*)((int)fileBuffer + pe.sectionTable[i].PointerToRawData.address);

		if (virtualAddress < virtualAddress_source && virtualAddress_source < (virtualAddress + virtualSize)){
			
			return fileAddress + (virtualAddress_source - virtualAddress);
		}

	}
	return 0;
}
posted on 2025-03-07 20:59  丁同亚的博客  阅读(34)  评论(0)    收藏  举报