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;
}
浙公网安备 33010602011771号