pe文件:exe dll ocx sys com
pe结构:MS-dos头 标准pe头 扩展pe头 数据目录 节表
4D5A 文件标志
#include<stdio.h>#include<Windows.h>int main(){ FILE * pFile = NULL; char * buffer; int NFileLength = 0; pFile = fopen(自行设置); fseek(pFile,0,SEEK_END); nFileLength = ftell(pFile); rewind(pFIle); int imageLength = nFileLength * sizeof(char) + 1; buffer = (char *)malloc(imageLength); memset(buffer,0,nFileLength * sizeof(char)+1); fread(buffer,1,imageLength,pFile); // _IMAGER_DOS_HEADER //msdos头结构体,可读取 PIMAGE_DOS_HEADER ReadDosHeader; ReadDosHeader = ( PIMAGE_DOS_HEADER)buffer; printf("%x",ReadDosHeader->e_magic); free(buffer); return 0;}e_lfanew 指向新的pe头 偏移量 0x3c
PE文件结构解析
标准PE头和扩展PE头
printf("PEheader\n");_IMAGE_NT_HEADERS =ReadNTHeaders; //分32 和 64 两个结构体IMAGE_NT_SIGNATURE = 0x00004550 //PE00ReadNTHeaders.
常用区段:
.text (code 代码段data 数据段 可读写 全局和静态变量rodata 只读数据段idata 导入表信息edata 导出表rsrc 资源段bss 未初始化数据crt 运行时代码库tls 线程局部存储reloc 重定位区段IMAGE_SIZEOF_FILE_HEADER等 //pe中一组宏定义常见属性
VA Virtual Address //虚拟内存地址 00000000h-0fffffffh
进程的基地址 + 相对虚拟内存地址
RVA //Reversc Virtual Address 相对虚拟地址(模块的基地址的偏移量
FOA File Offset Address 文件偏移地址 某个位置距离文件头的偏移量
注意处理文件的位数是32位还是64位
区段表结构解析及遍历PIMAGE_DOS_HEADER ReadDosHeader;ReadDosHeader = (PIMAGE_DOS_HEADER)buffer;ReadNTHeader = (PIMAGE_NT_HEADERS)(buffer + ReadDosHeader->e_lfanew);//区段解析遍历PIMAGE_SECTION_HEADER ReadSectionHeader = IMAGE_FIRST_SECTION(ReadNTHeaders);PIMAGE_FILE_HEADER pFileHeader = &ReadNTHders->FileHeader;for(int i = 0 ; i<pFileHeader.NumberOfSections;i++){ printf("name (区段名称):%s\n",ReadSectionHeader[i].Name); printf("VOffset起始的相对虚拟地址:%x\n", ReadSectionHeader[i].VirtualAddress); //等等等等 }
数据目录表结构与地址转换函数
数据目录表:_IMAGE_DATA_DIRECTION导入表导出表资源表异常目录表安全目录(签名,证书重定位表debug 表版权信息等表全局指针偏移目录线程局部存储表载入配置表绑定目录表导入地址表延迟导入表运行时描述符LOADPE.exe中均有
//计算偏移的函数#include<stdio.h>#include<Windows.h>//dwRva 是某个数据目录表的虚拟地址//buffer是读取的PE文件的缓冲区DWORD RvaToOffset(DWORD dwRva, char *buffer){ //DosHeader PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer; //PE Header PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer); //区段表 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt); //判断是否落在头部当中 if(dwRva < pSection[0].VirtualAddress){ return dwRva; } for(int i = 0;i<pNt->FileHeader.NumberOfSections ; i++){ //判断是否落在某个区段内 if(dwRva>= pSection[i].VirtualAddress && dwRva<=pSection[i].VirtualAddress + pSection[i].Misc.VirtualSize){ //是数据目录表到区段起始地址的偏移量 offset //pSection[i].PointerToRawData区段到文件头的偏移量 //返回的是数据目录表起始地址到文件头的偏移 return dwRva - pSection[i].VirtualAddress + pSection[i].PointerToRawData; } } }//VirtualADDRESS 起始地址//Size 长度//VirtualADDRESS + Size 结束地址
导入表结构解析
遍历动态链接库和API
IMAGE_IMPORT_DESCRIPTORIMAGE_THUNK_DATAIMAGE_IMPORT_BY_NAME//解析导入表函数void ImportTable(char* buffer){ //Dos //DosHeader PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer; /电脑/PE Header PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer); //定位导入表 PIMAGE_DATA_DIRECTORY pImportDir = (PIMAGE_DATA_DIRECTORY)(pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_IMPORT) //填充结构 PIMAGE_IMPORT_DESCRIPTOR pImport = (PIMAGE_IMPORT_DESCRIPTOR)(RvaToOffset(pImportDir->VirtualAddress,buffer) + buffer); //判断导入名称为不为空 while(pImport->Name != NULL){ char * szDLLName = (char *)(RvaToOffset(pImport->Name,buffer) + buffer);//通过rva计算名字地址 printf("DLLname %s\n",szDLLName); printf("time %08x\n",pImport->TimeDataStamp); printf("ForwarderChain:%08x\n", pImport->ForwarderChain); printf("name offset:%08x\n",pImport->Name); printf("table RVA/FirstThunk:%08x\n",pImport->FirstThunk); printf("OriginalFirstThunk:电脑%08x\n\n",pImport->OriginalFirstThunk); //指向导入地址表的RVA PIMAGE_THUNK_DATA pIat = (PIMAGE_THUNK_DATA)(RvaToOffset(pImport->OriginalFirstThunk,buffer) + buffer); DWORD index = 0; DWORD ImportOffset = 0; //被导入函数的序号 while(pIat->u1.Ordinal != 0){ printf("ThunkRva:%08x\n",pImport->OriginalFirstThunk + index); ImportOffset = RvaToOffset(pImport->OriginalFirstThunk,buffer); printf("ThunkOffset:%08x\n",ImportOffset+index); index += 4; if(pIat->u1.Ordinal & 0x80000000 != 1){ PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME)(RvaToOffset(pIat->u1.AddressOfData,buffer)+buffer); printf("APIname:%s\n",pName->Name); printf("Hint:%04x\n"电脑;,pName->Hint); printf("thunkValue:%08x\n\n",pIat->u1.Function); //被导入函数的地址↑ } pIat++; } pImport++; } }
导出表结构解析
_IMAGE_EXPORT_DIRECTORY
void ExportTable(char * buffer){ //Dos //DosHeader PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer; //PE Header PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer); //定位数据目录表中的导出表 PIMAGE_DATA_DIRECTORY pExportDir = (PIMAGE_DATA_DIRECTORY)(pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT) //导出表结构填充 PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(RvaToOffset(pExportDir->VirtualAddress,buffer) + buffer ) //名称 char* szName = (char *)(RvaToOffset(pExport->Name,buffer) + buffer) if(pExport->AddressOfFunctions == 0){ printf("当前没有导出表\n"); return ; } printf("导出表OFFSET:%08x \n", RvaToOffset(pExportDir->VirtualAddress,buffer)); printf("特征值:%08x\n", pExport->Characteristics); printf("基:%08x\n", pExport->Base); printf("名称的offser:%08x\n",pExport->Name); //等等基本信息 //函数数量 DWORD dwNumOfFun = pExport->NumberOfFunctions; //函数名数量 DWORD dwNumOfNames = pExport->NumberOfNames; //基 DWORD dwBase = pExport->Base; //导出地址表 PDWORD pEat32 = (PDWORD)(RvaToOffset(pExport->AddressOfFunctions,buffer)+buffer); //导出名称表 PDWORD pEnt32 = (PDWORD)(RvaToOffset(pExport->AddressOfNames,buffer)+buffer); //导出序号表 PWORD pId = (PWORD)(RvaToOffset(pExport->AddressOfNameOrdinals,buffer)+buffer); for(int i =0;i<dwNumOfFun;i++){ if(pEat32[i] == 0){ continue; } DOWRD Id = 0; for(;Id<dwNmuOfNames;Id++){ if(pId[Id] == i){ break; } } if(Id == dwNmuOfNames){ printf("Id:%x Address: 0x%08x Name[NULL] \n",i+dwbase,pEat32[i]); } else{ char * szFunName = (char*)(RvaToOffset(pEnt32[i],buffer)+buffer); printf("Id:%x Address: 0x%08x Name[%s] \n",i+dwbase,pEat32[i],szFunName); } } }
重定位表结构解析
//解析重定位表的函数主要用于动态链接库void RelocTable(char * buffer){ //IMAGE_BASE_RELOCATION // 0x1000的倍数 typedef struct _TYPE{ WORD Offset : 12; WORD Type:4; }TYPE *PTYPE; //Dos //Dos //DosHeader PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer; //PE Header PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer); //定位重定位表 PIMAGE_DATA_DISERCTORY pRelocDir = (PIMAGE_DATA_DISERCTORY)(RvaToOffset(pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_BASERELOC)); //填充重定位表的结构 PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)(RvaToOffset(pRelocDir->VirtualAddress,buffer) + buffer); //定位区段 PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt); while(pReloc->SizOfBlock != 0 ){ //找到本块内的第一个0x1000个字节的起始位置 DWORD dwCount = (pReloc->SizeOfBlock-8) / 2;//个数 DWORD dwRva = pReloc->VirtualAddress; PTYPE pRelocArr=(PTYPE)(pReloc + 1); printf("区段:%s \n",pSection->Name); printf("Rva:0x%08x\n",dwRva); printf("Items:%X h / %d D \n",pReloc->SizeOfBlock,pReloc->SizeOfBlock); //找到下一个0x1000字节的结构体 pReloc = (PIMAGE_BASE_RELOCATION)((char*)pReloc + pReloc->SizeOfBlock ); for(int i = 0 ;i<dwCount;i++){ PDWORD pData =(PDWORD) (RvaToOffset(pRelocArr[i].Offset+dwRva,buffer) + buffer); DWORD pDataOffset = RvaToOffset(pRelocArr[i].Offset+dwRva,buffer); printf("Rva:0x%08x\n",pRelocArr[i].Offset+dwRva); printf("区段:%08x\n",*pData); printf("Offset:%08x\n",pDataOffset); } } }
TLS表结构解析
TLS表:线程局部存储,
//解析TLS表的函数void TLSTable(char * buffer){ // _IMAGE_TLS_DIRECTORY32 // _IMAGE_TLS_DIRECTORY64 //区分32位和64位 //DosHeader PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer; //PE Header PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer); //定位数据目录表中的TLS表 PIMAGE_DATA_DIRECTORY pTLSDir = (pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_TLS); //填充TLS结构 PIMAGE_TLS_DIRECTORY pTLS = (PIMAGE_TLS_DIRECTORY)(RvaToOffset(pTLSDir->VirtualAddress,buffer) + buffer); printf("数据块开始VA:%08x\n",pTLS->StartAddressOfRawData); printf("数据块结束VA:%08x\n",pTLS->EndAddressOfRawData); printf("索引变量VA:%08x\n",pTLS->AddressOfIndex); printf("回调表VA:%08x\n",pTLS->AddressOfCallBakcs); print("填零大小:%08x\n",pTLS->SizeOfZeroFill); printf("特征值:%08x\n",pTLS->Characteristics); }
延迟导入表结构解析
_IMAGE_DELAYLOAD_DESCRIPTOR
//解析延迟导入表的函数void DeLAYImportTable(char* buffer){ //DosHeader PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer; //PE Header PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer); //定位数据目录表中的延迟导入表 PIMAGE_DATA_DIRECTORY pDelayLoadDir = (pNt->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); //填充延迟导入表的数据结构 PIMAGE_DELAYLOAD_DESCRIPTOR pDelayLoad = (PIMAGE_DELAYLOAD_DESCRIPTOR)(RvaToOffset(pDelayLoadDir->VirtualAddress,buffer) + buffer); while(pDelayLoad->DllNameRVA != NULL){ char * szDllName = (char*)(RvaToOffset(pDelayLoad->DllNameRVA,buffer) + buffer); printf("DLL name :%s\n",szDllName); printf("Attributes:%08x\n",pDelayLoad->Attributes); printf("ModuleHandleRVA:%08x\n",pDelayLoad->ModuleHandleRVA); printf("ImportAddressTableRVA:%08x\n",pDelayLoad->ImportAddressTableRVA); printf("BoundImportAddressTableRVA:%08x\n",pDelayLoad->BoundImportAddressTableRVA); printf("UnloadInformationTableRVA:%08x\n",pDelayLoad->UnloadInformationTableRVA); printf("TimeDataStamp:%08x\n\n",pDelayLoad->TimeDataStamp); pDelayLoad++; } }
资源表结构解析
//LoadPE查看
//typedef struct _IMAGE_RESOURCE_DIRECTORY{ }//_IMAGE_RESOURCE_DIRECTORY_ENTRY//_IMAGE_RESOURCE_DATA_ENTRYvoid ResourceTable(){ }
其他数据表的显示
//解析其他表
void DataTable(char* buffer){ //DosHeader PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)buffer; //PE Header PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + buffer); //定位数据目录表 PIMAGE_DATA_DIRECTORY pTableDir = (pNt->OptionalHeader.DataDirectory + //你想打印的表的宏定义); printf("xxx\n"); }
电脑