Merge branch 'cv' into next_version

Conflicts:
	blocks/DotNetUtils.cs
This commit is contained in:
de4dot 2012-02-12 14:47:24 +01:00
commit c15773b709
39 changed files with 3696 additions and 42 deletions

View File

@ -224,6 +224,7 @@ namespace de4dot.blocks {
// Returns the variable or null if it's not a ldloc/stloc instruction. It does not return
// a local variable if it's a ldloca/ldloca.s instruction.
public static VariableDefinition getLocalVar(IList<VariableDefinition> locals, Instruction instr) {
int index;
switch (instr.OpCode.Code) {
case Code.Ldloc:
case Code.Ldloc_S:
@ -235,17 +236,23 @@ namespace de4dot.blocks {
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
return locals[instr.OpCode.Code - Code.Ldloc_0];
index = instr.OpCode.Code - Code.Ldloc_0;
break;
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
return locals[instr.OpCode.Code - Code.Stloc_0];
index = instr.OpCode.Code - Code.Stloc_0;
break;
default:
return null;
}
if (index < locals.Count)
return locals[index];
return null;
}
public static bool isConditionalBranch(Code code) {
@ -465,7 +472,17 @@ namespace de4dot.blocks {
return null;
}
public static FieldDefinition getField(TypeDefinition type, string name) {
public static FieldDefinition getField(TypeDefinition type, string typeFullName) {
if (type == null)
return null;
foreach (var field in type.Fields) {
if (field.FieldType.FullName == typeFullName)
return field;
}
return null;
}
public static FieldDefinition getFieldByName(TypeDefinition type, string name) {
if (type == null)
return null;
foreach (var field in type.Fields) {
@ -670,6 +687,8 @@ namespace de4dot.blocks {
if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt)
continue;
var methodRef = call.Operand as MethodReference;
if (methodRef == null)
continue;
var type = getType(module, methodRef.DeclaringType);
var methodDef = getMethod(type, methodRef);
if (methodDef != null) {

2
cecil

@ -1 +1 @@
Subproject commit 9b28c58c35470f7cef5f03d3c50c9ba1e65b6843
Subproject commit d168993c52f46069f113bc2a85cef60da0834c68

View File

@ -47,6 +47,10 @@ namespace de4dot.code.PE {
get { return resources; }
}
internal SectionHeader[] Sections {
get { return sectionHeaders; }
}
public uint FileHeaderOffset {
get { return fileHeader.Offset; }
}

View File

@ -44,6 +44,7 @@
<HintPath>..\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Remoting" />
<Reference Include="System.XML" />
</ItemGroup>
@ -79,6 +80,20 @@
<Compile Include="deobfuscators\CliSecure\ResourceDecrypter.cs" />
<Compile Include="deobfuscators\CliSecure\StackFrameHelper.cs" />
<Compile Include="deobfuscators\CliSecure\StringDecrypter.cs" />
<Compile Include="deobfuscators\CodeVeil\AssemblyResolver.cs" />
<Compile Include="deobfuscators\CodeVeil\ErexResourceReader.cs" />
<Compile Include="deobfuscators\CodeVeil\InvalidDataException.cs" />
<Compile Include="deobfuscators\CodeVeil\MainType.cs" />
<Compile Include="deobfuscators\CodeVeil\MethodsDecrypter.cs" />
<Compile Include="deobfuscators\CodeVeil\ObfuscatorVersion.cs" />
<Compile Include="deobfuscators\CodeVeil\ResourceConverter.cs" />
<Compile Include="deobfuscators\CodeVeil\ResourceDecrypter.cs" />
<Compile Include="deobfuscators\CodeVeil\ResourceInfo.cs" />
<Compile Include="deobfuscators\CodeVeil\ResourceReader.cs" />
<Compile Include="deobfuscators\CodeVeil\StringDecrypter.cs" />
<Compile Include="deobfuscators\CodeVeil\Deobfuscator.cs" />
<Compile Include="deobfuscators\CodeVeil\ProxyDelegateFinder.cs" />
<Compile Include="deobfuscators\CodeVeil\TamperDetection.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\AntiDebugger.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\AssemblyResolver.cs" />
<Compile Include="deobfuscators\CryptoObfuscator\Deobfuscator.cs" />
@ -227,6 +242,15 @@
<Compile Include="renamer\TypeNames.cs" />
<Compile Include="renamer\TypeRenamerState.cs" />
<Compile Include="renamer\VariableNameState.cs" />
<Compile Include="resources\BuiltInResourceData.cs" />
<Compile Include="resources\IResourceData.cs" />
<Compile Include="resources\ResourceElement.cs" />
<Compile Include="resources\ResourceElementSet.cs" />
<Compile Include="resources\ResourceTypeCode.cs" />
<Compile Include="resources\ResourceDataCreator.cs" />
<Compile Include="resources\ResourceWriter.cs" />
<Compile Include="resources\UserResourceData.cs" />
<Compile Include="resources\UserResourceType.cs" />
<Compile Include="StringInliner.cs" />
<Compile Include="UserException.cs" />
<Compile Include="Utils.cs" />

View File

@ -113,6 +113,17 @@ namespace de4dot.code.deobfuscators {
return resultArray;
}
public static uint[] getInitializedUInt32Array(int arraySize, MethodDefinition method, ref int newarrIndex) {
var resultArray = getInitializedInt32Array(arraySize, method, ref newarrIndex);
if (resultArray == null)
return null;
var ary = new uint[resultArray.Length];
for (int i = 0; i < ary.Length; i++)
ary[i] = (uint)resultArray[i];
return ary;
}
public static Value[] getInitializedArray(int arraySize, MethodDefinition method, ref int newarrIndex, Code stelemOpCode) {
var resultValueArray = new Value[arraySize];
@ -143,7 +154,7 @@ namespace de4dot.code.deobfuscators {
case Code.Starg_S:
case Code.Stsfld:
case Code.Stfld:
if (emulator.peek() == theArray && i != newarrIndex + 1)
if (emulator.peek() == theArray && i != newarrIndex + 1 && i != newarrIndex + 2)
goto done;
break;
}

View File

@ -156,7 +156,7 @@ namespace de4dot.code.deobfuscators.Babel_NET {
}
void checkVersion(TypeDefinition attr) {
var versionField = DotNetUtils.getField(attr, "Version");
var versionField = DotNetUtils.getFieldByName(attr, "Version");
if (versionField != null && versionField.IsLiteral && versionField.Constant != null && versionField.Constant is string) {
var val = Regex.Match((string)versionField.Constant, @"^(\d+\.\d+\.\d+\.\d+)$");
if (val.Groups.Count < 2)

View File

@ -37,10 +37,6 @@ namespace de4dot.code.deobfuscators.CliSecure {
setDelegateCreatorMethod(lookup(method, "Could not find delegate creator method"));
}
T lookup<T>(T def, string errorMessage) where T : MemberReference {
return DeobUtils.lookup(module, def, errorMessage);
}
public void findDelegateCreator() {
foreach (var type in module.Types) {
var methodName = "System.Void " + type.FullName + "::icgd(System.Int32)";

View File

@ -0,0 +1,314 @@
/*
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;
using System.IO;
using System.Xml;
using Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeVeil {
class AssemblyResolver {
ModuleDefinition module;
EmbeddedResource bundleData;
EmbeddedResource bundleXmlFile;
TypeDefinition bundleType;
TypeDefinition assemblyManagerType;
TypeDefinition bundleStreamProviderIFace;
TypeDefinition xmlParserType;
TypeDefinition bundledAssemblyType;
TypeDefinition streamProviderType;
List<AssemblyInfo> infos = new List<AssemblyInfo>();
public class AssemblyInfo {
public string fullName;
public string simpleName;
public string extension;
public byte[] data;
public AssemblyInfo(string fullName, string extension, byte[] data) {
this.fullName = fullName;
this.simpleName = Utils.getAssemblySimpleName(fullName);
this.extension = extension;
this.data = data;
}
public override string ToString() {
return fullName;
}
}
public bool CanRemoveTypes {
get {
return bundleType != null &&
assemblyManagerType != null &&
bundleStreamProviderIFace != null &&
xmlParserType != null &&
bundledAssemblyType != null &&
streamProviderType != null;
}
}
public IEnumerable<TypeDefinition> BundleTypes {
get {
var list = new List<TypeDefinition>();
if (!CanRemoveTypes)
return list;
list.Add(bundleType);
list.Add(assemblyManagerType);
list.Add(bundleStreamProviderIFace);
list.Add(xmlParserType);
list.Add(bundledAssemblyType);
list.Add(streamProviderType);
return list;
}
}
public IEnumerable<AssemblyInfo> AssemblyInfos {
get { return infos; }
}
public EmbeddedResource BundleDataResource {
get { return bundleData; }
}
public EmbeddedResource BundleXmlFileResource {
get { return bundleXmlFile; }
}
public AssemblyResolver(ModuleDefinition module) {
this.module = module;
}
public void initialize() {
if (!findTypeAndResources())
return;
findEmbeddedAssemblies();
}
bool findTypeAndResources() {
var bundleDataTmp = DotNetUtils.getResource(module, ".bundle.dat") as EmbeddedResource;
var bundleXmlFileTmp = DotNetUtils.getResource(module, ".bundle.manifest") as EmbeddedResource;
if (bundleDataTmp == null || bundleXmlFileTmp == null)
return false;
var bundleTypeTmp = findBundleType();
if (bundleTypeTmp == null)
return false;
bundleData = bundleDataTmp;
bundleXmlFile = bundleXmlFileTmp;
bundleType = bundleTypeTmp;
findOtherTypes();
return true;
}
void findEmbeddedAssemblies() {
var data = bundleData.GetResourceData();
var doc = new XmlDocument();
doc.Load(XmlReader.Create(bundleXmlFile.GetResourceStream()));
var manifest = doc.DocumentElement;
if (manifest.Name.ToLowerInvariant() != "manifest") {
Log.w("Could not find Manifest element");
return;
}
foreach (var tmp in manifest.ChildNodes) {
var assemblyElem = tmp as XmlElement;
if (assemblyElem == null)
continue;
if (assemblyElem.Name.ToLowerInvariant() != "assembly") {
Log.w("Unknown element: {0}", assemblyElem.Name);
continue;
}
int offset = getAttributeValueInt32(assemblyElem, "offset");
if (offset < 0) {
Log.w("Could not find offset attribute");
continue;
}
var assemblyData = DeobUtils.inflate(data, offset, data.Length - offset, true);
var mod = ModuleDefinition.ReadModule(new MemoryStream(assemblyData));
infos.Add(new AssemblyInfo(mod.Assembly.FullName, DeobUtils.getExtension(mod.Kind), assemblyData));
}
}
static int getAttributeValueInt32(XmlElement elem, string attrName) {
var str = elem.GetAttribute(attrName);
if (string.IsNullOrEmpty(str))
return -1;
int value;
if (!int.TryParse(str, out value))
return -1;
return value;
}
TypeDefinition findBundleType() {
foreach (var type in module.Types) {
if (type.Namespace != "")
continue;
if (type.Fields.Count != 2)
continue;
var ctor = DotNetUtils.getMethod(type, ".ctor");
if (ctor == null || !ctor.IsPrivate)
continue;
if (!DotNetUtils.isMethod(ctor, "System.Void", "(System.Reflection.Assembly)"))
continue;
var initMethodTmp = findInitMethod(type);
if (initMethodTmp == null)
continue;
var getTempFilenameMethod = findGetTempFilenameMethod(type);
if (getTempFilenameMethod == null)
continue;
return type;
}
return null;
}
MethodDefinition findInitMethod(TypeDefinition type) {
foreach (var method in type.Methods) {
if (!method.IsStatic || method.Body == null)
continue;
if (!method.IsPublic && !method.IsAssembly)
continue;
if (!DotNetUtils.isMethod(method, "System.Void", "(System.Reflection.Assembly)"))
continue;
return method;
}
return null;
}
MethodDefinition findGetTempFilenameMethod(TypeDefinition type) {
foreach (var method in type.Methods) {
if (method.IsStatic || method.Body == null)
continue;
if (!method.IsPublic && !method.IsAssembly)
continue;
if (!DotNetUtils.isMethod(method, "System.String", "(System.String)"))
continue;
return method;
}
return null;
}
void findOtherTypes() {
findAssemblyManagerType();
findXmlParserType();
findStreamProviderType();
}
void findAssemblyManagerType() {
if (bundleType == null)
return;
foreach (var field in bundleType.Fields) {
var type = field.FieldType as TypeDefinition;
if (type == null)
continue;
if (type == bundleType)
continue;
if (type.Fields.Count != 2)
continue;
var ctor = DotNetUtils.getMethod(type, ".ctor");
if (ctor == null || ctor.Parameters.Count != 2)
continue;
var iface = ctor.Parameters[1].ParameterType as TypeDefinition;
if (iface == null || !iface.IsInterface)
continue;
assemblyManagerType = type;
bundleStreamProviderIFace = iface;
return;
}
}
void findXmlParserType() {
if (assemblyManagerType == null)
return;
foreach (var field in assemblyManagerType.Fields) {
var type = field.FieldType as TypeDefinition;
if (type == null || type.IsInterface)
continue;
var ctor = DotNetUtils.getMethod(type, ".ctor");
if (!DotNetUtils.isMethod(ctor, "System.Void", "()"))
continue;
if (type.Fields.Count != 1)
continue;
var git = type.Fields[0].FieldType as GenericInstanceType;
if (git == null)
continue;
if (git.ElementType.FullName != "System.Collections.Generic.List`1")
continue;
if (git.GenericArguments.Count != 1)
continue;
var type2 = git.GenericArguments[0] as TypeDefinition;
if (type2 == null)
continue;
xmlParserType = type;
bundledAssemblyType = type2;
return;
}
}
void findStreamProviderType() {
if (bundleType == null)
return;
var ctor = DotNetUtils.getMethod(bundleType, ".ctor");
if (!DotNetUtils.isMethod(ctor, "System.Void", "(System.Reflection.Assembly)"))
return;
foreach (var instr in ctor.Body.Instructions) {
if (instr.OpCode.Code != Code.Newobj)
continue;
var newobjCtor = instr.Operand as MethodDefinition;
if (newobjCtor == null)
continue;
if (newobjCtor.DeclaringType == assemblyManagerType)
continue;
if (!DotNetUtils.isMethod(newobjCtor, "System.Void", "(System.Reflection.Assembly,System.String)"))
continue;
var type = newobjCtor.DeclaringType;
if (type.Interfaces.Count != 1)
continue;
if (type.Interfaces[0] != bundleStreamProviderIFace)
continue;
streamProviderType = type;
return;
}
}
}
}

View File

@ -0,0 +1,286 @@
/*
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;
using Mono.Cecil;
using Mono.MyStuff;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeVeil {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
public const string THE_NAME = "CodeVeil";
public const string THE_TYPE = "cv";
const string DEFAULT_REGEX = @"!^[A-Za-z]{1,2}$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX;
public DeobfuscatorInfo()
: base(DEFAULT_REGEX) {
}
public override string Name {
get { return THE_NAME; }
}
public override string Type {
get { return THE_TYPE; }
}
public override IDeobfuscator createDeobfuscator() {
return new Deobfuscator(new Deobfuscator.Options {
ValidNameRegex = validNameRegex.get(),
});
}
protected override IEnumerable<Option> getOptionsInternal() {
return new List<Option>() {
};
}
}
class Deobfuscator : DeobfuscatorBase {
Options options;
string obfuscatorName = DeobfuscatorInfo.THE_NAME;
MainType mainType;
MethodsDecrypter methodsDecrypter;
ProxyDelegateFinder proxyDelegateFinder;
StringDecrypter stringDecrypter;
AssemblyResolver assemblyResolver;
TypeDefinition killType;
ResourceDecrypter resourceDecrypter;
internal class Options : OptionsBase {
}
public override string Type {
get { return DeobfuscatorInfo.THE_TYPE; }
}
public override string TypeLong {
get { return DeobfuscatorInfo.THE_NAME; }
}
public override string Name {
get { return obfuscatorName; }
}
public Deobfuscator(Options options)
: base(options) {
this.options = options;
StringFeatures = StringFeatures.AllowStaticDecryption | StringFeatures.AllowDynamicDecryption;
}
protected override int detectInternal() {
int val = 0;
int sum = toInt32(mainType.Detected) +
toInt32(methodsDecrypter.Detected) +
toInt32(stringDecrypter.Detected) +
toInt32(proxyDelegateFinder.Detected);
if (sum > 0)
val += 100 + 10 * (sum - 1);
if (killType != null)
val += 10;
return val;
}
protected override void scanForObfuscator() {
findKillType();
mainType = new MainType(module);
mainType.find();
proxyDelegateFinder = new ProxyDelegateFinder(module, mainType);
proxyDelegateFinder.findDelegateCreator();
methodsDecrypter = new MethodsDecrypter(mainType);
methodsDecrypter.find();
stringDecrypter = new StringDecrypter(module, mainType);
stringDecrypter.find();
var version = detectVersion();
if (!string.IsNullOrEmpty(version))
obfuscatorName = obfuscatorName + " " + version;
}
string detectVersion() {
if (mainType.Detected) {
switch (mainType.Version) {
case ObfuscatorVersion.Unknown:
return null;
case ObfuscatorVersion.V3:
return "3.x";
case ObfuscatorVersion.V4_0:
return "4.0";
case ObfuscatorVersion.V4_1:
return "4.1";
case ObfuscatorVersion.V5_0:
return "5.0";
default:
throw new ApplicationException("Unknown version");
}
}
return null;
}
void findKillType() {
foreach (var type in module.Types) {
if (type.FullName == "____KILL") {
killType = type;
break;
}
}
}
public override bool getDecryptedModule(ref byte[] newFileData, ref Dictionary<uint, DumpedMethod> dumpedMethods) {
if (!methodsDecrypter.Detected)
return false;
var fileData = DeobUtils.readModule(module);
if (!methodsDecrypter.decrypt(fileData, ref dumpedMethods))
return false;
newFileData = fileData;
return true;
}
public override IDeobfuscator moduleReloaded(ModuleDefinition module) {
var newOne = new Deobfuscator(options);
newOne.setModule(module);
newOne.mainType = new MainType(module, mainType);
newOne.methodsDecrypter = new MethodsDecrypter(mainType, methodsDecrypter);
newOne.stringDecrypter = new StringDecrypter(module, newOne.mainType, stringDecrypter);
newOne.proxyDelegateFinder = new ProxyDelegateFinder(module, newOne.mainType, proxyDelegateFinder);
newOne.killType = DeobUtils.lookup(module, killType, "Could not find KILL type");
return newOne;
}
public override void deobfuscateBegin() {
base.deobfuscateBegin();
addTypeToBeRemoved(killType, "KILL type");
mainType.initialize();
foreach (var initMethod in mainType.OtherInitMethods) {
addCctorInitCallToBeRemoved(initMethod);
addCtorInitCallToBeRemoved(initMethod);
}
if (Operations.DecryptStrings != OpDecryptString.None) {
stringDecrypter.initialize();
staticStringInliner.add(stringDecrypter.DecryptMethod, (method, args) => {
return stringDecrypter.decrypt((int)args[0]);
});
DeobfuscatedFile.stringDecryptersAdded();
addModuleCctorInitCallToBeRemoved(stringDecrypter.InitMethod);
addCallToBeRemoved(mainType.getInitStringDecrypterMethod(stringDecrypter.InitMethod), stringDecrypter.InitMethod);
addTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
}
assemblyResolver = new AssemblyResolver(module);
assemblyResolver.initialize();
dumpEmbeddedAssemblies();
removeTamperDetection();
proxyDelegateFinder.initialize();
proxyDelegateFinder.find();
resourceDecrypter = new ResourceDecrypter(module);
resourceDecrypter.initialize();
resourceDecrypter.decrypt();
if (resourceDecrypter.CanRemoveTypes) {
addTypeToBeRemoved(resourceDecrypter.ResourceFlagsType, "Obfuscator ResourceFlags type");
addTypeToBeRemoved(resourceDecrypter.ResType, "Obfuscator Res type");
addTypeToBeRemoved(resourceDecrypter.ResourceEnumeratorType, "Obfuscator ResourceEnumerator type");
addTypeToBeRemoved(resourceDecrypter.EncryptedResourceReaderType, "Obfuscator EncryptedResourceReader type");
addTypeToBeRemoved(resourceDecrypter.EncryptedResourceSetType, "Obfuscator EncryptedResourceSet type");
addTypeToBeRemoved(resourceDecrypter.EncryptedResourceStreamType, "Obfuscator EncryptedResourceStream type");
}
}
void removeTamperDetection() {
var tamperDetection = new TamperDetection(module, mainType);
tamperDetection.initialize();
foreach (var tamperDetectionMethod in tamperDetection.Methods)
addCctorInitCallToBeRemoved(tamperDetectionMethod);
addTypeToBeRemoved(tamperDetection.Type, "Tamper detection type");
}
void dumpEmbeddedAssemblies() {
foreach (var info in assemblyResolver.AssemblyInfos)
DeobfuscatedFile.createAssemblyFile(info.data, info.simpleName, info.extension);
addResourceToBeRemoved(assemblyResolver.BundleDataResource, "Embedded assemblies resource");
addResourceToBeRemoved(assemblyResolver.BundleXmlFileResource, "Embedded assemblies XML file resource");
addTypesToBeRemoved(assemblyResolver.BundleTypes, "Obfuscator assembly bundle types");
}
public override void deobfuscateMethodBegin(Blocks blocks) {
proxyDelegateFinder.deobfuscate(blocks);
base.deobfuscateMethodBegin(blocks);
}
public override void deobfuscateMethodEnd(Blocks blocks) {
mainType.removeInitCall(blocks);
resourceDecrypter.deobfuscate(blocks);
base.deobfuscateMethodEnd(blocks);
}
public override void deobfuscateEnd() {
bool canRemoveProxyTypes = proxyDelegateFinder.CanRemoveTypes;
if (!mainType.Detected) {
}
else if (mainType.Version >= ObfuscatorVersion.V5_0) {
if (!proxyDelegateFinder.FoundProxyType || canRemoveProxyTypes)
addTypeToBeRemoved(mainType.Type, "Main CV type");
}
else {
var type = mainType.Type;
if (!type.HasNestedTypes && !type.HasProperties && !type.HasEvents && !type.HasFields)
addTypeToBeRemoved(type, "Main CV type");
else {
foreach (var method in type.Methods)
addMethodToBeRemoved(method, "CV main type method");
}
}
removeTypesWithInvalidBaseTypes();
removeProxyDelegates(proxyDelegateFinder, canRemoveProxyTypes);
if (canRemoveProxyTypes) {
addTypeToBeRemoved(proxyDelegateFinder.IlGeneratorType, "Obfuscator proxy method ILGenerator type");
addTypeToBeRemoved(proxyDelegateFinder.FieldInfoType, "Obfuscator proxy method FieldInfo type");
addTypeToBeRemoved(proxyDelegateFinder.MethodInfoType, "Obfuscator proxy method MethodInfo type");
}
base.deobfuscateEnd();
}
public override IEnumerable<string> getStringDecrypterMethods() {
var list = new List<string>();
if (stringDecrypter.DecryptMethod != null)
list.Add(stringDecrypter.DecryptMethod.MetadataToken.ToInt32().ToString("X8"));
return list;
}
}
}

View File

@ -0,0 +1,88 @@
/*
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.code.deobfuscators.CodeVeil {
class ErexResourceReader {
BinaryReader reader;
uint[] key;
public ErexResourceReader(Stream stream) {
reader = new BinaryReader(stream);
}
public byte[] decrypt() {
if (reader.ReadUInt32() != 0x58455245)
throw new InvalidDataException("Invalid EREX sig");
if (reader.ReadInt32() > 1)
throw new ApplicationException("Invalid EREX file");
byte flags = reader.ReadByte();
bool isEncrypted = (flags & 1) != 0;
bool isDeflated = (flags & 2) != 0;
int length = reader.ReadInt32();
if (length < 0)
throw new ApplicationException("Invalid length");
if (isEncrypted)
readKey();
if (isDeflated)
reader = new BinaryReader(inflate(length));
if (isEncrypted)
reader = new BinaryReader(decrypt(length));
return reader.ReadBytes(length);
}
void readKey() {
key = new uint[reader.ReadByte()];
for (int i = 0; i < key.Length; i++)
key[i] = reader.ReadUInt32();
}
Stream inflate(int length) {
var data = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
return new MemoryStream(DeobUtils.inflate(data, true));
}
Stream decrypt(int length) {
var block = new uint[4];
var decrypted = new byte[16];
var outStream = new MemoryStream(length);
while (reader.BaseStream.Position < reader.BaseStream.Length) {
block[0] = reader.ReadUInt32();
block[1] = reader.ReadUInt32();
block[2] = reader.ReadUInt32();
block[3] = reader.ReadUInt32();
DeobUtils.xxteaDecrypt(block, key);
Buffer.BlockCopy(block, 0, decrypted, 0, decrypted.Length);
outStream.Write(decrypted, 0, decrypted.Length);
}
outStream.Position = 0;
return outStream;
}
}
}

View File

@ -0,0 +1,29 @@
/*
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;
namespace de4dot.code.deobfuscators.CodeVeil {
[Serializable]
class InvalidDataException : Exception {
public InvalidDataException(string msg)
: base(msg) {
}
}
}

View File

@ -0,0 +1,268 @@
/*
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;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeVeil {
// Detects the type CV adds to the assembly that gets called from <Module>::.cctor.
class MainType {
ModuleDefinition module;
TypeDefinition theType;
MethodDefinition initMethod;
MethodDefinition tamperCheckMethod;
ObfuscatorVersion obfuscatorVersion = ObfuscatorVersion.Unknown;
List<int> rvas = new List<int>(); // _stub and _executive
List<MethodDefinition> otherInitMethods = new List<MethodDefinition>();
public bool Detected {
get { return theType != null; }
}
public ObfuscatorVersion Version {
get { return obfuscatorVersion; }
}
public TypeDefinition Type {
get { return theType; }
}
public MethodDefinition InitMethod {
get { return initMethod; }
}
public List<MethodDefinition> OtherInitMethods {
get { return otherInitMethods; }
}
public MethodDefinition TamperCheckMethod {
get { return tamperCheckMethod; }
}
public List<int> Rvas {
get { return rvas; }
}
public MainType(ModuleDefinition module) {
this.module = module;
}
public MainType(ModuleDefinition module, MainType oldOne) {
this.module = module;
this.theType = lookup(oldOne.theType, "Could not find main type");
this.initMethod = lookup(oldOne.initMethod, "Could not find main type init method");
this.tamperCheckMethod = lookup(oldOne.tamperCheckMethod, "Could not find tamper detection method");
this.obfuscatorVersion = oldOne.obfuscatorVersion;
this.rvas = oldOne.rvas;
foreach (var otherInitMethod in otherInitMethods)
otherInitMethods.Add(lookup(otherInitMethod, "Could not find otherInitMethod"));
}
T lookup<T>(T def, string errorMessage) where T : MemberReference {
return DeobUtils.lookup(module, def, errorMessage);
}
public void find() {
var cctor = DotNetUtils.getModuleTypeCctor(module);
if (cctor == null)
return;
var instrs = cctor.Body.Instructions;
for (int i = 0; i < instrs.Count - 2; i++) {
var ldci4_1 = instrs[i];
if (!DotNetUtils.isLdcI4(ldci4_1))
continue;
var ldci4_2 = instrs[i + 1];
if (!DotNetUtils.isLdcI4(ldci4_2))
continue;
var call = instrs[i + 2];
if (call.OpCode.Code != Code.Call)
continue;
var initMethodTmp = call.Operand as MethodDefinition;
ObfuscatorVersion obfuscatorVersionTmp;
if (!checkInitMethod(initMethodTmp, out obfuscatorVersionTmp))
continue;
if (!checkMethodsType(initMethodTmp.DeclaringType))
continue;
obfuscatorVersion = obfuscatorVersionTmp;
theType = initMethodTmp.DeclaringType;
initMethod = initMethodTmp;
break;
}
}
static string[] fieldTypesV5 = new string[] {
"System.Byte[]",
"System.Collections.Generic.List`1<System.Delegate>",
"System.Runtime.InteropServices.GCHandle",
};
bool checkInitMethod(MethodDefinition initMethod, out ObfuscatorVersion obfuscatorVersionTmp) {
obfuscatorVersionTmp = ObfuscatorVersion.Unknown;
if (initMethod == null)
return false;
if (initMethod.Body == null)
return false;
if (!initMethod.IsStatic)
return false;
if (!DotNetUtils.isMethod(initMethod, "System.Void", "(System.Boolean,System.Boolean)"))
return false;
if (hasCodeString(initMethod, "E_FullTrust")) {
if (DotNetUtils.getPInvokeMethod(initMethod.DeclaringType, "user32", "CallWindowProcW") != null)
obfuscatorVersionTmp = ObfuscatorVersion.V4_1;
else
obfuscatorVersionTmp = ObfuscatorVersion.V4_0;
}
else if (hasCodeString(initMethod, "Full Trust Required"))
obfuscatorVersionTmp = ObfuscatorVersion.V3;
else if (initMethod.DeclaringType.HasNestedTypes && new FieldTypes(initMethod.DeclaringType).all(fieldTypesV5))
obfuscatorVersionTmp = ObfuscatorVersion.V5_0;
else
return false;
return true;
}
static bool hasCodeString(MethodDefinition method, string str) {
foreach (var s in DotNetUtils.getCodeStrings(method)) {
if (s == str)
return true;
}
return false;
}
bool checkMethodsType(TypeDefinition type) {
rvas = new List<int>();
var fields = getRvaFields(type);
if (fields.Count < 2) // RVAs for executive and stub are always present if encrypted methods
return true;
foreach (var field in fields)
rvas.Add(field.RVA);
return true;
}
static List<FieldDefinition> getRvaFields(TypeDefinition type) {
var fields = new List<FieldDefinition>();
foreach (var field in type.Fields) {
if (field.FieldType.EType != ElementType.U1 && field.FieldType.EType != ElementType.U4)
continue;
if (field.RVA == 0)
continue;
fields.Add(field);
}
return fields;
}
public void initialize() {
if (theType == null)
return;
tamperCheckMethod = findTamperCheckMethod();
otherInitMethods = findOtherInitMethods();
}
MethodDefinition findTamperCheckMethod() {
foreach (var method in theType.Methods) {
if (!method.IsStatic || method.Body == null)
continue;
if (!DotNetUtils.isMethod(method, "System.Void", "(System.Reflection.Assembly,System.UInt64)"))
continue;
return method;
}
return null;
}
List<MethodDefinition> findOtherInitMethods() {
var list = new List<MethodDefinition>();
foreach (var method in theType.Methods) {
if (!method.IsStatic)
continue;
if (method.Name == ".cctor")
continue;
if (!DotNetUtils.isMethod(method, "System.Void", "()"))
continue;
list.Add(method);
}
return list;
}
public MethodDefinition getInitStringDecrypterMethod(MethodDefinition stringDecrypterInitMethod) {
if (stringDecrypterInitMethod == null)
return null;
if (theType == null)
return null;
foreach (var method in theType.Methods) {
if (!method.IsStatic || method.Body == null)
continue;
if (callsMethod(method, stringDecrypterInitMethod))
return method;
}
return null;
}
bool callsMethod(MethodDefinition methodToCheck, MethodDefinition calledMethod) {
foreach (var info in DotNetUtils.getCalledMethods(module, methodToCheck)) {
if (info.Item2 == calledMethod)
return true;
}
return false;
}
public void removeInitCall(Blocks blocks) {
if (initMethod == null || theType == null)
return;
if (blocks.Method.Name != ".cctor")
return;
if (blocks.Method.DeclaringType != DotNetUtils.getModuleType(module))
return;
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count - 2; i++) {
if (!instrs[i].isLdcI4())
continue;
if (!instrs[i + 1].isLdcI4())
continue;
var call = instrs[i + 2];
if (call.OpCode.Code != Code.Call)
continue;
if (call.Operand != initMethod)
continue;
block.remove(i, 3);
return;
}
}
}
}
}

View File

@ -0,0 +1,312 @@
/*
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;
using System.IO;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
using Mono.MyStuff;
using de4dot.blocks;
using de4dot.code.PE;
namespace de4dot.code.deobfuscators.CodeVeil {
class MethodsDecrypter {
MainType mainType;
IDecrypter decrypter;
interface IDecrypter {
void initialize(byte[] methodsData);
bool decrypt(BinaryReader fileDataReader, DumpedMethod dm);
}
class Decrypter : IDecrypter {
BinaryReader methodsDataReader;
public virtual void initialize(byte[] methodsData) {
methodsDataReader = new BinaryReader(new MemoryStream(methodsData));
}
public virtual bool decrypt(BinaryReader fileDataReader, DumpedMethod dm) {
if (fileDataReader.ReadByte() != 0x2A)
return false; // Not a RET
int methodsDataOffset = DeobUtils.readVariableLengthInt32(fileDataReader);
methodsDataReader.BaseStream.Position = methodsDataOffset;
dm.mhCodeSize = (uint)DeobUtils.readVariableLengthInt32(methodsDataReader);
dm.code = methodsDataReader.ReadBytes((int)dm.mhCodeSize);
if ((dm.mhFlags & 8) != 0)
dm.extraSections = readExtraSections(methodsDataReader);
if (!decryptCode(dm))
return false;
return true;
}
protected virtual bool decryptCode(DumpedMethod dm) {
return true;
}
static void align(BinaryReader reader, int alignment) {
reader.BaseStream.Position = (reader.BaseStream.Position + alignment - 1) & ~(alignment - 1);
}
static byte[] readExtraSections(BinaryReader reader) {
align(reader, 4);
int startPos = (int)reader.BaseStream.Position;
parseSection(reader);
int size = (int)reader.BaseStream.Position - startPos;
reader.BaseStream.Position = startPos;
return reader.ReadBytes(size);
}
static void parseSection(BinaryReader reader) {
byte flags;
do {
align(reader, 4);
flags = reader.ReadByte();
if ((flags & 1) == 0)
throw new ApplicationException("Not an exception section");
if ((flags & 0x3E) != 0)
throw new ApplicationException("Invalid bits set");
if ((flags & 0x40) != 0) {
reader.BaseStream.Position--;
int num = (int)(reader.ReadUInt32() >> 8) / 24;
reader.BaseStream.Position += num * 24;
}
else {
int num = reader.ReadByte() / 12;
reader.BaseStream.Position += 2 + num * 12;
}
} while ((flags & 0x80) != 0);
}
}
class DecrypterV5 : Decrypter {
byte[] decryptKey;
public override void initialize(byte[] methodsData) {
var data = DeobUtils.inflate(methodsData, true);
decryptKey = BitConverter.GetBytes(BitConverter.ToUInt32(data, 0));
var newMethodsData = new byte[data.Length - 4];
Array.Copy(data, 4, newMethodsData, 0, newMethodsData.Length);
base.initialize(newMethodsData);
}
protected override bool decryptCode(DumpedMethod dm) {
var code = dm.code;
for (int i = 0; i < code.Length; i++) {
for (int j = 0; j < 4 && i + j < code.Length; j++)
code[i + j] ^= decryptKey[j];
}
return true;
}
}
public bool Detected {
get { return decrypter != null; }
}
public MethodsDecrypter(MainType mainType) {
this.mainType = mainType;
}
public MethodsDecrypter(MainType mainType, MethodsDecrypter oldOne) {
this.mainType = mainType;
}
public void find() {
if (!mainType.Detected)
return;
switch (mainType.Version) {
case ObfuscatorVersion.Unknown:
break;
case ObfuscatorVersion.V3:
case ObfuscatorVersion.V4_0:
case ObfuscatorVersion.V4_1:
decrypter = new Decrypter();
break;
case ObfuscatorVersion.V5_0:
decrypter = new DecrypterV5();
break;
default:
throw new ApplicationException("Unknown version");
}
}
public bool decrypt(byte[] fileData, ref Dictionary<uint, DumpedMethod> dumpedMethods) {
if (decrypter == null)
return false;
var peImage = new PeImage(fileData);
if (peImage.Sections.Length <= 0)
return false;
var methodsData = findMethodsData(peImage, fileData);
if (methodsData == null)
return false;
decrypter.initialize(methodsData);
dumpedMethods = createDumpedMethods(peImage, fileData, methodsData);
if (dumpedMethods == null)
return false;
return true;
}
Dictionary<uint, DumpedMethod> createDumpedMethods(PeImage peImage, byte[] fileData, byte[] methodsData) {
var dumpedMethods = new Dictionary<uint, DumpedMethod>();
var methodsDataReader = new BinaryReader(new MemoryStream(methodsData));
var fileDataReader = new BinaryReader(new MemoryStream(fileData));
var metadataTables = peImage.Cor20Header.createMetadataTables();
var methodDef = metadataTables.getMetadataType(MetadataIndex.iMethodDef);
uint methodDefOffset = methodDef.fileOffset;
for (int i = 0; i < methodDef.rows; i++, methodDefOffset += methodDef.totalSize) {
uint bodyRva = peImage.offsetReadUInt32(methodDefOffset);
if (bodyRva == 0)
continue;
uint bodyOffset = peImage.rvaToOffset(bodyRva);
var dm = new DumpedMethod();
dm.token = (uint)(0x06000001 + i);
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);
byte b = peImage.offsetReadByte(bodyOffset);
uint codeOffset;
if ((b & 3) == 2) {
if (b != 2)
continue; // not zero byte code size
dm.mhFlags = 2;
dm.mhMaxStack = 8;
dm.mhLocalVarSigTok = 0;
codeOffset = bodyOffset + 1;
}
else {
if (peImage.offsetReadUInt32(bodyOffset + 4) != 0)
continue; // not zero byte code size
dm.mhFlags = peImage.offsetReadUInt16(bodyOffset);
dm.mhMaxStack = peImage.offsetReadUInt16(bodyOffset + 2);
dm.mhLocalVarSigTok = peImage.offsetReadUInt32(bodyOffset + 8);
codeOffset = bodyOffset + (uint)(dm.mhFlags >> 12) * 4;
}
fileDataReader.BaseStream.Position = codeOffset;
if (!decrypter.decrypt(fileDataReader, dm))
continue;
dumpedMethods[dm.token] = dm;
}
return dumpedMethods;
}
// xor eax, eax / inc eax / pop esi edi edx ecx ebx / leave / ret 0Ch or 10h
static byte[] initializeMethodEnd = new byte[] {
0x33, 0xC0, 0x40, 0x5E, 0x5F, 0x5A, 0x59, 0x5B, 0xC9, 0xC2,
};
byte[] findMethodsData(PeImage peImage, byte[] fileData) {
var section = peImage.Sections[0];
var reader = new BinaryReader(new MemoryStream(fileData));
const int RVA_EXECUTIVE_OFFSET = 1 * 4;
const int ENC_CODE_OFFSET = 6 * 4;
int lastOffset = (int)(section.pointerToRawData + section.sizeOfRawData);
for (int offset = getStartOffset(peImage); offset < lastOffset; ) {
offset = findSig(fileData, offset, lastOffset, initializeMethodEnd);
if (offset < 0)
return null;
offset += initializeMethodEnd.Length;
short retImm16 = BitConverter.ToInt16(fileData, offset);
if (retImm16 != 0x0C && retImm16 != 0x10)
continue;
offset += 2;
if (offset + ENC_CODE_OFFSET + 4 > lastOffset)
return null;
// rva is 0 when the assembly has been embedded
int rva = BitConverter.ToInt32(fileData, offset + RVA_EXECUTIVE_OFFSET);
if (rva != 0 && mainType.Rvas.IndexOf(rva) < 0)
continue;
int relOffs = BitConverter.ToInt32(fileData, offset + ENC_CODE_OFFSET);
if (relOffs <= 0 || relOffs >= section.sizeOfRawData)
continue;
reader.BaseStream.Position = section.pointerToRawData + relOffs;
int size = DeobUtils.readVariableLengthInt32(reader);
int endOffset = relOffs + size;
if (endOffset < relOffs || endOffset > section.sizeOfRawData)
continue;
return reader.ReadBytes(size);
}
return null;
}
int getStartOffset(PeImage peImage) {
int minOffset = int.MaxValue;
foreach (var rva in mainType.Rvas) {
int rvaOffs = (int)peImage.rvaToOffset((uint)rva);
if (rvaOffs < minOffset)
minOffset = rvaOffs;
}
return minOffset == int.MaxValue ? 0 : minOffset;
}
static int findSig(byte[] fileData, int offset, int lastOffset, byte[] sig) {
for (int i = offset; i < lastOffset - sig.Length + 1; i++) {
if (fileData[i] != sig[0])
continue;
if (compare(fileData, i + 1, sig, 1, sig.Length - 1))
return i;
}
return -1;
}
static bool compare(byte[] a1, int i1, byte[] a2, int i2, int len) {
for (int i = 0; i < len; i++) {
if (a1[i1++] != a2[i2++])
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,28 @@
/*
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.code.deobfuscators.CodeVeil {
enum ObfuscatorVersion {
Unknown,
V3,
V4_0,
V4_1,
V5_0,
}
}

View File

@ -0,0 +1,286 @@
/*
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;
using System.IO;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeVeil {
class ProxyDelegateFinder : ProxyDelegateFinderBase {
MainType mainType;
Info info = new Info();
BinaryReader reader;
class Info {
public TypeDefinition proxyType;
public MethodDefinition initMethod;
public FieldDefinition dataField;
public TypeDefinition ilgeneratorType;
public TypeDefinition fieldInfoType;
public TypeDefinition methodInfoType;
}
class Context {
public int offset;
public Context(int offset) {
this.offset = offset;
}
}
public bool FoundProxyType {
get { return info.proxyType != null; }
}
public bool CanRemoveTypes {
get {
return info.proxyType != null &&
info.ilgeneratorType != null &&
info.fieldInfoType != null &&
info.methodInfoType != null;
}
}
public TypeDefinition IlGeneratorType {
get { return info.ilgeneratorType; }
}
public TypeDefinition FieldInfoType {
get { return info.fieldInfoType; }
}
public TypeDefinition MethodInfoType {
get { return info.methodInfoType; }
}
public ProxyDelegateFinder(ModuleDefinition module, MainType mainType)
: base(module) {
this.mainType = mainType;
}
public ProxyDelegateFinder(ModuleDefinition module, MainType mainType, ProxyDelegateFinder oldOne)
: base(module, oldOne) {
this.mainType = mainType;
info.proxyType = lookup(oldOne.info.proxyType, "Could not find proxyType");
info.initMethod = lookup(oldOne.info.initMethod, "Could not find initMethod");
info.dataField = lookup(oldOne.info.dataField, "Could not find dataField");
info.ilgeneratorType = lookup(oldOne.info.ilgeneratorType, "Could not find ilgeneratorType");
info.fieldInfoType = lookup(oldOne.info.fieldInfoType, "Could not find fieldInfoType");
info.methodInfoType = lookup(oldOne.info.methodInfoType, "Could not find methodInfoType");
}
protected override object checkCctor(TypeDefinition type, MethodDefinition cctor) {
var instrs = cctor.Body.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
var ldci4 = instrs[i];
if (!DotNetUtils.isLdcI4(ldci4))
continue;
var call = instrs[i + 1];
if (call.OpCode.Code != Code.Call)
continue;
if (call.Operand != info.initMethod)
continue;
int offset = DotNetUtils.getLdcI4Value(ldci4);
reader.BaseStream.Position = offset;
int rid = DeobUtils.readVariableLengthInt32(reader);
if (rid != type.MetadataToken.RID)
throw new ApplicationException("Invalid RID");
return string.Empty; // It's non-null
}
return null;
}
protected override void onFoundProxyDelegate(TypeDefinition type) {
}
protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) {
byte flags = reader.ReadByte();
int methodToken = 0x06000000 + ((flags & 0x3F) << 24) + DeobUtils.readVariableLengthInt32(reader);
int genericTypeToken = (flags & 0x40) == 0 ? -1 : 0x1B000000 + DeobUtils.readVariableLengthInt32(reader);
callOpcode = (flags & 0x80) != 0 ? OpCodes.Callvirt : OpCodes.Call;
calledMethod = module.LookupToken(methodToken) as MethodReference;
if (calledMethod == null)
throw new ApplicationException("Could not find method");
if (genericTypeToken != -1 && calledMethod.DeclaringType.MetadataToken.ToInt32() != genericTypeToken)
throw new ApplicationException("Invalid declaring type token");
}
public void findDelegateCreator() {
if (!mainType.Detected)
return;
var infoTmp = new Info();
if (!initializeInfo(infoTmp, mainType.Type))
return;
info = infoTmp;
setDelegateCreatorMethod(info.initMethod);
}
bool initializeInfo(Info infoTmp, TypeDefinition type) {
foreach (var dtype in type.NestedTypes) {
var cctor = DotNetUtils.getMethod(dtype, ".cctor");
if (cctor == null)
continue;
if (!initProxyType(infoTmp, cctor))
continue;
return true;
}
return false;
}
bool initProxyType(Info infoTmp, MethodDefinition method) {
foreach (var call in DotNetUtils.getCalledMethods(module, method)) {
if (!call.Item2.IsStatic)
continue;
if (!DotNetUtils.isMethod(call.Item2, "System.Void", "(System.Int32)"))
continue;
if (!checkProxyType(infoTmp, call.Item1))
continue;
infoTmp.proxyType = call.Item1;
infoTmp.initMethod = call.Item2;
return true;
}
return false;
}
static string[] requiredFields = new string[] {
"System.Byte[]",
"System.Int32",
"System.ModuleHandle",
"System.Reflection.Emit.OpCode",
"System.Reflection.Emit.OpCode[]",
};
bool checkProxyType(Info infoTmp, TypeDefinition type) {
if (type.NestedTypes.Count != 1)
return false;
if (!new FieldTypes(type).all(requiredFields))
return false;
var fields = getRvaFields(type);
if (fields.Count != 1)
return false;
var field = fields[0];
var fieldType = DotNetUtils.getType(module, field.FieldType);
if (type.NestedTypes.IndexOf(fieldType) < 0)
return false;
if (field.InitialValue == null || field.InitialValue.Length == 0)
return false;
infoTmp.dataField = field;
return true;
}
static List<FieldDefinition> getRvaFields(TypeDefinition type) {
var fields = new List<FieldDefinition>();
foreach (var field in type.Fields) {
if (field.RVA != 0)
fields.Add(field);
}
return fields;
}
protected override IEnumerable<TypeDefinition> getDelegateTypes() {
if (!mainType.Detected)
return new List<TypeDefinition>();
return mainType.Type.NestedTypes;
}
public void initialize() {
if (info.dataField == null)
return;
findOtherTypes();
var decompressed = DeobUtils.inflate(info.dataField.InitialValue, true);
reader = new BinaryReader(new MemoryStream(decompressed));
info.dataField.FieldType = module.TypeSystem.Byte;
info.dataField.InitialValue = new byte[1];
}
void findOtherTypes() {
if (info.proxyType == null)
return;
foreach (var method in info.proxyType.Methods) {
if (method.Parameters.Count != 4)
continue;
if (method.Parameters[2].ParameterType.FullName != "System.Type[]")
continue;
var methodType = method.Parameters[0].ParameterType as TypeDefinition;
var fieldType = method.Parameters[1].ParameterType as TypeDefinition;
var ilgType = method.Parameters[3].ParameterType as TypeDefinition;
if (!checkMethodType(methodType))
continue;
if (!checkFieldType(fieldType))
continue;
if (!checkIlGeneratorType(ilgType))
continue;
info.ilgeneratorType = ilgType;
info.methodInfoType = methodType;
info.fieldInfoType = fieldType;
}
}
bool checkMethodType(TypeDefinition type) {
if (type == null || type.BaseType == null || type.BaseType.EType != ElementType.Object)
return false;
if (type.Fields.Count != 1)
return false;
if (DotNetUtils.getField(type, "System.Reflection.MethodInfo") == null)
return false;
return true;
}
bool checkFieldType(TypeDefinition type) {
if (type == null || type.BaseType == null || type.BaseType.EType != ElementType.Object)
return false;
if (DotNetUtils.getField(type, "System.Reflection.FieldInfo") == null)
return false;
return true;
}
bool checkIlGeneratorType(TypeDefinition type) {
if (type == null || type.BaseType == null || type.BaseType.EType != ElementType.Object)
return false;
if (type.Fields.Count != 1)
return false;
if (DotNetUtils.getField(type, "System.Reflection.Emit.ILGenerator") == null)
return false;
return true;
}
}
}

View File

@ -0,0 +1,149 @@
/*
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 Mono.Cecil;
using de4dot.code.resources;
namespace de4dot.code.deobfuscators.CodeVeil {
class ResourceConverter {
ModuleDefinition module;
ResourceInfo[] infos;
ResourceDataCreator dataCreator;
public ResourceConverter(ModuleDefinition module, ResourceInfo[] infos) {
this.module = module;
this.dataCreator = new ResourceDataCreator(module);
this.infos = infos;
}
public byte[] convert() {
var resources = new ResourceElementSet();
foreach (var info in infos)
resources.add(convert(info));
var memStream = new MemoryStream();
ResourceWriter.write(module, memStream, resources);
return memStream.ToArray();
}
ResourceElement convert(ResourceInfo info) {
var reader = info.dataReader;
reader.BaseStream.Position = info.offset;
IResourceData resourceData;
int type = (info.flags & 0x7F);
switch (type) {
case 1: // bool
resourceData = dataCreator.create(reader.ReadBoolean());
break;
case 2: // byte
resourceData = dataCreator.create(reader.ReadByte());
break;
case 3: // byte[]
resourceData = dataCreator.create(reader.ReadBytes(info.length));
break;
case 4: // char[]
resourceData = dataCreator.create(reader.ReadChars(info.length));
break;
case 5: // sbyte
resourceData = dataCreator.create(reader.ReadSByte());
break;
case 6: // char
resourceData = dataCreator.create(reader.ReadChar());
break;
case 7: // decimal
resourceData = dataCreator.create(reader.ReadDecimal());
break;
case 8: // double
resourceData = dataCreator.create(reader.ReadDouble());
break;
case 9: // short
resourceData = dataCreator.create(reader.ReadInt16());
break;
case 10: // int
resourceData = dataCreator.create(reader.ReadInt32());
break;
case 11: // long
resourceData = dataCreator.create(reader.ReadInt64());
break;
case 12: // float
resourceData = dataCreator.create(reader.ReadSingle());
break;
case 13: // string
resourceData = dataCreator.create(reader.ReadString());
break;
case 14: // ushort
resourceData = dataCreator.create(reader.ReadUInt16());
break;
case 15: // uint
resourceData = dataCreator.create(reader.ReadUInt32());
break;
case 16: // ulong
resourceData = dataCreator.create(reader.ReadUInt64());
break;
case 17: // DateTime
resourceData = dataCreator.create(DateTime.FromBinary(reader.ReadInt64()));
break;
case 18: // TimeSpan
resourceData = dataCreator.create(TimeSpan.FromTicks(reader.ReadInt64()));
break;
case 19: // Icon
resourceData = dataCreator.createIcon(reader.ReadBytes(info.length));
break;
case 20: // Image
resourceData = dataCreator.createImage(reader.ReadBytes(info.length));
break;
case 31: // binary
resourceData = dataCreator.createSerialized(reader.ReadBytes(info.length));
break;
case 21: // Point (CV doesn't restore this type)
default:
throw new Exception("Unknown type");
}
return new ResourceElement() {
Name = info.name,
ResourceData = resourceData,
};
}
}
}

View File

@ -0,0 +1,395 @@
/*
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 Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeVeil {
class ResourceDecrypter {
ModuleDefinition module;
TypeDefinition encryptedResourceStreamType;
MethodDefinition getManifestResourceStreamMethod1;
MethodDefinition getManifestResourceStreamMethod2;
TypeDefinition encryptedResourceSetType;
MethodDefinition encryptedResourceSet_GetDefaultReader;
TypeDefinition encryptedResourceReaderType;
GenericInstanceType encryptedResourceReaderTypeDict;
TypeDefinition resType;
MethodDefinition resTypeCtor;
TypeDefinition resourceFlagsType;
TypeDefinition resourceEnumeratorType;
MethodReference Assembly_GetManifestResourceStream1;
MethodReference Assembly_GetManifestResourceStream2;
public bool CanRemoveTypes {
get {
return EncryptedResourceStreamType != null &&
EncryptedResourceSetType != null &&
EncryptedResourceReaderType != null &&
ResType != null &&
ResourceFlagsType != null &&
ResourceEnumeratorType != null;
}
}
public TypeDefinition EncryptedResourceStreamType {
get { return encryptedResourceStreamType; }
}
public TypeDefinition EncryptedResourceSetType {
get { return encryptedResourceSetType; }
}
public TypeDefinition EncryptedResourceReaderType {
get { return encryptedResourceReaderType; }
}
public TypeDefinition ResType {
get { return resType; }
}
public TypeDefinition ResourceFlagsType {
get { return resourceFlagsType; }
}
public TypeDefinition ResourceEnumeratorType {
get { return resourceEnumeratorType; }
}
public ResourceDecrypter(ModuleDefinition module) {
this.module = module;
}
public void initialize() {
initGetManifestMethods();
findEncryptedResourceStreamType();
findEncryptedResourceSet();
findEncryptedResourceReader();
findResType();
findResourceFlags();
findResourceEnumerator();
}
void initGetManifestMethods() {
var assemblyType = new TypeReference("System.Reflection", "Assembly", module, module.TypeSystem.Corlib);
var typeType = new TypeReference("System", "Type", module, module.TypeSystem.Corlib);
var streamType = new TypeReference("System.IO", "Stream", module, module.TypeSystem.Corlib);
Assembly_GetManifestResourceStream1 = new MethodReference("GetManifestResourceStream", streamType, assemblyType);
Assembly_GetManifestResourceStream1.HasThis = true;
Assembly_GetManifestResourceStream1.Parameters.Add(new ParameterDefinition(module.TypeSystem.String));
Assembly_GetManifestResourceStream2 = new MethodReference("GetManifestResourceStream", streamType, assemblyType);
Assembly_GetManifestResourceStream2.HasThis = true;
Assembly_GetManifestResourceStream2.Parameters.Add(new ParameterDefinition(typeType));
Assembly_GetManifestResourceStream2.Parameters.Add(new ParameterDefinition(module.TypeSystem.String));
}
void findResourceEnumerator() {
if (encryptedResourceReaderType == null)
return;
var resourceEnumeratorType_fields = new string[] {
"System.Collections.DictionaryEntry",
"System.Collections.IDictionaryEnumerator",
"System.Boolean",
encryptedResourceReaderType.FullName,
};
foreach (var type in module.Types) {
if (type.Namespace != "")
continue;
if (type.BaseType == null || type.BaseType.EType != ElementType.Object)
continue;
if (!hasInterface(type, "System.Collections.IDictionaryEnumerator"))
continue;
if (!new FieldTypes(type).all(resourceEnumeratorType_fields))
continue;
var ctor = DotNetUtils.getMethod(type, ".ctor");
if (ctor == null)
continue;
if (ctor.Parameters.Count != 1)
continue;
if (ctor.Parameters[0].ParameterType != encryptedResourceReaderType)
continue;
resourceEnumeratorType = type;
return;
}
}
void findResourceFlags() {
if (resTypeCtor == null || resTypeCtor.Parameters.Count != 4)
return;
var type = resTypeCtor.Parameters[2].ParameterType as TypeDefinition;
if (type == null || !type.IsEnum)
return;
resourceFlagsType = type;
}
static string[] resType_fields = new string[] {
"System.Int32",
"System.Object",
"System.String",
};
void findResType() {
if (encryptedResourceReaderTypeDict == null)
return;
var type = encryptedResourceReaderTypeDict.GenericArguments[1] as TypeDefinition;
if (type == null)
return;
if (type.BaseType == null || type.BaseType.EType != ElementType.Object)
return;
var ctor = DotNetUtils.getMethod(type, ".ctor");
if (ctor == null || ctor.Parameters.Count != 4)
return;
resTypeCtor = ctor;
resType = type;
}
static string[] encryptedResourceReaderType_fields = new string[] {
"System.Boolean",
"System.Int32",
"System.Int64",
"System.IO.BinaryReader",
"System.Runtime.Serialization.Formatters.Binary.BinaryFormatter",
};
void findEncryptedResourceReader() {
var type = getTypeFromCode(encryptedResourceSet_GetDefaultReader);
if (type == null)
return;
if (type.BaseType == null || !hasInterface(type, "System.Resources.IResourceReader"))
return;
if (!new FieldTypes(type).all(encryptedResourceReaderType_fields))
return;
var dictType = getDlxResDict(type);
if (dictType == null)
return;
if (findXxteaMethod(type) == null)
return;
encryptedResourceReaderType = type;
encryptedResourceReaderTypeDict = dictType;
}
static bool hasInterface(TypeDefinition type, string interfaceFullName) {
foreach (var iface in type.Interfaces) {
if (iface.FullName == interfaceFullName)
return true;
}
return false;
}
static GenericInstanceType getDlxResDict(TypeDefinition type) {
foreach (var field in type.Fields) {
var fieldType = field.FieldType as GenericInstanceType;
if (fieldType == null)
continue;
if (fieldType.ElementType.FullName != "System.Collections.Generic.Dictionary`2")
continue;
if (fieldType.GenericArguments.Count != 2)
continue;
if (fieldType.GenericArguments[0].FullName != "System.String")
continue;
if (!(fieldType.GenericArguments[1] is TypeDefinition))
continue;
return fieldType;
}
return null;
}
static TypeDefinition getTypeFromCode(MethodDefinition method) {
if (method == null || method.Body == null)
return null;
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code != Code.Ldtoken)
continue;
var type = instr.Operand as TypeDefinition;
if (type != null)
return type;
}
return null;
}
void findEncryptedResourceSet() {
foreach (var type in module.Types) {
if (type.Namespace != "")
continue;
if (type.BaseType == null || type.BaseType.FullName != "System.Resources.ResourceSet")
continue;
var ctor = DotNetUtils.getMethod(type, ".ctor");
if (!DotNetUtils.isMethod(ctor, "System.Void", "(System.Resources.IResourceReader)"))
continue;
var method = DotNetUtils.getMethod(type, "GetDefaultReader");
if (!DotNetUtils.isMethod(method, "System.Type", "()"))
continue;
if (method.Body == null || method.IsStatic || !method.IsVirtual)
continue;
encryptedResourceSet_GetDefaultReader = method;
encryptedResourceSetType = type;
return;
}
}
static string[] encryptedResourceStreamType_fields = new string[] {
"System.Byte",
"System.Byte[]",
"System.Boolean",
"System.Int32",
"System.Int64",
"System.IO.MemoryStream",
"System.IO.Stream",
"System.UInt32[]",
};
void findEncryptedResourceStreamType() {
foreach (var type in module.Types) {
if (type.Namespace != "")
continue;
if (type.BaseType == null || type.BaseType.FullName != "System.IO.Stream")
continue;
var ctor = DotNetUtils.getMethod(type, ".ctor");
if (!DotNetUtils.isMethod(ctor, "System.Void", "(System.IO.Stream)"))
continue;
if (!new FieldTypes(type).all(encryptedResourceStreamType_fields))
continue;
if (findXxteaMethod(type) == null)
continue;
MethodDefinition getManifestResourceStreamMethodTmp1, getManifestResourceStreamMethodTmp2;
if (!findManifestResourceStreamMethods(type, out getManifestResourceStreamMethodTmp1, out getManifestResourceStreamMethodTmp2))
continue;
getManifestResourceStreamMethod1 = getManifestResourceStreamMethodTmp1;
getManifestResourceStreamMethod2 = getManifestResourceStreamMethodTmp2;
encryptedResourceStreamType = type;
return;
}
}
static MethodDefinition findXxteaMethod(TypeDefinition type) {
foreach (var method in type.Methods) {
if (!method.IsPrivate || method.IsStatic || method.Body == null)
continue;
if (DotNetUtils.isMethod(method, "System.Void", "(System.UInt32[],System.UInt32[])")) {
if (!DeobUtils.hasInteger(method, 0x9E3779B9))
continue;
}
else if (DotNetUtils.isMethod(method, "System.Void", "(System.UInt32[],System.UInt32[],System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32)")) {
// Here if 5.0. 0x9E3779B9 is passed to it as the last arg.
}
else
continue;
if (!DeobUtils.hasInteger(method, 52))
continue;
return method;
}
return null;
}
static bool findManifestResourceStreamMethods(TypeDefinition type, out MethodDefinition getManifestResourceStreamMethodTmp1, out MethodDefinition getManifestResourceStreamMethodTmp2) {
getManifestResourceStreamMethodTmp1 = null;
getManifestResourceStreamMethodTmp2 = null;
foreach (var method in type.Methods) {
if (DotNetUtils.isMethod(method, "System.IO.Stream", "(System.Reflection.Assembly,System.String)"))
getManifestResourceStreamMethodTmp1 = method;
else if (DotNetUtils.isMethod(method, "System.IO.Stream", "(System.Reflection.Assembly,System.Type,System.String)"))
getManifestResourceStreamMethodTmp2 = method;
}
return getManifestResourceStreamMethodTmp1 != null && getManifestResourceStreamMethodTmp2 != null;
}
public void decrypt() {
for (int i = 0; i < module.Resources.Count; i++) {
var resource = module.Resources[i] as EmbeddedResource;
if (resource == null)
continue;
var decrypted = decrypt(resource.GetResourceStream());
if (decrypted == null)
continue;
Log.v("Decrypted resource {0}", Utils.toCsharpString(resource.Name));
module.Resources[i] = new EmbeddedResource(resource.Name, resource.Attributes, decrypted);
}
}
byte[] decrypt(Stream stream) {
try {
stream.Position = 0;
var reader = new BinaryReader(stream);
uint sig = reader.ReadUInt32();
stream.Position = 0;
if (sig == 0xBEEFCACE)
return decryptBeefcace(reader);
if (sig == 0x58455245)
return decryptErex(reader);
return null;
}
catch (InvalidDataException) {
return null;
}
catch (IOException) {
return null;
}
catch (Exception ex) {
Log.w("Got an exception when decrypting resources: {0} - {1}", ex.GetType(), ex.Message);
return null;
}
}
byte[] decryptBeefcace(BinaryReader reader) {
var resourceReader = new ResourceReader(reader);
return new ResourceConverter(module, resourceReader.read()).convert();
}
byte[] decryptErex(BinaryReader reader) {
return new ErexResourceReader(reader.BaseStream).decrypt();
}
public void deobfuscate(Blocks blocks) {
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var call = instrs[i];
if (call.OpCode.Code != Code.Call)
continue;
var calledMethod = call.Operand as MethodDefinition;
if (calledMethod == null)
continue;
MethodReference newMethod = null;
if (calledMethod == getManifestResourceStreamMethod1)
newMethod = Assembly_GetManifestResourceStream1;
else if (calledMethod == getManifestResourceStreamMethod2)
newMethod = Assembly_GetManifestResourceStream2;
if (newMethod == null)
continue;
instrs[i] = new Instr(Instruction.Create(OpCodes.Callvirt, newMethod));
}
}
}
}
}

View File

@ -0,0 +1,41 @@
/*
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.code.deobfuscators.CodeVeil {
class ResourceInfo {
public string name;
public byte flags;
public int offset;
public int length;
public BinaryReader dataReader;
public ResourceInfo(string name, byte flags, int offset, int length) {
this.name = name;
this.flags = flags;
this.offset = offset;
this.length = length;
}
public override string ToString() {
return string.Format("{0:X2} {1:X8} {2} {3}", flags, offset, length, name);
}
}
}

View File

@ -0,0 +1,129 @@
/*
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;
using System.IO;
using System.Text;
namespace de4dot.code.deobfuscators.CodeVeil {
class ResourceReader {
BinaryReader reader;
string resourceReader;
string resourceSet;
public string ResourceReaderName {
get { return resourceReader; }
}
public string ResourceSetName {
get { return resourceSet; }
}
public ResourceReader(Stream stream) {
stream.Position = 0;
reader = new BinaryReader(stream);
}
public ResourceReader(BinaryReader reader) {
this.reader = reader;
}
public ResourceInfo[] read() {
if (reader.ReadUInt32() != 0xBEEFCACE)
throw new InvalidDataException("Invalid magic");
if (reader.ReadUInt32() <= 0)
throw new InvalidDataException("Invalid number");
reader.ReadUInt32();
resourceReader = reader.ReadString();
if (Utils.StartsWith(resourceReader, "System.Resources.ResourceReader", StringComparison.Ordinal))
throw new InvalidDataException("Resource isn't encrypted");
resourceSet = reader.ReadString();
if (reader.ReadByte() != 1)
throw new ApplicationException("Invalid version");
int flags = reader.ReadByte();
if ((flags & 0xFC) != 0)
throw new ApplicationException("Invalid flags");
bool inflateData = (flags & 1) != 0;
bool encrypted = (flags & 2) != 0;
int numResources = reader.ReadInt32();
if (numResources < 0)
throw new ApplicationException("Invalid number of resources");
var infos = new ResourceInfo[numResources];
for (int i = 0; i < numResources; i++) {
var resourceName = readResourceName(reader, encrypted);
int offset = reader.ReadInt32();
byte resourceFlags = reader.ReadByte();
int resourceLength = (resourceFlags & 0x80) == 0 ? -1 : reader.ReadInt32();
infos[i] = new ResourceInfo(resourceName, resourceFlags, offset, resourceLength);
}
var dataReader = reader;
if (encrypted) {
var key = new uint[4];
key[0] = dataReader.ReadUInt32();
key[1] = dataReader.ReadUInt32();
int numDwords = dataReader.ReadInt32();
if (numDwords < 0 || numDwords >= 0x40000000)
throw new ApplicationException("Invalid number of encrypted dwords");
var encryptedData = new uint[numDwords];
for (int i = 0; i < numDwords; i++)
encryptedData[i] = dataReader.ReadUInt32();
key[2] = dataReader.ReadUInt32();
key[3] = dataReader.ReadUInt32();
DeobUtils.xxteaDecrypt(encryptedData, key);
byte[] decryptedData = new byte[encryptedData.Length * 4];
Buffer.BlockCopy(encryptedData, 0, decryptedData, 0, decryptedData.Length);
dataReader = new BinaryReader(new MemoryStream(decryptedData));
}
if (inflateData) {
var data = dataReader.ReadBytes((int)(dataReader.BaseStream.Length - dataReader.BaseStream.Position));
data = DeobUtils.inflate(data, true);
dataReader = new BinaryReader(new MemoryStream(data));
}
foreach (var info in infos)
info.dataReader = dataReader;
return infos;
}
static string readResourceName(BinaryReader reader, bool encrypted) {
if (!encrypted)
return reader.ReadString();
int len = reader.ReadInt32();
if (len < 0)
throw new ApplicationException("Invalid string length");
var sb = new StringBuilder(len);
for (int i = 0; i < len; i++)
sb.Append((char)rol3(reader.ReadChar()));
return sb.ToString();
}
static char rol3(char c) {
ushort s = (ushort)c;
return (char)((s << 3) | (s >> (16 - 3)));
}
}
}

View File

@ -0,0 +1,246 @@
/*
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 Mono.Cecil;
using Mono.Cecil.Cil;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeVeil {
class StringDecrypter {
ModuleDefinition module;
MainType mainType;
TypeDefinition decrypterType;
FieldDefinition stringDataField;
MethodDefinition initMethod;
MethodDefinition decrypterMethod;
string[] decryptedStrings;
public bool Detected {
get { return decrypterType != null; }
}
public TypeDefinition Type {
get { return decrypterType; }
}
public MethodDefinition InitMethod {
get { return initMethod; }
}
public MethodDefinition DecryptMethod {
get { return decrypterMethod; }
}
public StringDecrypter(ModuleDefinition module, MainType mainType) {
this.module = module;
this.mainType = mainType;
}
public StringDecrypter(ModuleDefinition module, MainType mainType, StringDecrypter oldOne) {
this.module = module;
this.mainType = mainType;
this.decrypterType = lookup(oldOne.decrypterType, "Could not find string decrypter type");
this.stringDataField = lookup(oldOne.stringDataField, "Could not find string data field");
this.initMethod = lookup(oldOne.initMethod, "Could not find string decrypter init method");
this.decrypterMethod = lookup(oldOne.decrypterMethod, "Could not find string decrypter method");
}
T lookup<T>(T def, string errorMessage) where T : MemberReference {
return DeobUtils.lookup(module, def, errorMessage);
}
public void find() {
var cctor = DotNetUtils.getModuleTypeCctor(module);
if (cctor == null)
return;
// V3-V4 calls string decrypter init method in <Module>::.cctor().
if (find(cctor))
return;
find_V5(cctor);
}
bool find(MethodDefinition method) {
if (method == null || method.Body == null || !method.IsStatic)
return false;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var call = instrs[i];
if (call.OpCode.Code != Code.Call)
continue;
var initMethodTmp = call.Operand as MethodDefinition;
if (initMethodTmp == null || initMethodTmp.Body == null || !initMethodTmp.IsStatic)
continue;
if (!DotNetUtils.isMethod(initMethodTmp, "System.Void", "()"))
continue;
if (!checkType(initMethodTmp.DeclaringType))
continue;
decrypterType = initMethodTmp.DeclaringType;
initMethod = initMethodTmp;
return true;
}
return false;
}
// The main decrypter type calls the string decrypter init method inside its init method
void find_V5(MethodDefinition method) {
if (!mainType.Detected)
return;
foreach (var info in DotNetUtils.getCalledMethods(module, mainType.InitMethod)) {
if (find(info.Item2))
return;
}
}
bool checkType(TypeDefinition type) {
if (!type.HasNestedTypes)
return false;
var stringDataFieldTmp = checkFields(type);
if (stringDataFieldTmp == null)
return false;
var fieldType = DotNetUtils.getType(module, stringDataFieldTmp.FieldType);
if (fieldType == null || type.NestedTypes.IndexOf(fieldType) < 0)
return false;
var decrypterMethodTmp = getDecrypterMethod(type);
if (decrypterMethodTmp == null)
return false;
stringDataField = stringDataFieldTmp;
decrypterMethod = decrypterMethodTmp;
return true;
}
static MethodDefinition getDecrypterMethod(TypeDefinition type) {
MethodDefinition foundMethod = null;
foreach (var method in type.Methods) {
if (method.Body == null || !method.IsStatic)
continue;
if (!DotNetUtils.isMethod(method, "System.String", "(System.Int32)"))
continue;
if (foundMethod != null)
return null;
foundMethod = method;
}
return foundMethod;
}
static string[] requiredFields = new string[] {
"System.Byte[]",
"System.Int32",
"System.Int32[]",
"System.String[]",
"System.UInt32[]",
};
FieldDefinition checkFields(TypeDefinition type) {
if (!new FieldTypes(type).all(requiredFields))
return null;
FieldDefinition stringData = null;
foreach (var field in type.Fields) {
if (field.RVA != 0) {
if (stringData != null)
return null;
stringData = field;
continue;
}
}
if (stringData == null)
return null;
var data = stringData.InitialValue;
if (data == null || data.Length == 0 || data.Length % 4 != 0)
return null;
return stringData;
}
public void initialize() {
if (initMethod == null || stringDataField == null)
return;
var key = getKey(initMethod);
if (key == null)
throw new ApplicationException("Could not find string decrypter key");
decryptStrings(key);
stringDataField.FieldType = module.TypeSystem.Byte;
stringDataField.InitialValue = new byte[1];
}
static uint[] getKey(MethodDefinition method) {
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
var ldci4 = instrs[i];
if (!DotNetUtils.isLdcI4(ldci4))
continue;
if (DotNetUtils.getLdcI4Value(ldci4) != 4)
continue;
if (instrs[i + 1].OpCode.Code != Code.Newarr)
continue;
i++;
var key = ArrayFinder.getInitializedUInt32Array(4, method, ref i);
if (key == null)
continue;
return key;
}
return null;
}
void decryptStrings(uint[] key) {
var data = stringDataField.InitialValue;
var encryptedData = new uint[data.Length / 4];
Buffer.BlockCopy(data, 0, encryptedData, 0, data.Length);
DeobUtils.xxteaDecrypt(encryptedData, key);
var decryptedData = new byte[data.Length];
Buffer.BlockCopy(encryptedData, 0, decryptedData, 0, data.Length);
var inflated = DeobUtils.inflate(decryptedData, 0, decryptedData.Length, true);
var reader = new BinaryReader(new MemoryStream(inflated));
int deflatedLength = DeobUtils.readVariableLengthInt32(reader);
int numStrings = DeobUtils.readVariableLengthInt32(reader);
decryptedStrings = new string[numStrings];
var offsets = new int[numStrings];
for (int i = 0; i < numStrings; i++)
offsets[i] = DeobUtils.readVariableLengthInt32(reader);
int startOffset = (int)reader.BaseStream.Position;
for (int i = 0; i < numStrings; i++) {
reader.BaseStream.Position = startOffset + offsets[i];
decryptedStrings[i] = reader.ReadString();
}
}
public string decrypt(int index) {
return decryptedStrings[index];
}
}
}

View File

@ -0,0 +1,151 @@
/*
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;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.CodeVeil {
class TamperDetection {
ModuleDefinition module;
MainType mainType;
TypeDefinition tamperDetectionType;
List<MethodDefinition> tamperDetectionMethods = new List<MethodDefinition>();
public TypeDefinition Type {
get { return tamperDetectionType; }
}
public List<MethodDefinition> Methods {
get { return tamperDetectionMethods; }
}
public TamperDetection(ModuleDefinition module, MainType mainType) {
this.module = module;
this.mainType = mainType;
}
public void initialize() {
if (!mainType.Detected)
return;
if (mainType.TamperCheckMethod == null)
return;
findTamperDetectionTypes();
}
void findTamperDetectionTypes() {
foreach (var type in module.Types) {
if (!type.HasNestedTypes)
continue;
if ((type.Attributes & ~TypeAttributes.Sealed) != 0)
continue;
if (!checkTamperDetectionClasses(type.NestedTypes))
continue;
tamperDetectionType = type;
findTamperDetectionMethods();
return;
}
}
void findTamperDetectionMethods() {
foreach (var type in tamperDetectionType.NestedTypes) {
foreach (var method in type.Methods) {
if (!method.IsStatic || method.Body == null)
continue;
if (method.Name == ".cctor")
continue;
if (DotNetUtils.isMethod(method, "System.Void", "()"))
tamperDetectionMethods.Add(method);
}
}
}
bool checkTamperDetectionClasses(IEnumerable<TypeDefinition> types) {
foreach (var type in types) {
if (!isTamperDetectionClass(type))
return false;
}
return true;
}
bool isTamperDetectionClass(TypeDefinition type) {
if (type.BaseType == null || type.BaseType.EType != ElementType.Object)
return false;
if ((type.Attributes & ~TypeAttributes.Sealed) != TypeAttributes.NestedAssembly)
return false;
MethodDefinition cctor = null, initMethod = null;
foreach (var method in type.Methods) {
if (!method.IsStatic || method.Body == null)
return false;
if (method.Name == ".cctor")
cctor = method;
else if (DotNetUtils.isMethod(method, "System.Void", "()"))
initMethod = method;
}
if (cctor == null || initMethod == null)
return false;
if (!callsMainTypeTamperCheckMethod(cctor))
return false;
return true;
}
bool callsMainTypeTamperCheckMethod(MethodDefinition method) {
foreach (var info in DotNetUtils.getCalledMethods(module, method)) {
if (info.Item2 == mainType.TamperCheckMethod)
return true;
}
var instructions = method.Body.Instructions;
for (int i = 0; i < instructions.Count; i++) {
var instrs = DotNetUtils.getInstructions(instructions, i, OpCodes.Ldtoken, OpCodes.Call, OpCodes.Call, OpCodes.Ldc_I8, OpCodes.Call);
if (instrs == null)
continue;
if (!checkInvokeCall(instrs[1], "System.Type", "(System.RuntimeTypeHandle)"))
continue;
if (!checkInvokeCall(instrs[2], "System.Reflection.Assembly", "(System.Object)"))
continue;
if (!checkInvokeCall(instrs[4], "System.Void", "(System.Reflection.Assembly,System.UInt64)"))
continue;
return true;
}
return false;
}
static bool checkInvokeCall(Instruction instr, string returnType, string parameters) {
var method = instr.Operand as MethodDefinition;
if (method == null)
return false;
if (method.Name != "Invoke")
return false;
return DotNetUtils.isMethod(method, returnType, parameters);
}
}
}

View File

@ -19,6 +19,7 @@
using System.Collections.Generic;
using Mono.Cecil;
using de4dot.blocks;
using de4dot.blocks.cflow;
namespace de4dot.code.deobfuscators.DeepSea {
@ -224,7 +225,7 @@ done:
addMethodToBeRemoved(assemblyResolver.HandlerMethod, "Assembly resolver handler method");
}
public override void deobfuscateMethodEnd(blocks.Blocks blocks) {
public override void deobfuscateMethodEnd(Blocks blocks) {
if (options.RestoreFields)
fieldsRestorer.deobfuscate(blocks);
base.deobfuscateMethodEnd(blocks);

View File

@ -222,6 +222,8 @@ namespace de4dot.code.deobfuscators.DeepSea {
}
short[] findKey() {
if (cctor.Module.Assembly == null)
return null;
var pkt = cctor.Module.Assembly.Name.PublicKeyToken;
if (pkt != null && pkt.Length > 0)
return getPublicKeyTokenKey(pkt);
@ -302,7 +304,7 @@ namespace de4dot.code.deobfuscators.DeepSea {
return false;
key = findKey();
if (key.Length == 0)
if (key == null || key.Length == 0)
return false;
return true;
@ -339,6 +341,8 @@ namespace de4dot.code.deobfuscators.DeepSea {
}
short[] findKey() {
if (cctor.Module.Assembly == null)
return null;
var pkt = cctor.Module.Assembly.Name.PublicKeyToken;
if (pkt != null && pkt.Length > 0)
return getPublicKeyTokenKey(pkt);
@ -433,6 +437,9 @@ namespace de4dot.code.deobfuscators.DeepSea {
}
public void find(ISimpleDeobfuscator simpleDeobfuscator) {
if (module.Assembly == null)
return;
bool hasPublicKeyToken = module.Assembly.Name.PublicKeyToken != null && module.Assembly.Name.PublicKeyToken.Length != 0;
foreach (var type in module.GetTypes()) {
if (!checkFields(type.Fields))

View File

@ -90,6 +90,27 @@ namespace de4dot.code.deobfuscators {
}
}
// Code converted from C implementation @ http://en.wikipedia.org/wiki/XXTEA (btea() func)
public static void xxteaDecrypt(uint[] v, uint[] key) {
const uint DELTA = 0x9E3779B9;
int n = v.Length;
uint rounds = (uint)(6 + 52 / n);
uint sum = rounds * DELTA;
uint y = v[0];
uint z;
//#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)))
do {
int e = (int)((sum >> 2) & 3);
int p;
for (p = n - 1; p > 0; p--) {
z = v[p - 1];
y = v[p] -= (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)));
}
z = v[n - 1];
y = v[0] -= (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)));
} while ((sum -= DELTA) != 0);
}
public static string getExtension(ModuleKind kind) {
switch (kind) {
case ModuleKind.Dll:
@ -129,5 +150,31 @@ namespace de4dot.code.deobfuscators {
}
return null;
}
public static int readVariableLengthInt32(BinaryReader reader) {
byte b = reader.ReadByte();
if ((b & 0x80) == 0)
return b;
if ((b & 0x40) == 0)
return (((int)b & 0x3F) << 8) + reader.ReadByte();
return (((int)b & 0x3F) << 24) +
((int)reader.ReadByte() << 16) +
((int)reader.ReadByte() << 8) +
reader.ReadByte();
}
public static bool hasInteger(MethodDefinition method, uint value) {
return hasInteger(method, (int)value);
}
public static bool hasInteger(MethodDefinition method, int value) {
foreach (var instr in method.Body.Instructions) {
if (!DotNetUtils.isLdcI4(instr))
continue;
if (DotNetUtils.getLdcI4Value(instr) == value)
return true;
}
return false;
}
}
}

View File

@ -180,10 +180,14 @@ namespace de4dot.code.deobfuscators {
restoreBaseType();
}
static bool isTypeWithInvalidBaseType(TypeDefinition moduleType, TypeDefinition type) {
return type.BaseType == null && !type.IsInterface && type != moduleType;
}
void restoreBaseType() {
var moduleType = DotNetUtils.getModuleType(module);
foreach (var type in module.GetTypes()) {
if (type.BaseType != null || type.IsInterface || type == moduleType)
if (!isTypeWithInvalidBaseType(moduleType, type))
continue;
Log.v("Adding System.Object as base type: {0} ({1:X8})",
Utils.removeNewlines(type),
@ -192,6 +196,15 @@ namespace de4dot.code.deobfuscators {
}
}
protected void removeTypesWithInvalidBaseTypes() {
var moduleType = DotNetUtils.getModuleType(module);
foreach (var type in module.GetTypes()) {
if (!isTypeWithInvalidBaseType(moduleType, type))
continue;
addTypeToBeRemoved(type, "Invalid type with no base type (anti-reflection)");
}
}
public virtual IEnumerable<string> getStringDecrypterMethods() {
return new List<string>();
}

View File

@ -68,6 +68,31 @@ namespace de4dot.code.deobfuscators {
this.module = module;
}
public ProxyDelegateFinderBase(ModuleDefinition module, ProxyDelegateFinderBase oldOne) {
this.module = module;
foreach (var method in oldOne.delegateCreatorMethods)
delegateCreatorMethods.Add(lookup(method, "Could not find delegate creator method"));
foreach (var kv in oldOne.delegateTypesDict)
delegateTypesDict[lookup(kv.Key, "Could not find delegate type")] = kv.Value;
foreach (var key in oldOne.fieldToDelegateInfo.getKeys())
fieldToDelegateInfo.add(lookup(key, "Could not find field"), copy(oldOne.fieldToDelegateInfo.find(key)));
foreach (var kv in oldOne.proxyMethodToField) {
var key = lookup(kv.Key, "Could not find proxy method");
var value = lookup(kv.Value, "Could not find proxy field");
proxyMethodToField[key] = value;
}
}
DelegateInfo copy(DelegateInfo di) {
var method = lookup(di.methodRef, "Could not find method ref");
var field = lookup(di.field, "Could not find delegate field");
return new DelegateInfo(field, method, di.callOpcode);
}
protected T lookup<T>(T def, string errorMessage) where T : MemberReference {
return DeobUtils.lookup(module, def, errorMessage);
}
public void setDelegateCreatorMethod(MethodDefinition delegateCreatorMethod) {
if (delegateCreatorMethod == null)
return;
@ -82,14 +107,21 @@ namespace de4dot.code.deobfuscators {
return false;
}
protected virtual IEnumerable<TypeDefinition> getDelegateTypes() {
foreach (var type in module.Types) {
if (type.BaseType == null || type.BaseType.FullName != "System.MulticastDelegate")
continue;
yield return type;
}
}
public void find() {
if (delegateCreatorMethods.Count == 0)
return;
Log.v("Finding all proxy delegates");
foreach (var type in module.Types) {
if (type.BaseType == null || type.BaseType.FullName != "System.MulticastDelegate")
continue;
foreach (var type in getDelegateTypes()) {
var cctor = DotNetUtils.getMethod(type, ".cctor");
if (cctor == null || !cctor.HasBody)
continue;
@ -263,15 +295,18 @@ namespace de4dot.code.deobfuscators {
if (stack < 0)
return null;
if (instr.OpCode != OpCodes.Call && instr.OpCode != OpCodes.Callvirt)
if (instr.OpCode != OpCodes.Call && instr.OpCode != OpCodes.Callvirt) {
if (stack <= 0)
return null;
continue;
var method = DotNetUtils.getMethod(module, instr.Operand as MethodReference);
if (method == null)
continue;
if (stack != (DotNetUtils.hasReturnValue(method) ? 1 : 0))
continue;
if (method.DeclaringType != di.field.DeclaringType)
}
var calledMethod = instr.Operand as MethodReference;
if (calledMethod == null)
return null;
if (stack != (DotNetUtils.hasReturnValue(calledMethod) ? 1 : 0))
continue;
if (calledMethod.Name != "Invoke")
return null;
return new BlockInstr {
Block = block,

View File

@ -99,8 +99,6 @@ namespace de4dot.code.deobfuscators.Unknown {
foreach (var type in module.Types) {
if (type.Namespace == "___codefort")
return "CodeFort";
if (type.FullName == "____KILL")
return "DeployLX CodeVeil";
if (type.FullName == "ZYXDNGuarder")
return "DNGuard HVM";
if (type.FullName == "InfaceMaxtoCode")

View File

@ -239,7 +239,10 @@ namespace de4dot.code.renamer {
if (!fieldInfo.gotNewName())
continue;
fieldDef.FieldDefinition.Name = fieldInfo.newName;
Log.v("Field: {0} ({1:X8}) => {2}", Utils.removeNewlines(fieldInfo.oldFullName), fieldDef.FieldDefinition.MetadataToken.ToUInt32(), fieldDef.FieldDefinition.FullName);
Log.v("Field: {0} ({1:X8}) => {2}",
Utils.removeNewlines(fieldInfo.oldFullName),
fieldDef.FieldDefinition.MetadataToken.ToUInt32(),
Utils.removeNewlines(fieldDef.FieldDefinition.FullName));
}
}
@ -251,7 +254,10 @@ namespace de4dot.code.renamer {
if (!propInfo.gotNewName())
continue;
propDef.PropertyDefinition.Name = propInfo.newName;
Log.v("Property: {0} ({1:X8}) => {2}", Utils.removeNewlines(propInfo.oldFullName), propDef.PropertyDefinition.MetadataToken.ToUInt32(), propDef.PropertyDefinition.FullName);
Log.v("Property: {0} ({1:X8}) => {2}",
Utils.removeNewlines(propInfo.oldFullName),
propDef.PropertyDefinition.MetadataToken.ToUInt32(),
Utils.removeNewlines(propDef.PropertyDefinition.FullName));
}
}
@ -263,7 +269,10 @@ namespace de4dot.code.renamer {
if (!eventInfo.gotNewName())
continue;
eventDef.EventDefinition.Name = eventInfo.newName;
Log.v("Event: {0} ({1:X8}) => {2}", Utils.removeNewlines(eventInfo.oldFullName), eventDef.EventDefinition.MetadataToken.ToUInt32(), eventDef.EventDefinition.FullName);
Log.v("Event: {0} ({1:X8}) => {2}",
Utils.removeNewlines(eventInfo.oldFullName),
eventDef.EventDefinition.MetadataToken.ToUInt32(),
Utils.removeNewlines(eventDef.EventDefinition.FullName));
}
}

View File

@ -0,0 +1,118 @@
/*
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.Runtime.Serialization;
namespace de4dot.code.resources {
class BuiltInResourceData : IResourceData {
readonly ResourceTypeCode code;
readonly object data;
public ResourceTypeCode Code {
get { return code; }
}
public BuiltInResourceData(ResourceTypeCode code, object data) {
this.code = code;
this.data = data;
}
public void writeData(BinaryWriter writer, IFormatter formatter) {
switch (code) {
case ResourceTypeCode.Null:
return;
case ResourceTypeCode.String:
writer.Write((string)data);
break;
case ResourceTypeCode.Boolean:
writer.Write((bool)data);
break;
case ResourceTypeCode.Char:
writer.Write((ushort)(char)data);
break;
case ResourceTypeCode.Byte:
writer.Write((byte)data);
break;
case ResourceTypeCode.SByte:
writer.Write((sbyte)data);
break;
case ResourceTypeCode.Int16:
writer.Write((short)data);
break;
case ResourceTypeCode.UInt16:
writer.Write((ushort)data);
break;
case ResourceTypeCode.Int32:
writer.Write((int)data);
break;
case ResourceTypeCode.UInt32:
writer.Write((uint)data);
break;
case ResourceTypeCode.Int64:
writer.Write((long)data);
break;
case ResourceTypeCode.UInt64:
writer.Write((ulong)data);
break;
case ResourceTypeCode.Single:
writer.Write((float)data);
break;
case ResourceTypeCode.Double:
writer.Write((double)data);
break;
case ResourceTypeCode.Decimal:
writer.Write((decimal)data);
break;
case ResourceTypeCode.DateTime:
writer.Write(((DateTime)data).ToBinary());
break;
case ResourceTypeCode.TimeSpan:
writer.Write(((TimeSpan)data).Ticks);
break;
case ResourceTypeCode.ByteArray:
var ary = (byte[])data;
writer.Write(ary.Length);
writer.Write(ary);
break;
default:
throw new ApplicationException("Unknown resource type code");
}
}
}
}

View File

@ -0,0 +1,28 @@
/*
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.Runtime.Serialization;
namespace de4dot.code.resources {
interface IResourceData {
ResourceTypeCode Code { get; }
void writeData(BinaryWriter writer, IFormatter formatter);
}
}

View File

@ -0,0 +1,234 @@
/*
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;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using Mono.Cecil;
namespace de4dot.code.resources {
class ResourceDataCreator {
ModuleDefinition module;
Dictionary<string, UserResourceType> dict = new Dictionary<string, UserResourceType>(StringComparer.Ordinal);
Dictionary<string, string> asmNameToAsmFullName = new Dictionary<string, string>(StringComparer.Ordinal);
public ResourceDataCreator(ModuleDefinition module) {
this.module = module;
}
public int Count {
get { return dict.Count; }
}
public BuiltInResourceData createNull() {
return new BuiltInResourceData(ResourceTypeCode.Null, null);
}
public BuiltInResourceData create(string value) {
return new BuiltInResourceData(ResourceTypeCode.String, value);
}
public BuiltInResourceData create(bool value) {
return new BuiltInResourceData(ResourceTypeCode.Boolean, value);
}
public BuiltInResourceData create(char value) {
return new BuiltInResourceData(ResourceTypeCode.Char, value);
}
public BuiltInResourceData create(byte value) {
return new BuiltInResourceData(ResourceTypeCode.Byte, value);
}
public BuiltInResourceData create(sbyte value) {
return new BuiltInResourceData(ResourceTypeCode.SByte, value);
}
public BuiltInResourceData create(short value) {
return new BuiltInResourceData(ResourceTypeCode.Int16, value);
}
public BuiltInResourceData create(ushort value) {
return new BuiltInResourceData(ResourceTypeCode.UInt16, value);
}
public BuiltInResourceData create(int value) {
return new BuiltInResourceData(ResourceTypeCode.Int32, value);
}
public BuiltInResourceData create(uint value) {
return new BuiltInResourceData(ResourceTypeCode.UInt32, value);
}
public BuiltInResourceData create(long value) {
return new BuiltInResourceData(ResourceTypeCode.Int64, value);
}
public BuiltInResourceData create(ulong value) {
return new BuiltInResourceData(ResourceTypeCode.UInt64, value);
}
public BuiltInResourceData create(float value) {
return new BuiltInResourceData(ResourceTypeCode.Single, value);
}
public BuiltInResourceData create(double value) {
return new BuiltInResourceData(ResourceTypeCode.Double, value);
}
public BuiltInResourceData create(decimal value) {
return new BuiltInResourceData(ResourceTypeCode.Decimal, value);
}
public BuiltInResourceData create(DateTime value) {
return new BuiltInResourceData(ResourceTypeCode.DateTime, value);
}
public BuiltInResourceData create(TimeSpan value) {
return new BuiltInResourceData(ResourceTypeCode.TimeSpan, value);
}
public BuiltInResourceData create(byte[] value) {
return new BuiltInResourceData(ResourceTypeCode.ByteArray, value);
}
public CharArrayResourceData create(char[] value) {
return new CharArrayResourceData(createUserResourceType(CharArrayResourceData.typeName), value);
}
public IconResourceData createIcon(byte[] value) {
return new IconResourceData(createUserResourceType(IconResourceData.typeName), value);
}
public ImageResourceData createImage(byte[] value) {
return new ImageResourceData(createUserResourceType(ImageResourceData.typeName), value);
}
public BinaryResourceData createSerialized(byte[] value) {
string assemblyName, typeName;
if (!getSerializedTypeAndAssemblyName(value, out assemblyName, out typeName))
throw new ApplicationException("Could not get serialized type name");
string fullName = string.Format("{0},{1}", typeName, assemblyName);
return new BinaryResourceData(createUserResourceType(fullName), value);
}
class MyBinder : SerializationBinder {
public class OkException : Exception {
public string AssemblyName { get; set; }
public string TypeName { get; set; }
}
public override Type BindToType(string assemblyName, string typeName) {
throw new OkException {
AssemblyName = assemblyName,
TypeName = typeName,
};
}
}
bool getSerializedTypeAndAssemblyName(byte[] value, out string assemblyName, out string typeName) {
try {
var formatter = new BinaryFormatter();
formatter.Binder = new MyBinder();
formatter.Deserialize(new MemoryStream(value));
}
catch (MyBinder.OkException ex) {
assemblyName = ex.AssemblyName;
typeName = ex.TypeName;
return true;
}
catch {
}
assemblyName = null;
typeName = null;
return false;
}
public UserResourceType createUserResourceType(string fullName) {
UserResourceType type;
if (dict.TryGetValue(fullName, out type))
return type;
var newFullName = getRealTypeFullName(fullName);
type = new UserResourceType(newFullName, ResourceTypeCode.UserTypes + dict.Count);
dict[fullName] = type;
dict[newFullName] = type;
return type;
}
static void splitTypeFullName(string fullName, out string typeName, out string assemblyName) {
int index = fullName.IndexOf(',');
if (index < 0) {
typeName = fullName;
assemblyName = null;
}
else {
typeName = fullName.Substring(0, index);
assemblyName = fullName.Substring(index + 1).Trim();
}
}
string getRealTypeFullName(string fullName) {
var newFullName = fullName;
string typeName, assemblyName;
splitTypeFullName(fullName, out typeName, out assemblyName);
if (!string.IsNullOrEmpty(assemblyName))
assemblyName = getRealAssemblyName(assemblyName);
if (!string.IsNullOrEmpty(assemblyName))
newFullName = string.Format("{0}, {1}", typeName, assemblyName);
return newFullName;
}
string getRealAssemblyName(string assemblyName) {
string newAsmName;
if (!asmNameToAsmFullName.TryGetValue(assemblyName, out newAsmName))
asmNameToAsmFullName[assemblyName] = newAsmName = tryGetRealAssemblyName(assemblyName);
return newAsmName;
}
string tryGetRealAssemblyName(string assemblyName) {
var simpleName = Utils.getAssemblySimpleName(assemblyName);
foreach (var asmRef in module.AssemblyReferences) {
if (asmRef.Name == simpleName)
return asmRef.FullName;
}
try {
return AssemblyResolver.Instance.Resolve(simpleName).FullName;
}
catch (ResolutionException) {
}
catch (AssemblyResolutionException) {
}
return null;
}
public List<UserResourceType> getSortedTypes() {
var list = new List<UserResourceType>(dict.Values);
list.Sort((a, b) => Utils.compareInt32((int)a.Code, (int)b.Code));
return list;
}
}
}

View File

@ -0,0 +1,25 @@
/*
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.code.resources {
class ResourceElement {
public string Name { get; set; }
public IResourceData ResourceData { get; set; }
}
}

View File

@ -0,0 +1,39 @@
/*
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.code.resources {
class ResourceElementSet {
Dictionary<string, ResourceElement> dict = new Dictionary<string, ResourceElement>(StringComparer.Ordinal);
public int Count {
get { return dict.Count; }
}
public IEnumerable<ResourceElement> ResourceElements {
get { return dict.Values; }
}
public void add(ResourceElement elem) {
dict[elem.Name] = elem;
}
}
}

View File

@ -0,0 +1,42 @@
/*
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.code.resources {
enum ResourceTypeCode {
Null,
String,
Boolean,
Char,
Byte,
SByte,
Int16,
UInt16,
Int32,
UInt32,
Int64,
UInt64,
Single,
Double,
Decimal,
DateTime,
TimeSpan,
ByteArray = 0x20,
UserTypes = 0x40,
}
}

View File

@ -0,0 +1,154 @@
/*
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;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using Mono.Cecil;
namespace de4dot.code.resources {
class ResourceWriter {
ModuleDefinition module;
BinaryWriter writer;
ResourceElementSet resources;
ResourceDataCreator typeCreator;
Dictionary<UserResourceData, UserResourceType> dataToNewType = new Dictionary<UserResourceData, UserResourceType>();
ResourceWriter(ModuleDefinition module, Stream stream, ResourceElementSet resources) {
this.module = module;
this.typeCreator = new ResourceDataCreator(module);
this.writer = new BinaryWriter(stream);
this.resources = resources;
}
public static void write(ModuleDefinition module, Stream stream, ResourceElementSet resources) {
new ResourceWriter(module, stream, resources).write();
}
void write() {
initializeUserTypes();
writer.Write(0xBEEFCACE);
writer.Write(1);
writeReaderType();
writer.Write(2);
writer.Write(resources.Count);
writer.Write(typeCreator.Count);
foreach (var userType in typeCreator.getSortedTypes())
writer.Write(userType.Name);
int extraBytes = 8 - ((int)writer.BaseStream.Position & 7);
if (extraBytes != 8) {
for (int i = 0; i < extraBytes; i++)
writer.Write((byte)'X');
}
var nameOffsetStream = new MemoryStream();
var nameOffsetWriter = new BinaryWriter(nameOffsetStream, Encoding.Unicode);
var dataStream = new MemoryStream();
var dataWriter = new BinaryWriter(dataStream);
var hashes = new int[resources.Count];
var offsets = new int[resources.Count];
var formatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File | StreamingContextStates.Persistence));
int index = 0;
foreach (var info in resources.ResourceElements) {
offsets[index] = (int)nameOffsetWriter.BaseStream.Position;
hashes[index] = (int)hash(info.Name);
index++;
nameOffsetWriter.Write(info.Name);
nameOffsetWriter.Write((int)dataWriter.BaseStream.Position);
writeData(dataWriter, info, formatter);
}
Array.Sort(hashes, offsets);
foreach (var hash in hashes)
writer.Write(hash);
foreach (var offset in offsets)
writer.Write(offset);
writer.Write((int)writer.BaseStream.Position + (int)nameOffsetStream.Length + 4);
writer.Write(nameOffsetStream.ToArray());
writer.Write(dataStream.ToArray());
}
void writeData(BinaryWriter writer, ResourceElement info, IFormatter formatter) {
var code = getResourceType(info.ResourceData);
writeUInt32(writer, (uint)code);
info.ResourceData.writeData(writer, formatter);
}
static void writeUInt32(BinaryWriter writer, uint value) {
while (value >= 0x80) {
writer.Write((byte)(value | 0x80));
value >>= 7;
}
writer.Write((byte)value);
}
ResourceTypeCode getResourceType(IResourceData data) {
if (data is BuiltInResourceData)
return data.Code;
var userData = (UserResourceData)data;
return dataToNewType[userData].Code;
}
static uint hash(string key) {
uint val = 0x1505;
foreach (var c in key)
val = ((val << 5) + val) ^ (uint)c;
return val;
}
void initializeUserTypes() {
foreach (var resource in resources.ResourceElements) {
var data = resource.ResourceData as UserResourceData;
if (data == null)
continue;
var newType = typeCreator.createUserResourceType(data.TypeName);
dataToNewType[data] = newType;
}
}
void writeReaderType() {
var memStream = new MemoryStream();
var headerWriter = new BinaryWriter(memStream);
var mscorlibFullName = getMscorlibFullname();
headerWriter.Write("System.Resources.ResourceReader, " + mscorlibFullName);
headerWriter.Write("System.Resources.RuntimeResourceSet");
writer.Write((int)memStream.Position);
writer.Write(memStream.ToArray());
}
string getMscorlibFullname() {
AssemblyNameReference mscorlibRef = null;
foreach (var asmRef in module.AssemblyReferences) {
if (asmRef.Name != "mscorlib")
continue;
if (mscorlibRef == null || mscorlibRef.Version == null || (asmRef.Version != null && asmRef.Version >= mscorlibRef.Version))
mscorlibRef = asmRef;
}
if (mscorlibRef != null)
return mscorlibRef.FullName;
return "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
}
}
}

View File

@ -0,0 +1,97 @@
/*
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.Drawing;
using System.IO;
using System.Runtime.Serialization;
namespace de4dot.code.resources {
abstract class UserResourceData : IResourceData {
readonly UserResourceType type;
public string TypeName {
get { return type.Name; }
}
public ResourceTypeCode Code {
get { return type.Code; }
}
public UserResourceData(UserResourceType type) {
this.type = type;
}
public abstract void writeData(BinaryWriter writer, IFormatter formatter);
}
class CharArrayResourceData : UserResourceData {
public static readonly string typeName = "System.Char[],mscorlib";
char[] data;
public CharArrayResourceData(UserResourceType type, char[] data)
: base(type) {
this.data = data;
}
public override void writeData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, data);
}
}
class IconResourceData : UserResourceData {
public static readonly string typeName = "System.Drawing.Icon,System.Drawing";
Icon icon;
public IconResourceData(UserResourceType type, byte[] data)
: base(type) {
icon = new Icon(new MemoryStream(data));
}
public override void writeData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, icon);
}
}
class ImageResourceData : UserResourceData {
public static readonly string typeName = "System.Drawing.Bitmap,System.Drawing";
Bitmap bitmap;
public ImageResourceData(UserResourceType type, byte[] data)
: base(type) {
bitmap = new Bitmap(Image.FromStream(new MemoryStream(data)));
}
public override void writeData(BinaryWriter writer, IFormatter formatter) {
formatter.Serialize(writer.BaseStream, bitmap);
}
}
class BinaryResourceData : UserResourceData {
byte[] data;
public BinaryResourceData(UserResourceType type, byte[] data)
: base(type) {
this.data = data;
}
public override void writeData(BinaryWriter writer, IFormatter formatter) {
writer.Write(data);
}
}
}

View File

@ -0,0 +1,42 @@
/*
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.code.resources {
class UserResourceType {
readonly string name;
readonly ResourceTypeCode code;
public string Name {
get { return name; }
}
public ResourceTypeCode Code {
get { return code; }
}
public UserResourceType(string name, ResourceTypeCode code) {
this.name = name;
this.code = code;
}
public override string ToString() {
return string.Format("{0:X2} {1}", (int)code, name);
}
}
}

View File

@ -192,20 +192,8 @@ namespace de4dot.cui {
catch (BadImageFormatException) {
return false; // Not a .NET file
}
catch (ArgumentOutOfRangeException) {
Log.w("Could not load file (argument out of range): {0}", file.Filename);
return false;
}
catch (UnauthorizedAccessException) {
Log.w("Could not load file (not authorized): {0}", file.Filename);
return false;
}
catch (NullReferenceException) {
Log.w("Could not load file (null ref): {0}", file.Filename);
return false;
}
catch (IOException) {
Log.w("Could not load file (io exception): {0}", file.Filename);
catch (Exception ex) {
Log.w("Could not load file ({0}): {1}", ex.GetType(), file.Filename);
return false;
}

View File

@ -32,6 +32,7 @@ namespace de4dot.cui {
new de4dot.code.deobfuscators.Unknown.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Babel_NET.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CliSecure.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CodeVeil.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.CryptoObfuscator.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.DeepSea.DeobfuscatorInfo(),
new de4dot.code.deobfuscators.Dotfuscator.DeobfuscatorInfo(),