为啥这个操作PE文件头的代码使用了这么奇怪的偏移值?
Posted
技术标签:
【中文标题】为啥这个操作PE文件头的代码使用了这么奇怪的偏移值?【英文标题】:Why does this code for manipulating PE file header use such strange offset value?为什么这个操作PE文件头的代码使用了这么奇怪的偏移值? 【发布时间】:2012-09-28 11:48:16 【问题描述】:Here's a piece of code for obtaining the time when a .NET assembly was built。注意:
const int c_LinkerTimestampOffset = 8;
及以后:
int secondsSince1970 = System.BitConverter.ToInt32(b, i + c_LinkerTimestampOffset);
此代码提取存储在程序集中的IMAGE_FILE_HEADER structure 的TimeDateStamp
成员。结构定义如下:
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;
和WORD
是两个字节,应该是两个字节对齐的。当我使用 Visual C++ 10 编译以下代码时:
IMAGE_FILE_HEADER header;
char* start = (char*)&header;
char* field = (char*)(&header.TimeDateStamp);
int diff = field - start;
diff
等于 4
,正如我个人预期的那样。
这是 C# 代码中的错误吗?为什么使用8
的偏移值?
【问题讨论】:
【参考方案1】:它用于跳过附加签名,因为i
包含到 NT 标头的偏移量,而不是文件图像标头(参见 formal PE structure):
typedef struct _IMAGE_NT_HEADERS
DWORD Signature; //<- we need to skip this
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER32 OptionalHeader;
IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
所以实际总和是sizeof(WORD /* FileHeader.Machine */) + sizeof(WORD /* FileHeader.NumberOfSections */) + sizeof(DWORD /* Signature */)
底线,不是错误,只是跳过一些结构嵌套/内联的一些魔法。
【讨论】:
【参考方案2】:DWORD 是一个 int 无符号值,4 个字节。
C# 代码不正确,它读取了 8 个字节。我认为应该是 4。
int secondsSince1970 = System.BitConverter.ToInt32(b, i + c_LinkerTimestampOffset);
几天前我写了一个PE阅读器。我将它用于“图像文件头”:
public class IMAGE_FILE_HEADER
public UInt16 Machine;
public UInt16 NumberOfSections;
public UInt32 TimeDateStamp;
public UInt32 PointerToSymbolTable;
public UInt32 NumberOfSymbols;
public UInt16 SizeOfOptionalHeader;
public UInt16 Characteristics;
【讨论】:
为什么DWORD
突然变成了8个字节?【参考方案3】:
您很可能会得到 8 字节的差异,因为您使用的是 64 位系统/目标平台,如果您使用的是 32 位,那将是您所期望的。
在 32 位系统上,DWORD 定义为 uint(32 位/4 字节),而在 64 位系统上,它定义为 ulong(64 位/8 字节)。
一个字本质上代表架构的地址大小。当它被创造出来时,WORD 是 16 位,而 DWORD 是双字,32 位(4 字节)。
人们会期望 DWORD 在 x86 系统上为 64 位/8 字节,但 MS 希望保留旧版支持,因此保留了旧定义:http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx
【讨论】:
不,DWORD
总是 4 个字节。以上是关于为啥这个操作PE文件头的代码使用了这么奇怪的偏移值?的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向ELF 文件格式 ( 程序头偏移量 | 节区头偏移量 | 处理器特定标志 | ELF 文件头大小 )