diff --git a/de4dot.code/PE/Cor20Header.cs b/de4dot.code/PE/Cor20Header.cs new file mode 100644 index 00000000..8664b6aa --- /dev/null +++ b/de4dot.code/PE/Cor20Header.cs @@ -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 . +*/ + +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; + } + } +} diff --git a/de4dot.code/PE/DataDirectory.cs b/de4dot.code/PE/DataDirectory.cs new file mode 100644 index 00000000..9dfe6a49 --- /dev/null +++ b/de4dot.code/PE/DataDirectory.cs @@ -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 . +*/ + +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); + } + } +} diff --git a/de4dot.code/PE/FileHeader.cs b/de4dot.code/PE/FileHeader.cs index cbe5ea64..8bff853c 100644 --- a/de4dot.code/PE/FileHeader.cs +++ b/de4dot.code/PE/FileHeader.cs @@ -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(); diff --git a/de4dot.code/PE/IFileLocation.cs b/de4dot.code/PE/IFileLocation.cs new file mode 100644 index 00000000..a69f422d --- /dev/null +++ b/de4dot.code/PE/IFileLocation.cs @@ -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 . +*/ + +namespace de4dot.PE { + interface IFileLocation { + uint Offset { get; } + uint Length { get; } + } +} diff --git a/de4dot.code/PE/OptionalHeader.cs b/de4dot.code/PE/OptionalHeader.cs index b7f5ca1c..91dbf3ce 100644 --- a/de4dot.code/PE/OptionalHeader.cs +++ b/de4dot.code/PE/OptionalHeader.cs @@ -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) { diff --git a/de4dot.code/PE/PeImage.cs b/de4dot.code/PE/PeImage.cs index efb4cd89..09302fd3 100644 --- a/de4dot.code/PE/PeImage.cs +++ b/de4dot.code/PE/PeImage.cs @@ -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); } } diff --git a/de4dot.code/PE/SectionHeader.cs b/de4dot.code/PE/SectionHeader.cs index bce7aa02..052df9d8 100644 --- a/de4dot.code/PE/SectionHeader.cs +++ b/de4dot.code/PE/SectionHeader.cs @@ -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); } diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 7548bd53..81d00452 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -109,7 +109,10 @@ + + +