PE文件-分析vc示范所有代码[不包含EXPORT TABLE]

来源:互联网 发布:恢复软件finaldata 编辑:程序博客网 时间:2024/06/04 23:12
#include <windows.h>#include <iostream>#define PE_FILE_NAME TEXT("C:\\WINDOWS\\system32\\notepad.exe")#define CREATE_FILE_FAILURE "创建文件失败"#define CREATE_MAPPING_FILE "创建文件映射对象失败"#define MAP_VIEW_FAILURE "映射文件到调用进程的地址空间失败"#define VALID_DOS_SIGNATURE "这个文件的DOS签名是有效的"#define VALID_PE_SIGNATURE "这个文件的PE签名是有效的"#define VALID_PE_FILE "这是一个有效的PE文件"#define INVALID_PE_FILE "这是一个无效的PE文件"#define WRITE_LINE(msg) std::cout << TEXT(msg) << std::endl;#define WRITE_LINE_EX(msg1,msg2) std::cout << TEXT(msg1) << TEXT(msg2) << std::endl;#define WRITE(msg) std::cout << TEXT(msg);#define PROCESS_FAILURE(msg) WRITE_LINE(msg)\return FALSE;#define PE_PARSE_NT_HEADER_CALLBACK void (*PARSE_NT_HEADER_CALLBACK)(IMAGE_NT_HEADERS*)=NULL#define PE_PARSE_SECTION_HEADER_CALLBACK void (*PARSE_SECTION_HEADER_CALLBACK)(IMAGE_SECTION_HEADER*,INT)=NULL#define PE_PARSE_IMPORT_TABLE_CALLBACK void (*PARSE_IMPORT_TABLE_CALLBACK)(IMAGE_DATA_DIRECTORY*,PVOID)/* 根据文件头获得文件节表头 */#define GET_IMAGE_SECTION_HEADER(lpNtHeader) ((IMAGE_SECTION_HEADER *)((byte*)lpNtHeader+sizeof(*lpNtHeader)))/* 根据文件头获得文件节数量 */#define GET_IMAGE_NUMBER_OF_SECTIONS(lpNtHeader) (lpNtHeader->FileHeader.NumberOfSections)/* 虚拟地址到文件偏移量 */#define RVA_TO_OFFSET(pImageBase,rva) ((PVOID)((byte*)pImageBase+rva))/* 映射文件到内存映像 */PVOID MapFileToView(LPCSTR filename);/* 获得PE文件头 */IMAGE_NT_HEADERS* GetPeHeader(LPVOID pMapping);/* 验证PE合法性函数 */BOOL Validate(LPVOID pMapping);/* 分析PE头函数 */void PARSE_NT_HEADER_CALLBACK(IMAGE_NT_HEADERS* lpNtHeader);/* 分析PE节表函数 */void PARSE_SECTION_HEADER_CALLBACK(IMAGE_SECTION_HEADER* lpSectionHeader,INT numberOfSections);/* 分析引入表 */void PARSE_IMPORT_TABLE_CALLBACK(IMAGE_DATA_DIRECTORY* lpImageDataDirectory,PVOID pImageBase);/* 将相对虚拟地址转换为文件偏移地址 */DWORD RVAToFileOffset(PVOID,DWORD);/* 显示DLL的所有引入函数 */void PARSE_IMPORT_TABLE_FUNCTION_CALLBACK(PVOID,IMAGE_THUNK_DATA*);void main(){//将文件映射到内存PVOID pMapping = MapFileToView(PE_FILE_NAME);//获取文件头IMAGE_NT_HEADERS* lpImageNtHeader = GetPeHeader(pMapping);if (lpImageNtHeader){//显示文件头信息PARSE_NT_HEADER_CALLBACK(lpImageNtHeader);//显示文件节头信息PARSE_SECTION_HEADER_CALLBACK(GET_IMAGE_SECTION_HEADER(lpImageNtHeader),GET_IMAGE_NUMBER_OF_SECTIONS(lpImageNtHeader));//分析导入表PARSE_IMPORT_TABLE_CALLBACK(&(lpImageNtHeader->OptionalHeader.DataDirectory[1]),pMapping);}//取消映射UnmapViewOfFile(pMapping);pMapping = NULL;}/* 映射文件到内存映像 */PVOID MapFileToView(LPCSTR filename){HANDLE fHandle = ::CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if (fHandle==INVALID_HANDLE_VALUE){PROCESS_FAILURE(CREATE_FILE_FAILURE);}HANDLE hMapping = ::CreateFileMapping(fHandle,NULL,PAGE_READONLY,NULL,NULL,NULL);if (hMapping==NULL){CloseHandle(fHandle);PROCESS_FAILURE(CREATE_MAPPING_FILE);}LPVOID pMapping = ::MapViewOfFile(hMapping,FILE_MAP_READ,NULL,NULL,NULL);if (pMapping==NULL){PROCESS_FAILURE(MAP_VIEW_FAILURE);}CloseHandle(hMapping);CloseHandle(fHandle);hMapping = NULL;fHandle = NULL;return pMapping;}/* 验证PE入口函数 */BOOL Validate(LPVOID pMapping){//1.validate IMAGE_DOS_HEADERIMAGE_DOS_HEADER * dosHeader = (IMAGE_DOS_HEADER*)pMapping;// if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE)// {// WRITE_LINE(VALID_DOS_SIGNATURE);// }IMAGE_NT_HEADERS * nt_header=(IMAGE_NT_HEADERS*)((byte*)pMapping+dosHeader->e_lfanew);// if (nt_header->Signature == IMAGE_NT_SIGNATURE)// {// WRITE_LINE(VALID_PE_SIGNATURE);// }// WRITE_LINE(// (// dosHeader->e_magic == IMAGE_DOS_SIGNATURE && nt_header->Signature == IMAGE_NT_SIGNATURE?// TEXT(VALID_PE_FILE):// TEXT(INVALID_PE_FILE)// )// );return dosHeader->e_magic == IMAGE_DOS_SIGNATURE && nt_header->Signature == IMAGE_NT_SIGNATURE;}IMAGE_NT_HEADERS* GetPeHeader(LPVOID pMapping){IMAGE_DOS_HEADER * dosHeader = (IMAGE_DOS_HEADER*)pMapping;IMAGE_NT_HEADERS * nt_header=(IMAGE_NT_HEADERS*)((byte*)pMapping+dosHeader->e_lfanew);//检查PE有效性if (dosHeader->e_magic == IMAGE_DOS_SIGNATURE && nt_header->Signature == IMAGE_NT_SIGNATURE)//如果PE头有效则返回PE头{return nt_header;}//PE头无效则取消内存映射释放资源并返回NULLUnmapViewOfFile(pMapping);pMapping = NULL;return NULL;}/* 分析NT_HEADER回调函数 */void PARSE_NT_HEADER_CALLBACK(IMAGE_NT_HEADERS* lpNtHeader){WRITE_LINE(TEXT("----------------------------------FILE HEADER------------------------------------------------"));WRITE_LINE((lpNtHeader->FileHeader.Machine==IMAGE_FILE_MACHINE_I386?TEXT("该程序运行所在机器:Intel 386"):TEXT("该程序运行所在机器:非Intel 386")));WRITE(TEXT("该程序的块数量:"));WRITE_LINE(lpNtHeader->FileHeader.NumberOfSections);WRITE_LINE(TEXT("----------------------------------FILE OPTIONAL HEADER--------------------------------------"));std::cout.setf(std::ios::hex,std::ios::basefield);//设置输出格式为16进制std::cout << TEXT("PE装载器准备运行的PE文件的第一个指令的RVA:") << lpNtHeader->OptionalHeader.AddressOfEntryPoint << std::endl;std::cout << TEXT("PE文件的优先装载地址:") << lpNtHeader->OptionalHeader.ImageBase << std::endl;std::cout << TEXT("内存中节对齐的粒度:") << lpNtHeader->OptionalHeader.SectionAlignment << std::endl;std::cout << TEXT("文件中节对齐的粒度:") << lpNtHeader->OptionalHeader.FileAlignment << std::endl;std::cout << TEXT("win32子系统版本[若PE文件是专门为Win32设计的,该子系统版本必定是4.0否则对话框不会有3维立体感]:") << lpNtHeader->OptionalHeader.MajorOperatingSystemVersion << "." << lpNtHeader->OptionalHeader.MinorOperatingSystemVersion << std::endl;std::cout << TEXT("内存中整个PE映像体的尺寸[它是所有头和节经过节对齐处理后的大小]:") << lpNtHeader->OptionalHeader.SizeOfImage << std::endl;std::cout << TEXT("所有头+节表的大小[也就等于文件尺寸减去文件中所有节的尺寸。可以以此值作为PE文件第一节的文件偏移量]:") << lpNtHeader->OptionalHeader.SizeOfHeaders << std::endl;std::cout << TEXT("PE文件属于子系统:") << (lpNtHeader->OptionalHeader.Subsystem==IMAGE_SUBSYSTEM_WINDOWS_GUI?TEXT("图形用户界面"):TEXT("字符界面")) << std::endl;WRITE_LINE(TEXT("----------------------------------FILE SECTION TABLE--------------------------------------"));//定位节表位置IMAGE_SECTION_HEADER *lpSectionHeader = (IMAGE_SECTION_HEADER *)((byte*)lpNtHeader+sizeof(*lpNtHeader));//PARSE_SECTION_HEADER_CALLBACK(lpSectionHeader,lpNtHeader->FileHeader.NumberOfSections);// for (int i=0;i<lpNtHeader->FileHeader.NumberOfSections;i++)// {// std::cout << lpSectionHeader->Name << "\0" << std::endl;// std::cout << TEXT("\t本节的RVA(相对虚拟地址):") << lpSectionHeader->VirtualAddress << std::endl;// std::cout << TEXT("\t经过文件对齐处理后节尺寸:") << lpSectionHeader->SizeOfRawData << std::endl;// std::cout << TEXT("\t本节基于文件的偏移量:") << lpSectionHeader->PointerToRawData << std::endl;// lpSectionHeader++;// }}/* 分析IMAGE_SECTION_HEADER回调函数 */void PARSE_SECTION_HEADER_CALLBACK(IMAGE_SECTION_HEADER* lpSectionHeader,INT numberOfSections){if (lpSectionHeader && numberOfSections){for (int i=0;i<numberOfSections;i++){std::cout << lpSectionHeader->Name << "\0" << std::endl;std::cout << TEXT("\t本节的RVA(相对虚拟地址):") << lpSectionHeader->VirtualAddress << std::endl;std::cout << TEXT("\t经过文件对齐处理后节尺寸:") << lpSectionHeader->SizeOfRawData << std::endl;std::cout << TEXT("\t本节基于文件的偏移量:") << lpSectionHeader->PointerToRawData << std::endl;lpSectionHeader++;}}}/* 分析PE导入表函数 IMAGE_DATA_DIRECTORY.VirtualAddress-->IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk/IMAGE_IMPORT_DESCRIPTOR.FirstThunk-->//IMAGE_IMPORT_DESCRIPTOR 数组以一个全0域元素结尾IMAGE_THUNK_DATA-->IMAGE_IMPORT_BY_NAME.Name*/void PARSE_IMPORT_TABLE_CALLBACK(IMAGE_DATA_DIRECTORY* lpImageDataDirectory,PVOID pImageBase){if (!lpImageDataDirectory)return;WRITE_LINE(TEXT("----------------------------------PARSE IMPORT TABLE----------------------------------------"));int dllcounter = 0;IMAGE_IMPORT_DESCRIPTOR* lpImageImportDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)((byte*)pImageBase+RVAToFileOffset(pImageBase,lpImageDataDirectory->VirtualAddress));while (lpImageImportDescriptor->Name!=NULL)//如果不是空元素{dllcounter++;WRITE_LINE((char*)((byte*)pImageBase+RVAToFileOffset(pImageBase,lpImageImportDescriptor->Name)));//输出当前的DLL名字DWORD thunk = (lpImageImportDescriptor->OriginalFirstThunk==NULL?lpImageImportDescriptor->FirstThunk:lpImageImportDescriptor->OriginalFirstThunk);PARSE_IMPORT_TABLE_FUNCTION_CALLBACK(pImageBase,(IMAGE_THUNK_DATA *)((byte*)pImageBase+RVAToFileOffset(pImageBase,thunk)));WRITE_LINE(TEXT("-------------------------------------------"));lpImageImportDescriptor++;}WRITE_LINE_EX(TEXT("导出DLL数目:"),TEXT(dllcounter));}/* 分析PE引出表函数 */void PARSE_EXPORT_TABLE_CALLBACK(IMAGE_DATA_DIRECTORY* lpImageDataDirectory,PVOID pImageBase){//尚未完成}void PARSE_IMPORT_TABLE_FUNCTION_CALLBACK(PVOID pImageBase,IMAGE_THUNK_DATA *lpImageThunkData){WRITE_LINE(TEXT("\t\tHint\t\tFunction"));while (lpImageThunkData->u1.Ordinal!=NULL){//对于每个数组元素,我们比对元素值是否等于IMAGE_ORDINAL_FLAG32。//如果该元素值的最高二进位为1,那么函数是由序数引入的,可以从该值的低字节提取序数。 //如果元素值的最高二进位为0,就可将该值作为RVA转入 IMAGE_IMPORT_BY_NAME 数组,跳过 Hint 就是函数名字了if(lpImageThunkData->u1.Ordinal & IMAGE_ORDINAL_FLAG32)//如果该元素值的最高二进位为1,那么函数是由序数引入的{WORD ordinal = (lpImageThunkData->u1.Ordinal & 0xFFFF);//从该值的低字节提取序数WRITE_LINE_EX(TEXT("\t\t"),ordinal);//输出该函数编号}else{IMAGE_IMPORT_BY_NAME* lpImageImportByName = (IMAGE_IMPORT_BY_NAME*)((byte*)pImageBase+RVAToFileOffset(pImageBase,lpImageThunkData->u1.Ordinal));WRITE(TEXT("\t\t0x"));WRITE(lpImageImportByName->Hint);WRITE(TEXT("\t\t"));WRITE_LINE((char*)(lpImageImportByName->Name));}lpImageThunkData++;}}/* 将相对虚拟地址转换为文件偏移地址 */DWORD RVAToFileOffset(PVOID pMappping,DWORD rva){//定位到DOS头IMAGE_DOS_HEADER* lpImageDosHeader = (IMAGE_DOS_HEADER*)pMappping;//定位到PE头IMAGE_NT_HEADERS* lpImageNtHeader = (IMAGE_NT_HEADERS*)((byte*)pMappping+lpImageDosHeader->e_lfanew);//定位到节表IMAGE_SECTION_HEADER* lpSectionTable = (IMAGE_SECTION_HEADER*)((byte*)lpImageNtHeader+sizeof(IMAGE_NT_HEADERS));//用节数量作循环次数int i = lpImageNtHeader->FileHeader.NumberOfSections;while(i>0)//检查所有块{if (rva>=lpSectionTable->VirtualAddress)//如果传入的rva大于等于当前节的虚拟地址{DWORD sectionEndAddr = lpSectionTable->VirtualAddress+lpSectionTable->SizeOfRawData;//当前节结束地址=当前节的虚拟地址+文件对齐处理后节尺寸if (rva<sectionEndAddr)//如果这个rva地址在这个块里面{DWORD r_rva = rva-lpSectionTable->VirtualAddress;//这个rva地址-当前节的虚拟地址[rva距离节的开始地址的距离]return lpSectionTable->PointerToRawData+r_rva;//当前节基于文件的偏移量+rva距离节的开始地址的距离}}lpSectionTable++;i--;}return rva;}


 

原创粉丝点击