概要
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
>
以上。