ILRepack/Steps/Win32Resources/PE/ImageReader.cs (80 lines of code) (raw):
//
// Copyright (c) 2018 Alexander Vostres
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
using System;
using System.IO;
using System.Linq;
namespace ILRepacking.Steps.Win32Resources.PE
{
class ImageReader : BinaryStreamReader
{
public bool Pe64 { get; private set; }
public Section[] Sections { get; private set; }
public ImageReader(Stream stream) : base(stream)
{
ReadImage();
}
void ReadImage()
{
if (BaseStream.Length < 128)
throw new BadImageFormatException();
// - DOSHeader
// PE 2
// Start 58
// Lfanew 4
// End 64
if (ReadUInt16 () != 0x5a4d)
throw new BadImageFormatException ();
Advance (58);
MoveTo (ReadUInt32 ());
if (ReadUInt32 () != 0x00004550)
throw new BadImageFormatException ();
// - PEFileHeader
// Machine 2
Advance(2);
// NumberOfSections 2
var sectionCount = ReadUInt16();
// TimeDateStamp 4
// PointerToSymbolTable 4
// NumberOfSymbols 4
// OptionalHeaderSize 2
// Characteristics 2
Advance(16);
ReadOptionalHeaders();
Sections = ReadSections(sectionCount);
}
public SectionData GetSectionData(string name)
{
var src = GetSection(name);
if (src == null)
{
return null;
}
MoveTo(src.PointerToRawData);
var bytes = ReadBytes((int) src.SizeOfRawData);
return new SectionData(src.VirtualAddress, bytes);
}
public Section GetSection(string name)
{
return Sections.FirstOrDefault(s => string.Equals(s.Name, name, StringComparison.Ordinal));
}
void ReadOptionalHeaders()
{
// - PEOptionalHeader
// - StandardFieldsHeader
// Magic 2
Pe64 = ReadUInt16() == 0x20b;
// pe32 || pe64
// CodeSize 4
// InitializedDataSize 4
// UninitializedDataSize4
// EntryPointRVA 4
// BaseOfCode 4
// BaseOfData 4 || 0
// - NTSpecificFieldsHeader
// ImageBase 4 || 8
// SectionAlignment 4
// FileAlignement 4
// OSMajor 2
// OSMinor 2
// UserMajor 2
// UserMinor 2
// SubSysMajor 2
// SubSysMinor 2
// Reserved 4
// ImageSize 4
// HeaderSize 4
// FileChecksum 4
// SubSystem 2
// DLLFlags 2
// StackReserveSize 4 || 8
// StackCommitSize 4 || 8
// HeapReserveSize 4 || 8
// HeapCommitSize 4 || 8
// LoaderFlags 4
// NumberOfDataDir 4
// - DataDirectoriesHeader
// ExportTable 8
// ImportTable 8
// ResourceTable 8
// ExceptionTable 8
// CertificateTable 8
// BaseRelocationTable 8
// Debug 8
// Copyright 8
// GlobalPtr 8
// TLSTable 8
// LoadConfigTable 8
// BoundImport 8
// IAT 8
// DelayImportDescriptor8
// CLIHeader 8
// Reserved 8
Advance(Pe64 ? 238 : 222);
}
string ReadZeroTerminatedString (int length)
{
int read = 0;
var buffer = new char [length];
var bytes = ReadBytes (length);
while (read < length) {
var current = bytes [read];
if (current == 0)
break;
buffer [read++] = (char) current;
}
return new string (buffer, 0, read);
}
Section[] ReadSections (ushort count)
{
var sections = new Section [count];
for (int i = 0; i < count; i++) {
var section = new Section ();
// Name
section.Name = ReadZeroTerminatedString (8);
// VirtualSize 4
section.VirtualSize = ReadUInt32 ();
// VirtualAddress 4
section.VirtualAddress = ReadUInt32 ();
// SizeOfRawData 4
section.SizeOfRawData = ReadUInt32 ();
// PointerToRawData 4
section.PointerToRawData = ReadUInt32 ();
// PointerToRelocations 4
// PointerToLineNumbers 4
// NumberOfRelocations 2
// NumberOfLineNumbers 2
// Characteristics 4
Advance (16);
sections [i] = section;
}
return sections;
}
}
}