概述
预备知识
MS-DOS头
PE文件头
IMAGE_FILE_HEADER
IMAGE_OPTIONAL_HEADER32
IMAGE_DATA_DIRECTORY
IMAGE_DIRECTORY_ENTRY_EXPORT
IMAGE_IMPORT_DESCRIPTOR
IMAGE_BASE_RELOCATION
节表信息
总体设计
不足
改进
详细设计
文件保存
关联信息的修改
文件位置计算器(FLC)
节信息(Section)
目录信息
导出表
导出表信息的展示
导出表信息的修改
导入表
资源
资源信息的获取
资源信息的展示
重定位信息
控件设计
Edit控件
信息的展示
限制用户输入
信息的获取
单选框控件
复选框与下拉框控件
复选框的设置
下拉框的设置
列表控件(ListCtrl)
列表右键弹出菜单
总结概述
最近学习了PE文件的知识,为了加深对知识的理解,任老师给我们布置了一个任务,自己完成一个PE编辑器。在写之前还觉得挺简单,到真正开始写的时候才发现有好多东西都不是想象中那么简单,有许多需要注意的地方。也多亏了这次写PE编辑器积累的经验,在写壳时给了我很大的帮助。
先说明一下文章中用到的一些词汇,不一定用的对。
文件缓存:读取磁盘上的一个PE文件,然后将这个PE文件保存到内存中的一段空间,使用new一段堆空间,或者使用文件映射的方式都行。
区段,节:都是指Section
偏移:一个特定位置基于某个指定位置的差值
FOA(File Offset Address):数据在PE文件中的地址叫文件偏移地址。这是文件在磁盘上存放时相对于文件开头的偏移
RVA(Relative Virtual Address):相对虚拟地址是内存地址相对于映射基址的偏移量。
映射基址:PE文件被系统PE加载器加载到内存后的首地址。预备知识
关于PE文件的知识,网上有很多资料,这里就不做深入的解释了,只说一些我写程序时遇到的问题,有一部分问题是写壳时遇到的,这里也一起总结一下。
●
[*]MS-DOS头
将PE文件读入内存中后,将文件缓存的首地址强制转换为IMAGE_DOS_HEADER 类型的指针就可以获取MS-DOS头的内容,在这个结构体中只需要关注两个字段e_magic 字段和e_lfanew字段
●
[*]e_magic字段用来检测是否有效的PE文件
●
[*]e_lfanew字段表示windows下PE文件头的偏移位置
●
[*]PE文件头
IMAGE_NT_HEADERS 用这个结构体来表示,通过MS-DOS头的e_lfanew字段的值加上文件缓存的起始地址可以获取该结构体类型的指针。
这个头在32位和64位系统上是不一样的,上面的结构体是一个宏,根据不同的编译选项生成不同的结构体
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_OPTIONAL_HEADER {
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
DWORD BaseOfData;
DWORD ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
DWORD SizeOfStackReserve;
DWORD SizeOfStackCommit;
DWORD SizeOfHeapReserve;
DWORD SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions;
DWORD AddressOfNames;
DWORD AddressOfNameOrdinals;
} IMAGE_EXPORT_DIRECTORY;
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
DWORD Characteristics;
DWORD OriginalFirstThunk;
} DUMMYUNIONNAME;
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
// WORD TypeOffset[1];
} IMAGE_BASE_RELOCATION;
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
} IMAGE_SECTION_HEADER;
/**
*@brief 将指针指向的内容保存到文件中
*/
DWORD SavePointerContent(LPVOID pContent,DWORD dwSize);
TCHAR szGet[9] = {0};
for (DWORD i=0,j=0;i<16;i++,j+=2,pData++)
{
// 将::GetDlgItem放到GetWindow中会获取不正确
hEdit = ::GetDlgItem(this->m_hWnd,EXPORT_RVA_EDIT+j);
::GetWindowText(hEdit,szGet,9);
swscanf_s(szGet,L"%x",&dwGet);
pData->VirtualAddress = dwGet;
hEdit = ::GetDlgItem(this->m_hWnd,EXPORT_RVA_EDIT+j+1);
::GetWindowText(hEdit,szGet,9);
swscanf_s(szGet,L"%x",&dwGet);
pData->Size = dwGet;
}
DWORD AddressOfFunctions; // RVA from base of image
DWORD AddressOfNames; // RVA from base of image
DWORD AddressOfNameOrdinals; // RVA from base of image
// 改变缓存中名称的值
memcpy_s(pName,pOri->strAPI.GetLength()+sizeof(char),
strOut,stcSave.strAPI.GetLength()+sizeof(char));
// 改变文件中的名称信息
dwOffset = (PBYTE)pName - m_pFileBuffer;
SetFilePointer(hFile,dwOffset,0,FILE_BEGIN);
WriteFile(hFile,pName,stcSave.strAPI.GetLength()+sizeof(char),
&dwWrite,NULL);
IMAGE_RESOURCE_DIRECTORY
IMAGE_RESOURCE_DATA_ENTRY
IMAGE_RESOURCE_DATA_ENTRY
…..
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: