potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

C# PEファイルのMS-DOSヘッダとNTヘッダのシグネチャをメモリマップトファイルで読み込む

PEファイルのMS-DOSヘッダ(IMAGE_DOS_HEADER)とNTヘッダ(IMAGE_NT_HEADERS)のシグネチャをメモリマップトファイルで読み込むサンプルコードです。IMAGE_DOS_HEADERは固定長配列を含むため、マーシャリングとGCHandleを利用しています。IMAGE_NT_HEADERSは最初のフィールドがシグネチャなので直接読み込んでいます。

using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.Text;

class Program
{
    static void Main()
    {
        var path = Path.Combine(Environment.SystemDirectory, "notepad.exe");

        using var mmap = MemoryMappedFile.CreateFromFile(path, FileMode.Open, null, 0, MemoryMappedFileAccess.Read);
        using var accessor = mmap.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read);

        ReadMarshalStructure<IMAGE_DOS_HEADER>(accessor, 0, out var imgDosHdr);
        var mzSignature = imgDosHdr.e_magic; // 0x5a4d
        var peSignature = accessor.ReadUInt32(imgDosHdr.e_lfanew); // 0x00004550
        var mzSignatureStr = Encoding.ASCII.GetString(BitConverter.GetBytes(mzSignature)); // "MZ"
        var peSignatureStr = Encoding.ASCII.GetString(BitConverter.GetBytes(peSignature)); // "PE\0\0"
    }

    private static void ReadMarshalStructure<T>(MemoryMappedViewAccessor accessor, long position, out T obj)
        where T : struct
    {
        var buffer = new byte[Marshal.SizeOf<T>()];
        accessor.ReadArray<byte>(position, buffer, 0, buffer.Length);
        var handle = default(GCHandle);
        try
        {
            handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            obj = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
        }
        finally
        {
            handle.Free();
        }
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct IMAGE_DOS_HEADER
    {
        public ushort e_magic;
        public ushort e_cblp;
        public ushort e_cp;
        public ushort e_crlc;
        public ushort e_cparhdr;
        public ushort e_minalloc;
        public ushort e_maxalloc;
        public ushort e_ss;
        public ushort e_sp;
        public ushort e_csum;
        public ushort e_ip;
        public ushort e_cs;
        public ushort e_lfarlc;
        public ushort e_ovno;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public ushort[] e_res;
        public ushort e_oemid;
        public ushort e_oeminfo;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
        public ushort[] e_res2;
        public int e_lfanew;
    }
}