清明节回来乘车到学校,没想到竟然做错了公交车。来回竟然多花了3个小时。。。。。。车子又挤。真的快无语了。
所以写下代码来泄愤。。。。
首先给大家推广下小甲鱼的网站
http://fishc.com/ 小甲鱼是个大帅锅(。。。。)
这个网站做的很齐全,里面讲汇编,PE,破解等很多好的资源。小甲鱼的视频讲解也是很详细的。自己看完书再看一遍小甲鱼的视频,最后自己再写代码巩固一下,感觉学习效果还是不错的。
好吧,接下来就不说废话了。先发一张图片,这个是比较完整的PE结构。图片有点大貌似不太好看。
然后从小甲鱼那里搞来的DOS头结构和PE头结构的数据结构如下(有中文翻译的)
IMAGE_DOS_HEADER STRUCT
{
+0h WORD e_magic // Magic DOS signature MZ(4Dh 5Ah) DOS可执行文件标记
+2h WORD e_cblp // Bytes on last page of file
+4h WORD e_cp // Pages in file
+6h WORD e_crlc // Relocations
+8h WORD e_cparhdr // Size of header in paragraphs
+0ah WORD e_minalloc // Minimun extra paragraphs needs
+0ch WORD e_maxalloc // Maximun extra paragraphs needs
+0eh WORD e_ss // intial(relative)SS value DOS代码的初始化堆栈SS
+10h WORD e_sp // intial SP value DOS代码的初始化堆栈指针SP
+12h WORD e_csum // Checksum
+14h WORD e_ip // intial IP value DOS代码的初始化指令入口[指针IP]
+16h WORD e_cs // intial(relative)CS value DOS代码的初始堆栈入口
+18h WORD e_lfarlc // File Address of relocation table
+1ah WORD e_ovno // Overlay number
+1ch WORD e_res[4] // Reserved words
+24h WORD e_oemid // OEM identifier(for e_oeminfo)
+26h WORD e_oeminfo // OEM information;e_oemid specific
+29h WORD e_res2[10] // Reserved words
+3ch DWORD e_lfanew // Offset to start of PE header 指向PE文件头
} IMAGE_DOS_HEADER ENDS
首先是IMAGE_NT_HEADERS 结构的定义:(啥?结构不会,先看看小甲鱼童鞋的《零基础入门学习C语言》关于结构方面的章节吧~)
IMAGE_NT_HEADERS STRUCT
{
+0h DWORDSignature
+4h IMAGE_FILE_HEADER FileHeader
+18h IMAGE_OPTIONAL_HEADER32OptionalHeader
} IMAGE_NT_HEADERS ENDS
在一个有效的 PE 文件里,Signature 字段被设置为00004550h, ASCII 码字符是“PE00”。标志这 PE 文件头的开始。
“PE00” 字符串是 PE 文件头的开始,DOS 头部的 e_lfanew 字段正是指向这里。
如下图所示:
typedef struct _IMAGE_FILE_HEADER
{
+04h WORD Machine; // 运行平台
+06h WORD NumberOfSections; // 文件的区块数目
+08h DWORD TimeDateStamp; // 文件创建日期和时间
+0Ch DWORD PointerToSymbolTable; // 指向符号表(主要用于调试)
+10h DWORD NumberOfSymbols; // 符号表中符号个数(同上)
+14h WORD SizeOfOptionalHeader; // IMAGE_OPTIONAL_HEADER32 结构大小
+16h WORD Characteristics; // 文件属性
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
该结构如下图所示:
(1)Machine:可执行文件的目标CPU类型。
Value | Meaning |
---|---|
|
x86 |
|
Intel Itanium |
|
x64 |
(2)NumberOfSection: 区块的数目。(注:区块表是紧跟在 IMAGE_NT_HEADERS 后边的)
(3)TimeDataStamp: 表明文件是何时被创建的。
这个值是自1970年1月1日以来用格林威治时间(GMT) 计算的秒数,这个值是比文件系统(FILESYSTEM)的日期时间更加精确的指示器。如何将这个值翻译请 看:http://home.fishc.com/space.php?uid=9&do=blog&id=555
提示:VC的话可以用_ctime 函数或者 gmtime 函数。
(4)PointerToSymbolTable: COFF 符号表的文件偏移位置,现在基本没用了。
(5)NumberOfSymbols: 如果有COFF 符号表,它代表其中的符号数目,COFF符号是一个大小固定的结构,如果想找到COFF 符号表的结束位置,则需要这个变量。
(6)SizeOfOptionalHeader: 紧跟着IMAGE_FILE_HEADER 后边的数据结构(IMAGE_OPTIONAL_HEADER)的大小。(对于32位PE文件,这个值通常是00E0h;对于64位PE32+文件,这个值是00F0h )。
(7)Characteristics: 文件属性,有选择的通过几个值可以运算得到。( 这些标志的有效值是定义于 winnt.h 内的 IMAGE_FILE_** 的值,具体含义见下表。普通的EXE文件这个字段的值一般是 0100h,DLL文件这个字段的值一般是 210Eh。)小甲鱼温馨提示:多种属性可以通过 “或运算” 使得同时拥有!
The characteristics of the image. This member can be one or more of the following values.
Value | Meaning |
---|---|
|
Relocation information was stripped from the file. The file must be loaded at its preferred base address. If the base address is not available, the loader reports an error. |
|
The file is executable (there are no unresolved external references). |
|
COFF line numbers were stripped from the file. |
|
COFF symbol table entries were stripped from file. |
|
Aggressively trim the working set. This value is obsolete as of Windows 2000. |
|
The application can handle addresses larger than 2 GB. |
|
The bytes of the word are reversed. This flag is obsolete. |
|
The computer supports 32-bit words. |
|
Debugging information was removed and stored separately in another file. |
|
If the image is on removable media, copy it to and run it from the swap file. |
|
If the image is on the network, copy it to and run it from the swap file. |
|
The image is a system file. |
|
The image is a DLL file. While it is an executable file, it cannot be run directly. |
|
The file should be run only on a uniprocessor computer. |
|
The bytes of the word are reversed. This flag is obsolete. |
最后是自己写的读取dos头和pe头的代码(参考了醒哥的博客www.kkmonster.com)
#include <stdio.h> #include <windows.h> #include <tchar.h> const TCHAR* FileName = "c:\\windows\\system32\\cmd.exe"; //文件目录 BYTE* pBase = NULL; //基地址 BYTE* fnReadFile(); //读取文件 int fnReadPE (BYTE *pBuffer); //读取PE文件信息 BYTE* fnReadDosHeader(BYTE* pBuffer); //读取dos文件头信息 int fnReadNTHeader(BYTE* pBuffer); //读取 PE文件头信息 int fnReadFileHeader(BYTE* ImageFileHeader); //读取PE文件头中的FileHeader结构的信息 int fnReadOptionalHeader(BYTE* ImageOptionalHeader); //读取PE文件头中的OptionalHeader结构的信息 int main() { BYTE* pBuffer = fnReadFile(); fnReadPE (pBuffer); return 0; } BYTE* fnReadFile() { printf("映射文件...\n"); HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //读取文件 if (hFile == INVALID_HANDLE_VALUE) { printf("打开文件出错\n"); return 0; } DWORD dwFileSize = GetFileSize(hFile, NULL); //获得文件大小 BYTE* pBuffer = new BYTE[dwFileSize]; //new相当于malloc DWORD dwSizeOfRead; if(!ReadFile(hFile, pBuffer, dwFileSize, &dwSizeOfRead, NULL)) { printf("读取文件出错\n"); pBase = NULL; return 0; } pBase = pBuffer; return pBase; //基地址 } int fnReadPE(BYTE *pBuffer) { printf("读取PE信息...\n"); BYTE* pBaseNTHeader = fnReadDosHeader(pBuffer); //调用fnReadDosHeader函数获取Dos头信息,并且获得PE文件头的基地址 if (!pBaseNTHeader) { return 1; } if (!fnReadNTHeader(pBaseNTHeader)) //读取PE文件头信息 { return 1; } return 0; } BYTE* fnReadDosHeader(BYTE* pBuffer) //读取dos文件头信息 { printf("读取DOS文件头...\n"); PIMAGE_DOS_HEADER SrcImageDosHeader = (PIMAGE_DOS_HEADER)pBuffer; if (SrcImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return 0; } else { printf("IMAGE_DOS_HEADER结构\n"); printf("e_magic :%04x DOS可执行文件标记\n",SrcImageDosHeader->e_magic); printf("e_cblp :%04x Bytes on last page of file\n",SrcImageDosHeader->e_cblp); printf("e_cp :%04x Page in file\n", SrcImageDosHeader->e_cp); printf("e_crlc :%04x Relocations\n", SrcImageDosHeader->e_crlc); printf("e_cparhdr :%04x Size of header in paragraphs\n", SrcImageDosHeader->e_cparhdr); printf("e_minalloc:%04x Minimum extra paragraphs needed\n", SrcImageDosHeader->e_minalloc); printf("e_maxalloc:%04x Maximum extra paragraphs needed\n", SrcImageDosHeader->e_maxalloc); printf("e_ss :%04x Initial (relative) SS value DOS代码的初始化堆栈SS\n", SrcImageDosHeader->e_ss); printf("e_sp :%04x Initial SP value DOS代码的初始化堆栈指针SP\n", SrcImageDosHeader->e_sp); printf("e_csum :%04x Checksum\n", SrcImageDosHeader->e_csum); printf("e_ip :%04x Initial IP value DOS代码的初始化指针入口\n", SrcImageDosHeader->e_ip); printf("e_cs :%04x Initial (relative) CS value DOS代码的初始堆栈入口\n", SrcImageDosHeader->e_cs); printf("e_lfarlc :%04x File address of elocation table\n", SrcImageDosHeader->e_lfarlc); printf("e_ovno :%04x Overlay number\n", SrcImageDosHeader->e_ovno); printf("e_res[4] :%04x, %04x, %04x, %04x Reserved words\n", SrcImageDosHeader->e_res[0],SrcImageDosHeader->e_res[1],SrcImageDosHeader->e_res[2],SrcImageDosHeader->e_res[3]); printf("e_oemid :%04x OEM identifier (for e_oeminfo)\n", SrcImageDosHeader->e_oemid); printf("e_oeminfo :%04x OEM information; e_oemid specific\n", SrcImageDosHeader->e_oeminfo); printf("e_res2[10]:%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x,%04x, Reserved words\n", SrcImageDosHeader->e_res2[0],SrcImageDosHeader->e_res2[1],SrcImageDosHeader->e_res2[2],SrcImageDosHeader->e_res2[3],SrcImageDosHeader->e_res2[4],SrcImageDosHeader->e_res2[5],SrcImageDosHeader->e_res2[6],SrcImageDosHeader->e_res2[7],SrcImageDosHeader->e_res2[8],SrcImageDosHeader->e_res2[9]); printf("e_lfanew :%04x File address of new exe header 指向PE文件头\n", SrcImageDosHeader->e_lfanew); } return (BYTE*) (pBuffer + SrcImageDosHeader->e_lfanew); } int fnReadNTHeader(BYTE* pBaseNTBuffer) { printf("读取PE文件头...\n"); PIMAGE_NT_HEADERS SrcImageNTHeader = (PIMAGE_NT_HEADERS)(pBaseNTBuffer); if (SrcImageNTHeader->Signature != IMAGE_NT_SIGNATURE) { return 1; } else { printf("IMAGE_NT_HEADERS结构\n"); printf("Signature :%08x\n", SrcImageNTHeader->Signature); fnReadFileHeader((BYTE*)&SrcImageNTHeader->FileHeader); //读取FileHeader结构的信息 fnReadOptionalHeader((BYTE*) &SrcImageNTHeader->OptionalHeader); //读取OptionalHeader结构的信息 } return 0; } int fnReadFileHeader(BYTE* ImageFileHeader) { PIMAGE_FILE_HEADER SrcImageFileHeader = (PIMAGE_FILE_HEADER)ImageFileHeader; printf("IMAGE_NT_HEADERS结构\n"); printf("Machine: %04x\n", SrcImageFileHeader->Machine); printf("NumberOfSections: %04x\n", SrcImageFileHeader->NumberOfSections); printf("TimeDateStamp: %08x\n", SrcImageFileHeader->TimeDateStamp); printf("PointerToSymbolTable: %08x\n", SrcImageFileHeader->PointerToSymbolTable); printf("NumberOfSymbols: %08x\n", SrcImageFileHeader->NumberOfSymbols); printf("SizeOfOptionalHeader: %04x\n", SrcImageFileHeader->SizeOfOptionalHeader); printf("Characteristics: %04x\n", SrcImageFileHeader->Characteristics); return 0; } int fnReadOptionalHeader(BYTE* ImageOptionalHeader) { PIMAGE_OPTIONAL_HEADER SrcImageOptional_Header = (PIMAGE_OPTIONAL_HEADER)ImageOptionalHeader; printf("IMAGE_OPTIONAL_HEADER结构\n"); // Standard fields. printf("Magic: %04x\n", SrcImageOptional_Header->Magic); printf("MajorLinkerVersion: %02x\n", SrcImageOptional_Header->MajorLinkerVersion); printf("MinorLinkerVersion: %02x\n", SrcImageOptional_Header->MinorLinkerVersion); printf("SizeOfCode: %08x\n", SrcImageOptional_Header->SizeOfCode); printf("SizeOfInitializedData: %08x\n", SrcImageOptional_Header->SizeOfInitializedData); printf("SizeOfUninitializedData: %08x\n", SrcImageOptional_Header->SizeOfUninitializedData); printf("AddressOfEntryPoint: %08x\n", SrcImageOptional_Header->AddressOfEntryPoint); printf("BaseOfCode: %08x\n", SrcImageOptional_Header->BaseOfCode); printf("BaseOfData: %08x\n", SrcImageOptional_Header->BaseOfData); // NT additional fields. printf("ImageBase: %08x\n", SrcImageOptional_Header->ImageBase); printf("SectionAlignment: %08x\n", SrcImageOptional_Header->SectionAlignment); printf("FileAlignmen: %08x\n", SrcImageOptional_Header->FileAlignment); printf("MajorOperatingSystemVersion:%04x\n", SrcImageOptional_Header->MajorOperatingSystemVersion); printf("MinorOperatingSystemVersion:%04x\n", SrcImageOptional_Header->MinorOperatingSystemVersion); printf("MajorImageVersion; %04x\n", SrcImageOptional_Header->MajorImageVersion); printf("MinorImageVersion: %04x\n", SrcImageOptional_Header->MinorImageVersion); printf("MajorSubsystemVersion: %04x\n", SrcImageOptional_Header->MajorSubsystemVersion); printf("MinorSubsystemVersion: %04x\n", SrcImageOptional_Header->MinorSubsystemVersion); printf("Win32VersionValue: %08x\n", SrcImageOptional_Header->Win32VersionValue); printf("SizeOfImage: %08x\n", SrcImageOptional_Header->SizeOfImage); printf("SizeOfHeaders: %08x\n", SrcImageOptional_Header->SizeOfHeaders); printf("CheckSum: %08x\n", SrcImageOptional_Header->CheckSum); printf("Subsystem: %04x\n", SrcImageOptional_Header->Subsystem); printf("DllCharacteristics: %04x\n", SrcImageOptional_Header->DllCharacteristics); printf("SizeOfStackReserve: %08x\n", SrcImageOptional_Header->SizeOfStackReserve); printf("SizeOfStackCommit: %08x\n", SrcImageOptional_Header->SizeOfStackCommit); printf("SizeOfHeapReserve: %08x\n", SrcImageOptional_Header->SizeOfHeapCommit); printf("SizeOfHeapCommit: %08x\n", SrcImageOptional_Header->SizeOfHeapCommit); printf("LoaderFlags: %08x\n", SrcImageOptional_Header->LoaderFlags); printf("NumberOfRvaAndSizes: %08x\n", SrcImageOptional_Header->NumberOfRvaAndSizes); //IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; return 0; }