【发布时间】:2019-07-07 16:22:22
【问题描述】:
出于兴趣,我一直在检查 .NET DLL,使用 ECMA-335 作为参考,据我所知,我犯了一个严重的错误,因为它似乎是错误的。我的错误来自这样一个事实,即 PE 文件头没有在 PE 签名之后立即出现。
ECMA-335 声明:
"II.25.2.2 PE文件头
PE 签名之后是 PE 文件头,包含以下内容:
偏移大小字段说明
0 2
机器总是 0x14c。”
现在,当我使用以下代码时,这适用于普通的非托管 DLL 和 EXE。
unsafe static void Stuff(Stream stream, byte[] buf)
{
int read = stream.Read(buf, 0, 1024);
// skip the first 128 bytes
// since that's the header
fixed (byte* ptr = buf)
{
// get the position of the signature?
int PEHeaderStart = *(int*)(ptr + 0x3c);
char PEsig1 = (char)*(ptr + PEHeaderStart); // P
char PEsig2 = (char)*(ptr + PEHeaderStart + 1); // E
char PEsig3 = (char)*(ptr + PEHeaderStart + 2); // \0
char PEsig4 = (char)*(ptr + PEHeaderStart + 3); // \0
ushort machine = *(ushort*)(ptr + PEHeaderStart + 4);
ushort noSections = *(ushort*)(ptr + PEHeaderStart + 6);
uint secondsFrom1970 = *(uint*)(ptr + PEHeaderStart + 8);
DateTime timeOfCreation = new DateTime(1970, 1, 1) + new TimeSpan((long)secondsFrom1970 * 1000 * 10000);
uint pointerToSymbolTable = *(uint*)(ptr + PEHeaderStart + 12);
uint numberOfSymbols = *(uint*)(ptr + PEHeaderStart + 16);
ushort sizeOfOptionalHeader = *(ushort*)(ptr + PEHeaderStart + 20);
ushort characteristics = *(ushort*)(ptr + PEHeaderStart + 22);
// flags from characteristics
bool IMAGE_FILE_RELOCS_STRIPPED = (characteristics & 0x0001) == 1;
bool IMAGE_FILE_EXECUTABLE_IMAGE = (characteristics & 0x002) == 1;
bool IMAGE_FILE_32BIT_MACHINE = (characteristics & 0x0100) == 1;
bool IMAGE_FILE_DLL = (characteristics & 0x2000) == 1;
int optionalHeaderStart = PEHeaderStart + 24;
// PE optional header
ushort magic = *(ushort*)(ptr + optionalHeaderStart);
byte lmajor = *(ptr + optionalHeaderStart + 2);
byte lminor = *(ptr + optionalHeaderStart + 3);
uint codesize = *(uint*)(ptr + optionalHeaderStart + 4);
}
}
机器号是幻数,timeOfCreation 有意义,PE 可选标头中的幻数是正确的。在0x3c指定的指针处,签名'PE\0\0'在那里,PE文件头紧随其后。
但是,当我尝试检查 .NET 托管的 DLL 时,我可以成功找到签名“PE\0\0”,但 PE 文件头不会立即出现。所以我后来得到的数字是垃圾。当机器编号为 34404 (0x8664) 而不是 ECMA-335 所说的 332 (0x14C) 时,这一点变得很明显。
我一定是做错了什么,或者没有阅读特定部分,但我现在无法弄清楚那是什么。
【问题讨论】:
-
规范有点过时,0x8664 实际上是sensible number。
-
托管 (.net) 程序集是 PE,我已经解析/检查了很多。他们是PE。你刚刚遇到一个 PE32+,它是 PE 格式的扩展,用于处理 64 位代码。