注:本代码目前只实现了打印功能,且只支持32位程序。
打印dos头、file头、option头、section头、export_Directory、Relocation_Directory。
其中读取的:export_Directory、Relocation_Directory是通过imagebuffer读取的。
节表插入代码、新增表功能还没有实现。
#include <stdio.h>
#include <windows.h>
#include <winnt.h>
#define FILE_PATH "C:\\ReverseTraining_1.exe"
void TextPrintfExportTable(PIMAGE_OPTIONAL_HEADER32 pOption32Header, LPVOID ImageBuffer);
void TextPrintfRelocationTable(PIMAGE_OPTIONAL_HEADER32 pOption32Header, LPVOID ImageBuffer);
//写一个rva转foa的函数
/*
* RVAToFOAfun: rva转foa
* 参数:rva 内存偏移;foa文件偏移
* 返回值:foa
* 用到的时候直接调用下这个函数就OK
*/
DWORD RVAToFOAfun(IN DWORD RVA,IN LPVOID FileBuffer) {
//现有的地址 - imagebase + ponitertodataraw;
//1、获取传进来一个RVA,filebuffer?
PIMAGE_DOS_HEADER pDos_Header = NULL;
PIMAGE_NT_HEADERS32 pNT_Header32 = NULL;
PIMAGE_NT_HEADERS64 pNT_Header64 = NULL;
PIMAGE_FILE_HEADER pFile_Header = NULL;
PIMAGE_OPTIONAL_HEADER32 pOption_Header32 = NULL;
PIMAGE_OPTIONAL_HEADER64 pOption_Header64 = NULL;
PIMAGE_SECTION_HEADER pSection_Header = NULL;
DWORD FOA=0;
if (!FileBuffer)
{
printf("FileBuffer有误\n");
return FOA;
}
pDos_Header = (PIMAGE_DOS_HEADER)FileBuffer;
pFile_Header = PIMAGE_FILE_HEADER((DWORD)pDos_Header->e_lfanew + (DWORD)FileBuffer + 4);
pOption_Header32 = PIMAGE_OPTIONAL_HEADER32((DWORD)pFile_Header + IMAGE_SIZEOF_FILE_HEADER);
pSection_Header = (PIMAGE_SECTION_HEADER)(pFile_Header->SizeOfOptionalHeader + (DWORD)pOption_Header32);
BOOL isMZ = (*((PWORD)(FileBuffer)) == IMAGE_DOS_SIGNATURE);
if (!isMZ)
{
printf("不是标准PE文件:%d\n", *((PWORD)(FileBuffer)));
return FOA;
}
//判断是否为有效的PE标志
BOOL isPE = (*(PDWORD(pDos_Header->e_lfanew + (DWORD)(FileBuffer)))) == IMAGE_NT_SIGNATURE;
if (!isPE)
{
printf("不是标准的PE文件:%d\n", *(PDWORD(pDos_Header->e_lfanew + (DWORD)(FileBuffer))));
return FOA;
}
for (int i = 0; i < pFile_Header->NumberOfSections; i++)
{
if ((RVA >= pSection_Header[i].VirtualAddress )&& (RVA < pOption_Header32->SizeOfImage - pOption_Header32->SizeOfHeaders))
{
FOA = RVA - (pSection_Header[i].VirtualAddress) + pSection_Header[i].PointerToRawData;
break;
}
}
return FOA;
}
//read_file:读取文件
// 参数:file_name 要读取的文件名
//返回读取到的文件字节大小,返回存放数据的缓冲区
DWORD read_file(IN LPCSTR file_name, OUT LPVOID* file_buffer ) {
SIZE_T file_size = 0;
//LPVOID temp_buffer = NULL;
FILE* pfile = NULL;
if (fopen_s(&pfile, file_name, "rb")) {
printf("打开文件:%s失败\n",file_name);
fclose(pfile);
return 0;
}
fseek(pfile,0,SEEK_END);
file_size=ftell(pfile);
rewind(pfile);
*file_buffer =calloc(1,file_size);
fread_s(*file_buffer,file_size,1,file_size,pfile);
fclose(pfile);
return file_size;
}
//从filebuffer 拉伸到image_buffer状态
DWORD FileBufferToImageBuffer(IN LPVOID* file_buffer,OUT LPVOID* image_buffer) {
PIMAGE_DOS_HEADER dos_header=NULL;
PIMAGE_NT_HEADERS32 nt_header32=NULL;
PIMAGE_NT_HEADERS64 nt_header64=NULL;
PIMAGE_FILE_HEADER file_header=NULL;
PIMAGE_OPTIONAL_HEADER32 option_header32=NULL;
PIMAGE_OPTIONAL_HEADER64 option_header64=NULL;
PIMAGE_SECTION_HEADER section_header=NULL;
dos_header = (PIMAGE_DOS_HEADER)*file_buffer;
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
{
printf("非可执行文件:%04X\n",dos_header->e_magic);
return 0;
}
if ( *((PDWORD)(dos_header->e_lfanew +(DWORD)(dos_header))) != IMAGE_NT_SIGNATURE)
{
printf("非可执行文件:%08X\n", *(PDWORD)(dos_header->e_lfanew + (DWORD)file_buffer));
return 0;
}
//需要取到section_header 中的信息,去转换才可以。
file_header = (PIMAGE_FILE_HEADER)(dos_header->e_lfanew + (DWORD)*file_buffer+4);
DWORD section_number = file_header->NumberOfSections;
DWORD size_option_header = file_header->SizeOfOptionalHeader;
option_header32 = (PIMAGE_OPTIONAL_HEADER32)((DWORD)file_header + IMAGE_SIZEOF_FILE_HEADER);
DWORD header32_size = option_header32->SizeOfHeaders;
DWORD image32_size= option_header32->SizeOfImage;
section_header =(PIMAGE_SECTION_HEADER)((DWORD)option_header32 + size_option_header);
LPVOID temp_buffer = calloc(image32_size,1);
memmove_s(temp_buffer, header32_size, *file_buffer, header32_size);
DWORD foa=0;
DWORD size_section_data=0;
DWORD va=0;
while (section_number--)
{
foa =section_header->PointerToRawData;
size_section_data =section_header->SizeOfRawData;
va =section_header->VirtualAddress;
/* if (foa==va)
{
continue;
}*/
memmove_s(LPVOID((DWORD)temp_buffer + va) , image32_size, LPVOID((DWORD)*file_buffer + foa), size_section_data);
section_header++;
}
*image_buffer =temp_buffer;
temp_buffer = NULL;
free(temp_buffer);
return image32_size;
}
//新增一个节表
DWORD addSectionHeader(IN LPVOID ImageBuffer,OUT LPVOID newImageBuffer) {
if (ImageBuffer == NULL) {
printf("未获取到有效数据\n");
free(ImageBuffer);
return 0;
}
//得到section表头,判断剩余空间是否够插入一个表头,如果不够,那么则将NT头前移,填充覆盖STUB,修改 DOS头指向
}
//打印目录项
//获取imagebuffer中的optionheader
DWORD TestPrintDirctory(IN LPVOID ImageBuffer) {
if (ImageBuffer == NULL) {
printf("未获取到有效数据\n");
free(ImageBuffer);
return 0;
}
//获取option头中的IMAGE_DATA_DIRECTORY_ARRAY DataDirArray
PIMAGE_DOS_HEADER dos_header=(PIMAGE_DOS_HEADER)ImageBuffer;
PIMAGE_NT_HEADERS NT_header =PIMAGE_NT_HEADERS(PDWORD((DWORD)dos_header->e_lfanew + (DWORD)ImageBuffer + 4 + IMAGE_SIZEOF_FILE_HEADER));
DWORD number_of_rva_andsize=NT_header->OptionalHeader.NumberOfRvaAndSizes;
PIMAGE_EXPORT_DIRECTORY export_directory;
export_directory->AddressOfFunctions;
PIMAGE_IMPORT_DESCRIPTOR ;
for (int i = 0; i < number_of_rva_andsize; i++)
{
NT_header->OptionalHeader.DataDirectory[i];
printf("%X",NT_header->OptionalHeader.DataDirectory[i]); ;
}
NT_header->OptionalHeader.DataDirectory[1].VirtualAddress;
}
VOID TestPrintNTHeaders(IN LPVOID ImageBuffer) {
DWORD size = 0;
//LPVOID pFileBuffer = nullptr;
PIMAGE_DOS_HEADER pDosHeader = nullptr;
PIMAGE_NT_HEADERS64 pNT64Header = nullptr;
PIMAGE_NT_HEADERS32 pNT32Header = nullptr;
PIMAGE_FILE_HEADER pFileHeader = nullptr;
PIMAGE_OPTIONAL_HEADER32 pOption32Header = nullptr;
PIMAGE_OPTIONAL_HEADER64 pOption64Header = nullptr;
PIMAGE_SECTION_HEADER pSectionHeader = nullptr;
if (!ImageBuffer)
{
printf("文件读取失败\n");
}
pDosHeader = (PIMAGE_DOS_HEADER)ImageBuffer;
if ((*(PWORD)(pDosHeader)) != (IMAGE_DOS_SIGNATURE))
{
printf("非标准PE文件:%d\n", (*(PWORD)(pDosHeader)));
free(ImageBuffer);
return;
}
//判断是否为有效的PE标志
if (* ( (PDWORD((DWORD)pDosHeader + pDosHeader->e_lfanew) )) != (IMAGE_NT_SIGNATURE))
{
printf("非标准PE文件:%d\n", ((DWORD((PDWORD)ImageBuffer)) + (pDosHeader->e_lfanew)));
free(ImageBuffer);
return;
}
pFileHeader = (PIMAGE_FILE_HEADER)(DWORD((DWORD)pDosHeader + pDosHeader->e_lfanew + 4));
pOption32Header = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pFileHeader+IMAGE_SIZEOF_FILE_HEADER);
pSectionHeader = PIMAGE_SECTION_HEADER((DWORD)pOption32Header+pFileHeader->SizeOfOptionalHeader);
//打印DOC头
printf("************************DOC头******************************\n");
printf("MZ标志:%04X\n", pDosHeader->e_magic);
printf("PE偏移:%04X\n", pDosHeader->e_lfanew);
printf("************************DOC头******************************\n");
//打印file头
printf("************************FILE头******************************\n");
printf("机器类型:%04X\n", pFileHeader->Machine);
printf("节的数量:%04d\n", pFileHeader->NumberOfSections);
printf("编译时间:%08X\n", pFileHeader->TimeDateStamp);
//printf("符号表信息:%d\n", pFileHeader->PointerToSymbolTable);
//printf("符号数量:%d\n", pFileHeader->NumberOfSymbols);
printf("可选头大小(size):%04X\n", pFileHeader->SizeOfOptionalHeader);
printf("Characteristics:%04X\n", pFileHeader->Characteristics);
printf("************************FILE头******************************\n");
//打印optional头
printf("************************OPTION头******************************\n");
printf("机器位数:%04X\n", pOption32Header->Magic);
//printf("链接器主要版本:%d\n", pOption32Header->MajorLinkerVersion);
//printf("链接器次要版本:%d\n", pOption32Header->MinorLinkerVersion);
printf("代码节的总大小:%08X\n", pOption32Header->SizeOfCode);
printf("初始化数据节大小:%08X\n", pOption32Header->SizeOfInitializedData);
printf("未初始化数据节大小:%08X\n", pOption32Header->SizeOfUninitializedData);
printf("入口地址:%p\n", pOption32Header->AddressOfEntryPoint);
printf("代码节相对于映像基地址的RVA:%08X\n", pOption32Header->BaseOfCode);
printf("数据节相对于映像基地址的RVA:%08X\n", pOption32Header->BaseOfData);
printf("内存中的基址:%08X\n", pOption32Header->ImageBase);
printf("内存中节对齐大小:%08X\n", pOption32Header->SectionAlignment);
printf("文件中节对齐大小:%08X\n", pOption32Header->FileAlignment);
//printf("目标操作系统的版本:%d\n", pOption32Header->MajorOperatingSystemVersion);
//printf("目标操作系统的版本:%d\n", pOption32Header->MinorOperatingSystemVersion);
//printf("映像版本:%d\n", pOption32Header->MajorImageVersion);
//printf("映像版本:%d\n", pOption32Header->MinorImageVersion);
//printf("子系统的版本:%d\n", pOption32Header->MajorSubsystemVersion);
//printf("子系统的版本:%d\n", pOption32Header->MinorSubsystemVersion);
//printf("通常保留0:%d\n", pOption32Header->Win32VersionValue);
printf("映像在内存的大小:%08X\n", pOption32Header->SizeOfImage);
printf("文件头的大小:%08X\n", pOption32Header->SizeOfHeaders);
printf("校验和:%08X\n", pOption32Header->CheckSum);
printf("子系统类型:%04X\n", pOption32Header->Subsystem);
printf("DllCharacteristics:%04X\n", pOption32Header->DllCharacteristics);
printf("栈的预留大小:%08X\n", pOption32Header->SizeOfStackReserve);
printf("栈的提交大小:%08X\n", pOption32Header->SizeOfStackCommit);
printf("堆的预留大小:%08X\n", pOption32Header->SizeOfHeapReserve);
printf("堆的提交大小:%08X\n", pOption32Header->SizeOfHeapCommit);
//printf("保留使用:%d\n", pOption32Header->LoaderFlags);
printf("dataDirectory[%08X]\n", pOption32Header->NumberOfRvaAndSizes);
printf("************************OPENTION头******************************\n");
//打印DOC头
while ((pFileHeader->NumberOfSections)--)
{
/*char szBuffer[IMAGE_SIZEOF_SHORT_NAME];
memset(szBuffer,0,9);
memcpy_s(szBuffer,IMAGE_SIZEOF_SHORT_NAME,pSectionHeader->Name,IMAGE_SIZEOF_SHORT_NAME);*/
printf("************************SECTION头******************************\n");
printf("节名称:%s\n", pSectionHeader->Name);
printf("节在内存占用大小:%08X\n", pSectionHeader->Misc.VirtualSize);
printf("节在虚拟空间的起始地址:%08X\n", pSectionHeader->VirtualAddress);
printf("原始数据大小:%08X\n", pSectionHeader->SizeOfRawData);
printf("节在文件的地址:%08X\n", pSectionHeader->PointerToRawData);
//printf("obj重定位表起始地址:%X\n", pSectionHeader->PointerToRelocations);
//printf("源代码行号信息:%X\n", pSectionHeader->PointerToLinenumbers);
//printf("obj 重定位条目数量:%X\n", pSectionHeader->NumberOfRelocations);
//printf("行号条目数量:%X\n", pSectionHeader->NumberOfLinenumbers);
printf("节Characteristics:%08X\n", pSectionHeader->Characteristics);
printf("************************SECTION头******************************\n");
pSectionHeader++;
}
TextPrintfExportTable(pOption32Header, ImageBuffer);
TextPrintfRelocationTable(pOption32Header, ImageBuffer);
//最后统一释放,不然容易遗漏,或多次释放。
//free(pFileBuffer);
return;
}
//打印导出表
void TextPrintfExportTable(PIMAGE_OPTIONAL_HEADER32 pOption32Header,LPVOID ImageBuffer) {
if (!pOption32Header)
{
printf("未获取PE头\n");
return;
}
const char* DirectoryEntryNames[] =
{
"EXPORT_TABLE",
"IMPORT_TABLE",
"RESOURCE_TABLE",
"EXCEPTION_TABLE",
"CERTIFICATE_TABLE",
"BASE_RELOCATION_TABLE",
"DEBUG",
"COPYRIGHT_TABLE",
"GLOBAL_PTR",
"TLS_TABLE",
"LOAD_CONFIG_TABLE",
"BOUND_IMPORT",
"IAT",
"DELAY_IMPORT_DESCRIPTOR",
"CLRRUNTIMEHEADER",
"RESERVED"
};
//依次读取DataDirArray 目录中的address
int i = 0;
while ((pOption32Header->NumberOfRvaAndSizes)--)
{
printf("序号:%d、TbaleNAME:【%s】\t,VirtualAddress:【%08X】,Size:【%08X】\n",i, DirectoryEntryNames[i], pOption32Header->DataDirectory[i].VirtualAddress, pOption32Header->DataDirectory[i].Size);
i++;
}
//pOption32Header->DataDirectory[0].VirtualAddress;
printf("====================================EXPORT TABLE=======================================\n");
PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)((pOption32Header->DataDirectory[0].VirtualAddress)+ (DWORD)ImageBuffer);
printf("Characteristics:【%08X】\n", pExportDirectory->Characteristics);
printf("TimeDateStamp:【%08X】\n", pExportDirectory->TimeDateStamp);
printf("MajorVersion:【%04X】\n", pExportDirectory->MajorVersion);
printf("MinorVersion:【%04X】\n", pExportDirectory->MinorVersion);
printf("Name:【%08X】\n", pExportDirectory->Name);
printf("Base:【%08X】\n", pExportDirectory->Base);
printf("NumberOfFunctions:【%08X】\n", pExportDirectory->NumberOfFunctions);
printf("NumberOfNames:【%08X】\n", pExportDirectory->NumberOfNames);
printf("AddressOfFunctions:【%08X】\n", pExportDirectory->AddressOfFunctions);
printf("AddressOfNames:【%08X】\n", pExportDirectory->AddressOfNames);
printf("AddressOfNameOrdinals:【%08X】\n", pExportDirectory->AddressOfNameOrdinals);
printf("====================================EXPORT TABLE=======================================\n");
}
/*
获取重定位表
*/
void TextPrintfRelocationTable(PIMAGE_OPTIONAL_HEADER32 pOption32Header, LPVOID ImageBuffer) {
if (!pOption32Header) {
printf("未获取PE头\n");
return;
}
printf("====================================RELOCATION TABLE=======================================\n");
//得到当前重定位表位置
PIMAGE_BASE_RELOCATION pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((DWORD)ImageBuffer + pOption32Header->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
DWORD i = 1;
//循环遍历重定位表
while (pRelocationDirectory->SizeOfBlock > 0) {
printf("第%d项:地址:%08X, SizeOfBlock: %08X\n", i++, pRelocationDirectory->VirtualAddress, pRelocationDirectory->SizeOfBlock);
//计算重定位条目的起始位置
PWORD pwRelocationEntries = (PWORD)((uintptr_t)pRelocationDirectory + sizeof(IMAGE_BASE_RELOCATION));
//计算有多少个重定位条目
WORD NumberOfRelocationEntries = (pRelocationDirectory->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD);
//循环重定位条目,分解重定位条目
for (DWORD j = 0; j < NumberOfRelocationEntries; j++) {
WORD wRelocationEntry = pwRelocationEntries[j];
//属性
DWORD dwRelocationType = (wRelocationEntry >> 12) & 0xF;
//地址
DWORD dwRelocationAddress = wRelocationEntry & 0xFFF;
printf(" 地址:%04X, 属性:0x%04X\n", pRelocationDirectory->VirtualAddress + dwRelocationAddress, dwRelocationType);
}
//移动到下一个重定位块。
pRelocationDirectory = (PIMAGE_BASE_RELOCATION)((uintptr_t)pRelocationDirectory + pRelocationDirectory->SizeOfBlock);
}
printf("====================================RELOCATION TABLE=======================================\n");
}
int main() {
LPVOID file_buffer = NULL;
LPVOID image_buffer = NULL;
read_file("C:\\Windows\\twain_32.dll", &file_buffer);
FileBufferToImageBuffer(&file_buffer,&image_buffer);
TestPrintNTHeaders(image_buffer);
free(file_buffer);
free(image_buffer);
return 0;
}