简体   繁体   English

.NET DLL / EXE PE是否令人困惑?

[英]Are .NET DLLs/EXEs PE confomant?

I've been inspecting a .NET DLL out of interest, using the ECMA-335 for reference, and as far as I can tell, I am making a grave mistake since it seem to be wrong. 我一直在检查.NET DLL的兴趣,使用ECMA-335作为参考,据我所知,我犯了一个严重的错误,因为它似乎是错误的。 My error comes from the fact that the PE file header doesn't appear immediately after the PE signature. 我的错误来自于PE签名后PE文件头不会立即出现的事实。

The ECMA-335 states that: ECMA-335指出:

"II.25.2.2 PE file header “II.25.2.2 PE文件头
Immediately after the PE signature is the PE File header consisting of the following: PE签名后的PE文件头立即包含以下内容:

Offset Size Field Description 偏移大小字段描述
0 2 0 2
Machine Always 0x14c." 机器总是0x14c。“

Now, when I use the following code, this works for normal, non managed DLLs and EXEs. 现在,当我使用以下代码时,这适用于普通的非托管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);
    }
}

The machine number is the magic number, and the timeOfCreation makes sense and the magic number in the PE optional header is correct. 机器编号是幻数,timeOfCreation是有意义的,PE可选标头中的幻数是正确的。 At the pointer specified in 0x3c, the signature 'PE\\0\\0' is there, and the PE file header comes directly afterwards. 在0x3c中指定的指针处,签名'PE \\ 0 \\ 0'就在那里,之后PE文件头直接出现。

However, when I try and inspect a .NET managed DLL, I can successfuly find the signature 'PE\\0\\0', but the PE file header doesn't come immediately afterwards. 但是,当我尝试检查.NET托管DLL时,我可以成功找到签名'PE \\ 0 \\ 0',但PE文件头不会立即出现。 So the number I get afterwards are garbage. 所以我之后获得的数字是垃圾。 This becomes apparent when the machine number is 34404 (0x8664) rather than 332 (0x14C) which the ECMA-335 says must be the case. 当机器编号为34404(0x8664)而不是332(0x14C)时,这一点就变得很明显,ECMA-335说的必须是这种情况。

I must be doing something wrong, or not read a specific part, but I can't work out what that is at the moment. 我一定是做错了什么,或者没有读过具体的部分,但我现在无法解决这个问题。

They are PE conformant, however, they do not contain sensible machine instructions. 它们符合PE标准,但是它们不包含合理的机器指令。 Try running dumpbin /disasm on one of them. 尝试在其中一个上运行dumpbin /disasm You will see it try to interpret the IL code as machine instructions, which gives you nonsense results. 您将看到它尝试将IL代码解释为机器指令,这会为您提供无意义的结果。 For example: 例如:

Microsoft (R) COFF/PE Dumper Version 14.16.27026.1
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file hello.exe

File Type: EXECUTABLE IMAGE

  00402000: 80 23 00           and         byte ptr [ebx],0
  00402003: 00 00              add         byte ptr [eax],al
  00402005: 00 00              add         byte ptr [eax],al
  00402007: 00 48 00           add         byte ptr [eax],cl
  0040200A: 00 00              add         byte ptr [eax],al
  0040200C: 02 00              add         al,byte ptr [eax]
  0040200E: 05 00 68 20 00     add         eax,206800h
  00402013: 00 E4              add         ah,ah
  00402015: 02 00              add         al,byte ptr [eax]
  00402017: 00 01              add         byte ptr [ecx],al
  00402019: 00 00              add         byte ptr [eax],al
  0040201B: 00 01              add         byte ptr [ecx],al
  0040201D: 00 00              add         byte ptr [eax],al
  0040201F: 06                 push        es
  00402020: 00 00              add         byte ptr [eax],al
  00402022: 00 00              add         byte ptr [eax],al
  00402024: 00 00              add         byte ptr [eax],al
  00402026: 00 00              add         byte ptr [eax],al
  00402028: 00 00              add         byte ptr [eax],al
  0040202A: 00 00              add         byte ptr [eax],al
  0040202C: 00 00              add         byte ptr [eax],al

This is fine, however, since the Windows loader knows how to load .NET assemblies so that the managed code is parsed and run instead. 但是,这很好,因为Windows加载程序知道如何加载.NET程序集,以便解析和运行托管代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM