Remove old PeImage code and use the new one

This commit is contained in:
de4dot 2012-11-21 11:14:20 +01:00
parent e9f90aad6e
commit 5b43e33a35
39 changed files with 369 additions and 2030 deletions

View File

@ -1,81 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public class Cor20Header : IFileLocation {
public uint cb;
public ushort majorRuntimeVersion;
public ushort minorRuntimeVersion;
public DataDirectory metadataDirectory;
public uint flags;
public uint entryPointToken;
public DataDirectory resources;
public DataDirectory strongNameSignature;
public DataDirectory codeManagerTable;
public DataDirectory vtableFixups;
public DataDirectory exportAddressTableJumps;
public DataDirectory managedNativeHeader;
public Metadata metadata;
BinaryReader reader;
public uint MetadataOffset {
get { return metadata.Offset; }
}
public uint MetadataHeaderLength {
get { return metadata.HeaderLength; }
}
uint offset;
public uint Offset {
get { return offset; }
}
public uint Length {
get { return 18 * 4; }
}
public Cor20Header(BinaryReader reader) {
this.reader = reader;
offset = (uint)reader.BaseStream.Position;
cb = reader.ReadUInt32();
majorRuntimeVersion = reader.ReadUInt16();
minorRuntimeVersion = reader.ReadUInt16();
metadataDirectory.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);
}
internal void initMetadataTable() {
metadata = new Metadata(reader);
}
public MetadataTables createMetadataTables() {
return new MetadataTables(reader, metadata);
}
}
}

View File

@ -1,36 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public 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

@ -1,46 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public class DotNetStream : IFileLocation {
public string name;
public uint fileOffset;
public uint length;
public uint Offset {
get { return fileOffset; }
}
public uint Length {
get { return length; }
}
public DotNetStream(string name, uint fileOffset, uint length) {
this.name = name;
this.fileOffset = fileOffset;
this.length = length;
}
public override string ToString() {
return string.Format("{0:X8} {1:X8} {2}", fileOffset, length, name);
}
}
}

View File

@ -1,58 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public enum Machine : ushort {
i386 = 0x14C,
ia64 = 0x200,
amd64 = 0x8664,
}
public class FileHeader : IFileLocation {
public Machine machine;
public ushort numberOfSections;
public uint timeDateStamp;
public uint pointerToSymbolTable;
public uint numberOfSymbols;
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();
pointerToSymbolTable = reader.ReadUInt32();
numberOfSymbols = reader.ReadUInt32();
sizeOfOptionalHeader = reader.ReadUInt16();
characteristics = reader.ReadUInt16();
}
}
}

View File

@ -1,25 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public interface IFileLocation {
uint Offset { get; }
uint Length { get; }
}
}

View File

@ -1,114 +0,0 @@
/*
Copyright (C) 2011-2012 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;
using System.Text;
namespace de4dot.PE {
public class Metadata : IFileLocation {
uint magic;
ushort majorVersion, minorVersion;
uint reserved;
string versionString;
ushort flags;
DotNetStream[] streams;
uint offset, headerLength, length;
public DotNetStream[] Streams {
get { return streams; }
}
public uint Offset {
get { return offset; }
}
public uint Length {
get { return length; }
}
public uint HeaderLength {
get { return headerLength; }
}
public uint HeaderEnd {
get { return offset + headerLength; }
}
public Metadata(BinaryReader reader) {
magic = reader.ReadUInt32();
if (magic != 0x424A5342)
return;
offset = (uint)reader.BaseStream.Position - 4;
majorVersion = reader.ReadUInt16();
minorVersion = reader.ReadUInt16();
reserved = reader.ReadUInt32();
versionString = readString(reader, reader.ReadInt32());
flags = reader.ReadUInt16();
int numStreams = reader.ReadUInt16();
streams = new DotNetStream[numStreams];
uint lastOffset = offset;
for (int i = 0; i < numStreams; i++) {
uint fileOffset = offset + reader.ReadUInt32();
uint size = reader.ReadUInt32();
string name = readAsciizString(reader);
streams[i] = new DotNetStream(name, fileOffset, size);
lastOffset = Math.Max(lastOffset, fileOffset + size);
}
lastOffset = Math.Max(lastOffset, (uint)reader.BaseStream.Position);
length = lastOffset - offset;
headerLength = (uint)reader.BaseStream.Position - offset;
}
public DotNetStream getStream(string name) {
foreach (var stream in streams) {
if (stream.name == name)
return stream;
}
return null;
}
string readString(BinaryReader reader, int len) {
var sb = new StringBuilder(len);
var nextPos = reader.BaseStream.Position + len;
for (int i = 0; i < len; i++) {
byte b = reader.ReadByte();
if (b == 0)
break;
sb.Append((char)b);
}
reader.BaseStream.Position = nextPos;
return sb.ToString();
}
string readAsciizString(BinaryReader reader) {
var sb = new StringBuilder();
while (true) {
byte b = reader.ReadByte();
if (b == 0)
break;
sb.Append((char)b);
}
reader.BaseStream.Position = (reader.BaseStream.Position + 3) & ~3;
return sb.ToString();
}
}
}

View File

@ -1,152 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
using MVT = MetadataVarType;
public class MetadataTables {
BinaryReader reader;
Metadata metadata;
byte heapOffsetSizes;
MetadataType[] metadataTypes = new MetadataType[64];
public MetadataTables(BinaryReader reader, Metadata metadata) {
this.reader = reader;
this.metadata = metadata;
init();
}
public MetadataType getMetadataType(MetadataIndex index) {
return metadataTypes[(int)index];
}
void seek(uint fileOffset) {
reader.BaseStream.Position = fileOffset;
}
// TODO: This table needs to be updated to support the other metadata tables.
static MetadataVarType[] metadataVarType = new MetadataVarType[] {
MVT.byte2, MVT.stringIndex, MVT.guidIndex, MVT.guidIndex, MVT.guidIndex, MVT.end, // 0
MVT.resolutionScope, MVT.stringIndex, MVT.stringIndex, MVT.end, // 1
MVT.byte4, MVT.stringIndex, MVT.stringIndex, MVT.typeDefOrRef, MVT.fieldIndex, MVT.methodDefIndex, MVT.end, // 2
MVT.end, // 3
MVT.byte2, MVT.stringIndex, MVT.blobIndex, MVT.end, // 4
MVT.methodDefIndex, MVT.end, // 5
MVT.byte4, MVT.byte2, MVT.byte2, MVT.stringIndex, MVT.blobIndex, MVT.paramIndex, MVT.end, // 6
MVT.end, // 7
MVT.byte2, MVT.byte2, MVT.stringIndex, MVT.end, // 8
MVT.typeDefIndex, MVT.typeDefOrRef, MVT.end, // 9
MVT.memberRefParent, MVT.stringIndex, MVT.blobIndex, MVT.end, // 10
MVT.byte1, MVT.byte1, MVT.hasConstant, MVT.blobIndex, MVT.end, // 11
MVT.hasCustomAttribute, MVT.customAttributeType, MVT.blobIndex, MVT.end,// 12
MVT.hasFieldMarshal, MVT.blobIndex, MVT.end, // 13
MVT.byte2, MVT.hasDeclSecurity, MVT.blobIndex, MVT.end, // 14
MVT.byte2, MVT.byte4, MVT.typeDefIndex, MVT.end, // 15
MVT.byte4, MVT.fieldIndex, MVT.end, // 16
MVT.blobIndex, MVT.end, // 17
MVT.typeDefIndex, MVT.eventIndex, MVT.end, // 18
MVT.end, // 19
MVT.byte2, MVT.stringIndex, MVT.typeDefOrRef, MVT.end, // 20
MVT.typeDefIndex, MVT.propertyIndex, MVT.end, // 21
MVT.end, // 22
MVT.byte2, MVT.stringIndex, MVT.blobIndex, MVT.end, // 23
MVT.byte2, MVT.methodDefIndex, MVT.hasSemantics, MVT.end, // 24
MVT.typeDefIndex, MVT.methodDefOrRef, MVT.methodDefOrRef, MVT.end, // 25
MVT.stringIndex, MVT.end, // 26
MVT.blobIndex, MVT.end, // 27
MVT.byte2, MVT.memberForwarded, MVT.stringIndex, MVT.moduleRefIndex, MVT.end, // 28
MVT.byte4, MVT.fieldIndex, MVT.end, // 29
MVT.end, // 30
MVT.end, // 31
MVT.byte4, MVT.byte2, MVT.byte2, MVT.byte2, MVT.byte2, MVT.byte4, MVT.blobIndex, MVT.stringIndex, MVT.stringIndex, MVT.end, // 32
MVT.byte4, MVT.end, // 33
MVT.byte4, MVT.byte4, MVT.byte4, MVT.end, // 34
MVT.byte2, MVT.byte2, MVT.byte2, MVT.byte2, MVT.byte4, MVT.blobIndex, MVT.stringIndex, MVT.stringIndex, MVT.blobIndex, MVT.end, // 35
MVT.byte4, MVT.assemblyRefIndex, MVT.end, // 36
MVT.byte4, MVT.byte4, MVT.byte4, MVT.assemblyRefIndex, MVT.end, // 37
MVT.byte4, MVT.stringIndex, MVT.blobIndex, MVT.end, // 38
MVT.byte4, MVT.byte4, MVT.stringIndex, MVT.stringIndex, MVT.implementation, MVT.end,// 39
MVT.byte4, MVT.byte4, MVT.stringIndex, MVT.implementation, MVT.end, // 40
MVT.typeDefIndex, MVT.typeDefIndex, MVT.end, // 41
MVT.byte2, MVT.byte2, MVT.typeOrMethodDef, MVT.stringIndex, MVT.end, // 42
MVT.end, // 43
MVT.genericParamIndex, MVT.typeDefOrRef, MVT.end, // 44
MVT.end, // 45
MVT.end, // 46
MVT.end, // 47
MVT.end, // 48
MVT.end, // 49
MVT.end, // 50
MVT.end, // 51
MVT.end, // 52
MVT.end, // 53
MVT.end, // 54
MVT.end, // 55
MVT.end, // 56
MVT.end, // 57
MVT.end, // 58
MVT.end, // 59
MVT.end, // 60
MVT.end, // 61
MVT.end, // 62
MVT.end, // 63
MVT.stop
};
void init() {
var streamTable = metadata.getStream("#~") ?? metadata.getStream("#-");
if (streamTable == null)
throw new ApplicationException("Could not find #~ stream");
seek(streamTable.Offset);
reader.ReadUInt32(); // reserved
reader.ReadUInt16(); // major + minor version
heapOffsetSizes = reader.ReadByte();
reader.ReadByte(); // always 1
ulong validMask = reader.ReadUInt64();
reader.ReadUInt64(); // sorted
var numRows = new uint[64];
for (int i = 0; validMask != 0; i++, validMask >>= 1) {
if ((validMask & 1) != 0)
numRows[i] = reader.ReadUInt32();
}
var builder = new MetadataTypeBuilder(heapOffsetSizes, numRows);
uint fileOffset = (uint)reader.BaseStream.Position;
for (int i = 0, j = 0; ; i++) {
if (metadataVarType[i] == MVT.end) {
var mdType = builder.create();
mdType.rows = numRows[j];
mdType.fileOffset = fileOffset;
fileOffset += mdType.rows * mdType.totalSize;
metadataTypes[j++] = mdType;
}
else if (metadataVarType[i] == MVT.stop)
break;
else
builder.field(metadataVarType[i]);
}
}
}
}

View File

@ -1,89 +0,0 @@
/*
Copyright (C) 2011-2012 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.Collections.Generic;
namespace de4dot.PE {
public enum MetadataIndex {
iModule = 0,
iTypeRef = 1,
iTypeDef = 2,
iField = 4,
iMethodDef = 6,
iParam = 8,
iInterfaceImpl = 9,
iMemberRef = 10,
iConstant = 11,
iCustomAttribute = 12,
iFieldMarshal = 13,
iDeclSecurity = 14,
iClassLayout = 15,
iFieldLayout = 16,
iStandAloneSig = 17,
iEventMap = 18,
iEvent = 20,
iPropertyMap = 21,
iProperty = 23,
iMethodSemantics = 24,
iMethodImpl = 25,
iModuleRef = 26,
iTypeSpec = 27,
iImplMap = 28,
iFieldRVA = 29,
iAssembly = 32,
iAssemblyProcessor = 33,
iAssemblyOS = 34,
iAssemblyRef = 35,
iAssemblyRefProcessor = 36,
iAssemblyRefOS = 37,
iFile = 38,
iExportedType = 39,
iManifestResource = 40,
iNestedClass = 41,
iGenericParam = 42,
iGenericParamConstraint = 44,
};
public class MetadataType {
public uint fileOffset;
public uint rows;
public uint totalSize;
public List<MetadataField> fields;
public MetadataType(List<MetadataField> fields) {
this.fields = fields;
totalSize = 0;
foreach (var field in fields)
totalSize += (uint)field.size;
}
public override string ToString() {
return string.Format("MDType: {0:X8}, {1} rows, {2} bytes, {3} fields", fileOffset, rows, totalSize, fields.Count);
}
}
public struct MetadataField {
public int offset;
public int size;
public override string ToString() {
return string.Format("offset: {0}, size {1}", offset, size);
}
}
}

View File

@ -1,203 +0,0 @@
/*
Copyright (C) 2011-2012 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.Collections.Generic;
namespace de4dot.PE {
enum MetadataVarType {
end,
stop,
byte1,
byte2,
byte4,
stringIndex, // index into #String heap
guidIndex, // index into #GUID heap
blobIndex, // index into #Blob heap
resolutionScope,
typeDefOrRef,
fieldIndex,
methodDefIndex,
paramIndex,
typeDefIndex,
eventIndex,
propertyIndex,
moduleRefIndex,
assemblyRefIndex,
genericParamIndex,
memberRefParent,
hasConstant,
hasCustomAttribute,
customAttributeType,
hasFieldMarshal,
hasDeclSecurity,
hasSemantics,
methodDefOrRef,
memberForwarded,
implementation,
typeOrMethodDef,
};
class MetadataTypeBuilder {
byte heapOffsetSizes;
uint[] numRows;
List<MetadataField> fields;
int offset;
public MetadataTypeBuilder(byte heapOffsetSizes, uint[] numRows) {
this.heapOffsetSizes = heapOffsetSizes;
this.numRows = numRows;
reset();
}
void reset() {
offset = 0;
fields = new List<MetadataField>();
}
public MetadataType create() {
var type = new MetadataType(fields);
reset();
return type;
}
public void field(MetadataVarType type) {
int size;
switch (type) {
case MetadataVarType.byte1:
size = 1;
break;
case MetadataVarType.byte2:
size = 2;
break;
case MetadataVarType.byte4:
size = 4;
break;
case MetadataVarType.stringIndex:
size = (heapOffsetSizes & 1) != 0 ? 4 : 2;
break;
case MetadataVarType.guidIndex:
size = (heapOffsetSizes & 2) != 0 ? 4 : 2;
break;
case MetadataVarType.blobIndex:
size = (heapOffsetSizes & 4) != 0 ? 4 : 2;
break;
case MetadataVarType.resolutionScope:
size = getSize(14, new MetadataIndex[] { MetadataIndex.iModule, MetadataIndex.iModuleRef, MetadataIndex.iAssemblyRef, MetadataIndex.iTypeRef });
break;
case MetadataVarType.typeDefOrRef:
size = getSize(14, new MetadataIndex[] { MetadataIndex.iTypeDef, MetadataIndex.iTypeRef, MetadataIndex.iTypeSpec });
break;
case MetadataVarType.memberRefParent:
size = getSize(13, new MetadataIndex[] { MetadataIndex.iTypeDef, MetadataIndex.iTypeRef, MetadataIndex.iModuleRef, MetadataIndex.iMethodDef, MetadataIndex.iTypeSpec });
break;
case MetadataVarType.hasConstant:
size = getSize(14, new MetadataIndex[] { MetadataIndex.iField, MetadataIndex.iParam, MetadataIndex.iProperty });
break;
case MetadataVarType.hasCustomAttribute:
size = getSize(11, new MetadataIndex[] {
MetadataIndex.iMethodDef, MetadataIndex.iField, MetadataIndex.iTypeRef,
MetadataIndex.iTypeDef, MetadataIndex.iParam, MetadataIndex.iInterfaceImpl,
MetadataIndex.iMemberRef, MetadataIndex.iModule /*TODO:, MetadataIndex.iPermission*/,
MetadataIndex.iProperty, MetadataIndex.iEvent, MetadataIndex.iStandAloneSig,
MetadataIndex.iModuleRef, MetadataIndex.iTypeSpec, MetadataIndex.iAssembly,
MetadataIndex.iAssemblyRef, MetadataIndex.iFile, MetadataIndex.iExportedType,
MetadataIndex.iManifestResource,
});
break;
case MetadataVarType.customAttributeType:
size = getSize(13, new MetadataIndex[] { MetadataIndex.iMethodDef, MetadataIndex.iMemberRef }); // others aren't used
break;
case MetadataVarType.hasFieldMarshal:
size = getSize(15, new MetadataIndex[] { MetadataIndex.iField, MetadataIndex.iParam });
break;
case MetadataVarType.hasDeclSecurity:
size = getSize(14, new MetadataIndex[] { MetadataIndex.iTypeDef, MetadataIndex.iMethodDef, MetadataIndex.iAssembly });
break;
case MetadataVarType.hasSemantics:
size = getSize(15, new MetadataIndex[] { MetadataIndex.iEvent, MetadataIndex.iProperty });
break;
case MetadataVarType.methodDefOrRef:
size = getSize(15, new MetadataIndex[] { MetadataIndex.iMethodDef, MetadataIndex.iMemberRef });
break;
case MetadataVarType.memberForwarded:
size = getSize(15, new MetadataIndex[] { MetadataIndex.iField, MetadataIndex.iMethodDef });
break;
case MetadataVarType.implementation:
size = getSize(14, new MetadataIndex[] { MetadataIndex.iFile, MetadataIndex.iAssemblyRef, MetadataIndex.iExportedType });
break;
case MetadataVarType.typeOrMethodDef:
size = getSize(15, new MetadataIndex[] { MetadataIndex.iTypeDef, MetadataIndex.iMethodDef });
break;
case MetadataVarType.fieldIndex:
size = getSize(MetadataIndex.iField);
break;
case MetadataVarType.methodDefIndex:
size = getSize(MetadataIndex.iMethodDef);
break;
case MetadataVarType.paramIndex:
size = getSize(MetadataIndex.iParam);
break;
case MetadataVarType.typeDefIndex:
size = getSize(MetadataIndex.iTypeDef);
break;
case MetadataVarType.eventIndex:
size = getSize(MetadataIndex.iEvent);
break;
case MetadataVarType.propertyIndex:
size = getSize(MetadataIndex.iProperty);
break;
case MetadataVarType.moduleRefIndex:
size = getSize(MetadataIndex.iModuleRef);
break;
case MetadataVarType.assemblyRefIndex:
size = getSize(MetadataIndex.iAssemblyRef);
break;
case MetadataVarType.genericParamIndex:
size = getSize(MetadataIndex.iGenericParam);
break;
default:
throw new ApplicationException("Unknown type");
}
var field = new MetadataField();
field.offset = offset;
field.size = size;
fields.Add(field);
offset += size;
}
uint getMaxRows(MetadataIndex[] indexes) {
uint maxRows = 0;
for (int i = 0; i < indexes.Length; i++)
maxRows = Math.Max(maxRows, numRows[(int)indexes[i]]);
return maxRows;
}
int getSize(int bits, MetadataIndex[] indexes) {
uint maxNum = 1U << bits;
uint maxRows = getMaxRows(indexes);
return maxRows <= maxNum ? 2 : 4;
}
int getSize(MetadataIndex index) {
return getSize(16, new MetadataIndex[] { index });
}
}
}

View File

@ -1,119 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public class OptionalHeader : IFileLocation {
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;
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();
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].read(reader);
length = (uint)reader.BaseStream.Position - offset;
}
public uint offsetOfDataDirectory(int n) {
return offset + length - (uint)(16 - n) * 8;
}
ulong read4Or8(BinaryReader reader) {
if (is32bit())
return reader.ReadUInt32();
return reader.ReadUInt64();
}
public bool is32bit() {
return magic != 0x20B;
}
}
}

View File

@ -1,285 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public class PeImage {
BinaryReader reader;
BinaryWriter writer;
FileHeader fileHeader;
OptionalHeader optionalHeader;
SectionHeader[] sectionHeaders;
Cor20Header cor20Header;
SectionHeader dotNetSection;
Resources resources;
public BinaryReader Reader {
get { return reader; }
}
public uint ImageLength {
get { return (uint)reader.BaseStream.Length; }
}
public Cor20Header Cor20Header {
get { return cor20Header; }
}
public Resources Resources {
get { return resources; }
}
public FileHeader FileHeader {
get { return fileHeader; }
}
public OptionalHeader OptionalHeader {
get { return optionalHeader; }
}
public SectionHeader[] Sections {
get { return sectionHeaders; }
}
public uint FileHeaderOffset {
get { return fileHeader.Offset; }
}
public PeImage(byte[] data)
: this(new MemoryStream(data)) {
}
public PeImage(Stream stream) {
reader = new BinaryReader(stream);
if (stream.CanWrite)
writer = new BinaryWriter(stream);
init();
}
public SectionHeader findSection(string displayName) {
foreach (var section in sectionHeaders) {
if (section.displayName == displayName)
return section;
}
return null;
}
void seek(uint position) {
reader.BaseStream.Position = position;
}
void seekRva(uint rva) {
seek(rvaToOffset(rva));
}
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);
uint netRva = optionalHeader.dataDirectories[14].virtualAddress;
if (netRva != 0) {
seekRva(netRva);
cor20Header = new Cor20Header(reader);
dotNetSection = getSectionHeaderRva(netRva);
seekRva(cor20Header.metadataDirectory.virtualAddress);
cor20Header.initMetadataTable();
}
uint resourceRva = optionalHeader.dataDirectories[2].virtualAddress;
uint resourceOffset = 0;
if (resourceRva != 0)
resourceOffset = rvaToOffset(resourceRva);
resources = new Resources(reader, resourceOffset, optionalHeader.dataDirectories[2].size);
}
SectionHeader getSectionHeaderRva(uint rva) {
for (int i = 0; i < sectionHeaders.Length; i++) {
var section = sectionHeaders[i];
if (section.virtualAddress <= rva && rva < section.virtualAddress + Math.Max(section.virtualSize, section.sizeOfRawData))
return section;
}
return null;
}
SectionHeader getSectionHeaderOffset(uint offset) {
for (int i = 0; i < sectionHeaders.Length; i++) {
var section = sectionHeaders[i];
if (section.pointerToRawData <= offset && offset < section.pointerToRawData + section.sizeOfRawData)
return section;
}
return null;
}
public uint rvaToOffset(uint rva) {
var section = getSectionHeaderRva(rva);
if (section == null)
throw new ApplicationException(string.Format("Invalid RVA {0:X8}", rva));
return rva - section.virtualAddress + section.pointerToRawData;
}
public uint offsetToRva(uint offset) {
var section = getSectionHeaderOffset(offset);
if (section == null)
throw new ApplicationException(string.Format("Invalid offset {0:X8}", offset));
return offset - section.pointerToRawData + section.virtualAddress;
}
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 dotNetSafeWriteOffset(uint offset, byte[] data) {
if (cor20Header != null) {
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;
}
offsetWrite(offset, data);
return true;
}
public bool dotNetSafeWrite(uint rva, byte[] data) {
return dotNetSafeWriteOffset(rvaToOffset(rva), data);
}
public void write(uint rva, byte[] data) {
seekRva(rva);
writer.Write(data);
}
public void writeUInt16(uint rva, ushort data) {
seekRva(rva);
writer.Write(data);
}
public void writeUInt32(uint rva, uint data) {
seekRva(rva);
writer.Write(data);
}
public byte readByte(uint rva) {
seekRva(rva);
return reader.ReadByte();
}
public ushort readUInt16(uint rva) {
seekRva(rva);
return reader.ReadUInt16();
}
public uint readUInt32(uint rva) {
seekRva(rva);
return reader.ReadUInt32();
}
public int readInt32(uint rva) {
seekRva(rva);
return reader.ReadInt32();
}
public byte[] readBytes(uint rva, int size) {
seekRva(rva);
return reader.ReadBytes(size);
}
public void offsetWrite(uint offset, byte[] data) {
seek(offset);
writer.Write(data);
}
public byte[] offsetReadBytes(uint offset, int size) {
seek(offset);
return reader.ReadBytes(size);
}
public uint offsetRead(uint offset, int size) {
if (size == 2) return offsetReadUInt16(offset);
if (size == 4) return offsetReadUInt32(offset);
throw new NotImplementedException();
}
public byte offsetReadByte(uint offset) {
seek(offset);
return reader.ReadByte();
}
public ushort offsetReadUInt16(uint offset) {
seek(offset);
return reader.ReadUInt16();
}
public uint offsetReadUInt32(uint offset) {
seek(offset);
return reader.ReadUInt32();
}
public void offsetWrite(uint offset, uint data, int size) {
if (size == 2)
offsetWriteUInt16(offset, (ushort)data);
else if (size == 4)
offsetWriteUInt32(offset, data);
else
throw new NotImplementedException();
}
public void offsetWriteUInt16(uint offset, ushort data) {
seek(offset);
writer.Write(data);
}
public void offsetWriteUInt32(uint offset, uint data) {
seek(offset);
writer.Write(data);
}
public byte[] readAllBytes() {
seek(0);
return reader.ReadBytes((int)reader.BaseStream.Length);
}
}
}

View File

@ -1,49 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public class ResourceData : ResourceDirectoryEntry {
uint rva;
uint size;
public uint RVA {
get { return rva; }
}
public uint Size {
get { return size; }
}
public ResourceData(int id, uint rva, uint size)
: base(id) {
this.rva = rva;
this.size = size;
}
public ResourceData(string name, uint dataOffset, uint dataSize)
: base(name) {
this.rva = dataOffset;
this.size = dataSize;
}
public override string ToString() {
return string.Format("RVA: {0:X8} SIZE: {1:X8}, NAME: {2}", rva, size, getName());
}
}
}

View File

@ -1,124 +0,0 @@
/*
Copyright (C) 2011-2012 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.Collections.Generic;
namespace de4dot.PE {
public class ResourceDirectory : ResourceDirectoryEntry {
Resources resources;
int offset;
List<ResourceData> resourceDataList = new List<ResourceData>();
List<ResourceDirectory> resourceDirectoryList = new List<ResourceDirectory>();
public List<ResourceData> Data {
get { return resourceDataList; }
}
public List<ResourceDirectory> Directories {
get { return resourceDirectoryList; }
}
public ResourceDirectory(int id, Resources resources, int offset)
: base(id) {
init(resources, offset);
}
public ResourceDirectory(string name, Resources resources, int offset)
: base(name) {
init(resources, offset);
}
void init(Resources resources, int offset) {
this.resources = resources;
this.offset = offset;
initializeEntries();
}
public ResourceDirectory getDirectory(int id) {
return find(resourceDirectoryList, id);
}
public ResourceDirectory getDirectory(string name) {
return find(resourceDirectoryList, name);
}
public ResourceData getData(int id) {
return find(resourceDataList, id);
}
public ResourceData getData(string name) {
return find(resourceDataList, name);
}
void initializeEntries() {
if (offset < 0)
return;
if (!resources.isSizeAvailable(offset, 16))
return;
if (!resources.seek(offset + 12))
return;
int named = resources.readUInt16();
int ids = resources.readUInt16();
int total = named + ids;
if (!resources.isSizeAvailable(total * 8))
return;
for (int i = 0, entryOffset = offset + 16; i < total; i++, entryOffset += 8) {
resources.seek(entryOffset);
uint nameOrId = resources.readUInt32();
uint dataOrDirectory = resources.readUInt32();
string name = null;
int id = -1;
if ((nameOrId & 0x80000000) != 0) {
name = resources.readString((int)(nameOrId & 0x7FFFFFFF));
if (name == null)
break;
}
else
id = (int)nameOrId;
if ((dataOrDirectory & 0x80000000) == 0) {
if (!resources.seek((int)dataOrDirectory))
break;
if (!resources.isSizeAvailable(16))
break;
uint dataRva = resources.readUInt32();
uint dataSize = resources.readUInt32();
if (name == null)
resourceDataList.Add(new ResourceData(id, dataRva, dataSize));
else
resourceDataList.Add(new ResourceData(name, dataRva, dataSize));
}
else {
int directoryOffset = (int)(dataOrDirectory & 0x7FFFFFFF);
if (name == null)
resourceDirectoryList.Add(new ResourceDirectory(id, resources, directoryOffset));
else
resourceDirectoryList.Add(new ResourceDirectory(name, resources, directoryOffset));
}
}
}
public override string ToString() {
return string.Format("OFS: {0:X8}, NAME: {1}", offset, getName());
}
}
}

View File

@ -1,73 +0,0 @@
/*
Copyright (C) 2011-2012 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.Collections.Generic;
namespace de4dot.PE {
public abstract class ResourceDirectoryEntry {
protected readonly string name;
protected readonly int id;
public bool HasStringName {
get { return name != null; }
}
public bool HasId {
get { return !HasStringName; }
}
public string Name {
get { return name; }
}
public int Id {
get { return id; }
}
public ResourceDirectoryEntry(int id) {
this.name = null;
this.id = id;
}
public ResourceDirectoryEntry(string name) {
this.name = name;
this.id = -1;
}
protected string getName() {
return HasStringName ? name : id.ToString();
}
protected static T find<T>(IEnumerable<T> list, int id) where T : ResourceDirectoryEntry {
foreach (var dirEntry in list) {
if (dirEntry.HasId && dirEntry.Id == id)
return dirEntry;
}
return null;
}
protected static T find<T>(IEnumerable<T> list, string name) where T : ResourceDirectoryEntry {
foreach (var dirEntry in list) {
if (dirEntry.HasStringName && dirEntry.Name == name)
return dirEntry;
}
return null;
}
}
}

View File

@ -1,93 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public class Resources {
BinaryReader reader;
uint startOffset;
uint totalSize;
ResourceDirectory root;
public BinaryReader Reader {
get { return reader; }
}
public Resources(BinaryReader reader, uint startOffset, uint totalSize) {
this.reader = reader;
this.startOffset = startOffset;
this.totalSize = totalSize;
}
public ResourceDirectory getRoot() {
if (root != null)
return root;
return root = new ResourceDirectory("root", this, startOffset == 0 ? -1 : 0);
}
public bool isSizeAvailable(int offset, int size) {
if (offset < 0 || offset + size < offset)
return false;
return (uint)(offset + size) <= totalSize;
}
public bool isSizeAvailable(int size) {
return isSizeAvailable((int)(reader.BaseStream.Position - startOffset), size);
}
public bool seek(int offset) {
if (!isSizeAvailable(offset, 0))
return false;
reader.BaseStream.Position = startOffset + offset;
return true;
}
public ushort readUInt16() {
return reader.ReadUInt16();
}
public uint readUInt32() {
return reader.ReadUInt32();
}
public byte[] readBytes(int size) {
return reader.ReadBytes(size);
}
public string readString(int offset) {
if (!seek(offset))
return null;
if (!isSizeAvailable(2))
return null;
int size = readUInt16();
int sizeInBytes = size * 2;
if (!isSizeAvailable(sizeInBytes))
return null;
var stringData = readBytes(sizeInBytes);
try {
return Encoding.Unicode.GetString(stringData);
}
catch {
return null;
}
}
}
}

View File

@ -1,76 +0,0 @@
/*
Copyright (C) 2011-2012 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 {
public class SectionHeader : IFileLocation {
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;
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();
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 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

@ -73,22 +73,6 @@
<Compile Include="InstructionListParser.cs" />
<Compile Include="MemberDefDict.cs" />
<Compile Include="MethodBlocks.cs" />
<Compile Include="PE\Cor20Header.cs" />
<Compile Include="PE\DataDirectory.cs" />
<Compile Include="PE\DotNetStream.cs" />
<Compile Include="PE\FileHeader.cs" />
<Compile Include="PE\IFileLocation.cs" />
<Compile Include="PE\Metadata.cs" />
<Compile Include="PE\MetadataTables.cs" />
<Compile Include="PE\MetadataType.cs" />
<Compile Include="PE\MetadataTypeBuilder.cs" />
<Compile Include="PE\OptionalHeader.cs" />
<Compile Include="PE\PeImage.cs" />
<Compile Include="PE\ResourceData.cs" />
<Compile Include="PE\ResourceDirectory.cs" />
<Compile Include="PE\ResourceDirectoryEntry.cs" />
<Compile Include="PE\Resources.cs" />
<Compile Include="PE\SectionHeader.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScopeBlock.cs" />
<Compile Include="TryBlock.cs" />

View File

@ -153,7 +153,7 @@
<Compile Include="deobfuscators\DeobUtils.cs" />
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.cs" />
<Compile Include="deobfuscators\Dotfuscator\StringDecrypter.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\MyPEImage.cs" />
<Compile Include="deobfuscators\MyPEImage.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\v3\AntiStrongName.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeDecrypter.cs" />
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeUnpacker.cs" />

View File

@ -22,7 +22,6 @@ using System.Collections.Generic;
using System.IO;
using dot10.DotNet;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.Agile_NET {
class CliSecureRtType {
@ -192,13 +191,9 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
bool findNativeCode(byte[] moduleBytes) {
var stream = moduleBytes != null ?
(Stream)new MemoryStream(moduleBytes) :
(Stream)new FileStream(module.Location, FileMode.Open, FileAccess.Read, FileShare.Read);
using (stream) {
var peImage = new PeImage(stream);
var bytes = moduleBytes != null ? moduleBytes : DeobUtils.readModule(module);
using (var peImage = new MyPEImage(bytes))
return foundSig = MethodsDecrypter.detect(peImage);
}
}
public bool isAtLeastVersion50() {

View File

@ -23,7 +23,6 @@ using dot10.IO;
using dot10.PE;
using dot10.DotNet;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.Agile_NET {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
@ -209,11 +208,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return false;
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
var peImage = new PeImage(fileData);
if (!new MethodsDecrypter().decrypt(peImage, module, cliSecureRtType, ref dumpedMethods)) {
Logger.v("Methods aren't encrypted or invalid signature");
return false;
using (var peImage = new MyPEImage(fileData)) {
if (!new MethodsDecrypter().decrypt(peImage, module, cliSecureRtType, ref dumpedMethods)) {
Logger.v("Methods aren't encrypted or invalid signature");
return false;
}
}
newFileData = fileData;

View File

@ -20,8 +20,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using dot10.IO;
using dot10.PE;
using dot10.DotNet;
using de4dot.PE;
using dot10.DotNet.MD;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET {
@ -61,7 +63,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
Pro,
}
PeImage peImage;
MyPEImage peImage;
ModuleDefMD module;
CliSecureRtType csRtType;
CodeHeader codeHeader = new CodeHeader();
@ -73,35 +75,36 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
abstract class DecrypterBase : IDecrypter {
protected readonly PeImage peImage;
protected readonly MyPEImage peImage;
protected readonly CodeHeader codeHeader;
protected readonly uint endOfMetadata;
public DecrypterBase(PeImage peImage, CodeHeader codeHeader) {
public DecrypterBase(MyPEImage peImage, CodeHeader codeHeader) {
this.peImage = peImage;
this.codeHeader = codeHeader;
endOfMetadata = peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size);
var mdDir = peImage.Cor20Header.MetaData;
endOfMetadata = peImage.rvaToOffset((uint)mdDir.VirtualAddress + mdDir.Size);
}
public abstract MethodBodyHeader decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections);
protected MethodBodyHeader getCodeBytes(byte[] methodBody, out byte[] code, out byte[] extraSections) {
return MethodBodyParser.parseMethodBody(new BinaryReader(new MemoryStream(methodBody)), out code, out extraSections);
return MethodBodyParser.parseMethodBody(MemoryImageStream.Create(methodBody), out code, out extraSections);
}
}
// CS 1.1 (could be other versions too)
class Decrypter10 {
PeImage peImage;
MyPEImage peImage;
CsBlowfish blowfish;
public Decrypter10(PeImage peImage, byte[] key) {
public Decrypter10(MyPEImage peImage, byte[] key) {
this.peImage = peImage;
this.blowfish = new CsBlowfish(key);
}
public MethodBodyHeader decrypt(uint bodyOffset, out byte[] code, out byte[] extraSections) {
peImage.Reader.BaseStream.Position = bodyOffset;
peImage.Reader.Position = bodyOffset;
var mbHeader = MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
blowfish.decrypt(code);
return mbHeader;
@ -110,31 +113,31 @@ namespace de4dot.code.deobfuscators.Agile_NET {
// CS 3.0 (could be other versions too)
class Decrypter30 : DecrypterBase {
public Decrypter30(PeImage peImage, CodeHeader codeHeader)
public Decrypter30(MyPEImage peImage, CodeHeader codeHeader)
: base(peImage, codeHeader) {
}
public override MethodBodyHeader decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
peImage.Reader.BaseStream.Position = peImage.rvaToOffset(methodInfo.codeOffs);
peImage.Reader.Position = peImage.rvaToOffset(methodInfo.codeOffs);
return MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
}
}
// CS 4.0 (could be other versions too)
class Decrypter40 : DecrypterBase {
public Decrypter40(PeImage peImage, CodeHeader codeHeader)
public Decrypter40(MyPEImage peImage, CodeHeader codeHeader)
: base(peImage, codeHeader) {
}
public override MethodBodyHeader decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
peImage.Reader.BaseStream.Position = endOfMetadata + methodInfo.codeOffs;
peImage.Reader.Position = endOfMetadata + methodInfo.codeOffs;
return MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
}
}
// CS 4.5 (could be other versions too)
class Decrypter45 : DecrypterBase {
public Decrypter45(PeImage peImage, CodeHeader codeHeader)
public Decrypter45(MyPEImage peImage, CodeHeader codeHeader)
: base(peImage, codeHeader) {
}
@ -153,7 +156,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
class Decrypter5 : DecrypterBase {
readonly uint codeHeaderSize;
public Decrypter5(PeImage peImage, CodeHeader codeHeader, uint codeHeaderSize)
public Decrypter5(MyPEImage peImage, CodeHeader codeHeader, uint codeHeaderSize)
: base(peImage, codeHeader) {
this.codeHeaderSize = codeHeaderSize;
}
@ -174,7 +177,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
class ProDecrypter : DecrypterBase {
readonly uint[] key = new uint[4];
public ProDecrypter(PeImage peImage, CodeHeader codeHeader)
public ProDecrypter(MyPEImage peImage, CodeHeader codeHeader)
: base(peImage, codeHeader) {
for (int i = 0; i < 4; i++)
key[i] = be_readUInt32(codeHeader.decryptionKey, i * 4);
@ -222,7 +225,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
interface ICsHeader {
IDecrypter createDecrypter();
List<MethodInfo> getMethodInfos(uint codeHeaderOffset);
void patchMethodDefTable(MetadataType methodDefTable, IList<MethodInfo> methodInfos);
void patchMethodTable(MDTable methodDefTable, IList<MethodInfo> methodInfos);
}
abstract class CsHeaderBase : ICsHeader {
@ -236,7 +239,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
public abstract IDecrypter createDecrypter();
public virtual void patchMethodDefTable(MetadataType methodDefTable, IList<MethodInfo> methodInfos) {
public virtual void patchMethodTable(MDTable methodDefTable, IList<MethodInfo> methodInfos) {
}
public abstract List<MethodInfo> getMethodInfos(uint codeHeaderOffset);
@ -347,10 +350,10 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return getMethodInfos4(codeHeaderOffset);
}
public override void patchMethodDefTable(MetadataType methodDefTable, IList<MethodInfo> methodInfos) {
uint offset = methodDefTable.fileOffset - methodDefTable.totalSize;
public override void patchMethodTable(MDTable methodDefTable, IList<MethodInfo> methodInfos) {
uint offset = (uint)methodDefTable.StartOffset - methodDefTable.RowSize;
foreach (var methodInfo in methodInfos) {
offset += methodDefTable.totalSize;
offset += methodDefTable.RowSize;
if (methodInfo.flags == 0 || methodInfo.codeOffs == 0)
continue;
uint rva = methodsDecrypter.peImage.offsetReadUInt32(offset);
@ -370,7 +373,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
V52, // 5.2+ (or maybe 5.1+)
}
List<CsHeaderVersion> getCsHeaderVersions(uint codeHeaderOffset, MetadataType methodDefTable) {
List<CsHeaderVersion> getCsHeaderVersions(uint codeHeaderOffset, MDTable methodDefTable) {
if (sigType == SigType.Old)
return new List<CsHeaderVersion> { CsHeaderVersion.V10 };
if (!isOldHeader(methodDefTable))
@ -408,10 +411,10 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
}
bool isOldHeader(MetadataType methodDefTable) {
if (methodDefTable.totalSize != codeHeader.methodDefElemSize)
bool isOldHeader(MDTable methodDefTable) {
if (methodDefTable.RowSize != codeHeader.methodDefElemSize)
return true;
if (methodDefTable.fileOffset - peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress) != codeHeader.methodDefTableOffset)
if ((uint)methodDefTable.StartOffset - peImage.rvaToOffset((uint)peImage.Cor20Header.MetaData.VirtualAddress) != codeHeader.methodDefTableOffset)
return true;
return false;
@ -434,7 +437,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
Error,
}
public bool decrypt(PeImage peImage, ModuleDefMD module, CliSecureRtType csRtType, ref DumpedMethods dumpedMethods) {
public bool decrypt(MyPEImage peImage, ModuleDefMD module, CliSecureRtType csRtType, ref DumpedMethods dumpedMethods) {
this.peImage = peImage;
this.csRtType = csRtType;
this.module = module;
@ -469,27 +472,27 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return moduleCctorBytes;
}
static uint getCodeHeaderOffset(PeImage peImage) {
return peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size);
static uint getCodeHeaderOffset(MyPEImage peImage) {
return peImage.rvaToOffset((uint)peImage.Cor20Header.MetaData.VirtualAddress + peImage.Cor20Header.MetaData.Size);
}
static string[] sections = new string[] {
".text", ".rsrc", ".data", ".rdata",
};
static uint getOldCodeHeaderOffset(PeImage peImage) {
static uint getOldCodeHeaderOffset(MyPEImage peImage) {
var sect = getLastOf(peImage, sections);
if (sect == null || sect.virtualSize < 0x100)
if (sect == null || sect.VirtualSize < 0x100)
return 0;
return peImage.rvaToOffset(sect.virtualAddress + sect.virtualSize - 0x100);
return peImage.rvaToOffset((uint)sect.VirtualAddress + sect.VirtualSize - 0x100);
}
static SectionHeader getLastOf(PeImage peImage, string[] sections) {
SectionHeader sect = null;
static ImageSectionHeader getLastOf(MyPEImage peImage, string[] sections) {
ImageSectionHeader sect = null;
foreach (var name in sections) {
var sect2 = peImage.findSection(name);
if (sect2 == null)
continue;
if (sect == null || sect2.virtualAddress > sect.virtualAddress)
if (sect == null || sect2.VirtualAddress > sect.VirtualAddress)
sect = sect2;
}
return sect;
@ -500,8 +503,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (sigType == SigType.Unknown)
return DecryptResult.NotEncrypted;
var metadataTables = peImage.Cor20Header.createMetadataTables();
var methodDefTable = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
var methodDefTable = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
foreach (var version in getCsHeaderVersions(codeHeaderOffset, methodDefTable)) {
try {
@ -534,66 +536,44 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return codeHeaderOffset;
}
void decryptMethodsOld(MetadataType methodDefTable, ref DumpedMethods dumpedMethods) {
void decryptMethodsOld(MDTable methodDefTable, ref DumpedMethods dumpedMethods) {
dumpedMethods = new DumpedMethods();
uint offset = methodDefTable.fileOffset;
var decrypter = new Decrypter10(peImage, codeHeader.decryptionKey);
for (int i = 0; i < methodDefTable.rows; i++, offset += methodDefTable.totalSize) {
for (uint rid = 1; rid <= methodDefTable.Rows; rid++) {
var dm = new DumpedMethod();
dm.token = 0x06000001 + (uint)i;
var method = (MethodDef)module.ResolveMethod(MDToken.ToRID(dm.token));
if (method == null || method.DeclaringType == DotNetUtils.getModuleType(module))
var method = (MethodDef)module.ResolveMethod(rid);
if (method == null || method.DeclaringType == module.GlobalType)
continue;
uint rva = peImage.offsetReadUInt32(offset + (uint)methodDefTable.fields[0].offset);
if (rva == 0)
peImage.readMethodTableRowTo(dm, rid);
if (dm.mdRVA == 0)
continue;
uint bodyOffset = peImage.rvaToOffset(rva);
dm.mdRVA = peImage.offsetRead(offset + (uint)methodDefTable.fields[0].offset, methodDefTable.fields[0].size);
dm.mdImplFlags = peImage.offsetReadUInt16(offset + (uint)methodDefTable.fields[1].offset);
dm.mdFlags = peImage.offsetReadUInt16(offset + (uint)methodDefTable.fields[2].offset);
dm.mdName = peImage.offsetRead(offset + (uint)methodDefTable.fields[3].offset, methodDefTable.fields[3].size);
dm.mdSignature = peImage.offsetRead(offset + (uint)methodDefTable.fields[4].offset, methodDefTable.fields[4].size);
dm.mdParamList = peImage.offsetRead(offset + (uint)methodDefTable.fields[5].offset, methodDefTable.fields[5].size);
uint bodyOffset = peImage.rvaToOffset(dm.mdRVA);
var mbHeader = decrypter.decrypt(bodyOffset, out dm.code, out dm.extraSections);
dm.mhFlags = mbHeader.flags;
dm.mhMaxStack = mbHeader.maxStack;
dm.mhCodeSize = (uint)dm.code.Length;
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
peImage.updateMethodHeaderInfo(dm, mbHeader);
dumpedMethods.add(dm);
}
}
void decryptMethods(uint codeHeaderOffset, MetadataType methodDefTable, ICsHeader csHeader, ref DumpedMethods dumpedMethods) {
void decryptMethods(uint codeHeaderOffset, MDTable methodDefTable, ICsHeader csHeader, ref DumpedMethods dumpedMethods) {
var methodInfos = csHeader.getMethodInfos(codeHeaderOffset);
csHeader.patchMethodDefTable(methodDefTable, methodInfos);
csHeader.patchMethodTable(methodDefTable, methodInfos);
dumpedMethods = new DumpedMethods();
uint offset = methodDefTable.fileOffset;
decrypter = csHeader.createDecrypter();
for (int i = 0; i < methodInfos.Count; i++, offset += methodDefTable.totalSize) {
var methodInfo = methodInfos[i];
for (uint rid = 1; rid <= (uint)methodInfos.Count; rid++) {
var methodInfo = methodInfos[(int)rid - 1];
if (methodInfo.codeOffs == 0)
continue;
var dm = new DumpedMethod();
dm.token = 0x06000001 + (uint)i;
dm.mdRVA = peImage.offsetRead(offset + (uint)methodDefTable.fields[0].offset, methodDefTable.fields[0].size);
dm.mdImplFlags = peImage.offsetReadUInt16(offset + (uint)methodDefTable.fields[1].offset);
dm.mdFlags = peImage.offsetReadUInt16(offset + (uint)methodDefTable.fields[2].offset);
dm.mdName = peImage.offsetRead(offset + (uint)methodDefTable.fields[3].offset, methodDefTable.fields[3].size);
dm.mdSignature = peImage.offsetRead(offset + (uint)methodDefTable.fields[4].offset, methodDefTable.fields[4].size);
dm.mdParamList = peImage.offsetRead(offset + (uint)methodDefTable.fields[5].offset, methodDefTable.fields[5].size);
peImage.readMethodTableRowTo(dm, rid);
var mbHeader = decrypter.decrypt(methodInfo, out dm.code, out dm.extraSections);
dm.mhFlags = mbHeader.flags;
dm.mhMaxStack = mbHeader.maxStack;
dm.mhCodeSize = (uint)dm.code.Length;
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
peImage.updateMethodHeaderInfo(dm, mbHeader);
dumpedMethods.add(dm);
}
@ -622,7 +602,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return getSigType(signature) != SigType.Unknown;
}
public static bool detect(PeImage peImage) {
public static bool detect(MyPEImage peImage) {
try {
uint codeHeaderOffset = getCodeHeaderOffset(peImage);
if (isValidSignature(peImage.offsetReadBytes(codeHeaderOffset, 16)))

View File

@ -21,7 +21,6 @@ using System;
using System.Collections.Generic;
using dot10.DotNet;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.CodeFort {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {

View File

@ -19,11 +19,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using dot10.IO;
using dot10.DotNet;
using dot10.DotNet.Emit;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.CodeVeil {
class MethodsDecrypter {
@ -32,23 +31,22 @@ namespace de4dot.code.deobfuscators.CodeVeil {
interface IDecrypter {
void initialize(byte[] methodsData);
bool decrypt(BinaryReader fileDataReader, DumpedMethod dm);
bool decrypt(IBinaryReader fileDataReader, DumpedMethod dm);
}
class Decrypter : IDecrypter {
BinaryReader methodsDataReader;
IBinaryReader methodsDataReader;
public virtual void initialize(byte[] methodsData) {
methodsDataReader = new BinaryReader(new MemoryStream(methodsData));
methodsDataReader = MemoryImageStream.Create(methodsData);
}
public virtual bool decrypt(BinaryReader fileDataReader, DumpedMethod dm) {
public virtual bool decrypt(IBinaryReader fileDataReader, DumpedMethod dm) {
if (fileDataReader.ReadByte() != 0x2A)
return false; // Not a RET
int methodsDataOffset = DeobUtils.readVariableLengthInt32(fileDataReader);
methodsDataReader.BaseStream.Position = methodsDataOffset;
methodsDataReader.Position = fileDataReader.ReadCompressedUInt32();
dm.mhCodeSize = (uint)DeobUtils.readVariableLengthInt32(methodsDataReader);
dm.mhCodeSize = methodsDataReader.ReadCompressedUInt32();
dm.code = methodsDataReader.ReadBytes((int)dm.mhCodeSize);
if ((dm.mhFlags & 8) != 0)
dm.extraSections = MethodBodyParser.readExtraSections(methodsDataReader);
@ -126,46 +124,38 @@ namespace de4dot.code.deobfuscators.CodeVeil {
if (decrypter == null)
return false;
var peImage = new PeImage(fileData);
if (peImage.Sections.Length <= 0)
return false;
using (var peImage = new MyPEImage(fileData)) {
if (peImage.Sections.Count <= 0)
return false;
var methodsData = findMethodsData(peImage, fileData);
if (methodsData == null)
return false;
var methodsData = findMethodsData(peImage, fileData);
if (methodsData == null)
return false;
decrypter.initialize(methodsData);
decrypter.initialize(methodsData);
dumpedMethods = createDumpedMethods(peImage, fileData, methodsData);
if (dumpedMethods == null)
return false;
dumpedMethods = createDumpedMethods(peImage, fileData, methodsData);
if (dumpedMethods == null)
return false;
}
return true;
}
DumpedMethods createDumpedMethods(PeImage peImage, byte[] fileData, byte[] methodsData) {
DumpedMethods createDumpedMethods(MyPEImage peImage, byte[] fileData, byte[] methodsData) {
var dumpedMethods = new DumpedMethods();
var methodsDataReader = new BinaryReader(new MemoryStream(methodsData));
var fileDataReader = new BinaryReader(new MemoryStream(fileData));
var metadataTables = peImage.Cor20Header.createMetadataTables();
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
uint methodDefOffset = methodDef.fileOffset;
for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) {
uint bodyRva = peImage.offsetReadUInt32(methodDefOffset);
if (bodyRva == 0)
continue;
uint bodyOffset = peImage.rvaToOffset(bodyRva);
var methodsDataReader = MemoryImageStream.Create(methodsData);
var fileDataReader = MemoryImageStream.Create(fileData);
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
for (uint rid = 1; rid <= methodDef.Rows; rid++) {
var dm = new DumpedMethod();
dm.token = (uint)(0x06000001 + i);
dm.mdRVA = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[0].offset, methodDef.fields[0].size);
dm.mdImplFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[1].offset);
dm.mdFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[2].offset);
dm.mdName = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size);
dm.mdSignature = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size);
dm.mdParamList = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size);
peImage.readMethodTableRowTo(dm, rid);
if (dm.mdRVA == 0)
continue;
uint bodyOffset = peImage.rvaToOffset(dm.mdRVA);
byte b = peImage.offsetReadByte(bodyOffset);
uint codeOffset;
@ -187,7 +177,7 @@ namespace de4dot.code.deobfuscators.CodeVeil {
dm.mhLocalVarSigTok = peImage.offsetReadUInt32(bodyOffset + 8);
codeOffset = bodyOffset + (uint)(dm.mhFlags >> 12) * 4;
}
fileDataReader.BaseStream.Position = codeOffset;
fileDataReader.Position = codeOffset;
if (!decrypter.decrypt(fileDataReader, dm))
continue;
@ -202,14 +192,14 @@ namespace de4dot.code.deobfuscators.CodeVeil {
static byte[] initializeMethodEnd = new byte[] {
0x33, 0xC0, 0x40, 0x5E, 0x5F, 0x5A, 0x59, 0x5B, 0xC9, 0xC2,
};
byte[] findMethodsData(PeImage peImage, byte[] fileData) {
byte[] findMethodsData(MyPEImage peImage, byte[] fileData) {
var section = peImage.Sections[0];
var reader = new BinaryReader(new MemoryStream(fileData));
var reader = MemoryImageStream.Create(fileData);
const int RVA_EXECUTIVE_OFFSET = 1 * 4;
const int ENC_CODE_OFFSET = 6 * 4;
int lastOffset = (int)(section.pointerToRawData + section.sizeOfRawData);
int lastOffset = (int)(section.PointerToRawData + section.SizeOfRawData);
for (int offset = getStartOffset(peImage); offset < lastOffset; ) {
offset = findSig(fileData, offset, lastOffset, initializeMethodEnd);
if (offset < 0)
@ -229,13 +219,13 @@ namespace de4dot.code.deobfuscators.CodeVeil {
continue;
int relOffs = BitConverter.ToInt32(fileData, offset + ENC_CODE_OFFSET);
if (relOffs <= 0 || relOffs >= section.sizeOfRawData)
if (relOffs <= 0 || relOffs >= section.SizeOfRawData)
continue;
reader.BaseStream.Position = section.pointerToRawData + relOffs;
reader.Position = section.PointerToRawData + relOffs;
int size = DeobUtils.readVariableLengthInt32(reader);
int size = (int)reader.ReadCompressedUInt32();
int endOffset = relOffs + size;
if (endOffset < relOffs || endOffset > section.sizeOfRawData)
if (endOffset < relOffs || endOffset > section.SizeOfRawData)
continue;
return reader.ReadBytes(size);
@ -244,7 +234,7 @@ namespace de4dot.code.deobfuscators.CodeVeil {
return null;
}
int getStartOffset(PeImage peImage) {
int getStartOffset(MyPEImage peImage) {
int minOffset = int.MaxValue;
foreach (var rva in mainType.Rvas) {
int rvaOffs = (int)peImage.rvaToOffset((uint)rva);

View File

@ -21,7 +21,6 @@ using System;
using System.Collections.Generic;
using dot10.DotNet;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.CodeWall {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
@ -164,10 +163,10 @@ namespace de4dot.code.deobfuscators.CodeWall {
return false;
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
var peImage = new PeImage(fileData);
if (!methodsDecrypter.decrypt(peImage, ref dumpedMethods))
return false;
using (var peImage = new MyPEImage(fileData)) {
if (!methodsDecrypter.decrypt(peImage, ref dumpedMethods))
return false;
}
newFileData = fileData;
return true;

View File

@ -20,7 +20,6 @@
using System;
using dot10.DotNet;
using dot10.DotNet.Emit;
using de4dot.PE;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeWall {
@ -67,50 +66,33 @@ namespace de4dot.code.deobfuscators.CodeWall {
return false;
}
public bool decrypt(PeImage peImage, ref DumpedMethods dumpedMethods) {
public bool decrypt(MyPEImage peImage, ref DumpedMethods dumpedMethods) {
dumpedMethods = new DumpedMethods();
bool decrypted = false;
var metadataTables = peImage.Cor20Header.createMetadataTables();
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
uint methodDefOffset = methodDef.fileOffset;
for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) {
uint bodyRva = peImage.offsetReadUInt32(methodDefOffset);
if (bodyRva == 0)
continue;
uint bodyOffset = peImage.rvaToOffset(bodyRva);
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
for (uint rid = 1; rid <= methodDef.Rows; rid++) {
var dm = new DumpedMethod();
dm.token = (uint)(0x06000001 + i);
peImage.readMethodTableRowTo(dm, rid);
byte[] code, extraSections;
peImage.Reader.BaseStream.Position = bodyOffset;
var mbHeader = MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
if (code.Length < 6 || code[0] != 0x2A || code[1] != 0x2A)
if (dm.mdRVA == 0)
continue;
dm.code = code;
dm.extraSections = extraSections;
uint bodyOffset = peImage.rvaToOffset(dm.mdRVA);
int seed = BitConverter.ToInt32(code, 2);
Array.Copy(newCodeHeader, code, newCodeHeader.Length);
peImage.Reader.Position = bodyOffset;
var mbHeader = MethodBodyParser.parseMethodBody(peImage.Reader, out dm.code, out dm.extraSections);
peImage.updateMethodHeaderInfo(dm, mbHeader);
if (dm.code.Length < 6 || dm.code[0] != 0x2A || dm.code[1] != 0x2A)
continue;
int seed = BitConverter.ToInt32(dm.code, 2);
Array.Copy(newCodeHeader, dm.code, newCodeHeader.Length);
if (seed == 0)
decrypt(code);
decrypt(dm.code);
else
decrypt(code, seed);
dm.mdRVA = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[0].offset, methodDef.fields[0].size);
dm.mdImplFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[1].offset);
dm.mdFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[2].offset);
dm.mdName = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size);
dm.mdSignature = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size);
dm.mdParamList = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size);
dm.mhFlags = mbHeader.flags;
dm.mhMaxStack = mbHeader.maxStack;
dm.mhCodeSize = (uint)dm.code.Length;
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
decrypt(dm.code, seed);
dumpedMethods.add(dm);
decrypted = true;

View File

@ -21,8 +21,8 @@ using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using dot10.PE;
using dot10.DotNet;
using de4dot.PE;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.MPRESS {
@ -159,7 +159,7 @@ namespace de4dot.code.deobfuscators.MPRESS {
if (checkMethods(type, methods_v1x)) {
var lfMethod = DotNetUtils.getMethod(type, "System.Boolean", "(System.String,System.Byte[]&)");
if (lfMethod != null) {
if (DeobUtils.hasInteger(lfMethod, (int)Machine.amd64))
if (DeobUtils.hasInteger(lfMethod, (int)Machine.AMD64))
return Version.V218;
return Version.V1x_217;
}
@ -194,37 +194,39 @@ namespace de4dot.code.deobfuscators.MPRESS {
return false;
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
var peImage = new PeImage(fileData);
var section = peImage.Sections[peImage.Sections.Length - 1];
var offset = section.pointerToRawData;
offset += 16;
byte[] decompressed;
using (var peImage = new MyPEImage(fileData)) {
var section = peImage.Sections[peImage.Sections.Count - 1];
var offset = section.PointerToRawData;
offset += 16;
byte[] decompressed, compressed;
int compressedLen;
switch (version) {
case Version.V0x:
compressedLen = fileData.Length - (int)offset;
compressed = peImage.offsetReadBytes(offset, compressedLen);
decompressed = Lzmat.decompress_old(compressed);
if (decompressed == null)
throw new ApplicationException("LZMAT decompression failed");
break;
byte[] compressed;
int compressedLen;
switch (version) {
case Version.V0x:
compressedLen = fileData.Length - (int)offset;
compressed = peImage.offsetReadBytes(offset, compressedLen);
decompressed = Lzmat.decompress_old(compressed);
if (decompressed == null)
throw new ApplicationException("LZMAT decompression failed");
break;
case Version.V1x_217:
case Version.V218:
if (peImage.FileHeader.machine == Machine.amd64 && version == Version.V218)
offset = section.pointerToRawData + section.virtualSize;
int decompressedLen = (int)peImage.offsetReadUInt32(offset);
compressedLen = fileData.Length - (int)offset - 4;
compressed = peImage.offsetReadBytes(offset + 4, compressedLen);
decompressed = new byte[decompressedLen];
uint decompressedLen2;
if (Lzmat.decompress(decompressed, out decompressedLen2, compressed) != LzmatStatus.OK)
throw new ApplicationException("LZMAT decompression failed");
break;
case Version.V1x_217:
case Version.V218:
if (peImage.PEImage.ImageNTHeaders.FileHeader.Machine == Machine.AMD64 && version == Version.V218)
offset = section.PointerToRawData + section.VirtualSize;
int decompressedLen = (int)peImage.offsetReadUInt32(offset);
compressedLen = fileData.Length - (int)offset - 4;
compressed = peImage.offsetReadBytes(offset + 4, compressedLen);
decompressed = new byte[decompressedLen];
uint decompressedLen2;
if (Lzmat.decompress(decompressed, out decompressedLen2, compressed) != LzmatStatus.OK)
throw new ApplicationException("LZMAT decompression failed");
break;
default:
throw new ApplicationException("Unknown MPRESS version");
default:
throw new ApplicationException("Unknown MPRESS version");
}
}
newFileData = decompressed;

View File

@ -17,22 +17,27 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using de4dot.PE;
using System;
namespace de4dot.code.deobfuscators.MaxtoCode {
class DecrypterInfo {
class DecrypterInfo : IDisposable {
public MainType mainType;
public readonly PeImage peImage;
public readonly MyPEImage peImage;
public readonly PeHeader peHeader;
public readonly McKey mcKey;
public readonly byte[] fileData;
public DecrypterInfo(MainType mainType, byte[] fileData) {
this.mainType = mainType;
this.peImage = new PeImage(fileData);
this.peImage = new MyPEImage(fileData);
this.peHeader = new PeHeader(mainType, peImage);
this.mcKey = new McKey(peImage, peHeader);
this.fileData = fileData;
}
public void Dispose() {
if (peImage != null)
peImage.Dispose();
}
}
}

View File

@ -120,10 +120,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
newOne.setModule(module);
newOne.mainType = new MainType(module, mainType);
newOne.decrypterInfo = decrypterInfo;
newOne.decrypterInfo.mainType = newOne.mainType;
decrypterInfo = null;
if (newOne.decrypterInfo != null)
newOne.decrypterInfo.mainType = newOne.mainType;
return newOne;
}
void freePEImage() {
if (decrypterInfo != null)
decrypterInfo.Dispose();
decrypterInfo = null;
}
public override void deobfuscateBegin() {
base.deobfuscateBegin();
@ -134,6 +142,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.decrypt((uint)args[0]));
DeobfuscatedFile.stringDecryptersAdded();
}
else
freePEImage();
foreach (var method in mainType.InitMethods)
addCctorInitCallToBeRemoved(method);
@ -142,6 +152,11 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
removeInvalidResources();
}
public override void deobfuscateEnd() {
freePEImage();
base.deobfuscateEnd();
}
static Encoding getEncoding(int cp) {
try {
return Encoding.GetEncoding(cp);

View File

@ -19,7 +19,6 @@
using System;
using System.IO;
using de4dot.PE;
namespace de4dot.code.deobfuscators.MaxtoCode {
class McKey {
@ -30,7 +29,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
get { return data[index]; }
}
public McKey(PeImage peImage, PeHeader peHeader) {
public McKey(MyPEImage peImage, PeHeader peHeader) {
this.peHeader = peHeader;
try {
this.data = peImage.readBytes(peHeader.getMcKeyRva(), 0x2000);

View File

@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using de4dot.PE;
using dot10.IO;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.MaxtoCode {
@ -31,7 +31,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
class MethodInfos {
MainType mainType;
PeImage peImage;
MyPEImage peImage;
PeHeader peHeader;
McKey mcKey;
uint structSize;
@ -61,7 +61,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
}
}
public MethodInfos(MainType mainType, PeImage peImage, PeHeader peHeader, McKey mcKey) {
public MethodInfos(MainType mainType, MyPEImage peImage, PeHeader peHeader, McKey mcKey) {
this.mainType = mainType;
this.peImage = peImage;
this.peHeader = peHeader;
@ -463,55 +463,21 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
var methodInfos = new MethodInfos(decrypterInfo.mainType, peImage, decrypterInfo.peHeader, decrypterInfo.mcKey);
methodInfos.initializeInfos();
var metadataTables = peImage.Cor20Header.createMetadataTables();
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
uint methodDefOffset = methodDef.fileOffset;
for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) {
uint bodyRva = peImage.offsetReadUInt32(methodDefOffset);
if (bodyRva == 0)
continue;
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
for (uint rid = 1; rid <= methodDef.Rows; rid++) {
var dm = new DumpedMethod();
peImage.readMethodTableRowTo(dm, rid);
var info = methodInfos.lookup(bodyRva);
var info = methodInfos.lookup(dm.mdRVA);
if (info == null)
continue;
uint bodyOffset = peImage.rvaToOffset(bodyRva);
ushort magic = peImage.offsetReadUInt16(bodyOffset);
ushort magic = peImage.readUInt16(dm.mdRVA);
if (magic != 0xFFF3)
continue;
var dm = new DumpedMethod();
dm.token = (uint)(0x06000001 + i);
dm.mdRVA = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[0].offset, methodDef.fields[0].size);
dm.mdImplFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[1].offset);
dm.mdFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[2].offset);
dm.mdName = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size);
dm.mdSignature = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size);
dm.mdParamList = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size);
var reader = new BinaryReader(new MemoryStream(info.body));
byte b = reader.ReadByte();
if ((b & 3) == 2) {
dm.mhFlags = 2;
dm.mhMaxStack = 8;
dm.mhCodeSize = (uint)(b >> 2);
dm.mhLocalVarSigTok = 0;
}
else {
reader.BaseStream.Position--;
dm.mhFlags = reader.ReadUInt16();
dm.mhMaxStack = reader.ReadUInt16();
dm.mhCodeSize = reader.ReadUInt32();
dm.mhLocalVarSigTok = reader.ReadUInt32();
uint codeOffset = (uint)(dm.mhFlags >> 12) * 4;
reader.BaseStream.Position += codeOffset - 12;
}
dm.code = reader.ReadBytes((int)dm.mhCodeSize);
if ((dm.mhFlags & 8) != 0) {
reader.BaseStream.Position = (reader.BaseStream.Position + 3) & ~3;
dm.extraSections = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
}
var mbHeader = MethodBodyParser.parseMethodBody(MemoryImageStream.Create(info.body), out dm.code, out dm.extraSections);
peImage.updateMethodHeaderInfo(dm, mbHeader);
dumpedMethods.add(dm);
}
@ -529,8 +495,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
uint resourceSize = peHeader.readUInt32(0x0E14) ^ mcKey.readUInt32(0x00AA);
if (resourceRva == 0 || resourceSize == 0)
return;
if (resourceRva != peImage.Cor20Header.resources.virtualAddress ||
resourceSize != peImage.Cor20Header.resources.size) {
if (resourceRva != (uint)peImage.Cor20Header.Resources.VirtualAddress ||
resourceSize != peImage.Cor20Header.Resources.Size) {
Logger.w("Invalid resource RVA and size found");
}
@ -551,10 +517,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
uint usHeapSize = peHeader.readUInt32(0x0E04) ^ mcKey.readUInt32(0x0082);
if (usHeapRva == 0 || usHeapSize == 0)
return;
var usHeap = peImage.Cor20Header.metadata.getStream("#US");
if (usHeap == null ||
peImage.rvaToOffset(usHeapRva) != usHeap.fileOffset ||
usHeapSize != usHeap.Length) {
var usHeap = peImage.DotNetFile.MetaData.USStream;
if (usHeap.StartOffset == 0 || // Start offset is 0 if it's not present in the file
peImage.rvaToOffset(usHeapRva) != (uint)usHeap.StartOffset ||
usHeapSize != (uint)(usHeap.EndOffset - usHeap.StartOffset)) {
Logger.w("Invalid #US heap RVA and size found");
}

View File

@ -18,7 +18,6 @@
*/
using System;
using de4dot.PE;
namespace de4dot.code.deobfuscators.MaxtoCode {
enum EncryptionVersion {
@ -40,7 +39,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
get { return version; }
}
public PeHeader(MainType mainType, PeImage peImage) {
public PeHeader(MainType mainType, MyPEImage peImage) {
uint headerOffset;
version = getHeaderOffsetAndVersion(peImage, out headerOffset);
headerData = peImage.offsetReadBytes(headerOffset, 0x1000);
@ -58,7 +57,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return BitConverter.ToUInt32(headerData, offset);
}
static EncryptionVersion getHeaderOffsetAndVersion(PeImage peImage, out uint headerOffset) {
static EncryptionVersion getHeaderOffsetAndVersion(MyPEImage peImage, out uint headerOffset) {
headerOffset = 0;
var version = getVersion(peImage, headerOffset);
@ -69,8 +68,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
if (section == null)
return EncryptionVersion.Unknown;
headerOffset = section.pointerToRawData;
uint end = section.pointerToRawData + section.sizeOfRawData - 0x1000 + 1;
headerOffset = section.PointerToRawData;
uint end = section.PointerToRawData + section.SizeOfRawData - 0x1000 + 1;
while (headerOffset < end) {
version = getVersion(peImage, headerOffset);
if (version != EncryptionVersion.Unknown)
@ -81,7 +80,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return EncryptionVersion.Unknown;
}
static EncryptionVersion getVersion(PeImage peImage, uint headerOffset) {
static EncryptionVersion getVersion(MyPEImage peImage, uint headerOffset) {
uint m1lo = peImage.offsetReadUInt32(headerOffset + 0x900);
uint m1hi = peImage.offsetReadUInt32(headerOffset + 0x904);

View File

@ -19,6 +19,7 @@
using System;
using System.IO;
using dot10.IO;
namespace de4dot.code.deobfuscators {
[Serializable]
@ -39,7 +40,7 @@ namespace de4dot.code.deobfuscators {
}
static class MethodBodyParser {
public static MethodBodyHeader parseMethodBody(BinaryReader reader, out byte[] code, out byte[] extraSections) {
public static MethodBodyHeader parseMethodBody(IBinaryReader reader, out byte[] code, out byte[] extraSections) {
try {
return parseMethodBody2(reader, out code, out extraSections);
}
@ -49,14 +50,10 @@ namespace de4dot.code.deobfuscators {
}
public static bool verify(byte[] data) {
return verify(new BinaryReader(new MemoryStream(data)));
return verify(MemoryImageStream.Create(data));
}
public static bool verify(Stream data) {
return verify(new BinaryReader(data));
}
public static bool verify(BinaryReader reader) {
public static bool verify(IBinaryReader reader) {
try {
byte[] code, extraSections;
parseMethodBody(reader, out code, out extraSections);
@ -67,7 +64,7 @@ namespace de4dot.code.deobfuscators {
}
}
static MethodBodyHeader parseMethodBody2(BinaryReader reader, out byte[] code, out byte[] extraSections) {
static MethodBodyHeader parseMethodBody2(IBinaryReader reader, out byte[] code, out byte[] extraSections) {
var mbHeader = new MethodBodyHeader();
uint codeOffset;
@ -95,7 +92,7 @@ namespace de4dot.code.deobfuscators {
else
throw new InvalidMethodBody();
if (mbHeader.codeSize + codeOffset > reader.BaseStream.Length)
if (mbHeader.codeSize + codeOffset > reader.Length)
throw new InvalidMethodBody();
code = reader.ReadBytes((int)mbHeader.codeSize);
@ -107,11 +104,11 @@ namespace de4dot.code.deobfuscators {
return mbHeader;
}
static void align(BinaryReader reader, int alignment) {
reader.BaseStream.Position = (reader.BaseStream.Position + alignment - 1) & ~(alignment - 1);
static void align(IBinaryReader reader, int alignment) {
reader.Position = (reader.Position + alignment - 1) & ~(alignment - 1);
}
public static byte[] readExtraSections(BinaryReader reader) {
public static byte[] readExtraSections(IBinaryReader reader) {
try {
return readExtraSections2(reader);
}
@ -120,16 +117,16 @@ namespace de4dot.code.deobfuscators {
}
}
static byte[] readExtraSections2(BinaryReader reader) {
static byte[] readExtraSections2(IBinaryReader reader) {
align(reader, 4);
int startPos = (int)reader.BaseStream.Position;
int startPos = (int)reader.Position;
parseSection(reader);
int size = (int)reader.BaseStream.Position - startPos;
reader.BaseStream.Position = startPos;
int size = (int)reader.Position - startPos;
reader.Position = startPos;
return reader.ReadBytes(size);
}
static void parseSection(BinaryReader reader) {
static void parseSection(IBinaryReader reader) {
byte flags;
do {
align(reader, 4);
@ -141,20 +138,20 @@ namespace de4dot.code.deobfuscators {
throw new InvalidMethodBody("Invalid bits set");
if ((flags & 0x40) != 0) {
reader.BaseStream.Position--;
reader.Position--;
int num = (int)(reader.ReadUInt32() >> 8) / 24;
reader.BaseStream.Position += num * 24;
reader.Position += num * 24;
}
else {
int num = reader.ReadByte() / 12;
reader.BaseStream.Position += 2 + num * 12;
reader.Position += 2 + num * 12;
}
} while ((flags & 0x80) != 0);
}
static byte peek(BinaryReader reader) {
static byte peek(IBinaryReader reader) {
byte b = reader.ReadByte();
reader.BaseStream.Position--;
reader.Position--;
return b;
}
}

View File

@ -1,21 +1,51 @@
using System;
using System.Collections.Generic;
using dot10.IO;
using dot10.PE;
using dot10.DotNet.MD;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.dotNET_Reactor {
namespace de4dot.code.deobfuscators {
sealed class MyPEImage : IDisposable {
IPEImage peImage;
byte[] peImageData;
IImageStream peStream;
DotNetFile dnFile;
bool dnFileInitialized;
ImageSectionHeader dotNetSection;
bool ownPeImage;
public DotNetFile DotNetFile {
get {
if (dnFileInitialized)
return dnFile;
dnFileInitialized = true;
var dotNetDir = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[14];
if (dotNetDir.VirtualAddress != 0 && dotNetDir.Size >= 0x48) {
dnFile = DotNetFile.Load(peImage, false);
dotNetSection = findSection(dotNetDir.VirtualAddress);
}
return dnFile;
}
}
public ImageCor20Header Cor20Header {
get { return DotNetFile.MetaData.ImageCor20Header; }
}
public IBinaryReader Reader {
get { return peStream; }
}
public IPEImage PEImage {
get { return peImage; }
}
public IList<ImageSectionHeader> Sections {
get { return peImage.ImageSectionHeaders; }
}
public uint Length {
get { return (uint)peStream.Length; }
}
@ -33,13 +63,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor {
void initialize(IPEImage peImage) {
this.peImage = peImage;
this.peStream = peImage.CreateFullStream();
//TODO: Only init this if they use the .NET MD
var dotNetDir = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[14];
if (dotNetDir.VirtualAddress != 0 && dotNetDir.Size >= 0x48) {
dnFile = DotNetFile.Load(peImage, false);
dotNetSection = findSection(dotNetDir.VirtualAddress);
}
}
ImageSectionHeader findSection(RVA rva) {
@ -50,10 +73,66 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor {
return null;
}
public ImageSectionHeader findSection(string name) {
foreach (var section in peImage.ImageSectionHeaders) {
if (section.DisplayName == name)
return section;
}
return null;
}
public void readMethodTableRowTo(DumpedMethod dm, uint rid) {
dm.token = 0x06000000 + rid;
var row = DotNetFile.MetaData.TablesStream.ReadMethodRow(rid);
if (row == null)
throw new ArgumentException("Invalid Method rid");
dm.mdRVA = row.RVA;
dm.mdImplFlags = row.ImplFlags;
dm.mdFlags = row.Flags;
dm.mdName = row.Name;
dm.mdSignature = row.Signature;
dm.mdParamList = row.ParamList;
}
public void updateMethodHeaderInfo(DumpedMethod dm, MethodBodyHeader mbHeader) {
dm.mhFlags = mbHeader.flags;
dm.mhMaxStack = mbHeader.maxStack;
dm.mhCodeSize = dm.code == null ? 0 : (uint)dm.code.Length;
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
}
public uint rvaToOffset(uint rva) {
return (uint)peImage.ToFileOffset((RVA)rva);
}
static bool isInside(ImageSectionHeader section, uint offset, uint length) {
return offset >= section.PointerToRawData && offset + length <= section.PointerToRawData + section.SizeOfRawData;
}
public void writeUInt32(uint rva, uint data) {
offsetWriteUInt32(rvaToOffset(rva), data);
}
public void writeUInt16(uint rva, ushort data) {
offsetWriteUInt16(rvaToOffset(rva), data);
}
public byte readByte(uint rva) {
return offsetReadByte(rvaToOffset(rva));
}
public int readInt32(uint rva) {
return (int)offsetReadUInt32(rvaToOffset(rva));
}
public ushort readUInt16(uint rva) {
return offsetReadUInt16(rvaToOffset(rva));
}
public byte[] readBytes(uint rva, int size) {
return offsetReadBytes(rvaToOffset(rva), size);
}
public void offsetWriteUInt32(uint offset, uint val) {
peImageData[offset + 0] = (byte)val;
peImageData[offset + 1] = (byte)(val >> 8);
@ -99,14 +178,14 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor {
}
public bool dotNetSafeWriteOffset(uint offset, byte[] data) {
if (dnFile != null) {
if (DotNetFile != null) {
uint length = (uint)data.Length;
if (!isInside(dotNetSection, offset, length))
return false;
if (intersect(offset, length, dnFile.MetaData.ImageCor20Header))
if (intersect(offset, length, DotNetFile.MetaData.ImageCor20Header))
return false;
if (intersect(offset, length, dnFile.MetaData.MetaDataHeader))
if (intersect(offset, length, DotNetFile.MetaData.MetaDataHeader))
return false;
}

View File

@ -22,7 +22,6 @@ using System.Collections.Generic;
using System.Text;
using dot10.DotNet;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
// Find the type that decrypts strings and calls the native lib

View File

@ -23,7 +23,6 @@ using System.IO;
using dot10.DotNet;
using de4dot.blocks;
using de4dot.blocks.cflow;
using de4dot.PE;
namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
class MemoryPatcher {

View File

@ -26,7 +26,6 @@ using dot10.DotNet;
using dot10.DotNet.Emit;
using dot10.DotNet.Writer;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
@ -42,7 +41,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
BoolOption decryptResources;
BoolOption removeNamespaces;
BoolOption removeAntiStrongName;
NoArgOption dumpNativeMethods;
public DeobfuscatorInfo()
: base(DEFAULT_REGEX) {
@ -55,7 +53,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
decryptResources = new BoolOption(null, makeArgName("rsrc"), "Decrypt resources", true);
removeNamespaces = new BoolOption(null, makeArgName("ns1"), "Clear namespace if there's only one class in it", true);
removeAntiStrongName = new BoolOption(null, makeArgName("sn"), "Remove anti strong name code", true);
dumpNativeMethods = new NoArgOption(null, makeArgName("dump-native"), "Dump native methods to filename.dll.native");
}
public override string Name {
@ -78,7 +75,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
DecryptResources = decryptResources.get(),
RemoveNamespaces = removeNamespaces.get(),
RemoveAntiStrongName = removeAntiStrongName.get(),
DumpNativeMethods = dumpNativeMethods.get(),
});
}
@ -93,7 +89,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
decryptResources,
removeNamespaces,
removeAntiStrongName,
dumpNativeMethods,
};
}
}
@ -102,7 +97,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
Options options;
string obfuscatorName = DeobfuscatorInfo.THE_NAME;
PeImage peImage;
MyPEImage peImage;
byte[] fileData;
MethodsDecrypter methodsDecrypter;
StringDecrypter stringDecrypter;
@ -129,7 +124,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
public bool DecryptResources { get; set; }
public bool RemoveNamespaces { get; set; }
public bool RemoveAntiStrongName { get; set; }
public bool DumpNativeMethods { get; set; }
}
public override string Type {
@ -376,7 +370,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (count != 0)
return false;
fileData = ModuleBytes ?? DeobUtils.readModule(module);
peImage = new PeImage(fileData);
peImage = new MyPEImage(fileData);
if (!options.DecryptMethods)
return false;
@ -385,30 +379,16 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (!methodsDecrypter.decrypt(peImage, DeobfuscatedFile, ref dumpedMethods, tokenToNativeCode))
return false;
if (options.DumpNativeMethods) {
using (var fileStream = new FileStream(module.Location + ".native", FileMode.Create, FileAccess.Write, FileShare.Read)) {
var sortedTokens = new List<uint>(tokenToNativeCode.Keys);
sortedTokens.Sort();
var writer = new BinaryWriter(fileStream);
var nops = new byte[] { 0x90, 0x90, 0x90, 0x90 };
foreach (var token in sortedTokens) {
writer.Write((byte)0xB8);
writer.Write(token);
writer.Write(tokenToNativeCode[token]);
writer.Write(nops);
}
}
}
newFileData = fileData;
return true;
}
public override IDeobfuscator moduleReloaded(ModuleDefMD module) {
freePEImage();
var newOne = new Deobfuscator(options);
newOne.setModule(module);
newOne.fileData = fileData;
newOne.peImage = new PeImage(fileData);
newOne.peImage = new MyPEImage(fileData);
newOne.methodsDecrypter = new MethodsDecrypter(module, methodsDecrypter);
newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter);
newOne.booleanDecrypter = new BooleanDecrypter(module, booleanDecrypter);
@ -418,6 +398,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return newOne;
}
void freePEImage() {
if (peImage != null)
peImage.Dispose();
peImage = null;
}
public override void deobfuscateBegin() {
base.deobfuscateBegin();
@ -426,6 +412,8 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
proxyCallFixer.find();
stringDecrypter.init(peImage, fileData, DeobfuscatedFile);
if (!stringDecrypter.Detected)
freePEImage();
booleanDecrypter.init(fileData, DeobfuscatedFile);
booleanValueInliner = new BooleanValueInliner();
emptyClass = new EmptyClass(module);
@ -575,6 +563,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
}
public override void deobfuscateEnd() {
freePEImage();
removeProxyDelegates(proxyCallFixer);
removeInlinedMethods();
if (options.RestoreTypes)
@ -608,7 +597,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
}
public override void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) {
if (!options.DecryptMethods)
if (!options.DecryptMethods || !methodsDecrypter.HasNativeMethods)
return;
switch (evt) {
case ModuleWriterEvent.Begin:

View File

@ -26,7 +26,6 @@ using dot10.DotNet.MD;
using dot10.DotNet.Emit;
using dot10.DotNet.Writer;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
class MethodsDecrypter {
@ -124,7 +123,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
static short[] nativeLdci4 = new short[] { 0x55, 0x8B, 0xEC, 0xB8, -1, -1, -1, -1, 0x5D, 0xC3 };
static short[] nativeLdci4_0 = new short[] { 0x55, 0x8B, 0xEC, 0x33, 0xC0, 0x5D, 0xC3 };
public bool decrypt(PeImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref DumpedMethods dumpedMethods, Dictionary<uint, byte[]> tokenToNativeCode) {
public bool decrypt(MyPEImage peImage, ISimpleDeobfuscator simpleDeobfuscator, ref DumpedMethods dumpedMethods, Dictionary<uint, byte[]> tokenToNativeCode) {
if (encryptedResource.Method == null)
return false;
@ -138,20 +137,20 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
xorKey = getXorKey();
xorEncrypt(methodsData);
var methodsDataReader = new BinaryReader(new MemoryStream(methodsData));
var methodsDataReader = MemoryImageStream.Create(methodsData);
int patchCount = methodsDataReader.ReadInt32();
int mode = methodsDataReader.ReadInt32();
int tmp = methodsDataReader.ReadInt32();
methodsDataReader.BaseStream.Position -= 4;
methodsDataReader.Position -= 4;
if ((tmp & 0xFF000000) == 0x06000000) {
// It's method token + rva. DNR 3.7.0.3 (and earlier?) - 3.9.0.1
methodsDataReader.BaseStream.Position += 8L * patchCount;
methodsDataReader.Position += 8L * patchCount;
patchCount = methodsDataReader.ReadInt32();
mode = methodsDataReader.ReadInt32();
patchDwords(peImage, methodsDataReader, patchCount);
while (methodsDataReader.BaseStream.Position < methodsData.Length - 1) {
while (methodsDataReader.Position < methodsData.Length - 1) {
uint token = methodsDataReader.ReadUInt32();
int numDwords = methodsDataReader.ReadInt32();
patchDwords(peImage, methodsDataReader, numDwords / 2);
@ -160,7 +159,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
else if (!hooksJitter || mode == 1) {
// DNR 3.9.8.0, 4.0, 4.1, 4.2, 4.3, 4.4
patchDwords(peImage, methodsDataReader, patchCount);
while (methodsDataReader.BaseStream.Position < methodsData.Length - 1) {
while (methodsDataReader.Position < methodsData.Length - 1) {
uint rva = methodsDataReader.ReadUInt32();
uint token = methodsDataReader.ReadUInt32(); // token, unknown, or index
int size = methodsDataReader.ReadInt32();
@ -171,13 +170,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
else {
// DNR 4.0 - 4.4 (jitter is hooked)
var metadataTables = peImage.Cor20Header.createMetadataTables();
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
var rvaToIndex = new Dictionary<uint, int>((int)methodDef.rows);
uint offset = methodDef.fileOffset;
for (int i = 0; i < methodDef.rows; i++) {
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
var rvaToIndex = new Dictionary<uint, int>((int)methodDef.Rows);
uint offset = (uint)methodDef.StartOffset;
for (int i = 0; i < methodDef.Rows; i++) {
uint rva = peImage.offsetReadUInt32(offset);
offset += methodDef.totalSize;
offset += methodDef.RowSize;
if (rva == 0)
continue;
@ -191,7 +189,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
patchDwords(peImage, methodsDataReader, patchCount);
int count = methodsDataReader.ReadInt32();
dumpedMethods = new DumpedMethods();
while (methodsDataReader.BaseStream.Position < methodsData.Length - 1) {
while (methodsDataReader.Position < methodsData.Length - 1) {
uint rva = methodsDataReader.ReadUInt32();
uint index = methodsDataReader.ReadUInt32();
bool isNativeCode = index >= 0x70000000;
@ -203,6 +201,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
Logger.w("Could not find method having code RVA {0:X8}", rva);
continue;
}
uint methodToken = 0x06000001 + (uint)methodIndex;
if (isNativeCode) {
@ -234,27 +233,14 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
}
var dm = new DumpedMethod();
dm.token = methodToken;
peImage.readMethodTableRowTo(dm, MDToken.ToRID(methodToken));
dm.code = methodData;
offset = methodDef.fileOffset + (uint)(methodIndex * methodDef.totalSize);
rva = peImage.offsetReadUInt32(offset);
dm.mdRVA = peImage.offsetRead(offset + (uint)methodDef.fields[0].offset, methodDef.fields[0].size);
dm.mdImplFlags = peImage.offsetReadUInt16(offset + (uint)methodDef.fields[1].offset);
dm.mdFlags = peImage.offsetReadUInt16(offset + (uint)methodDef.fields[2].offset);
dm.mdName = peImage.offsetRead(offset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size);
dm.mdSignature = peImage.offsetRead(offset + (uint)methodDef.fields[4].offset, methodDef.fields[4].size);
dm.mdParamList = peImage.offsetRead(offset + (uint)methodDef.fields[5].offset, methodDef.fields[5].size);
var codeReader = peImage.Reader;
codeReader.BaseStream.Position = peImage.rvaToOffset(rva);
byte[] code, extraSections;
var mb = MethodBodyParser.parseMethodBody(codeReader, out code, out extraSections);
dm.mhFlags = mb.flags;
dm.mhMaxStack = mb.maxStack;
dm.mhCodeSize = (uint)dm.code.Length;
dm.mhLocalVarSigTok = mb.localVarSigTok;
dm.extraSections = extraSections;
codeReader.Position = peImage.rvaToOffset(dm.mdRVA);
byte[] code;
var mbHeader = MethodBodyParser.parseMethodBody(codeReader, out code, out dm.extraSections);
peImage.updateMethodHeaderInfo(dm, mbHeader);
dumpedMethods.add(dm);
}
@ -263,7 +249,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return true;
}
static void patchDwords(PeImage peImage, BinaryReader reader, int count) {
static void patchDwords(MyPEImage peImage, IBinaryReader reader, int count) {
for (int i = 0; i < count; i++) {
uint rva = reader.ReadUInt32();
uint data = reader.ReadUInt32();

View File

@ -20,10 +20,10 @@
using System;
using System.Text;
using System.Collections.Generic;
using dot10.PE;
using dot10.DotNet;
using dot10.DotNet.Emit;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
class StringDecrypter {
@ -32,7 +32,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
List<DecrypterInfo> decrypterInfos = new List<DecrypterInfo>();
MethodDef otherStringDecrypter;
byte[] decryptedData;
PeImage peImage;
MyPEImage peImage;
byte[] fileData;
StringDecrypterVersion stringDecrypterVersion;
@ -153,7 +153,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
}
}
public void init(PeImage peImage, byte[] fileData, ISimpleDeobfuscator simpleDeobfuscator) {
public void init(MyPEImage peImage, byte[] fileData, ISimpleDeobfuscator simpleDeobfuscator) {
if (encryptedResource.Method == null)
return;
this.peImage = peImage;

View File

@ -23,8 +23,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Reflection;
using dot10.DotNet;
using dot10.DotNet.MD;
using de4dot.blocks;
using de4dot.PE;
namespace de4dot.mdecrypt {
public class DynamicMethodsDecrypter {
@ -90,7 +90,7 @@ namespace de4dot.mdecrypt {
bool compileMethodIsThisCall;
IntPtr ourCodeAddr;
de4dot.PE.MetadataType methodDefTable;
MDTable methodDefTable;
IntPtr methodDefTablePtr;
ModuleDefMD dot10Module;
MethodDef moduleCctor;
@ -148,11 +148,11 @@ namespace de4dot.mdecrypt {
hInstModule = Marshal.GetHINSTANCE(moduleToDecrypt);
moduleToDecryptScope = getScope(moduleToDecrypt);
var peFile = new PeImage(File.ReadAllBytes(moduleToDecrypt.FullyQualifiedName));
methodDefTable = peFile.Cor20Header.createMetadataTables().getMetadataType(MetadataIndex.iMethodDef);
methodDefTablePtr = new IntPtr((byte*)hInstModule + peFile.offsetToRva(methodDefTable.fileOffset));
dot10Module = ModuleDefMD.Load(hInstModule);
methodDefTable = dot10Module.TablesStream.MethodTable;
methodDefTablePtr = new IntPtr((byte*)hInstModule + (uint)dot10Module.MetaData.PEImage.ToRVA(methodDefTable.StartOffset));
initializeMonoCecilMethods();
initializeDot10Methods();
}
}
@ -173,9 +173,8 @@ namespace de4dot.mdecrypt {
return field.GetValue(obj);
}
unsafe void initializeMonoCecilMethods() {
dot10Module = ModuleDefMD.Load(moduleToDecrypt.FullyQualifiedName);
moduleCctor = DotNetUtils.getModuleTypeCctor(dot10Module);
unsafe void initializeDot10Methods() {
moduleCctor = dot10Module.GlobalType.FindStaticConstructor();
if (moduleCctor == null)
moduleCctorCodeRva = 0;
else {
@ -422,22 +421,22 @@ namespace de4dot.mdecrypt {
}
unsafe void updateFromMethodDefTableRow() {
int methodIndex = (int)(ctx.dm.token - 0x06000001);
byte* row = (byte*)methodDefTablePtr + methodIndex * methodDefTable.totalSize;
ctx.dm.mdRVA = read(row, methodDefTable.fields[0]);
ctx.dm.mdImplFlags = (ushort)read(row, methodDefTable.fields[1]);
ctx.dm.mdFlags = (ushort)read(row, methodDefTable.fields[2]);
ctx.dm.mdName = read(row, methodDefTable.fields[3]);
ctx.dm.mdSignature = read(row, methodDefTable.fields[4]);
ctx.dm.mdParamList = read(row, methodDefTable.fields[5]);
uint methodIndex = ctx.dm.token - 0x06000001;
byte* row = (byte*)methodDefTablePtr + methodIndex * methodDefTable.RowSize;
ctx.dm.mdRVA = read(row, methodDefTable.Columns[0]);
ctx.dm.mdImplFlags = (ushort)read(row, methodDefTable.Columns[1]);
ctx.dm.mdFlags = (ushort)read(row, methodDefTable.Columns[2]);
ctx.dm.mdName = read(row, methodDefTable.Columns[3]);
ctx.dm.mdSignature = read(row, methodDefTable.Columns[4]);
ctx.dm.mdParamList = read(row, methodDefTable.Columns[5]);
}
static unsafe uint read(byte* row, MetadataField mdField) {
switch (mdField.size) {
case 1: return *(row + mdField.offset);
case 2: return *(ushort*)(row + mdField.offset);
case 4: return *(uint*)(row + mdField.offset);
default: throw new ApplicationException(string.Format("Unknown size: {0}", mdField.size));
static unsafe uint read(byte* row, ColumnInfo colInfo) {
switch (colInfo.Size) {
case 1: return *(row + colInfo.Offset);
case 2: return *(ushort*)(row + colInfo.Offset);
case 4: return *(uint*)(row + colInfo.Offset);
default: throw new ApplicationException(string.Format("Unknown size: {0}", colInfo.Size));
}
}
@ -457,8 +456,8 @@ namespace de4dot.mdecrypt {
var dumpedMethods = new DumpedMethods();
if (decryptMethodsInfo.methodsToDecrypt == null) {
for (uint i = 0; i < methodDefTable.rows; i++)
dumpedMethods.add(decryptMethod(0x06000001 + i));
for (uint rid = 1; rid <= methodDefTable.Rows; rid++)
dumpedMethods.add(decryptMethod(0x06000000 + rid));
}
else {
foreach (var token in decryptMethodsInfo.methodsToDecrypt)
@ -476,7 +475,7 @@ namespace de4dot.mdecrypt {
ctx.dm = new DumpedMethod();
ctx.dm.token = token;
ctx.method = dot10Module.ResolveToken(token) as MethodDef;
ctx.method = dot10Module.ResolveMethod(MDToken.ToRID(token));
if (ctx.method == null)
throw new ApplicationException(string.Format("Could not find method {0:X8}", token));