cscの作法 その244

# 概要
cscの作法、調べてみた。
exeファイルをパースしてみた。

# サンプルコード

```
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

public class PEReader {
	[StructLayout(LayoutKind.Sequential)]
	public struct IMAGE_DOS_HEADER {
		public UInt16 e_magic;
		public UInt16 e_cblp;
		public UInt16 e_cp;
		public UInt16 e_crlc;
		public UInt16 e_cparhdr;
		public UInt16 e_minalloc;
		public UInt16 e_maxalloc;
		public UInt16 e_ss;
		public UInt16 e_sp;
		public UInt16 e_csum;
		public UInt16 e_ip;
		public UInt16 e_cs;
		public UInt16 e_lfarlc;
		public UInt16 e_ovno;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
		public UInt16[] e_res1;
		public UInt16 e_oemid;
		public UInt16 e_oeminfo;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
		public UInt16[] e_res2;
		public UInt32 e_lfanew;
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct IMAGE_NT_HEADERS {
		public UInt32 Signature;
		public IMAGE_FILE_HEADER FileHeader;
		public IMAGE_OPTIONAL_HEADER32 OptionalHeader32;
		public IMAGE_OPTIONAL_HEADER64 OptionalHeader64;
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct IMAGE_FILE_HEADER {
		public UInt16 Machine;
		public UInt16 NumberOfSections;
		public UInt32 TimeDateStamp;
		public UInt32 PointerToSymbolTable;
		public UInt32 NumberOfSymbols;
		public UInt16 SizeOfOptionalHeader;
		public UInt16 Characteristics;
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct IMAGE_OPTIONAL_HEADER32 {
		public UInt16 Magic;
		public Byte MajorLinkerVersion;
		public Byte MinorLinkerVersion;
		public UInt32 SizeOfCode;
		public UInt32 SizeOfInitializedData;
		public UInt32 SizeOfUninitializedData;
		public UInt32 AddressOfEntryPoint;
		public UInt32 BaseOfCode;
		public UInt32 BaseOfData;
		public UInt32 ImageBase;
		public UInt32 SectionAlignment;
		public UInt32 FileAlignment;
		public UInt16 MajorOperatingSystemVersion;
		public UInt16 MinorOperatingSystemVersion;
		public UInt16 MajorImageVersion;
		public UInt16 MinorImageVersion;
		public UInt16 MajorSubsystemVersion;
		public UInt16 MinorSubsystemVersion;
		public UInt32 Win32VersionValue;
		public UInt32 SizeOfImage;
		public UInt32 SizeOfHeaders;
		public UInt32 CheckSum;
		public UInt16 Subsystem;
		public UInt16 DllCharacteristics;
		public UInt32 SizeOfStackReserve;
		public UInt32 SizeOfStackCommit;
		public UInt32 SizeOfHeapReserve;
		public UInt32 SizeOfHeapCommit;
		public UInt32 LoaderFlags;
		public UInt32 NumberOfRvaAndSizes;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
		public IMAGE_DATA_DIRECTORY[] DataDirectory;
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct IMAGE_OPTIONAL_HEADER64 {
		public UInt16 Magic;
		public Byte MajorLinkerVersion;
		public Byte MinorLinkerVersion;
		public UInt32 SizeOfCode;
		public UInt32 SizeOfInitializedData;
		public UInt32 SizeOfUninitializedData;
		public UInt32 AddressOfEntryPoint;
		public UInt32 BaseOfCode;
		public UInt64 ImageBase;
		public UInt32 SectionAlignment;
		public UInt32 FileAlignment;
		public UInt16 MajorOperatingSystemVersion;
		public UInt16 MinorOperatingSystemVersion;
		public UInt16 MajorImageVersion;
		public UInt16 MinorImageVersion;
		public UInt16 MajorSubsystemVersion;
		public UInt16 MinorSubsystemVersion;
		public UInt32 Win32VersionValue;
		public UInt32 SizeOfImage;
		public UInt32 SizeOfHeaders;
		public UInt32 CheckSum;
		public UInt16 Subsystem;
		public UInt16 DllCharacteristics;
		public UInt64 SizeOfStackReserve;
		public UInt64 SizeOfStackCommit;
		public UInt64 SizeOfHeapReserve;
		public UInt64 SizeOfHeapCommit;
		public UInt32 LoaderFlags;
		public UInt32 NumberOfRvaAndSizes;
		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
		public IMAGE_DATA_DIRECTORY[] DataDirectory;
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct IMAGE_DATA_DIRECTORY {
		public UInt32 VirtualAddress;
		public UInt32 Size;
	}
	[StructLayout(LayoutKind.Sequential)]
	public struct IMAGE_SECTION_HEADER {
		[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
		public string Name;
		public Misc Misc;
		public UInt32 VirtualAddress;
		public UInt32 SizeOfRawData;
		public UInt32 PointerToRawData;
		public UInt32 PointerToRelocations;
		public UInt32 PointerToLinenumbers;
		public UInt16 NumberOfRelocations;
		public UInt16 NumberOfLinenumbers;
		public UInt32 Characteristics;
	}
	[StructLayout(LayoutKind.Explicit)]
	public struct Misc {
		[FieldOffset(0)]
		public UInt32 PhysicalAddress;
		[FieldOffset(0)]
		public UInt32 VirtualSize;
	}
	[StructLayout(LayoutKind.Sequential, Pack = 1)]
	public struct IMAGE_COR20_HEADER {
		public uint cb;
		public ushort MajorRuntimeVersion;
		public ushort MinorRuntimeVersion;
		public IMAGE_DATA_DIRECTORY MetaData;
		public uint Flags;
		public uint EntryPointToken;
		public IMAGE_DATA_DIRECTORY Resources;
		public IMAGE_DATA_DIRECTORY StrongNameSignature;
		public IMAGE_DATA_DIRECTORY CodeManagerTable;
		public IMAGE_DATA_DIRECTORY VTableFixups;
		public IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
		public IMAGE_DATA_DIRECTORY ManagedNativeHeader;
	}
	private readonly IMAGE_DOS_HEADER _dosHeader;
	private IMAGE_NT_HEADERS _ntHeaders;
	private readonly IList<IMAGE_SECTION_HEADER> _sectionHeaders = new List<IMAGE_SECTION_HEADER>();
	public PEReader(BinaryReader reader) {
		reader.BaseStream.Seek(0, SeekOrigin.Begin);
		_dosHeader = MarshalBytesTo<IMAGE_DOS_HEADER>(reader);
		if (_dosHeader.e_magic != 0x5a4d)
		{
			throw new InvalidOperationException("File is not a portable executable.");
		}
		reader.BaseStream.Seek(_dosHeader.e_lfanew, SeekOrigin.Begin);
		_ntHeaders.Signature = MarshalBytesTo<UInt32>(reader);
		if (_ntHeaders.Signature != 0x4550)
		{
			throw new InvalidOperationException("Invalid portable executable signature in NT header.");
		}
		_ntHeaders.FileHeader = MarshalBytesTo<IMAGE_FILE_HEADER>(reader);
		if (Is32bitAssembly())
		{
			Load32bitOptionalHeaders(reader);
		}
		else
		{
			Load64bitOptionalHeaders(reader);
		}
		foreach (IMAGE_SECTION_HEADER header in _sectionHeaders)
		{
			reader.BaseStream.Seek(header.PointerToRawData, SeekOrigin.Begin);
			byte[] sectiondata = reader.ReadBytes((int) header.SizeOfRawData);
		}
	}
	public IMAGE_DOS_HEADER GetDOSHeader() {
		return _dosHeader;
	}
	public UInt32 GetPESignature() {
		return _ntHeaders.Signature;
	}
	public IMAGE_FILE_HEADER GetFileHeader() {
		return _ntHeaders.FileHeader;
	}
	public IMAGE_OPTIONAL_HEADER32 GetOptionalHeaders32() {
		return _ntHeaders.OptionalHeader32;
	}
	public IMAGE_OPTIONAL_HEADER64 GetOptionalHeaders64() {
		return _ntHeaders.OptionalHeader64;
	}
	public IList<IMAGE_SECTION_HEADER> GetSectionHeaders() {
		return _sectionHeaders;
	}
	public bool Is32bitAssembly() {
		return ((_ntHeaders.FileHeader.Characteristics & 0x0100) == 0x0100);
	}
	private void Load64bitOptionalHeaders(BinaryReader reader) {
		_ntHeaders.OptionalHeader64 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER64>(reader);
		if (_ntHeaders.OptionalHeader64.NumberOfRvaAndSizes != 0x10)
		{
			throw new InvalidOperationException("Invalid number of data directories in NT header");
		}
		for (int i = 0; i < _ntHeaders.OptionalHeader64.NumberOfRvaAndSizes; i++)
		{
			if (_ntHeaders.OptionalHeader64.DataDirectory[i].Size > 0)
			{
				_sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(reader));
			}
		}
	}
	private void Load32bitOptionalHeaders(BinaryReader reader) {
		_ntHeaders.OptionalHeader32 = MarshalBytesTo<IMAGE_OPTIONAL_HEADER32>(reader);
		if (_ntHeaders.OptionalHeader32.NumberOfRvaAndSizes != 0x10)
		{
			throw new InvalidOperationException("Invalid number of data directories in NT header");
		}
		for (int i = 0; i < _ntHeaders.OptionalHeader32.NumberOfRvaAndSizes; i++)
		{
			if (_ntHeaders.OptionalHeader32.DataDirectory[i].Size > 0)
			{
				_sectionHeaders.Add(MarshalBytesTo<IMAGE_SECTION_HEADER>(reader));
			}
		}
	}
	private static T MarshalBytesTo<T>(BinaryReader reader) {
		byte[] bytes = reader.ReadBytes(Marshal.SizeOf(typeof(T)));
		GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
		T theStructure = (T) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
		handle.Free();
		return theStructure;
	}
	static void Main(string[] args) {
		Stream stream = new FileStream(args[0], FileMode.Open);
		PEReader pe = new PEReader(new BinaryReader(stream));
		IMAGE_DOS_HEADER dosh = pe.GetDOSHeader();
		Console.WriteLine("IMAGE_DOS_HEADER.e_magic: 0x" + dosh.e_magic.ToString("X"));
		Console.WriteLine("IMAGE_NT_HEADERS.Signature: 0x" + pe.GetPESignature().ToString("X"));
		IMAGE_FILE_HEADER flh = pe.GetFileHeader();
		Console.WriteLine("IMAGE_FILE_HEADER.Machine: 0x" + flh.Machine.ToString("X"));
		Console.WriteLine("IMAGE_FILE_HEADER.NumberOfSections: 0x" + flh.NumberOfSections.ToString("X"));
		Console.WriteLine("IMAGE_FILE_HEADER.Characteristics: 0x" + flh.Characteristics.ToString("X"));
		if ((flh.Characteristics & 0x0100) == 0x0100)
		{
			IMAGE_OPTIONAL_HEADER32 oph = pe.GetOptionalHeaders32();
			Console.WriteLine("IMAGE_OPTION_HEADER.Magic: 0x" + oph.Magic.ToString("X"));
			Console.WriteLine("IMAGE_OPTION_HEADER.MajorLinkerVersion: 0x" + oph.MajorLinkerVersion.ToString("X"));
			Console.WriteLine("IMAGE_OPTION_HEADER.MinorLinkerVersion: 0x" + oph.MinorLinkerVersion.ToString("X"));
			Console.WriteLine("IMAGE_OPTION_HEADER.SizeOfCode: 0x" + oph.SizeOfCode.ToString("X"));
		}
		else
		{
			IMAGE_OPTIONAL_HEADER64 oph = pe.GetOptionalHeaders64();
			Console.WriteLine("IMAGE_OPTION_HEADER.Magic: 0x" + oph.Magic.ToString("X"));
			Console.WriteLine("IMAGE_OPTION_HEADER.MajorLinkerVersion: 0x" + oph.MajorLinkerVersion.ToString("X"));
			Console.WriteLine("IMAGE_OPTION_HEADER.MinorLinkerVersion: 0x" + oph.MinorLinkerVersion.ToString("X"));
			Console.WriteLine("IMAGE_OPTION_HEADER.SizeOfCode: 0x" + oph.SizeOfCode.ToString("X"));
		}
		var sels = pe.GetSectionHeaders();
		foreach (IMAGE_SECTION_HEADER header in sels)
		{
			Console.WriteLine("IMAGE_SECTION_HEADER.Name: " + header.Name);
		}
	}
}





```

# 実行結果

```
>pe0 mkpe3.exe
IMAGE_DOS_HEADER.e_magic: 0x5A4D
IMAGE_NT_HEADERS.Signature: 0x4550
IMAGE_FILE_HEADER.Machine: 0x8664
IMAGE_FILE_HEADER.NumberOfSections: 0x2
IMAGE_FILE_HEADER.Characteristics: 0x2F
IMAGE_OPTION_HEADER.Magic: 0x20B
IMAGE_OPTION_HEADER.MajorLinkerVersion: 0x0
IMAGE_OPTION_HEADER.MinorLinkerVersion: 0x0
IMAGE_OPTION_HEADER.SizeOfCode: 0x0
IMAGE_SECTION_HEADER.Name: .text

>

```


以上。