// PE001.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include<windows.h> #include<time.h> //函数声明,转换文件偏移量 DWORD CalcOffect(DWORD Rva); int _tmain(int argc, _TCHAR* argv[]) { //删除文件 //DeleteFile(TEXT("D:\Test.txt")); //拷贝文件,同时也可以改名字 //CopyFile(TEXT("D:\Test.txt"), TEXT("D:\123\Testhehe.txt"),TRUE); //移动文件,同时也可以改名字 //MoveFile(TEXT("D:\Test.txt"), TEXT("D:\123\Testheihei.txt")); //设置文件指针,这个函数需要注意一下。 //SetFilePointer() //得到文件的句柄 HANDLE hFile = CreateFile( TEXT("D:\5.exe"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); //获得文件大小 DWORD dwFileSize = GetFileSize(hFile, NULL); char *pFile = new char[dwFileSize]; DWORD dwRubbish = 0; //将文件内容读取到开辟的空间中 ReadFile(hFile, pFile, dwFileSize, &dwRubbish, NULL); if (((PIMAGE_DOS_HEADER)pFile)->e_magic != IMAGE_DOS_SIGNATURE) { //不是DOS头,返回 return -1; } //将文件偏移值取出,保存 DWORD dwNewPos = (DWORD)pFile + ((PIMAGE_DOS_HEADER)pFile)->e_lfanew; //将地址转换为NT头指针 PIMAGE_NT_HEADERS32 pNTHeader = (PIMAGE_NT_HEADERS32)(dwNewPos); if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) { //不是NT头,说明不是PE文件,返回 return -1; } //取出NT头文件中成员 PIMAGE_FILE_HEADER pFileHeader = &(pNTHeader->FileHeader); //打印出头文件中结构体成员 printf("文件运行平台: %x ", pFileHeader->Machine); printf("区段的数量: %x ", pFileHeader->NumberOfSections); printf("文件创建时间: %x ", pFileHeader->TimeDateStamp); printf("符号表偏移: %x ", pFileHeader->PointerToSymbolTable); printf("符号个数: %x ", pFileHeader->NumberOfSymbols); printf("扩展头大小: %x ", pFileHeader->SizeOfOptionalHeader); printf("PE文件的一些属性:%x ", pFileHeader->Characteristics); //转换时间 tm *FIleTime = gmtime((time_t *)pFileHeader->TimeDateStamp); //扩展头信息打印 PIMAGE_OPTIONAL_HEADER32 pOptionalHeader = &(pNTHeader->OptionalHeader); printf("魔数: %x ", pOptionalHeader->Magic); printf("所有代码区段的总大小: %x ", pOptionalHeader->SizeOfCode); printf("已初始化数据总大小: %x ", pOptionalHeader->SizeOfInitializedData); printf("未初始化数据总大小: %x ", pOptionalHeader->SizeOfUninitializedData); printf("程序开始执行的相对虚拟地址: %x ", pOptionalHeader->AddressOfEntryPoint); printf("起始代码的相对虚拟地址: %x ", pOptionalHeader->BaseOfCode); printf("起始数据的相对虚拟地址: %x ", pOptionalHeader->BaseOfData); printf("默认加载基址: %x ", pOptionalHeader->ImageBase); printf("块对齐数: %x ", pOptionalHeader->SectionAlignment); printf("文件对齐数: %x ", pOptionalHeader->FileAlignment); printf("内存大小: %x ", pOptionalHeader->SizeOfImage); printf("文件起始偏移: %x ", pOptionalHeader->SizeOfHeaders); printf("子系统: %x ", pOptionalHeader->Subsystem); printf("特征标志: %x ", pOptionalHeader->DllCharacteristics); printf("栈最大值: %x ", pOptionalHeader->SizeOfStackReserve); printf("栈初始值: %x ", pOptionalHeader->SizeOfStackCommit); printf("堆最大值: %x ", pOptionalHeader->SizeOfHeapReserve); printf("堆初始值: %x ", pOptionalHeader->SizeOfHeapCommit); printf("数据目录个数: %x ", pOptionalHeader->NumberOfRvaAndSizes); //读取数据目录表信息 PIMAGE_DATA_DIRECTORY pDataDirectory = pOptionalHeader->DataDirectory; //循环读取出数据目录中的相对虚拟地址和大小 DWORD i = 0; while (i != 0x10) { //显示相对虚拟地址 printf("第 %d 个相对虚拟地址 %7x", i, pDataDirectory[i].VirtualAddress); printf(" 大小为: %7x ", pDataDirectory[i].Size); i++; } //区段头表 PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNTHeader); //循环输出,区段表信息,可以用两种方式判断结束,一个是文件头给出的区段的数量 //可以用那个,也可以判断最后一个全零的区段头 int j = 0; while (j<pOptionalHeader->NumberOfRvaAndSizes) { //输出或者获取每一个pSectionHeader中的成员 printf("名称:%7x V0ffset:%7x VSize:%7x ROffset:%7x RSize:%7x 标志:%7x ", pSectionHeader->Name, //区段名称 pSectionHeader->VirtualAddress, //起始的相对虚拟地址 pSectionHeader->Misc, //加载后区段大小 pSectionHeader->PointerToRawData, //文件偏移 pSectionHeader->SizeOfRawData, //区段大小,文件中 pSectionHeader->Characteristics //区段的属性 ); ++pSectionHeader; j++; } ////计算偏移量 //DWORD CalcOffect(DWORD Rva) //{ // //获取NT头 // PIMAGE_NT_HEADERS32 pNTHeader = (PIMAGE_NT_HEADERS32)((long)pFile + (PIMAGE_DOS_HEADER)pFile->e_lfanew); // //获取区段头表 // PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNTHeader); // //循环比较它在哪个区段中,不在这个区段就继续循环,注意假如 // //VirtualAddress比SizeOfRawData大的话,说明大出来的部分是未初始化的数据,所以这里要用SizeOfRawData // while (!(Rva) > pSectionHeader->VirtualAddress&&Rva < // pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)) // { // ++pSectionHeader; // //防止错误的PE文件引发崩溃 // if (pSectionHeader->PointerToRawData == 0) // return 0; // } // return Rva - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData; //}; return 0; }