大家好。 先说几句题外话,是关于《恶意代码拦截插件1.1》的问题,由于一些问题。导致我并没有什么时间更新和修改BUG。
可能部分用户会不能正常拦截。楼主有空的话再进行更新和修复。最近两天在学习PE格式。
本次的软件非常简单,只是学习PE格式顺手写下来的小软件。强烈建议论坛开一个编程板块。。。。好吧,牢骚结束。下面开始介绍。此篇文章与其说软件发布,不与说是PE格式的学习。
软件界面:
下面看看示意图, 这是PE的头部示意图。 看下面几个结构 PE文件中的DOS部分由MZ格式的文件头和可执行代码部分组成,可执行代码被称为“DOS块”(DOS stub)。MZ格式的文件头由IMAGE_DOS_HEADER结构定义:
IMAGE_DOS_HEADER STRUCT
e_magic WORD ? ;DOS可执行文件标记,为“MZ”
e_cblp WORD ?
e_cp WORD ?
e_crlc WORD ?
e_cparhdr WORD ?
e_minalloc WORD ?
e_maxalloc WORD ?
e_ss WORD ? ;DOS代码的初始化堆栈段
e_sp WORD ? ;DOS代码的初始化堆栈指针
e_csum WORD ?
e_ip WORD ? ;DOS代码的入口IP
e_cs WORD ? ;DOS代码的入口CS
e_lfarlc WORD ?
e_ovno WORD ?
e_res WORD 4 dup(?)
e_oemid WORD ?
e_oeminfo WORD ?
e_res2 WORD 10 dup(?)
e_lfanew DWORD ? ;指向PE文件头
IMAGE_DOS_HEADER ENDS
DOS文件头的前面部分并不陌生,第一个字段e_magic被定义成字符“MZ”(在Windows.inc文件中已经预定义为IMAGE_DOS_SIGNATURE)作为识别标志,后面的一些字段指明了入口地址、堆栈位置和重定位表位置等。
其中 我们还要关心的是e_lfanew这个字段,e_lfanew字段是真正PE文件头的相对偏移(RVA),其指出真正PE头的文件偏移位置,它占用四个字节,位于文件开始偏移3Ch字节中。
IMAGE_NT_HEADERS STRUCT
Signature DWORD ? ;PE文件标识
FileHeader IMAGE_FILE_HEADER <>
OptionalHeader IMAGE_OPTIONAL_HEADER32 <>
IMAGE_NT_HEADERS ENDS 而里面的IMAGE_OPTIONAL_HEADER32有如下值 IMAGE_OPTIONAL_HEADER32 STRUCT
Magic WORD ? ;0018h 107h=ROM Image,10Bh=exe Image
MajorLinkerVersion BYTE ? ;001ah 链接器版本号
MinorLinkerVersion BYTE ? ;001bh
SizeOfCode DWORD ? ;001ch 所有含代码的节的总大小
SizeOfInitializedData DWORD? ;0020h所有含已初始化数据的节的总大小
SizeOfUninitializedData DWORD ? ;0024h 所有含未初始化数据的节的大小
AddressOfEntryPoint DWORD ? ;0028h 程序执行入口RVA
BaseOfCode DWORD ? ;002ch 代码的节的起始RVA
BaseOfData DWORD ? ;0030h 数据的节的起始RVA
ImageBase DWORD ? ;0034h 程序的建议装载地址
SectionAlignment DWORD ? ;0038h 内存中的节的对齐粒度
FileAlignment DWORD ? ;003ch 文件中的节的对齐粒度
MajorOperatingSystemVersion WORD ? ;0040h 操作系统主版本号
MinorOperatingSystemVersion WORD ? ;0042h 操作系统副版本号
MajorImageVersion WORD ? ;0044h可运行于操作系统的最小版本号
MinorImageVersion WORD ? ;0046h
MajorSubsystemVersion WORD ?;0048h 可运行于操作系统的最小子版本号
MinorSubsystemVersion WORD ? ;004ah
Win32VersionValue DWORD ? ;004ch 未用
SizeOfImage DWORD ? ;0050h 内存中整个PE映像尺寸
SizeOfHeaders DWORD ? ;0054h 所有头+节表的大小
CheckSum DWORD ? ;0058h
Subsystem WORD ? ;005ch 文件的子系统
DllCharacteristics WORD ? ;005eh
SizeOfStackReserve DWORD ? ;0060h 初始化时的堆栈大小
SizeOfStackCommit DWORD ? ;0064h 初始化时实际提交的堆栈大小
SizeOfHeapReserve DWORD ? ;0068h 初始化时保留的堆大小
SizeOfHeapCommit DWORD ? ;006ch 初始化时实际提交的堆大小
LoaderFlags DWORD ? ;0070h 未用
NumberOfRvaAndSizes DWORD ? ;0074h 下面的数据目录结构的数量
DataDirectory IMAGE_DATA_DIRECTORY 16 dup(<>) ;0078h
IMAGE_OPTIONAL_HEADER32 ENDS
IMAGE_SECTION_HEADERS结构
IMAGE_SECTION_HEADER STRUCT
Name1 db IMAGE_SIZEOF_SHORT_NAME dup(?) ;8个字节的节区名称
union Misc
PhysicalAddress dd ?
VirtualSize dd ? ;节区的尺寸
ends
VirtualAddress dd ? ;节区的RVA地址
SizeOfRawData dd ? ;在文件中对齐后的尺寸
PointerToRawData dd ? ;在文件中的偏移
PointerToRelocations dd ? ;在OBJ文件中使用
PointerToLinenumbers dd ? ;行号表的位置(供调试用)
NumberOfRelocations dw ? ;在OBJ文件中使用
NumberOfLinenumbers dw ? ;行号表中行号的数量
Characteristics dd ? ;节的属性
IMAGE_SECTION_HEADER ENDS
看这些结构知道,
DOS头e_lfanew---->指向IMAGE_NT_HEADERS结构 而IMAGE_SECTION_HEADER=e_lfanew+IMAGE_NT_HEADERS 也就是指向节。
代码很短,看看代码做了哪些工作? //打开文件 strFilePath指出了路径 HANDLE hFile = CreateFile(strFilePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
MessageBox(L"文件打开错误", L"错误");
return ;
}
IMAGE_DOS_HEADER dosHeader;//声明ODS_HEADER结构
BOOL bRet;
DWORD readSize;
bRet = ReadFile(hFile, &dosHeader, sizeof(dosHeader), &readSize, NULL);//获取结构内容
if (!bRet)
{
MessageBox(L"读取错误", L"错误");
CloseHandle(hFile);
return ;
}
if (dosHeader.e_magic != IMAGE_DOS_SIGNATURE)//判断dosHeader.e_magic 是否为IMAGE_DOS_SIGNATURE,也就是"MZ"。打开winhex可以看到PE头的这两个字符。
{
MessageBox(L"不是PE文件", L"错误");
}
printf("DOS头长度:%X\n", dosHeader.e_lfanew);
IMAGE_NT_HEADERS peHeader;//IMAGE_NT_HEADERS 结构
SetFilePointer(hFile, dosHeader.e_lfanew, NULL, FILE_BEGIN);//定位指针到dosHeader.e_lfanew,上面说到dosHeader.e_lfanew刚好指向IMAGE_NT_HEADERS
bRet = ReadFile(hFile, &peHeader, sizeof(peHeader), &readSize, NULL);
if (!bRet)
{
MessageBox(L"读取错误", L"错误");
return ;
CloseHandle(hFile);
}
if (peHeader.Signature != IMAGE_NT_SIGNATURE)//跟上面的MZ一样,判断Signature是否是"PE"这两个字符
{
MessageBox(L"不是PE文件", L"错误");
return ;
CloseHandle(hFile);
}
IMAGE_OPTIONAL_HEADER32 imOpHeader; // IMAGE_OPTIONAL_HEADER32结构
imOpHeader = peHeader.OptionalHeader;
CStringW Goep, GimageB, GCode, GImageSize, GDimage;
Goep.Format(L"%08X", imOpHeader.AddressOfEntryPoint);//从结构里获取程序的入口地址(这里是文件偏移地址,内存中会加上基址,一般是04000000)
GimageB.Format(L"%08X", imOpHeader.ImageBase);//获取基址
GCode.Format(L"%08X", imOpHeader.BaseOfCode);
GImageSize.Format(L"%08X", imOpHeader.SizeOfImage);//获取基址大小
GDimage.Format(L"%08X", imOpHeader.BaseOfData);//数据大小
下面这些是显示出来。不做解释
SetDlgItemText(IDC_EDIT2, GimageB);
SetDlgItemText(IDC_EDIT3, Goep);
SetDlgItemText(IDC_EDIT4, GCode);
SetDlgItemText(IDC_EDIT5, GImageSize);
SetDlgItemText(IDC_EDIT6, GDimage); IMAGE_SECTION_HEADER Section; int ii = peHeader.FileHeader.NumberOfSections;//段数目。NumberOfSections指向节的数目
int iii = 0;
iii = dosHeader.e_lfanew + sizeof(peHeader);
int s = sizeof(Section);
m_list.DeleteAllItems();
for (int i = 0; i < ii; i++)
{
SetFilePointer(hFile, iii + s*i, NULL, FILE_BEGIN);//定位指针到节的位置
bRet = ReadFile(hFile, &Section, sizeof(Section), &readSize, NULL);
if (!bRet)
{
MessageBox(L"读取错误",L"错误");
return ;
CloseHandle(hFile);
}
CString namea,Vaddr,Vsize,Raddr,Rsize;
namea.Format(L"%S", Section.Name);
Vaddr.Format(L"%08X", Section.VirtualAddress);//--
Vsize.Format(L"%08X", Section.Misc);
Raddr.Format(L"%08X", Section.PointerToRawData);
Rsize.Format(L"%08X", Section.SizeOfRawData);//--
m_list.InsertItem(i , namea);
m_list.SetItemText(i, 1, Vaddr);//--
m_list.SetItemText(i , 2, Vsize);
m_list.SetItemText(i, 3, Raddr);
m_list.SetItemText(i , 4, Rsize);//--
}
源码放送。。。
|