Add .NET header and a method to more safely write to a .NET PE image

This commit is contained in:
de4dot 2011-10-27 22:21:45 +02:00
parent 61b1f7a06a
commit 9c83c22469
8 changed files with 243 additions and 19 deletions

View File

@ -0,0 +1,96 @@
/*
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 {
class Cor20Header : IFileLocation {
public uint cb;
public ushort majorRuntimeVersion;
public ushort minorRuntimeVersion;
public DataDirectory metaData;
public uint flags;
public uint entryPointToken;
public DataDirectory resources;
public DataDirectory strongNameSignature;
public DataDirectory codeManagerTable;
public DataDirectory vtableFixups;
public DataDirectory exportAddressTableJumps;
public DataDirectory managedNativeHeader;
uint mdOffset, mdHeaderLength;
public uint MetadataOffset {
get { return mdOffset; }
}
public uint MetadataHeaderLength {
get { return mdHeaderLength; }
}
uint offset;
public uint Offset {
get { return offset; }
}
public uint Length {
get { return 18 * 4; }
}
public Cor20Header(BinaryReader reader) {
offset = (uint)reader.BaseStream.Position;
cb = reader.ReadUInt32();
majorRuntimeVersion = reader.ReadUInt16();
minorRuntimeVersion = reader.ReadUInt16();
metaData.read(reader);
flags = reader.ReadUInt32();
entryPointToken = reader.ReadUInt32();
resources.read(reader);
strongNameSignature.read(reader);
codeManagerTable.read(reader);
vtableFixups.read(reader);
exportAddressTableJumps.read(reader);
managedNativeHeader.read(reader);
}
public void initMetadataTable(BinaryReader reader) {
if (reader.ReadUInt32() != 0x424A5342)
return;
mdOffset = (uint)reader.BaseStream.Position - 4;
reader.ReadUInt16(); // major version
reader.ReadUInt16(); // minor version
reader.ReadUInt32(); // reserved
int slen = reader.ReadInt32();
reader.BaseStream.Position += slen;
reader.ReadUInt16(); // flags
int streams = reader.ReadUInt16();
for (int i = 0; i < streams; i++) {
uint offset = reader.ReadUInt32();
uint size = reader.ReadUInt32();
skipString(reader);
}
mdHeaderLength = (uint)reader.BaseStream.Position - mdOffset;
}
void skipString(BinaryReader reader) {
while (reader.ReadByte() != 0) {
// nothing
}
reader.BaseStream.Position = (reader.BaseStream.Position + 3) & ~3;
}
}
}

View File

@ -0,0 +1,36 @@
/*
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 void read(BinaryReader reader) {
virtualAddress = reader.ReadUInt32();
size = reader.ReadUInt32();
}
public override string ToString() {
return string.Format("{0:X8} {1:X8}", virtualAddress, size);
}
}
}

View File

@ -26,7 +26,7 @@ namespace de4dot.PE {
amd64 = 0x8664,
}
class FileHeader {
class FileHeader : IFileLocation {
public Machine machine;
public ushort numberOfSections;
public uint timeDateStamp;
@ -35,7 +35,17 @@ namespace de4dot.PE {
public ushort sizeOfOptionalHeader;
public ushort characteristics;
uint offset;
public uint Offset {
get { return offset; }
}
public uint Length {
get { return 5 * 4; }
}
public FileHeader(BinaryReader reader) {
offset = (uint)reader.BaseStream.Position;
machine = (Machine)reader.ReadUInt16();
numberOfSections = reader.ReadUInt16();
timeDateStamp = reader.ReadUInt32();

View File

@ -0,0 +1,25 @@
/*
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/>.
*/
namespace de4dot.PE {
interface IFileLocation {
uint Offset { get; }
uint Length { get; }
}
}

View File

@ -20,16 +20,7 @@
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 {
class OptionalHeader : IFileLocation {
public ushort magic;
public byte majorLinkerVersion;
public byte minorLinkerVersion;
@ -62,7 +53,17 @@ namespace de4dot.PE {
public uint numberOfRvaAndSizes;
public DataDirectory[] dataDirectories;
uint offset, length;
public uint Offset {
get { return offset; }
}
public uint Length {
get { return length; }
}
public OptionalHeader(BinaryReader reader) {
offset = (uint)reader.BaseStream.Position;
magic = reader.ReadUInt16();
majorLinkerVersion = reader.ReadByte();
minorLinkerVersion = reader.ReadByte();
@ -96,10 +97,9 @@ namespace de4dot.PE {
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();
}
for (int i = 0; i < dataDirectories.Length; i++)
dataDirectories[i].read(reader);
length = (uint)reader.BaseStream.Position - offset;
}
ulong read4Or8(BinaryReader reader) {

View File

@ -27,6 +27,8 @@ namespace de4dot.PE {
FileHeader fileHeader;
OptionalHeader optionalHeader;
SectionHeader[] sectionHeaders;
Cor20Header cor20Header;
SectionHeader dotNetSection;
public PeImage(byte[] data)
: this(new MemoryStream(data)) {
@ -43,6 +45,10 @@ namespace de4dot.PE {
reader.BaseStream.Position = position;
}
void seekRva(uint rva) {
seek(rvaToOffset(rva));
}
void skip(int bytes) {
reader.BaseStream.Position += bytes;
}
@ -62,6 +68,15 @@ namespace de4dot.PE {
sectionHeaders = new SectionHeader[fileHeader.numberOfSections];
for (int i = 0; i < sectionHeaders.Length; i++)
sectionHeaders[i] = new SectionHeader(reader);
uint netOffset = optionalHeader.dataDirectories[14].virtualAddress;
if (netOffset != 0) {
seekRva(netOffset);
cor20Header = new Cor20Header(reader);
dotNetSection = getSectionHeader(netOffset);
seekRva(cor20Header.metaData.virtualAddress);
cor20Header.initMetadataTable(reader);
}
}
SectionHeader getSectionHeader(uint rva) {
@ -80,18 +95,43 @@ namespace de4dot.PE {
return rva - section.virtualAddress + section.pointerToRawData;
}
bool intersect(uint offset1, uint length1, uint offset2, uint length2) {
return !(offset1 + length1 <= offset2 || offset2 + length2 <= offset1);
}
bool intersect(uint offset, uint length, IFileLocation location) {
return intersect(offset, length, location.Offset, location.Length);
}
public bool dotNetSafeWrite(uint rva, byte[] data) {
if (cor20Header != null) {
uint offset = rvaToOffset(rva);
uint length = (uint)data.Length;
if (!dotNetSection.isInside(offset, length))
return false;
if (intersect(offset, length, cor20Header))
return false;
if (intersect(offset, length, cor20Header.MetadataOffset, cor20Header.MetadataHeaderLength))
return false;
}
write(rva, data);
return true;
}
public void write(uint rva, byte[] data) {
seek(rvaToOffset(rva));
seekRva(rva);
writer.Write(data);
}
public int readInt32(uint rva) {
seek(rvaToOffset(rva));
seekRva(rva);
return reader.ReadInt32();
}
public byte[] readBytes(uint rva, int size) {
seek(rvaToOffset(rva));
seekRva(rva);
return reader.ReadBytes(size);
}
}

View File

@ -21,7 +21,7 @@ using System.IO;
using System.Text;
namespace de4dot.PE {
class SectionHeader {
class SectionHeader : IFileLocation {
public byte[] name;
public uint virtualSize;
public uint virtualAddress;
@ -34,7 +34,17 @@ namespace de4dot.PE {
public uint characteristics;
public string displayName;
uint offset;
public uint Offset {
get { return offset; }
}
public uint Length {
get { return 10 * 4; }
}
public SectionHeader(BinaryReader reader) {
offset = (uint)reader.BaseStream.Position;
name = reader.ReadBytes(8);
virtualSize = reader.ReadUInt32();
virtualAddress = reader.ReadUInt32();
@ -55,6 +65,10 @@ namespace de4dot.PE {
displayName = sb.ToString();
}
public bool isInside(uint offset, uint length) {
return offset >= pointerToRawData && offset + length <= pointerToRawData + sizeOfRawData;
}
public override string ToString() {
return string.Format("{0:X8} {1:X8} {2:X8} - {3}", virtualAddress, virtualSize, sizeOfRawData, displayName);
}

View File

@ -109,7 +109,10 @@
<Compile Include="NameRegexes.cs" />
<Compile Include="ObfuscatedFile.cs" />
<Compile Include="Option.cs" />
<Compile Include="PE\Cor20Header.cs" />
<Compile Include="PE\DataDirectory.cs" />
<Compile Include="PE\FileHeader.cs" />
<Compile Include="PE\IFileLocation.cs" />
<Compile Include="PE\OptionalHeader.cs" />
<Compile Include="PE\PeImage.cs" />
<Compile Include="PE\SectionHeader.cs" />