清明节回来乘车到学校,没想到竟然做错了公交车。来回竟然多花了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
Signature 字段:
在一个有效的 PE 文件里,Signature 字段被设置为00004550h, ASCII 码字符是“PE00”。标志这 PE 文件头的开始。
“PE00” 字符串是 PE 文件头的开始,DOS 头部的 e_lfanew 字段正是指向这里。
如下图所示:
![PE教程,PE视频教程,PE原理,PE头教程](http://fishc.com/uploads/allimg/120113/9_120113221105_1.gif)
IMAGE_FILE_HEADER 结构
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;
}
这只是初步,代码还有待完善。。。。