// 滴水三期3.27导入表.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
using namespace std;
//向上取值函数
size_t AlignUp(size_t value, size_t alignment) {
return (value + alignment - 1) & ~(alignment - 1);
}
//得到PE文件大小
long GetSize(char* fileName) {
FILE* file = NULL;
errno_t err = fopen_s(&file, fileName, "rb");
if (err != 0) {
cout << "文件打开失败!" << endl;
fclose(file);
return 0;
}
long fileSize = 0;
fseek(file, 0, SEEK_END);
fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
fclose(file);
return fileSize;
}
//RVA转FOA
DWORD RVA_TO_FOA(char* fileBuffer, long long RVAaddress) {
PIMAGE_DOS_HEADER fileDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
PIMAGE_NT_HEADERS fileNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + fileDosHeader->e_lfanew);
if (fileNTHeader->Signature != IMAGE_NT_SIGNATURE) {
cout << "PE的NT头错误!" << endl;
return 0;
}
PIMAGE_FILE_HEADER fileFileHeader = &(fileNTHeader->FileHeader);
PIMAGE_OPTIONAL_HEADER fileOptionHeader = &(fileNTHeader->OptionalHeader);
PIMAGE_SECTION_HEADER fileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)fileOptionHeader + fileFileHeader->SizeOfOptionalHeader);
int sectionNum = 0;
for (int i = 0; i < fileFileHeader->NumberOfSections; i++) {
if (RVAaddress >= (fileSectionHeader + i)->VirtualAddress && RVAaddress < (fileSectionHeader + i)->VirtualAddress + (fileSectionHeader + i)->Misc.VirtualSize) {
sectionNum = i;
break;
}
}
long long offsetSize = RVAaddress - (fileSectionHeader + sectionNum)->VirtualAddress;
DWORD fileAdderss = (DWORD)((fileSectionHeader + sectionNum)->PointerToRawData + offsetSize);
//cout << hex <<"RVAaddress:"<< RVAaddress<<"转换====》" << "文件地址:" << fileAdderss << endl;
return fileAdderss;
}
//FOA转RVA
//这里的FOA要减去fileBuffer
DWORD FOA_TO_RVA(char* fileBuffer, long long FOAaddress) {
PIMAGE_DOS_HEADER fileDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
PIMAGE_NT_HEADERS fileNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + fileDosHeader->e_lfanew);
if (fileNTHeader->Signature != IMAGE_NT_SIGNATURE) {
cout << "PE的NT头错误X!" << endl;
return 0;
}
PIMAGE_FILE_HEADER fileFileHeader = &(fileNTHeader->FileHeader);
PIMAGE_OPTIONAL_HEADER fileOptionHeader = &(fileNTHeader->OptionalHeader);
PIMAGE_SECTION_HEADER fileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)fileOptionHeader + fileFileHeader->SizeOfOptionalHeader);
int sectionNum = 0;
for (int i = 0; i < fileFileHeader->NumberOfSections; i++) {
if (FOAaddress >= (fileSectionHeader + i)->PointerToRawData && FOAaddress < (fileSectionHeader + i)->PointerToRawData + (fileSectionHeader + i)->SizeOfRawData) {
sectionNum = i;
break;
}
}
long long offsetSize = FOAaddress - (fileSectionHeader + sectionNum)->PointerToRawData;
DWORD fileAdderss = (DWORD)((fileSectionHeader + sectionNum)->VirtualAddress + offsetSize);
//cout << hex <<"RVAaddress:"<< RVAaddress<<"转换====》" << "文件地址:" << fileAdderss << endl;
return fileAdderss;
}
//要移动导出表,需要新增一个节,因此,我们需要先给dll文件新增加一个节
void PrintImportTable(char* fileName) {
//先得到大小
long long fileSize = GetSize(fileName);
//得到大小后,再申请内存 这里为了简单,我就不重新申请了内存了,所以,这里就直接将后面需要扩大的节的大小写进来
char* fileBuffer = (char*)malloc(fileSize);
if (!fileBuffer) {
cout << "RVA_TO_FOA---->fileBuffer内存申请失败!" << endl;
free(fileBuffer);
return;
}
//如果内存申请成功,那么就要读fileBuffer,读之前,先打开文件
FILE* file = NULL;
errno_t err = fopen_s(&file, fileName, "rb");
if (err != 0) {
cout << "文件打开失败!" << endl;
free(fileBuffer);
fclose(file);
return;
}
//如果打开也没问题,那么就需要真正的开始读了
fread(fileBuffer, 1, fileSize, file);
if ((*(PWORD)fileBuffer) != IMAGE_DOS_SIGNATURE) {
cout << "PE文件格式错误!" << endl;;
free(fileBuffer);
fclose(file);
return;
}
PIMAGE_DOS_HEADER fileDosHeader = (PIMAGE_DOS_HEADER)fileBuffer;
PIMAGE_NT_HEADERS fileNTHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)fileBuffer + fileDosHeader->e_lfanew);
if (fileNTHeader->Signature != IMAGE_NT_SIGNATURE) {
cout << "PE的NT头错误!" << endl;
free(fileBuffer);
fclose(file);
return;
}
PIMAGE_FILE_HEADER fileFileHeader = &(fileNTHeader->FileHeader);
PIMAGE_OPTIONAL_HEADER fileOptionHeader = &(fileNTHeader->OptionalHeader);
PIMAGE_SECTION_HEADER fileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)fileOptionHeader + fileFileHeader->SizeOfOptionalHeader);
//以上步骤与之前类似
//找到导入表RVA
DWORD importTableRVA = fileOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
PIMAGE_IMPORT_DESCRIPTOR importTable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD_PTR)fileBuffer + RVA_TO_FOA(fileBuffer, importTableRVA));
//Name是RVA地址
//cout << "第一个DLL名称:" << hex << (importTable + 1)->Name << endl << sizeof(IMAGE_IMPORT_DESCRIPTOR) << endl;;
//cout << "数值:" << importTable << endl;
//因为不知道导入表有多少个,只知道,在导入表后会有sizeof(IMAGE_IMPORT_DESCRIPTOR)个0,因此我们需要用while循环
while (importTable->Characteristics != 0 || importTable->FirstThunk != 0 || importTable->ForwarderChain != 0 || importTable->Name != 0 || importTable->OriginalFirstThunk != 0 || importTable->TimeDateStamp != 0) {
char* importTableName = (char*)((DWORD_PTR)fileBuffer + RVA_TO_FOA(fileBuffer, importTable->Name));
cout << "=================================================" << endl;
cout << "导入表名:" << hex << left << setw(15) << importTableName << " 磁盘偏移:" << RVA_TO_FOA(fileBuffer, importTableRVA) << "OriginalFirstThunk:" << importTable->OriginalFirstThunk << endl;
//打印INT表
PDWORD intTables = (PDWORD)((DWORD_PTR)fileBuffer+RVA_TO_FOA(fileBuffer,importTable->OriginalFirstThunk));
//因为INT表我们也不知道有多少个,所以还是需要while循环。而且还需要进行判断,如果最高位是1,则要去除最高位,剩下的是导出序号,如果不是1,则是指向byName表。
while (*intTables != 0) {
if ((*intTables & 0x80000000) == 0x80000000) {
uint32_t lower31Bits = (*intTables) & 0x7FFFFFFF;
cout << "INT表存放值:" << hex << left << setw(10) << *intTables << "序号:" << lower31Bits << endl;
}
else {
PIMAGE_IMPORT_BY_NAME intTablesByNameTable = (PIMAGE_IMPORT_BY_NAME)((DWORD_PTR)fileBuffer + RVA_TO_FOA(fileBuffer, *intTables));
char* intTablesByNameTableInName = intTablesByNameTable->Name;
cout << "INT表存放值:" << hex << left << setw(10) << *intTables <<setw(8)<< "name:" << setw(25)<<intTablesByNameTableInName << "nameFOA:" << RVA_TO_FOA(fileBuffer, *intTables) << endl;
}
intTables++;
}
//在打印IAT表,该表在运行前与INT表中的值一样
//打印INT表
PDWORD iatTables = (PDWORD)((DWORD_PTR)fileBuffer + RVA_TO_FOA(fileBuffer, importTable->FirstThunk));
while (*iatTables)
{
cout << "iatTables:" << *iatTables << endl;
iatTables++;
}
importTableRVA = importTableRVA + sizeof(IMAGE_IMPORT_DESCRIPTOR);
importTable++;
}
free(fileBuffer);
fclose(file);
}
int main()
{
char fileName[] = "C:\Users\zyjsuper\Desktop\test\IPMsg.exe";
PrintImportTable(fileName);
}
原文始发于微信公众号(loochSec):PE逆向-打印导入表
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论