Remove old PeImage code and use the new one
This commit is contained in:
parent
e9f90aad6e
commit
5b43e33a35
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -73,22 +73,6 @@
|
||||||
<Compile Include="InstructionListParser.cs" />
|
<Compile Include="InstructionListParser.cs" />
|
||||||
<Compile Include="MemberDefDict.cs" />
|
<Compile Include="MemberDefDict.cs" />
|
||||||
<Compile Include="MethodBlocks.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="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="ScopeBlock.cs" />
|
<Compile Include="ScopeBlock.cs" />
|
||||||
<Compile Include="TryBlock.cs" />
|
<Compile Include="TryBlock.cs" />
|
||||||
|
|
|
@ -153,7 +153,7 @@
|
||||||
<Compile Include="deobfuscators\DeobUtils.cs" />
|
<Compile Include="deobfuscators\DeobUtils.cs" />
|
||||||
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.cs" />
|
<Compile Include="deobfuscators\Dotfuscator\Deobfuscator.cs" />
|
||||||
<Compile Include="deobfuscators\Dotfuscator\StringDecrypter.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\AntiStrongName.cs" />
|
||||||
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeDecrypter.cs" />
|
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeDecrypter.cs" />
|
||||||
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeUnpacker.cs" />
|
<Compile Include="deobfuscators\dotNET_Reactor\v3\ApplicationModeUnpacker.cs" />
|
||||||
|
|
|
@ -22,7 +22,6 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Agile_NET {
|
namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
class CliSecureRtType {
|
class CliSecureRtType {
|
||||||
|
@ -192,14 +191,10 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findNativeCode(byte[] moduleBytes) {
|
bool findNativeCode(byte[] moduleBytes) {
|
||||||
var stream = moduleBytes != null ?
|
var bytes = moduleBytes != null ? moduleBytes : DeobUtils.readModule(module);
|
||||||
(Stream)new MemoryStream(moduleBytes) :
|
using (var peImage = new MyPEImage(bytes))
|
||||||
(Stream)new FileStream(module.Location, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
||||||
using (stream) {
|
|
||||||
var peImage = new PeImage(stream);
|
|
||||||
return foundSig = MethodsDecrypter.detect(peImage);
|
return foundSig = MethodsDecrypter.detect(peImage);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public bool isAtLeastVersion50() {
|
public bool isAtLeastVersion50() {
|
||||||
return DotNetUtils.hasPinvokeMethod(cliSecureRtType, "LoadLibraryA");
|
return DotNetUtils.hasPinvokeMethod(cliSecureRtType, "LoadLibraryA");
|
||||||
|
|
|
@ -23,7 +23,6 @@ using dot10.IO;
|
||||||
using dot10.PE;
|
using dot10.PE;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Agile_NET {
|
namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||||
|
@ -209,12 +208,12 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
|
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
|
||||||
var peImage = new PeImage(fileData);
|
using (var peImage = new MyPEImage(fileData)) {
|
||||||
|
|
||||||
if (!new MethodsDecrypter().decrypt(peImage, module, cliSecureRtType, ref dumpedMethods)) {
|
if (!new MethodsDecrypter().decrypt(peImage, module, cliSecureRtType, ref dumpedMethods)) {
|
||||||
Logger.v("Methods aren't encrypted or invalid signature");
|
Logger.v("Methods aren't encrypted or invalid signature");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newFileData = fileData;
|
newFileData = fileData;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -20,8 +20,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using dot10.IO;
|
||||||
|
using dot10.PE;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using de4dot.PE;
|
using dot10.DotNet.MD;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Agile_NET {
|
namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
|
@ -61,7 +63,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
Pro,
|
Pro,
|
||||||
}
|
}
|
||||||
|
|
||||||
PeImage peImage;
|
MyPEImage peImage;
|
||||||
ModuleDefMD module;
|
ModuleDefMD module;
|
||||||
CliSecureRtType csRtType;
|
CliSecureRtType csRtType;
|
||||||
CodeHeader codeHeader = new CodeHeader();
|
CodeHeader codeHeader = new CodeHeader();
|
||||||
|
@ -73,35 +75,36 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class DecrypterBase : IDecrypter {
|
abstract class DecrypterBase : IDecrypter {
|
||||||
protected readonly PeImage peImage;
|
protected readonly MyPEImage peImage;
|
||||||
protected readonly CodeHeader codeHeader;
|
protected readonly CodeHeader codeHeader;
|
||||||
protected readonly uint endOfMetadata;
|
protected readonly uint endOfMetadata;
|
||||||
|
|
||||||
public DecrypterBase(PeImage peImage, CodeHeader codeHeader) {
|
public DecrypterBase(MyPEImage peImage, CodeHeader codeHeader) {
|
||||||
this.peImage = peImage;
|
this.peImage = peImage;
|
||||||
this.codeHeader = codeHeader;
|
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);
|
public abstract MethodBodyHeader decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections);
|
||||||
|
|
||||||
protected MethodBodyHeader getCodeBytes(byte[] methodBody, 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)
|
// CS 1.1 (could be other versions too)
|
||||||
class Decrypter10 {
|
class Decrypter10 {
|
||||||
PeImage peImage;
|
MyPEImage peImage;
|
||||||
CsBlowfish blowfish;
|
CsBlowfish blowfish;
|
||||||
|
|
||||||
public Decrypter10(PeImage peImage, byte[] key) {
|
public Decrypter10(MyPEImage peImage, byte[] key) {
|
||||||
this.peImage = peImage;
|
this.peImage = peImage;
|
||||||
this.blowfish = new CsBlowfish(key);
|
this.blowfish = new CsBlowfish(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBodyHeader decrypt(uint bodyOffset, out byte[] code, out byte[] extraSections) {
|
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);
|
var mbHeader = MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
|
||||||
blowfish.decrypt(code);
|
blowfish.decrypt(code);
|
||||||
return mbHeader;
|
return mbHeader;
|
||||||
|
@ -110,31 +113,31 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
|
|
||||||
// CS 3.0 (could be other versions too)
|
// CS 3.0 (could be other versions too)
|
||||||
class Decrypter30 : DecrypterBase {
|
class Decrypter30 : DecrypterBase {
|
||||||
public Decrypter30(PeImage peImage, CodeHeader codeHeader)
|
public Decrypter30(MyPEImage peImage, CodeHeader codeHeader)
|
||||||
: base(peImage, codeHeader) {
|
: base(peImage, codeHeader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override MethodBodyHeader decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
|
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);
|
return MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CS 4.0 (could be other versions too)
|
// CS 4.0 (could be other versions too)
|
||||||
class Decrypter40 : DecrypterBase {
|
class Decrypter40 : DecrypterBase {
|
||||||
public Decrypter40(PeImage peImage, CodeHeader codeHeader)
|
public Decrypter40(MyPEImage peImage, CodeHeader codeHeader)
|
||||||
: base(peImage, codeHeader) {
|
: base(peImage, codeHeader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override MethodBodyHeader decrypt(MethodInfo methodInfo, out byte[] code, out byte[] extraSections) {
|
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);
|
return MethodBodyParser.parseMethodBody(peImage.Reader, out code, out extraSections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CS 4.5 (could be other versions too)
|
// CS 4.5 (could be other versions too)
|
||||||
class Decrypter45 : DecrypterBase {
|
class Decrypter45 : DecrypterBase {
|
||||||
public Decrypter45(PeImage peImage, CodeHeader codeHeader)
|
public Decrypter45(MyPEImage peImage, CodeHeader codeHeader)
|
||||||
: base(peImage, codeHeader) {
|
: base(peImage, codeHeader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +156,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
class Decrypter5 : DecrypterBase {
|
class Decrypter5 : DecrypterBase {
|
||||||
readonly uint codeHeaderSize;
|
readonly uint codeHeaderSize;
|
||||||
|
|
||||||
public Decrypter5(PeImage peImage, CodeHeader codeHeader, uint codeHeaderSize)
|
public Decrypter5(MyPEImage peImage, CodeHeader codeHeader, uint codeHeaderSize)
|
||||||
: base(peImage, codeHeader) {
|
: base(peImage, codeHeader) {
|
||||||
this.codeHeaderSize = codeHeaderSize;
|
this.codeHeaderSize = codeHeaderSize;
|
||||||
}
|
}
|
||||||
|
@ -174,7 +177,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
class ProDecrypter : DecrypterBase {
|
class ProDecrypter : DecrypterBase {
|
||||||
readonly uint[] key = new uint[4];
|
readonly uint[] key = new uint[4];
|
||||||
|
|
||||||
public ProDecrypter(PeImage peImage, CodeHeader codeHeader)
|
public ProDecrypter(MyPEImage peImage, CodeHeader codeHeader)
|
||||||
: base(peImage, codeHeader) {
|
: base(peImage, codeHeader) {
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
key[i] = be_readUInt32(codeHeader.decryptionKey, i * 4);
|
key[i] = be_readUInt32(codeHeader.decryptionKey, i * 4);
|
||||||
|
@ -222,7 +225,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
interface ICsHeader {
|
interface ICsHeader {
|
||||||
IDecrypter createDecrypter();
|
IDecrypter createDecrypter();
|
||||||
List<MethodInfo> getMethodInfos(uint codeHeaderOffset);
|
List<MethodInfo> getMethodInfos(uint codeHeaderOffset);
|
||||||
void patchMethodDefTable(MetadataType methodDefTable, IList<MethodInfo> methodInfos);
|
void patchMethodTable(MDTable methodDefTable, IList<MethodInfo> methodInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class CsHeaderBase : ICsHeader {
|
abstract class CsHeaderBase : ICsHeader {
|
||||||
|
@ -236,7 +239,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
|
|
||||||
public abstract IDecrypter createDecrypter();
|
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);
|
public abstract List<MethodInfo> getMethodInfos(uint codeHeaderOffset);
|
||||||
|
@ -347,10 +350,10 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return getMethodInfos4(codeHeaderOffset);
|
return getMethodInfos4(codeHeaderOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void patchMethodDefTable(MetadataType methodDefTable, IList<MethodInfo> methodInfos) {
|
public override void patchMethodTable(MDTable methodDefTable, IList<MethodInfo> methodInfos) {
|
||||||
uint offset = methodDefTable.fileOffset - methodDefTable.totalSize;
|
uint offset = (uint)methodDefTable.StartOffset - methodDefTable.RowSize;
|
||||||
foreach (var methodInfo in methodInfos) {
|
foreach (var methodInfo in methodInfos) {
|
||||||
offset += methodDefTable.totalSize;
|
offset += methodDefTable.RowSize;
|
||||||
if (methodInfo.flags == 0 || methodInfo.codeOffs == 0)
|
if (methodInfo.flags == 0 || methodInfo.codeOffs == 0)
|
||||||
continue;
|
continue;
|
||||||
uint rva = methodsDecrypter.peImage.offsetReadUInt32(offset);
|
uint rva = methodsDecrypter.peImage.offsetReadUInt32(offset);
|
||||||
|
@ -370,7 +373,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
V52, // 5.2+ (or maybe 5.1+)
|
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)
|
if (sigType == SigType.Old)
|
||||||
return new List<CsHeaderVersion> { CsHeaderVersion.V10 };
|
return new List<CsHeaderVersion> { CsHeaderVersion.V10 };
|
||||||
if (!isOldHeader(methodDefTable))
|
if (!isOldHeader(methodDefTable))
|
||||||
|
@ -408,10 +411,10 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isOldHeader(MetadataType methodDefTable) {
|
bool isOldHeader(MDTable methodDefTable) {
|
||||||
if (methodDefTable.totalSize != codeHeader.methodDefElemSize)
|
if (methodDefTable.RowSize != codeHeader.methodDefElemSize)
|
||||||
return true;
|
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 true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -434,7 +437,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
Error,
|
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.peImage = peImage;
|
||||||
this.csRtType = csRtType;
|
this.csRtType = csRtType;
|
||||||
this.module = module;
|
this.module = module;
|
||||||
|
@ -469,27 +472,27 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return moduleCctorBytes;
|
return moduleCctorBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint getCodeHeaderOffset(PeImage peImage) {
|
static uint getCodeHeaderOffset(MyPEImage peImage) {
|
||||||
return peImage.rvaToOffset(peImage.Cor20Header.metadataDirectory.virtualAddress + peImage.Cor20Header.metadataDirectory.size);
|
return peImage.rvaToOffset((uint)peImage.Cor20Header.MetaData.VirtualAddress + peImage.Cor20Header.MetaData.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string[] sections = new string[] {
|
static string[] sections = new string[] {
|
||||||
".text", ".rsrc", ".data", ".rdata",
|
".text", ".rsrc", ".data", ".rdata",
|
||||||
};
|
};
|
||||||
static uint getOldCodeHeaderOffset(PeImage peImage) {
|
static uint getOldCodeHeaderOffset(MyPEImage peImage) {
|
||||||
var sect = getLastOf(peImage, sections);
|
var sect = getLastOf(peImage, sections);
|
||||||
if (sect == null || sect.virtualSize < 0x100)
|
if (sect == null || sect.VirtualSize < 0x100)
|
||||||
return 0;
|
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) {
|
static ImageSectionHeader getLastOf(MyPEImage peImage, string[] sections) {
|
||||||
SectionHeader sect = null;
|
ImageSectionHeader sect = null;
|
||||||
foreach (var name in sections) {
|
foreach (var name in sections) {
|
||||||
var sect2 = peImage.findSection(name);
|
var sect2 = peImage.findSection(name);
|
||||||
if (sect2 == null)
|
if (sect2 == null)
|
||||||
continue;
|
continue;
|
||||||
if (sect == null || sect2.virtualAddress > sect.virtualAddress)
|
if (sect == null || sect2.VirtualAddress > sect.VirtualAddress)
|
||||||
sect = sect2;
|
sect = sect2;
|
||||||
}
|
}
|
||||||
return sect;
|
return sect;
|
||||||
|
@ -500,8 +503,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
if (sigType == SigType.Unknown)
|
if (sigType == SigType.Unknown)
|
||||||
return DecryptResult.NotEncrypted;
|
return DecryptResult.NotEncrypted;
|
||||||
|
|
||||||
var metadataTables = peImage.Cor20Header.createMetadataTables();
|
var methodDefTable = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
||||||
var methodDefTable = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
|
|
||||||
|
|
||||||
foreach (var version in getCsHeaderVersions(codeHeaderOffset, methodDefTable)) {
|
foreach (var version in getCsHeaderVersions(codeHeaderOffset, methodDefTable)) {
|
||||||
try {
|
try {
|
||||||
|
@ -534,66 +536,44 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return codeHeaderOffset;
|
return codeHeaderOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void decryptMethodsOld(MetadataType methodDefTable, ref DumpedMethods dumpedMethods) {
|
void decryptMethodsOld(MDTable methodDefTable, ref DumpedMethods dumpedMethods) {
|
||||||
dumpedMethods = new DumpedMethods();
|
dumpedMethods = new DumpedMethods();
|
||||||
uint offset = methodDefTable.fileOffset;
|
|
||||||
var decrypter = new Decrypter10(peImage, codeHeader.decryptionKey);
|
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();
|
var dm = new DumpedMethod();
|
||||||
dm.token = 0x06000001 + (uint)i;
|
|
||||||
|
|
||||||
var method = (MethodDef)module.ResolveMethod(MDToken.ToRID(dm.token));
|
var method = (MethodDef)module.ResolveMethod(rid);
|
||||||
if (method == null || method.DeclaringType == DotNetUtils.getModuleType(module))
|
if (method == null || method.DeclaringType == module.GlobalType)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint rva = peImage.offsetReadUInt32(offset + (uint)methodDefTable.fields[0].offset);
|
peImage.readMethodTableRowTo(dm, rid);
|
||||||
if (rva == 0)
|
if (dm.mdRVA == 0)
|
||||||
continue;
|
continue;
|
||||||
uint bodyOffset = peImage.rvaToOffset(rva);
|
uint bodyOffset = peImage.rvaToOffset(dm.mdRVA);
|
||||||
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);
|
|
||||||
|
|
||||||
var mbHeader = decrypter.decrypt(bodyOffset, out dm.code, out dm.extraSections);
|
var mbHeader = decrypter.decrypt(bodyOffset, out dm.code, out dm.extraSections);
|
||||||
dm.mhFlags = mbHeader.flags;
|
peImage.updateMethodHeaderInfo(dm, mbHeader);
|
||||||
dm.mhMaxStack = mbHeader.maxStack;
|
|
||||||
dm.mhCodeSize = (uint)dm.code.Length;
|
|
||||||
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
|
|
||||||
|
|
||||||
dumpedMethods.add(dm);
|
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);
|
var methodInfos = csHeader.getMethodInfos(codeHeaderOffset);
|
||||||
csHeader.patchMethodDefTable(methodDefTable, methodInfos);
|
csHeader.patchMethodTable(methodDefTable, methodInfos);
|
||||||
|
|
||||||
dumpedMethods = new DumpedMethods();
|
dumpedMethods = new DumpedMethods();
|
||||||
uint offset = methodDefTable.fileOffset;
|
|
||||||
decrypter = csHeader.createDecrypter();
|
decrypter = csHeader.createDecrypter();
|
||||||
for (int i = 0; i < methodInfos.Count; i++, offset += methodDefTable.totalSize) {
|
for (uint rid = 1; rid <= (uint)methodInfos.Count; rid++) {
|
||||||
var methodInfo = methodInfos[i];
|
var methodInfo = methodInfos[(int)rid - 1];
|
||||||
if (methodInfo.codeOffs == 0)
|
if (methodInfo.codeOffs == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var dm = new DumpedMethod();
|
var dm = new DumpedMethod();
|
||||||
dm.token = 0x06000001 + (uint)i;
|
peImage.readMethodTableRowTo(dm, rid);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
var mbHeader = decrypter.decrypt(methodInfo, out dm.code, out dm.extraSections);
|
var mbHeader = decrypter.decrypt(methodInfo, out dm.code, out dm.extraSections);
|
||||||
dm.mhFlags = mbHeader.flags;
|
peImage.updateMethodHeaderInfo(dm, mbHeader);
|
||||||
dm.mhMaxStack = mbHeader.maxStack;
|
|
||||||
dm.mhCodeSize = (uint)dm.code.Length;
|
|
||||||
dm.mhLocalVarSigTok = mbHeader.localVarSigTok;
|
|
||||||
|
|
||||||
dumpedMethods.add(dm);
|
dumpedMethods.add(dm);
|
||||||
}
|
}
|
||||||
|
@ -622,7 +602,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
|
||||||
return getSigType(signature) != SigType.Unknown;
|
return getSigType(signature) != SigType.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool detect(PeImage peImage) {
|
public static bool detect(MyPEImage peImage) {
|
||||||
try {
|
try {
|
||||||
uint codeHeaderOffset = getCodeHeaderOffset(peImage);
|
uint codeHeaderOffset = getCodeHeaderOffset(peImage);
|
||||||
if (isValidSignature(peImage.offsetReadBytes(codeHeaderOffset, 16)))
|
if (isValidSignature(peImage.offsetReadBytes(codeHeaderOffset, 16)))
|
||||||
|
|
|
@ -21,7 +21,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.CodeFort {
|
namespace de4dot.code.deobfuscators.CodeFort {
|
||||||
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||||
|
|
|
@ -19,11 +19,10 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using dot10.IO;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using dot10.DotNet.Emit;
|
using dot10.DotNet.Emit;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.CodeVeil {
|
namespace de4dot.code.deobfuscators.CodeVeil {
|
||||||
class MethodsDecrypter {
|
class MethodsDecrypter {
|
||||||
|
@ -32,23 +31,22 @@ namespace de4dot.code.deobfuscators.CodeVeil {
|
||||||
|
|
||||||
interface IDecrypter {
|
interface IDecrypter {
|
||||||
void initialize(byte[] methodsData);
|
void initialize(byte[] methodsData);
|
||||||
bool decrypt(BinaryReader fileDataReader, DumpedMethod dm);
|
bool decrypt(IBinaryReader fileDataReader, DumpedMethod dm);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Decrypter : IDecrypter {
|
class Decrypter : IDecrypter {
|
||||||
BinaryReader methodsDataReader;
|
IBinaryReader methodsDataReader;
|
||||||
|
|
||||||
public virtual void initialize(byte[] methodsData) {
|
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)
|
if (fileDataReader.ReadByte() != 0x2A)
|
||||||
return false; // Not a RET
|
return false; // Not a RET
|
||||||
int methodsDataOffset = DeobUtils.readVariableLengthInt32(fileDataReader);
|
methodsDataReader.Position = fileDataReader.ReadCompressedUInt32();
|
||||||
methodsDataReader.BaseStream.Position = methodsDataOffset;
|
|
||||||
|
|
||||||
dm.mhCodeSize = (uint)DeobUtils.readVariableLengthInt32(methodsDataReader);
|
dm.mhCodeSize = methodsDataReader.ReadCompressedUInt32();
|
||||||
dm.code = methodsDataReader.ReadBytes((int)dm.mhCodeSize);
|
dm.code = methodsDataReader.ReadBytes((int)dm.mhCodeSize);
|
||||||
if ((dm.mhFlags & 8) != 0)
|
if ((dm.mhFlags & 8) != 0)
|
||||||
dm.extraSections = MethodBodyParser.readExtraSections(methodsDataReader);
|
dm.extraSections = MethodBodyParser.readExtraSections(methodsDataReader);
|
||||||
|
@ -126,8 +124,8 @@ namespace de4dot.code.deobfuscators.CodeVeil {
|
||||||
if (decrypter == null)
|
if (decrypter == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var peImage = new PeImage(fileData);
|
using (var peImage = new MyPEImage(fileData)) {
|
||||||
if (peImage.Sections.Length <= 0)
|
if (peImage.Sections.Count <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var methodsData = findMethodsData(peImage, fileData);
|
var methodsData = findMethodsData(peImage, fileData);
|
||||||
|
@ -139,33 +137,25 @@ namespace de4dot.code.deobfuscators.CodeVeil {
|
||||||
dumpedMethods = createDumpedMethods(peImage, fileData, methodsData);
|
dumpedMethods = createDumpedMethods(peImage, fileData, methodsData);
|
||||||
if (dumpedMethods == null)
|
if (dumpedMethods == null)
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DumpedMethods createDumpedMethods(PeImage peImage, byte[] fileData, byte[] methodsData) {
|
DumpedMethods createDumpedMethods(MyPEImage peImage, byte[] fileData, byte[] methodsData) {
|
||||||
var dumpedMethods = new DumpedMethods();
|
var dumpedMethods = new DumpedMethods();
|
||||||
|
|
||||||
var methodsDataReader = new BinaryReader(new MemoryStream(methodsData));
|
var methodsDataReader = MemoryImageStream.Create(methodsData);
|
||||||
var fileDataReader = new BinaryReader(new MemoryStream(fileData));
|
var fileDataReader = MemoryImageStream.Create(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 methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
||||||
|
for (uint rid = 1; rid <= methodDef.Rows; rid++) {
|
||||||
var dm = new DumpedMethod();
|
var dm = new DumpedMethod();
|
||||||
dm.token = (uint)(0x06000001 + i);
|
|
||||||
dm.mdRVA = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[0].offset, methodDef.fields[0].size);
|
peImage.readMethodTableRowTo(dm, rid);
|
||||||
dm.mdImplFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[1].offset);
|
if (dm.mdRVA == 0)
|
||||||
dm.mdFlags = peImage.offsetReadUInt16(methodDefOffset + (uint)methodDef.fields[2].offset);
|
continue;
|
||||||
dm.mdName = peImage.offsetRead(methodDefOffset + (uint)methodDef.fields[3].offset, methodDef.fields[3].size);
|
uint bodyOffset = peImage.rvaToOffset(dm.mdRVA);
|
||||||
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);
|
|
||||||
|
|
||||||
byte b = peImage.offsetReadByte(bodyOffset);
|
byte b = peImage.offsetReadByte(bodyOffset);
|
||||||
uint codeOffset;
|
uint codeOffset;
|
||||||
|
@ -187,7 +177,7 @@ namespace de4dot.code.deobfuscators.CodeVeil {
|
||||||
dm.mhLocalVarSigTok = peImage.offsetReadUInt32(bodyOffset + 8);
|
dm.mhLocalVarSigTok = peImage.offsetReadUInt32(bodyOffset + 8);
|
||||||
codeOffset = bodyOffset + (uint)(dm.mhFlags >> 12) * 4;
|
codeOffset = bodyOffset + (uint)(dm.mhFlags >> 12) * 4;
|
||||||
}
|
}
|
||||||
fileDataReader.BaseStream.Position = codeOffset;
|
fileDataReader.Position = codeOffset;
|
||||||
|
|
||||||
if (!decrypter.decrypt(fileDataReader, dm))
|
if (!decrypter.decrypt(fileDataReader, dm))
|
||||||
continue;
|
continue;
|
||||||
|
@ -202,14 +192,14 @@ namespace de4dot.code.deobfuscators.CodeVeil {
|
||||||
static byte[] initializeMethodEnd = new byte[] {
|
static byte[] initializeMethodEnd = new byte[] {
|
||||||
0x33, 0xC0, 0x40, 0x5E, 0x5F, 0x5A, 0x59, 0x5B, 0xC9, 0xC2,
|
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 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 RVA_EXECUTIVE_OFFSET = 1 * 4;
|
||||||
const int ENC_CODE_OFFSET = 6 * 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; ) {
|
for (int offset = getStartOffset(peImage); offset < lastOffset; ) {
|
||||||
offset = findSig(fileData, offset, lastOffset, initializeMethodEnd);
|
offset = findSig(fileData, offset, lastOffset, initializeMethodEnd);
|
||||||
if (offset < 0)
|
if (offset < 0)
|
||||||
|
@ -229,13 +219,13 @@ namespace de4dot.code.deobfuscators.CodeVeil {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int relOffs = BitConverter.ToInt32(fileData, offset + ENC_CODE_OFFSET);
|
int relOffs = BitConverter.ToInt32(fileData, offset + ENC_CODE_OFFSET);
|
||||||
if (relOffs <= 0 || relOffs >= section.sizeOfRawData)
|
if (relOffs <= 0 || relOffs >= section.SizeOfRawData)
|
||||||
continue;
|
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;
|
int endOffset = relOffs + size;
|
||||||
if (endOffset < relOffs || endOffset > section.sizeOfRawData)
|
if (endOffset < relOffs || endOffset > section.SizeOfRawData)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return reader.ReadBytes(size);
|
return reader.ReadBytes(size);
|
||||||
|
@ -244,7 +234,7 @@ namespace de4dot.code.deobfuscators.CodeVeil {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getStartOffset(PeImage peImage) {
|
int getStartOffset(MyPEImage peImage) {
|
||||||
int minOffset = int.MaxValue;
|
int minOffset = int.MaxValue;
|
||||||
foreach (var rva in mainType.Rvas) {
|
foreach (var rva in mainType.Rvas) {
|
||||||
int rvaOffs = (int)peImage.rvaToOffset((uint)rva);
|
int rvaOffs = (int)peImage.rvaToOffset((uint)rva);
|
||||||
|
|
|
@ -21,7 +21,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.CodeWall {
|
namespace de4dot.code.deobfuscators.CodeWall {
|
||||||
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||||
|
@ -164,10 +163,10 @@ namespace de4dot.code.deobfuscators.CodeWall {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
|
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
|
||||||
var peImage = new PeImage(fileData);
|
using (var peImage = new MyPEImage(fileData)) {
|
||||||
|
|
||||||
if (!methodsDecrypter.decrypt(peImage, ref dumpedMethods))
|
if (!methodsDecrypter.decrypt(peImage, ref dumpedMethods))
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
newFileData = fileData;
|
newFileData = fileData;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
using System;
|
using System;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using dot10.DotNet.Emit;
|
using dot10.DotNet.Emit;
|
||||||
using de4dot.PE;
|
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.CodeWall {
|
namespace de4dot.code.deobfuscators.CodeWall {
|
||||||
|
@ -67,50 +66,33 @@ namespace de4dot.code.deobfuscators.CodeWall {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool decrypt(PeImage peImage, ref DumpedMethods dumpedMethods) {
|
public bool decrypt(MyPEImage peImage, ref DumpedMethods dumpedMethods) {
|
||||||
dumpedMethods = new DumpedMethods();
|
dumpedMethods = new DumpedMethods();
|
||||||
|
|
||||||
bool decrypted = false;
|
bool decrypted = false;
|
||||||
|
|
||||||
var metadataTables = peImage.Cor20Header.createMetadataTables();
|
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
||||||
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
|
for (uint rid = 1; rid <= methodDef.Rows; rid++) {
|
||||||
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 dm = new DumpedMethod();
|
var dm = new DumpedMethod();
|
||||||
dm.token = (uint)(0x06000001 + i);
|
peImage.readMethodTableRowTo(dm, rid);
|
||||||
|
|
||||||
byte[] code, extraSections;
|
if (dm.mdRVA == 0)
|
||||||
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)
|
|
||||||
continue;
|
continue;
|
||||||
dm.code = code;
|
uint bodyOffset = peImage.rvaToOffset(dm.mdRVA);
|
||||||
dm.extraSections = extraSections;
|
|
||||||
|
|
||||||
int seed = BitConverter.ToInt32(code, 2);
|
peImage.Reader.Position = bodyOffset;
|
||||||
Array.Copy(newCodeHeader, code, newCodeHeader.Length);
|
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)
|
if (seed == 0)
|
||||||
decrypt(code);
|
decrypt(dm.code);
|
||||||
else
|
else
|
||||||
decrypt(code, seed);
|
decrypt(dm.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;
|
|
||||||
|
|
||||||
dumpedMethods.add(dm);
|
dumpedMethods.add(dm);
|
||||||
decrypted = true;
|
decrypted = true;
|
||||||
|
|
|
@ -21,8 +21,8 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using dot10.PE;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using de4dot.PE;
|
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.MPRESS {
|
namespace de4dot.code.deobfuscators.MPRESS {
|
||||||
|
@ -159,7 +159,7 @@ namespace de4dot.code.deobfuscators.MPRESS {
|
||||||
if (checkMethods(type, methods_v1x)) {
|
if (checkMethods(type, methods_v1x)) {
|
||||||
var lfMethod = DotNetUtils.getMethod(type, "System.Boolean", "(System.String,System.Byte[]&)");
|
var lfMethod = DotNetUtils.getMethod(type, "System.Boolean", "(System.String,System.Byte[]&)");
|
||||||
if (lfMethod != null) {
|
if (lfMethod != null) {
|
||||||
if (DeobUtils.hasInteger(lfMethod, (int)Machine.amd64))
|
if (DeobUtils.hasInteger(lfMethod, (int)Machine.AMD64))
|
||||||
return Version.V218;
|
return Version.V218;
|
||||||
return Version.V1x_217;
|
return Version.V1x_217;
|
||||||
}
|
}
|
||||||
|
@ -194,12 +194,13 @@ namespace de4dot.code.deobfuscators.MPRESS {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
|
byte[] fileData = ModuleBytes ?? DeobUtils.readModule(module);
|
||||||
var peImage = new PeImage(fileData);
|
byte[] decompressed;
|
||||||
var section = peImage.Sections[peImage.Sections.Length - 1];
|
using (var peImage = new MyPEImage(fileData)) {
|
||||||
var offset = section.pointerToRawData;
|
var section = peImage.Sections[peImage.Sections.Count - 1];
|
||||||
|
var offset = section.PointerToRawData;
|
||||||
offset += 16;
|
offset += 16;
|
||||||
|
|
||||||
byte[] decompressed, compressed;
|
byte[] compressed;
|
||||||
int compressedLen;
|
int compressedLen;
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case Version.V0x:
|
case Version.V0x:
|
||||||
|
@ -212,8 +213,8 @@ namespace de4dot.code.deobfuscators.MPRESS {
|
||||||
|
|
||||||
case Version.V1x_217:
|
case Version.V1x_217:
|
||||||
case Version.V218:
|
case Version.V218:
|
||||||
if (peImage.FileHeader.machine == Machine.amd64 && version == Version.V218)
|
if (peImage.PEImage.ImageNTHeaders.FileHeader.Machine == Machine.AMD64 && version == Version.V218)
|
||||||
offset = section.pointerToRawData + section.virtualSize;
|
offset = section.PointerToRawData + section.VirtualSize;
|
||||||
int decompressedLen = (int)peImage.offsetReadUInt32(offset);
|
int decompressedLen = (int)peImage.offsetReadUInt32(offset);
|
||||||
compressedLen = fileData.Length - (int)offset - 4;
|
compressedLen = fileData.Length - (int)offset - 4;
|
||||||
compressed = peImage.offsetReadBytes(offset + 4, compressedLen);
|
compressed = peImage.offsetReadBytes(offset + 4, compressedLen);
|
||||||
|
@ -226,6 +227,7 @@ namespace de4dot.code.deobfuscators.MPRESS {
|
||||||
default:
|
default:
|
||||||
throw new ApplicationException("Unknown MPRESS version");
|
throw new ApplicationException("Unknown MPRESS version");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newFileData = decompressed;
|
newFileData = decompressed;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -17,22 +17,27 @@
|
||||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using de4dot.PE;
|
using System;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.MaxtoCode {
|
namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
class DecrypterInfo {
|
class DecrypterInfo : IDisposable {
|
||||||
public MainType mainType;
|
public MainType mainType;
|
||||||
public readonly PeImage peImage;
|
public readonly MyPEImage peImage;
|
||||||
public readonly PeHeader peHeader;
|
public readonly PeHeader peHeader;
|
||||||
public readonly McKey mcKey;
|
public readonly McKey mcKey;
|
||||||
public readonly byte[] fileData;
|
public readonly byte[] fileData;
|
||||||
|
|
||||||
public DecrypterInfo(MainType mainType, byte[] fileData) {
|
public DecrypterInfo(MainType mainType, byte[] fileData) {
|
||||||
this.mainType = mainType;
|
this.mainType = mainType;
|
||||||
this.peImage = new PeImage(fileData);
|
this.peImage = new MyPEImage(fileData);
|
||||||
this.peHeader = new PeHeader(mainType, peImage);
|
this.peHeader = new PeHeader(mainType, peImage);
|
||||||
this.mcKey = new McKey(peImage, peHeader);
|
this.mcKey = new McKey(peImage, peHeader);
|
||||||
this.fileData = fileData;
|
this.fileData = fileData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
if (peImage != null)
|
||||||
|
peImage.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,10 +120,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
newOne.setModule(module);
|
newOne.setModule(module);
|
||||||
newOne.mainType = new MainType(module, mainType);
|
newOne.mainType = new MainType(module, mainType);
|
||||||
newOne.decrypterInfo = decrypterInfo;
|
newOne.decrypterInfo = decrypterInfo;
|
||||||
|
decrypterInfo = null;
|
||||||
|
if (newOne.decrypterInfo != null)
|
||||||
newOne.decrypterInfo.mainType = newOne.mainType;
|
newOne.decrypterInfo.mainType = newOne.mainType;
|
||||||
return newOne;
|
return newOne;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void freePEImage() {
|
||||||
|
if (decrypterInfo != null)
|
||||||
|
decrypterInfo.Dispose();
|
||||||
|
decrypterInfo = null;
|
||||||
|
}
|
||||||
|
|
||||||
public override void deobfuscateBegin() {
|
public override void deobfuscateBegin() {
|
||||||
base.deobfuscateBegin();
|
base.deobfuscateBegin();
|
||||||
|
|
||||||
|
@ -134,6 +142,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.decrypt((uint)args[0]));
|
staticStringInliner.add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.decrypt((uint)args[0]));
|
||||||
DeobfuscatedFile.stringDecryptersAdded();
|
DeobfuscatedFile.stringDecryptersAdded();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
freePEImage();
|
||||||
|
|
||||||
foreach (var method in mainType.InitMethods)
|
foreach (var method in mainType.InitMethods)
|
||||||
addCctorInitCallToBeRemoved(method);
|
addCctorInitCallToBeRemoved(method);
|
||||||
|
@ -142,6 +152,11 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
removeInvalidResources();
|
removeInvalidResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void deobfuscateEnd() {
|
||||||
|
freePEImage();
|
||||||
|
base.deobfuscateEnd();
|
||||||
|
}
|
||||||
|
|
||||||
static Encoding getEncoding(int cp) {
|
static Encoding getEncoding(int cp) {
|
||||||
try {
|
try {
|
||||||
return Encoding.GetEncoding(cp);
|
return Encoding.GetEncoding(cp);
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.MaxtoCode {
|
namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
class McKey {
|
class McKey {
|
||||||
|
@ -30,7 +29,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
get { return data[index]; }
|
get { return data[index]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public McKey(PeImage peImage, PeHeader peHeader) {
|
public McKey(MyPEImage peImage, PeHeader peHeader) {
|
||||||
this.peHeader = peHeader;
|
this.peHeader = peHeader;
|
||||||
try {
|
try {
|
||||||
this.data = peImage.readBytes(peHeader.getMcKeyRva(), 0x2000);
|
this.data = peImage.readBytes(peHeader.getMcKeyRva(), 0x2000);
|
||||||
|
|
|
@ -21,7 +21,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using de4dot.PE;
|
using dot10.IO;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.MaxtoCode {
|
namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
|
@ -31,7 +31,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
|
|
||||||
class MethodInfos {
|
class MethodInfos {
|
||||||
MainType mainType;
|
MainType mainType;
|
||||||
PeImage peImage;
|
MyPEImage peImage;
|
||||||
PeHeader peHeader;
|
PeHeader peHeader;
|
||||||
McKey mcKey;
|
McKey mcKey;
|
||||||
uint structSize;
|
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.mainType = mainType;
|
||||||
this.peImage = peImage;
|
this.peImage = peImage;
|
||||||
this.peHeader = peHeader;
|
this.peHeader = peHeader;
|
||||||
|
@ -463,55 +463,21 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
var methodInfos = new MethodInfos(decrypterInfo.mainType, peImage, decrypterInfo.peHeader, decrypterInfo.mcKey);
|
var methodInfos = new MethodInfos(decrypterInfo.mainType, peImage, decrypterInfo.peHeader, decrypterInfo.mcKey);
|
||||||
methodInfos.initializeInfos();
|
methodInfos.initializeInfos();
|
||||||
|
|
||||||
var metadataTables = peImage.Cor20Header.createMetadataTables();
|
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
||||||
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
|
for (uint rid = 1; rid <= methodDef.Rows; rid++) {
|
||||||
uint methodDefOffset = methodDef.fileOffset;
|
var dm = new DumpedMethod();
|
||||||
for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) {
|
peImage.readMethodTableRowTo(dm, rid);
|
||||||
uint bodyRva = peImage.offsetReadUInt32(methodDefOffset);
|
|
||||||
if (bodyRva == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var info = methodInfos.lookup(bodyRva);
|
var info = methodInfos.lookup(dm.mdRVA);
|
||||||
if (info == null)
|
if (info == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint bodyOffset = peImage.rvaToOffset(bodyRva);
|
ushort magic = peImage.readUInt16(dm.mdRVA);
|
||||||
ushort magic = peImage.offsetReadUInt16(bodyOffset);
|
|
||||||
if (magic != 0xFFF3)
|
if (magic != 0xFFF3)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var dm = new DumpedMethod();
|
var mbHeader = MethodBodyParser.parseMethodBody(MemoryImageStream.Create(info.body), out dm.code, out dm.extraSections);
|
||||||
dm.token = (uint)(0x06000001 + i);
|
peImage.updateMethodHeaderInfo(dm, mbHeader);
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
dumpedMethods.add(dm);
|
dumpedMethods.add(dm);
|
||||||
}
|
}
|
||||||
|
@ -529,8 +495,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
uint resourceSize = peHeader.readUInt32(0x0E14) ^ mcKey.readUInt32(0x00AA);
|
uint resourceSize = peHeader.readUInt32(0x0E14) ^ mcKey.readUInt32(0x00AA);
|
||||||
if (resourceRva == 0 || resourceSize == 0)
|
if (resourceRva == 0 || resourceSize == 0)
|
||||||
return;
|
return;
|
||||||
if (resourceRva != peImage.Cor20Header.resources.virtualAddress ||
|
if (resourceRva != (uint)peImage.Cor20Header.Resources.VirtualAddress ||
|
||||||
resourceSize != peImage.Cor20Header.resources.size) {
|
resourceSize != peImage.Cor20Header.Resources.Size) {
|
||||||
Logger.w("Invalid resource RVA and size found");
|
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);
|
uint usHeapSize = peHeader.readUInt32(0x0E04) ^ mcKey.readUInt32(0x0082);
|
||||||
if (usHeapRva == 0 || usHeapSize == 0)
|
if (usHeapRva == 0 || usHeapSize == 0)
|
||||||
return;
|
return;
|
||||||
var usHeap = peImage.Cor20Header.metadata.getStream("#US");
|
var usHeap = peImage.DotNetFile.MetaData.USStream;
|
||||||
if (usHeap == null ||
|
if (usHeap.StartOffset == 0 || // Start offset is 0 if it's not present in the file
|
||||||
peImage.rvaToOffset(usHeapRva) != usHeap.fileOffset ||
|
peImage.rvaToOffset(usHeapRva) != (uint)usHeap.StartOffset ||
|
||||||
usHeapSize != usHeap.Length) {
|
usHeapSize != (uint)(usHeap.EndOffset - usHeap.StartOffset)) {
|
||||||
Logger.w("Invalid #US heap RVA and size found");
|
Logger.w("Invalid #US heap RVA and size found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.MaxtoCode {
|
namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
enum EncryptionVersion {
|
enum EncryptionVersion {
|
||||||
|
@ -40,7 +39,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
get { return version; }
|
get { return version; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public PeHeader(MainType mainType, PeImage peImage) {
|
public PeHeader(MainType mainType, MyPEImage peImage) {
|
||||||
uint headerOffset;
|
uint headerOffset;
|
||||||
version = getHeaderOffsetAndVersion(peImage, out headerOffset);
|
version = getHeaderOffsetAndVersion(peImage, out headerOffset);
|
||||||
headerData = peImage.offsetReadBytes(headerOffset, 0x1000);
|
headerData = peImage.offsetReadBytes(headerOffset, 0x1000);
|
||||||
|
@ -58,7 +57,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return BitConverter.ToUInt32(headerData, offset);
|
return BitConverter.ToUInt32(headerData, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static EncryptionVersion getHeaderOffsetAndVersion(PeImage peImage, out uint headerOffset) {
|
static EncryptionVersion getHeaderOffsetAndVersion(MyPEImage peImage, out uint headerOffset) {
|
||||||
headerOffset = 0;
|
headerOffset = 0;
|
||||||
|
|
||||||
var version = getVersion(peImage, headerOffset);
|
var version = getVersion(peImage, headerOffset);
|
||||||
|
@ -69,8 +68,8 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
if (section == null)
|
if (section == null)
|
||||||
return EncryptionVersion.Unknown;
|
return EncryptionVersion.Unknown;
|
||||||
|
|
||||||
headerOffset = section.pointerToRawData;
|
headerOffset = section.PointerToRawData;
|
||||||
uint end = section.pointerToRawData + section.sizeOfRawData - 0x1000 + 1;
|
uint end = section.PointerToRawData + section.SizeOfRawData - 0x1000 + 1;
|
||||||
while (headerOffset < end) {
|
while (headerOffset < end) {
|
||||||
version = getVersion(peImage, headerOffset);
|
version = getVersion(peImage, headerOffset);
|
||||||
if (version != EncryptionVersion.Unknown)
|
if (version != EncryptionVersion.Unknown)
|
||||||
|
@ -81,7 +80,7 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
|
||||||
return EncryptionVersion.Unknown;
|
return EncryptionVersion.Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
static EncryptionVersion getVersion(PeImage peImage, uint headerOffset) {
|
static EncryptionVersion getVersion(MyPEImage peImage, uint headerOffset) {
|
||||||
uint m1lo = peImage.offsetReadUInt32(headerOffset + 0x900);
|
uint m1lo = peImage.offsetReadUInt32(headerOffset + 0x900);
|
||||||
uint m1hi = peImage.offsetReadUInt32(headerOffset + 0x904);
|
uint m1hi = peImage.offsetReadUInt32(headerOffset + 0x904);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using dot10.IO;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators {
|
namespace de4dot.code.deobfuscators {
|
||||||
[Serializable]
|
[Serializable]
|
||||||
|
@ -39,7 +40,7 @@ namespace de4dot.code.deobfuscators {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MethodBodyParser {
|
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 {
|
try {
|
||||||
return parseMethodBody2(reader, out code, out extraSections);
|
return parseMethodBody2(reader, out code, out extraSections);
|
||||||
}
|
}
|
||||||
|
@ -49,14 +50,10 @@ namespace de4dot.code.deobfuscators {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool verify(byte[] data) {
|
public static bool verify(byte[] data) {
|
||||||
return verify(new BinaryReader(new MemoryStream(data)));
|
return verify(MemoryImageStream.Create(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool verify(Stream data) {
|
public static bool verify(IBinaryReader reader) {
|
||||||
return verify(new BinaryReader(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool verify(BinaryReader reader) {
|
|
||||||
try {
|
try {
|
||||||
byte[] code, extraSections;
|
byte[] code, extraSections;
|
||||||
parseMethodBody(reader, out code, out 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();
|
var mbHeader = new MethodBodyHeader();
|
||||||
|
|
||||||
uint codeOffset;
|
uint codeOffset;
|
||||||
|
@ -95,7 +92,7 @@ namespace de4dot.code.deobfuscators {
|
||||||
else
|
else
|
||||||
throw new InvalidMethodBody();
|
throw new InvalidMethodBody();
|
||||||
|
|
||||||
if (mbHeader.codeSize + codeOffset > reader.BaseStream.Length)
|
if (mbHeader.codeSize + codeOffset > reader.Length)
|
||||||
throw new InvalidMethodBody();
|
throw new InvalidMethodBody();
|
||||||
code = reader.ReadBytes((int)mbHeader.codeSize);
|
code = reader.ReadBytes((int)mbHeader.codeSize);
|
||||||
|
|
||||||
|
@ -107,11 +104,11 @@ namespace de4dot.code.deobfuscators {
|
||||||
return mbHeader;
|
return mbHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void align(BinaryReader reader, int alignment) {
|
static void align(IBinaryReader reader, int alignment) {
|
||||||
reader.BaseStream.Position = (reader.BaseStream.Position + alignment - 1) & ~(alignment - 1);
|
reader.Position = (reader.Position + alignment - 1) & ~(alignment - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] readExtraSections(BinaryReader reader) {
|
public static byte[] readExtraSections(IBinaryReader reader) {
|
||||||
try {
|
try {
|
||||||
return readExtraSections2(reader);
|
return readExtraSections2(reader);
|
||||||
}
|
}
|
||||||
|
@ -120,16 +117,16 @@ namespace de4dot.code.deobfuscators {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte[] readExtraSections2(BinaryReader reader) {
|
static byte[] readExtraSections2(IBinaryReader reader) {
|
||||||
align(reader, 4);
|
align(reader, 4);
|
||||||
int startPos = (int)reader.BaseStream.Position;
|
int startPos = (int)reader.Position;
|
||||||
parseSection(reader);
|
parseSection(reader);
|
||||||
int size = (int)reader.BaseStream.Position - startPos;
|
int size = (int)reader.Position - startPos;
|
||||||
reader.BaseStream.Position = startPos;
|
reader.Position = startPos;
|
||||||
return reader.ReadBytes(size);
|
return reader.ReadBytes(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseSection(BinaryReader reader) {
|
static void parseSection(IBinaryReader reader) {
|
||||||
byte flags;
|
byte flags;
|
||||||
do {
|
do {
|
||||||
align(reader, 4);
|
align(reader, 4);
|
||||||
|
@ -141,20 +138,20 @@ namespace de4dot.code.deobfuscators {
|
||||||
throw new InvalidMethodBody("Invalid bits set");
|
throw new InvalidMethodBody("Invalid bits set");
|
||||||
|
|
||||||
if ((flags & 0x40) != 0) {
|
if ((flags & 0x40) != 0) {
|
||||||
reader.BaseStream.Position--;
|
reader.Position--;
|
||||||
int num = (int)(reader.ReadUInt32() >> 8) / 24;
|
int num = (int)(reader.ReadUInt32() >> 8) / 24;
|
||||||
reader.BaseStream.Position += num * 24;
|
reader.Position += num * 24;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int num = reader.ReadByte() / 12;
|
int num = reader.ReadByte() / 12;
|
||||||
reader.BaseStream.Position += 2 + num * 12;
|
reader.Position += 2 + num * 12;
|
||||||
}
|
}
|
||||||
} while ((flags & 0x80) != 0);
|
} while ((flags & 0x80) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte peek(BinaryReader reader) {
|
static byte peek(IBinaryReader reader) {
|
||||||
byte b = reader.ReadByte();
|
byte b = reader.ReadByte();
|
||||||
reader.BaseStream.Position--;
|
reader.Position--;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,51 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using dot10.IO;
|
using dot10.IO;
|
||||||
using dot10.PE;
|
using dot10.PE;
|
||||||
using dot10.DotNet.MD;
|
using dot10.DotNet.MD;
|
||||||
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.dotNET_Reactor {
|
namespace de4dot.code.deobfuscators {
|
||||||
sealed class MyPEImage : IDisposable {
|
sealed class MyPEImage : IDisposable {
|
||||||
IPEImage peImage;
|
IPEImage peImage;
|
||||||
byte[] peImageData;
|
byte[] peImageData;
|
||||||
IImageStream peStream;
|
IImageStream peStream;
|
||||||
DotNetFile dnFile;
|
DotNetFile dnFile;
|
||||||
|
bool dnFileInitialized;
|
||||||
ImageSectionHeader dotNetSection;
|
ImageSectionHeader dotNetSection;
|
||||||
bool ownPeImage;
|
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 {
|
public IPEImage PEImage {
|
||||||
get { return peImage; }
|
get { return peImage; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IList<ImageSectionHeader> Sections {
|
||||||
|
get { return peImage.ImageSectionHeaders; }
|
||||||
|
}
|
||||||
|
|
||||||
public uint Length {
|
public uint Length {
|
||||||
get { return (uint)peStream.Length; }
|
get { return (uint)peStream.Length; }
|
||||||
}
|
}
|
||||||
|
@ -33,13 +63,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor {
|
||||||
void initialize(IPEImage peImage) {
|
void initialize(IPEImage peImage) {
|
||||||
this.peImage = peImage;
|
this.peImage = peImage;
|
||||||
this.peStream = peImage.CreateFullStream();
|
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) {
|
ImageSectionHeader findSection(RVA rva) {
|
||||||
|
@ -50,10 +73,66 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor {
|
||||||
return null;
|
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) {
|
static bool isInside(ImageSectionHeader section, uint offset, uint length) {
|
||||||
return offset >= section.PointerToRawData && offset + length <= section.PointerToRawData + section.SizeOfRawData;
|
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) {
|
public void offsetWriteUInt32(uint offset, uint val) {
|
||||||
peImageData[offset + 0] = (byte)val;
|
peImageData[offset + 0] = (byte)val;
|
||||||
peImageData[offset + 1] = (byte)(val >> 8);
|
peImageData[offset + 1] = (byte)(val >> 8);
|
||||||
|
@ -99,14 +178,14 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor {
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool dotNetSafeWriteOffset(uint offset, byte[] data) {
|
public bool dotNetSafeWriteOffset(uint offset, byte[] data) {
|
||||||
if (dnFile != null) {
|
if (DotNetFile != null) {
|
||||||
uint length = (uint)data.Length;
|
uint length = (uint)data.Length;
|
||||||
|
|
||||||
if (!isInside(dotNetSection, offset, length))
|
if (!isInside(dotNetSection, offset, length))
|
||||||
return false;
|
return false;
|
||||||
if (intersect(offset, length, dnFile.MetaData.ImageCor20Header))
|
if (intersect(offset, length, DotNetFile.MetaData.ImageCor20Header))
|
||||||
return false;
|
return false;
|
||||||
if (intersect(offset, length, dnFile.MetaData.MetaDataHeader))
|
if (intersect(offset, length, DotNetFile.MetaData.MetaDataHeader))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
|
namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
|
||||||
// Find the type that decrypts strings and calls the native lib
|
// Find the type that decrypts strings and calls the native lib
|
||||||
|
|
|
@ -23,7 +23,6 @@ using System.IO;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.blocks.cflow;
|
using de4dot.blocks.cflow;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
|
namespace de4dot.code.deobfuscators.dotNET_Reactor.v3 {
|
||||||
class MemoryPatcher {
|
class MemoryPatcher {
|
||||||
|
|
|
@ -26,7 +26,6 @@ using dot10.DotNet;
|
||||||
using dot10.DotNet.Emit;
|
using dot10.DotNet.Emit;
|
||||||
using dot10.DotNet.Writer;
|
using dot10.DotNet.Writer;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||||
|
@ -42,7 +41,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
BoolOption decryptResources;
|
BoolOption decryptResources;
|
||||||
BoolOption removeNamespaces;
|
BoolOption removeNamespaces;
|
||||||
BoolOption removeAntiStrongName;
|
BoolOption removeAntiStrongName;
|
||||||
NoArgOption dumpNativeMethods;
|
|
||||||
|
|
||||||
public DeobfuscatorInfo()
|
public DeobfuscatorInfo()
|
||||||
: base(DEFAULT_REGEX) {
|
: base(DEFAULT_REGEX) {
|
||||||
|
@ -55,7 +53,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
decryptResources = new BoolOption(null, makeArgName("rsrc"), "Decrypt resources", true);
|
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);
|
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);
|
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 {
|
public override string Name {
|
||||||
|
@ -78,7 +75,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
DecryptResources = decryptResources.get(),
|
DecryptResources = decryptResources.get(),
|
||||||
RemoveNamespaces = removeNamespaces.get(),
|
RemoveNamespaces = removeNamespaces.get(),
|
||||||
RemoveAntiStrongName = removeAntiStrongName.get(),
|
RemoveAntiStrongName = removeAntiStrongName.get(),
|
||||||
DumpNativeMethods = dumpNativeMethods.get(),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +89,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
decryptResources,
|
decryptResources,
|
||||||
removeNamespaces,
|
removeNamespaces,
|
||||||
removeAntiStrongName,
|
removeAntiStrongName,
|
||||||
dumpNativeMethods,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +97,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
Options options;
|
Options options;
|
||||||
string obfuscatorName = DeobfuscatorInfo.THE_NAME;
|
string obfuscatorName = DeobfuscatorInfo.THE_NAME;
|
||||||
|
|
||||||
PeImage peImage;
|
MyPEImage peImage;
|
||||||
byte[] fileData;
|
byte[] fileData;
|
||||||
MethodsDecrypter methodsDecrypter;
|
MethodsDecrypter methodsDecrypter;
|
||||||
StringDecrypter stringDecrypter;
|
StringDecrypter stringDecrypter;
|
||||||
|
@ -129,7 +124,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
public bool DecryptResources { get; set; }
|
public bool DecryptResources { get; set; }
|
||||||
public bool RemoveNamespaces { get; set; }
|
public bool RemoveNamespaces { get; set; }
|
||||||
public bool RemoveAntiStrongName { get; set; }
|
public bool RemoveAntiStrongName { get; set; }
|
||||||
public bool DumpNativeMethods { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Type {
|
public override string Type {
|
||||||
|
@ -376,7 +370,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
if (count != 0)
|
if (count != 0)
|
||||||
return false;
|
return false;
|
||||||
fileData = ModuleBytes ?? DeobUtils.readModule(module);
|
fileData = ModuleBytes ?? DeobUtils.readModule(module);
|
||||||
peImage = new PeImage(fileData);
|
peImage = new MyPEImage(fileData);
|
||||||
|
|
||||||
if (!options.DecryptMethods)
|
if (!options.DecryptMethods)
|
||||||
return false;
|
return false;
|
||||||
|
@ -385,30 +379,16 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
if (!methodsDecrypter.decrypt(peImage, DeobfuscatedFile, ref dumpedMethods, tokenToNativeCode))
|
if (!methodsDecrypter.decrypt(peImage, DeobfuscatedFile, ref dumpedMethods, tokenToNativeCode))
|
||||||
return false;
|
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;
|
newFileData = fileData;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IDeobfuscator moduleReloaded(ModuleDefMD module) {
|
public override IDeobfuscator moduleReloaded(ModuleDefMD module) {
|
||||||
|
freePEImage();
|
||||||
var newOne = new Deobfuscator(options);
|
var newOne = new Deobfuscator(options);
|
||||||
newOne.setModule(module);
|
newOne.setModule(module);
|
||||||
newOne.fileData = fileData;
|
newOne.fileData = fileData;
|
||||||
newOne.peImage = new PeImage(fileData);
|
newOne.peImage = new MyPEImage(fileData);
|
||||||
newOne.methodsDecrypter = new MethodsDecrypter(module, methodsDecrypter);
|
newOne.methodsDecrypter = new MethodsDecrypter(module, methodsDecrypter);
|
||||||
newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter);
|
newOne.stringDecrypter = new StringDecrypter(module, stringDecrypter);
|
||||||
newOne.booleanDecrypter = new BooleanDecrypter(module, booleanDecrypter);
|
newOne.booleanDecrypter = new BooleanDecrypter(module, booleanDecrypter);
|
||||||
|
@ -418,6 +398,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
return newOne;
|
return newOne;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void freePEImage() {
|
||||||
|
if (peImage != null)
|
||||||
|
peImage.Dispose();
|
||||||
|
peImage = null;
|
||||||
|
}
|
||||||
|
|
||||||
public override void deobfuscateBegin() {
|
public override void deobfuscateBegin() {
|
||||||
base.deobfuscateBegin();
|
base.deobfuscateBegin();
|
||||||
|
|
||||||
|
@ -426,6 +412,8 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
proxyCallFixer.find();
|
proxyCallFixer.find();
|
||||||
|
|
||||||
stringDecrypter.init(peImage, fileData, DeobfuscatedFile);
|
stringDecrypter.init(peImage, fileData, DeobfuscatedFile);
|
||||||
|
if (!stringDecrypter.Detected)
|
||||||
|
freePEImage();
|
||||||
booleanDecrypter.init(fileData, DeobfuscatedFile);
|
booleanDecrypter.init(fileData, DeobfuscatedFile);
|
||||||
booleanValueInliner = new BooleanValueInliner();
|
booleanValueInliner = new BooleanValueInliner();
|
||||||
emptyClass = new EmptyClass(module);
|
emptyClass = new EmptyClass(module);
|
||||||
|
@ -575,6 +563,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void deobfuscateEnd() {
|
public override void deobfuscateEnd() {
|
||||||
|
freePEImage();
|
||||||
removeProxyDelegates(proxyCallFixer);
|
removeProxyDelegates(proxyCallFixer);
|
||||||
removeInlinedMethods();
|
removeInlinedMethods();
|
||||||
if (options.RestoreTypes)
|
if (options.RestoreTypes)
|
||||||
|
@ -608,7 +597,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) {
|
public override void OnWriterEvent(ModuleWriterBase writer, ModuleWriterEvent evt) {
|
||||||
if (!options.DecryptMethods)
|
if (!options.DecryptMethods || !methodsDecrypter.HasNativeMethods)
|
||||||
return;
|
return;
|
||||||
switch (evt) {
|
switch (evt) {
|
||||||
case ModuleWriterEvent.Begin:
|
case ModuleWriterEvent.Begin:
|
||||||
|
|
|
@ -26,7 +26,6 @@ using dot10.DotNet.MD;
|
||||||
using dot10.DotNet.Emit;
|
using dot10.DotNet.Emit;
|
||||||
using dot10.DotNet.Writer;
|
using dot10.DotNet.Writer;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
class MethodsDecrypter {
|
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 = 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 };
|
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)
|
if (encryptedResource.Method == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -138,20 +137,20 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
xorKey = getXorKey();
|
xorKey = getXorKey();
|
||||||
xorEncrypt(methodsData);
|
xorEncrypt(methodsData);
|
||||||
|
|
||||||
var methodsDataReader = new BinaryReader(new MemoryStream(methodsData));
|
var methodsDataReader = MemoryImageStream.Create(methodsData);
|
||||||
int patchCount = methodsDataReader.ReadInt32();
|
int patchCount = methodsDataReader.ReadInt32();
|
||||||
int mode = methodsDataReader.ReadInt32();
|
int mode = methodsDataReader.ReadInt32();
|
||||||
|
|
||||||
int tmp = methodsDataReader.ReadInt32();
|
int tmp = methodsDataReader.ReadInt32();
|
||||||
methodsDataReader.BaseStream.Position -= 4;
|
methodsDataReader.Position -= 4;
|
||||||
if ((tmp & 0xFF000000) == 0x06000000) {
|
if ((tmp & 0xFF000000) == 0x06000000) {
|
||||||
// It's method token + rva. DNR 3.7.0.3 (and earlier?) - 3.9.0.1
|
// 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();
|
patchCount = methodsDataReader.ReadInt32();
|
||||||
mode = methodsDataReader.ReadInt32();
|
mode = methodsDataReader.ReadInt32();
|
||||||
|
|
||||||
patchDwords(peImage, methodsDataReader, patchCount);
|
patchDwords(peImage, methodsDataReader, patchCount);
|
||||||
while (methodsDataReader.BaseStream.Position < methodsData.Length - 1) {
|
while (methodsDataReader.Position < methodsData.Length - 1) {
|
||||||
uint token = methodsDataReader.ReadUInt32();
|
uint token = methodsDataReader.ReadUInt32();
|
||||||
int numDwords = methodsDataReader.ReadInt32();
|
int numDwords = methodsDataReader.ReadInt32();
|
||||||
patchDwords(peImage, methodsDataReader, numDwords / 2);
|
patchDwords(peImage, methodsDataReader, numDwords / 2);
|
||||||
|
@ -160,7 +159,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
else if (!hooksJitter || mode == 1) {
|
else if (!hooksJitter || mode == 1) {
|
||||||
// DNR 3.9.8.0, 4.0, 4.1, 4.2, 4.3, 4.4
|
// DNR 3.9.8.0, 4.0, 4.1, 4.2, 4.3, 4.4
|
||||||
patchDwords(peImage, methodsDataReader, patchCount);
|
patchDwords(peImage, methodsDataReader, patchCount);
|
||||||
while (methodsDataReader.BaseStream.Position < methodsData.Length - 1) {
|
while (methodsDataReader.Position < methodsData.Length - 1) {
|
||||||
uint rva = methodsDataReader.ReadUInt32();
|
uint rva = methodsDataReader.ReadUInt32();
|
||||||
uint token = methodsDataReader.ReadUInt32(); // token, unknown, or index
|
uint token = methodsDataReader.ReadUInt32(); // token, unknown, or index
|
||||||
int size = methodsDataReader.ReadInt32();
|
int size = methodsDataReader.ReadInt32();
|
||||||
|
@ -171,13 +170,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
else {
|
else {
|
||||||
// DNR 4.0 - 4.4 (jitter is hooked)
|
// DNR 4.0 - 4.4 (jitter is hooked)
|
||||||
|
|
||||||
var metadataTables = peImage.Cor20Header.createMetadataTables();
|
var methodDef = peImage.DotNetFile.MetaData.TablesStream.MethodTable;
|
||||||
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
|
var rvaToIndex = new Dictionary<uint, int>((int)methodDef.Rows);
|
||||||
var rvaToIndex = new Dictionary<uint, int>((int)methodDef.rows);
|
uint offset = (uint)methodDef.StartOffset;
|
||||||
uint offset = methodDef.fileOffset;
|
for (int i = 0; i < methodDef.Rows; i++) {
|
||||||
for (int i = 0; i < methodDef.rows; i++) {
|
|
||||||
uint rva = peImage.offsetReadUInt32(offset);
|
uint rva = peImage.offsetReadUInt32(offset);
|
||||||
offset += methodDef.totalSize;
|
offset += methodDef.RowSize;
|
||||||
if (rva == 0)
|
if (rva == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -191,7 +189,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
patchDwords(peImage, methodsDataReader, patchCount);
|
patchDwords(peImage, methodsDataReader, patchCount);
|
||||||
int count = methodsDataReader.ReadInt32();
|
int count = methodsDataReader.ReadInt32();
|
||||||
dumpedMethods = new DumpedMethods();
|
dumpedMethods = new DumpedMethods();
|
||||||
while (methodsDataReader.BaseStream.Position < methodsData.Length - 1) {
|
while (methodsDataReader.Position < methodsData.Length - 1) {
|
||||||
uint rva = methodsDataReader.ReadUInt32();
|
uint rva = methodsDataReader.ReadUInt32();
|
||||||
uint index = methodsDataReader.ReadUInt32();
|
uint index = methodsDataReader.ReadUInt32();
|
||||||
bool isNativeCode = index >= 0x70000000;
|
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);
|
Logger.w("Could not find method having code RVA {0:X8}", rva);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint methodToken = 0x06000001 + (uint)methodIndex;
|
uint methodToken = 0x06000001 + (uint)methodIndex;
|
||||||
|
|
||||||
if (isNativeCode) {
|
if (isNativeCode) {
|
||||||
|
@ -234,27 +233,14 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
}
|
}
|
||||||
|
|
||||||
var dm = new DumpedMethod();
|
var dm = new DumpedMethod();
|
||||||
dm.token = methodToken;
|
peImage.readMethodTableRowTo(dm, MDToken.ToRID(methodToken));
|
||||||
dm.code = methodData;
|
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;
|
var codeReader = peImage.Reader;
|
||||||
codeReader.BaseStream.Position = peImage.rvaToOffset(rva);
|
codeReader.Position = peImage.rvaToOffset(dm.mdRVA);
|
||||||
byte[] code, extraSections;
|
byte[] code;
|
||||||
var mb = MethodBodyParser.parseMethodBody(codeReader, out code, out extraSections);
|
var mbHeader = MethodBodyParser.parseMethodBody(codeReader, out code, out dm.extraSections);
|
||||||
dm.mhFlags = mb.flags;
|
peImage.updateMethodHeaderInfo(dm, mbHeader);
|
||||||
dm.mhMaxStack = mb.maxStack;
|
|
||||||
dm.mhCodeSize = (uint)dm.code.Length;
|
|
||||||
dm.mhLocalVarSigTok = mb.localVarSigTok;
|
|
||||||
dm.extraSections = extraSections;
|
|
||||||
|
|
||||||
dumpedMethods.add(dm);
|
dumpedMethods.add(dm);
|
||||||
}
|
}
|
||||||
|
@ -263,7 +249,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
return true;
|
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++) {
|
for (int i = 0; i < count; i++) {
|
||||||
uint rva = reader.ReadUInt32();
|
uint rva = reader.ReadUInt32();
|
||||||
uint data = reader.ReadUInt32();
|
uint data = reader.ReadUInt32();
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using dot10.PE;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
using dot10.DotNet.Emit;
|
using dot10.DotNet.Emit;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
class StringDecrypter {
|
class StringDecrypter {
|
||||||
|
@ -32,7 +32,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
|
||||||
List<DecrypterInfo> decrypterInfos = new List<DecrypterInfo>();
|
List<DecrypterInfo> decrypterInfos = new List<DecrypterInfo>();
|
||||||
MethodDef otherStringDecrypter;
|
MethodDef otherStringDecrypter;
|
||||||
byte[] decryptedData;
|
byte[] decryptedData;
|
||||||
PeImage peImage;
|
MyPEImage peImage;
|
||||||
byte[] fileData;
|
byte[] fileData;
|
||||||
StringDecrypterVersion stringDecrypterVersion;
|
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)
|
if (encryptedResource.Method == null)
|
||||||
return;
|
return;
|
||||||
this.peImage = peImage;
|
this.peImage = peImage;
|
||||||
|
|
|
@ -23,8 +23,8 @@ using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using dot10.DotNet;
|
using dot10.DotNet;
|
||||||
|
using dot10.DotNet.MD;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
using de4dot.PE;
|
|
||||||
|
|
||||||
namespace de4dot.mdecrypt {
|
namespace de4dot.mdecrypt {
|
||||||
public class DynamicMethodsDecrypter {
|
public class DynamicMethodsDecrypter {
|
||||||
|
@ -90,7 +90,7 @@ namespace de4dot.mdecrypt {
|
||||||
bool compileMethodIsThisCall;
|
bool compileMethodIsThisCall;
|
||||||
IntPtr ourCodeAddr;
|
IntPtr ourCodeAddr;
|
||||||
|
|
||||||
de4dot.PE.MetadataType methodDefTable;
|
MDTable methodDefTable;
|
||||||
IntPtr methodDefTablePtr;
|
IntPtr methodDefTablePtr;
|
||||||
ModuleDefMD dot10Module;
|
ModuleDefMD dot10Module;
|
||||||
MethodDef moduleCctor;
|
MethodDef moduleCctor;
|
||||||
|
@ -148,11 +148,11 @@ namespace de4dot.mdecrypt {
|
||||||
hInstModule = Marshal.GetHINSTANCE(moduleToDecrypt);
|
hInstModule = Marshal.GetHINSTANCE(moduleToDecrypt);
|
||||||
moduleToDecryptScope = getScope(moduleToDecrypt);
|
moduleToDecryptScope = getScope(moduleToDecrypt);
|
||||||
|
|
||||||
var peFile = new PeImage(File.ReadAllBytes(moduleToDecrypt.FullyQualifiedName));
|
dot10Module = ModuleDefMD.Load(hInstModule);
|
||||||
methodDefTable = peFile.Cor20Header.createMetadataTables().getMetadataType(MetadataIndex.iMethodDef);
|
methodDefTable = dot10Module.TablesStream.MethodTable;
|
||||||
methodDefTablePtr = new IntPtr((byte*)hInstModule + peFile.offsetToRva(methodDefTable.fileOffset));
|
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);
|
return field.GetValue(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void initializeMonoCecilMethods() {
|
unsafe void initializeDot10Methods() {
|
||||||
dot10Module = ModuleDefMD.Load(moduleToDecrypt.FullyQualifiedName);
|
moduleCctor = dot10Module.GlobalType.FindStaticConstructor();
|
||||||
moduleCctor = DotNetUtils.getModuleTypeCctor(dot10Module);
|
|
||||||
if (moduleCctor == null)
|
if (moduleCctor == null)
|
||||||
moduleCctorCodeRva = 0;
|
moduleCctorCodeRva = 0;
|
||||||
else {
|
else {
|
||||||
|
@ -422,22 +421,22 @@ namespace de4dot.mdecrypt {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe void updateFromMethodDefTableRow() {
|
unsafe void updateFromMethodDefTableRow() {
|
||||||
int methodIndex = (int)(ctx.dm.token - 0x06000001);
|
uint methodIndex = ctx.dm.token - 0x06000001;
|
||||||
byte* row = (byte*)methodDefTablePtr + methodIndex * methodDefTable.totalSize;
|
byte* row = (byte*)methodDefTablePtr + methodIndex * methodDefTable.RowSize;
|
||||||
ctx.dm.mdRVA = read(row, methodDefTable.fields[0]);
|
ctx.dm.mdRVA = read(row, methodDefTable.Columns[0]);
|
||||||
ctx.dm.mdImplFlags = (ushort)read(row, methodDefTable.fields[1]);
|
ctx.dm.mdImplFlags = (ushort)read(row, methodDefTable.Columns[1]);
|
||||||
ctx.dm.mdFlags = (ushort)read(row, methodDefTable.fields[2]);
|
ctx.dm.mdFlags = (ushort)read(row, methodDefTable.Columns[2]);
|
||||||
ctx.dm.mdName = read(row, methodDefTable.fields[3]);
|
ctx.dm.mdName = read(row, methodDefTable.Columns[3]);
|
||||||
ctx.dm.mdSignature = read(row, methodDefTable.fields[4]);
|
ctx.dm.mdSignature = read(row, methodDefTable.Columns[4]);
|
||||||
ctx.dm.mdParamList = read(row, methodDefTable.fields[5]);
|
ctx.dm.mdParamList = read(row, methodDefTable.Columns[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsafe uint read(byte* row, MetadataField mdField) {
|
static unsafe uint read(byte* row, ColumnInfo colInfo) {
|
||||||
switch (mdField.size) {
|
switch (colInfo.Size) {
|
||||||
case 1: return *(row + mdField.offset);
|
case 1: return *(row + colInfo.Offset);
|
||||||
case 2: return *(ushort*)(row + mdField.offset);
|
case 2: return *(ushort*)(row + colInfo.Offset);
|
||||||
case 4: return *(uint*)(row + mdField.offset);
|
case 4: return *(uint*)(row + colInfo.Offset);
|
||||||
default: throw new ApplicationException(string.Format("Unknown size: {0}", mdField.size));
|
default: throw new ApplicationException(string.Format("Unknown size: {0}", colInfo.Size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,8 +456,8 @@ namespace de4dot.mdecrypt {
|
||||||
var dumpedMethods = new DumpedMethods();
|
var dumpedMethods = new DumpedMethods();
|
||||||
|
|
||||||
if (decryptMethodsInfo.methodsToDecrypt == null) {
|
if (decryptMethodsInfo.methodsToDecrypt == null) {
|
||||||
for (uint i = 0; i < methodDefTable.rows; i++)
|
for (uint rid = 1; rid <= methodDefTable.Rows; rid++)
|
||||||
dumpedMethods.add(decryptMethod(0x06000001 + i));
|
dumpedMethods.add(decryptMethod(0x06000000 + rid));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
foreach (var token in decryptMethodsInfo.methodsToDecrypt)
|
foreach (var token in decryptMethodsInfo.methodsToDecrypt)
|
||||||
|
@ -476,7 +475,7 @@ namespace de4dot.mdecrypt {
|
||||||
ctx.dm = new DumpedMethod();
|
ctx.dm = new DumpedMethod();
|
||||||
ctx.dm.token = token;
|
ctx.dm.token = token;
|
||||||
|
|
||||||
ctx.method = dot10Module.ResolveToken(token) as MethodDef;
|
ctx.method = dot10Module.ResolveMethod(MDToken.ToRID(token));
|
||||||
if (ctx.method == null)
|
if (ctx.method == null)
|
||||||
throw new ApplicationException(string.Format("Could not find method {0:X8}", token));
|
throw new ApplicationException(string.Format("Could not find method {0:X8}", token));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user