Add PE image reader/writer code

This commit is contained in:
de4dot 2011-10-26 14:20:38 +02:00
parent 349ebc4e72
commit 794b9dfd77
5 changed files with 317 additions and 0 deletions

View File

@ -0,0 +1,48 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.IO;
namespace de4dot.PE {
enum Machine : ushort {
i386 = 0x14C,
ia64 = 0x200,
amd64 = 0x8664,
}
class FileHeader {
public Machine machine;
public ushort numberOfSections;
public uint timeDateStamp;
public uint pointerToSymbolTable;
public uint numberOfSymbols;
public ushort sizeOfOptionalHeader;
public ushort characteristics;
public FileHeader(BinaryReader reader) {
machine = (Machine)reader.ReadUInt16();
numberOfSections = reader.ReadUInt16();
timeDateStamp = reader.ReadUInt32();
pointerToSymbolTable = reader.ReadUInt32();
numberOfSymbols = reader.ReadUInt32();
sizeOfOptionalHeader = reader.ReadUInt16();
characteristics = reader.ReadUInt16();
}
}
}

View File

@ -0,0 +1,115 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.IO;
namespace de4dot.PE {
struct DataDirectory {
public uint virtualAddress;
public uint size;
public override string ToString() {
return string.Format("{0:X8} {1:X8}", virtualAddress, size);
}
}
class OptionalHeader {
public ushort magic;
public byte majorLinkerVersion;
public byte minorLinkerVersion;
public uint sizeOfCode;
public uint sizeOfInitializedData;
public uint sizeOfUninitializedData;
public uint addressOfEntryPoint;
public uint baseOfCode;
public uint baseOfData; // 32-bit only
public ulong imageBase;
public uint sectionAlignment;
public uint fileAlignment;
public ushort majorOperatingSystemVersion;
public ushort minorOperatingSystemVersion;
public ushort majorImageVersion;
public ushort minorImageVersion;
public ushort majorSubsystemVersion;
public ushort minorSubsystemVersion;
public uint win32VersionValue;
public uint sizeOfImage;
public uint sizeOfHeaders;
public uint checkSum;
public ushort subsystem;
public ushort dllCharacteristics;
public ulong sizeOfStackReserve;
public ulong sizeOfStackCommit;
public ulong sizeOfHeapReserve;
public ulong sizeOfHeapCommit;
public uint loaderFlags;
public uint numberOfRvaAndSizes;
public DataDirectory[] dataDirectories;
public OptionalHeader(BinaryReader reader) {
magic = reader.ReadUInt16();
majorLinkerVersion = reader.ReadByte();
minorLinkerVersion = reader.ReadByte();
sizeOfCode = reader.ReadUInt32();
sizeOfInitializedData = reader.ReadUInt32();
sizeOfUninitializedData = reader.ReadUInt32();
addressOfEntryPoint = reader.ReadUInt32();
baseOfCode = reader.ReadUInt32();
if (is32bit())
baseOfData = reader.ReadUInt32();
imageBase = read4Or8(reader);
sectionAlignment = reader.ReadUInt32();
fileAlignment = reader.ReadUInt32();
majorOperatingSystemVersion = reader.ReadUInt16();
minorOperatingSystemVersion = reader.ReadUInt16();
majorImageVersion = reader.ReadUInt16();
minorImageVersion = reader.ReadUInt16();
majorSubsystemVersion = reader.ReadUInt16();
minorSubsystemVersion = reader.ReadUInt16();
win32VersionValue = reader.ReadUInt32();
sizeOfImage = reader.ReadUInt32();
sizeOfHeaders = reader.ReadUInt32();
checkSum = reader.ReadUInt32();
subsystem = reader.ReadUInt16();
dllCharacteristics = reader.ReadUInt16();
sizeOfStackReserve = read4Or8(reader);
sizeOfStackCommit = read4Or8(reader);
sizeOfHeapReserve = read4Or8(reader);
sizeOfHeapCommit = read4Or8(reader);
loaderFlags = reader.ReadUInt32();
numberOfRvaAndSizes = reader.ReadUInt32();
dataDirectories = new DataDirectory[16];
for (int i = 0; i < dataDirectories.Length; i++) {
dataDirectories[i].virtualAddress = reader.ReadUInt32();
dataDirectories[i].size = reader.ReadUInt32();
}
}
ulong read4Or8(BinaryReader reader) {
if (is32bit())
return reader.ReadUInt32();
return reader.ReadUInt64();
}
public bool is32bit() {
return magic != 0x20B;
}
}
}

88
de4dot.code/PE/PeImage.cs Normal file
View File

@ -0,0 +1,88 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
namespace de4dot.PE {
class PeImage {
BinaryReader reader;
BinaryWriter writer;
FileHeader fileHeader;
OptionalHeader optionalHeader;
SectionHeader[] sectionHeaders;
public PeImage(byte[] data)
: this(new MemoryStream(data)) {
}
public PeImage(Stream stream) {
reader = new BinaryReader(stream);
writer = new BinaryWriter(stream);
init();
}
void seek(uint position) {
reader.BaseStream.Position = position;
}
void skip(int bytes) {
reader.BaseStream.Position += bytes;
}
void init() {
seek(0);
if (reader.ReadUInt16() != 0x5A4D)
throw new BadImageFormatException("Not a PE file");
skip(29 * 2);
seek(reader.ReadUInt32());
if (reader.ReadUInt32() != 0x4550)
throw new BadImageFormatException("Not a PE file");
fileHeader = new FileHeader(reader);
optionalHeader = new OptionalHeader(reader);
sectionHeaders = new SectionHeader[fileHeader.numberOfSections];
for (int i = 0; i < sectionHeaders.Length; i++)
sectionHeaders[i] = new SectionHeader(reader);
}
SectionHeader getSectionHeader(uint rva) {
for (int i = 0; i < sectionHeaders.Length; i++) {
var section = sectionHeaders[i];
if (section.virtualAddress <= rva && rva < section.virtualAddress + section.virtualSize)
return section;
}
return null;
}
uint rvaToOffset(uint rva) {
var section = getSectionHeader(rva);
if (section == null)
throw new ApplicationException(string.Format("Invalid RVA {0:X8}", rva));
return rva - section.virtualAddress + section.pointerToRawData;
}
public void write(uint rva, byte[] data) {
seek(rvaToOffset(rva));
writer.Write(data);
}
}
}

View File

@ -0,0 +1,62 @@
/*
Copyright (C) 2011 de4dot@gmail.com
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System.IO;
using System.Text;
namespace de4dot.PE {
class SectionHeader {
public byte[] name;
public uint virtualSize;
public uint virtualAddress;
public uint sizeOfRawData;
public uint pointerToRawData;
public uint pointerToRelocations;
public uint pointerToLinenumbers;
public ushort numberOfRelocations;
public ushort numberOfLinenumbers;
public uint characteristics;
public string displayName;
public SectionHeader(BinaryReader reader) {
name = reader.ReadBytes(8);
virtualSize = reader.ReadUInt32();
virtualAddress = reader.ReadUInt32();
sizeOfRawData = reader.ReadUInt32();
pointerToRawData = reader.ReadUInt32();
pointerToRelocations = reader.ReadUInt32();
pointerToLinenumbers = reader.ReadUInt32();
numberOfRelocations = reader.ReadUInt16();
numberOfLinenumbers = reader.ReadUInt16();
characteristics = reader.ReadUInt32();
var sb = new StringBuilder(name.Length);
foreach (var c in name) {
if (c == 0)
break;
sb.Append((char)c);
}
displayName = sb.ToString();
}
public override string ToString() {
return string.Format("{0:X8} {1:X8} {2:X8} - {3}", virtualAddress, virtualSize, sizeOfRawData, displayName);
}
}
}

View File

@ -103,6 +103,10 @@
<Compile Include="NameRegexes.cs" />
<Compile Include="ObfuscatedFile.cs" />
<Compile Include="Option.cs" />
<Compile Include="PE\FileHeader.cs" />
<Compile Include="PE\OptionalHeader.cs" />
<Compile Include="PE\PeImage.cs" />
<Compile Include="PE\SectionHeader.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="renamer\DefinitionsRenamer.cs" />