Merge branch 'goliath' into newcode
This commit is contained in:
commit
b647a9387b
|
@ -115,6 +115,17 @@
|
|||
<Compile Include="deobfuscators\dotNET_Reactor\v3\MemoryPatcher.cs" />
|
||||
<Compile Include="deobfuscators\Eazfuscator\Deobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\ExceptionLoggerRemover.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\ArrayDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\ArrayValueInliner.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\DecrypterBase.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\Deobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\IntegerDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\IntegerValueInliner.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\LocalsRestorer.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\LogicalExpressionFixer.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\ProxyDelegateFinder.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\StringDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\Goliath_NET\StrongNameChecker.cs" />
|
||||
<Compile Include="deobfuscators\IDeobfuscatedFile.cs" />
|
||||
<Compile Include="deobfuscators\IDeobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\IDeobfuscatorInfo.cs" />
|
||||
|
|
48
de4dot.code/deobfuscators/Goliath_NET/ArrayDecrypter.cs
Normal file
48
de4dot.code/deobfuscators/Goliath_NET/ArrayDecrypter.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Mono.Cecil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class ArrayDecrypter : DecrypterBase {
|
||||
public ArrayDecrypter(ModuleDefinition module)
|
||||
: base(module) {
|
||||
}
|
||||
|
||||
static string[] requiredFields = new string[] {
|
||||
"System.Byte[]",
|
||||
"System.Collections.Generic.Dictionary`2<System.Int32,System.Byte[]>",
|
||||
};
|
||||
protected override bool checkDecrypterType(TypeDefinition type) {
|
||||
return new FieldTypes(type).exactly(requiredFields);
|
||||
}
|
||||
|
||||
protected override bool checkDelegateInvokeMethod(MethodDefinition invokeMethod) {
|
||||
return DotNetUtils.isMethod(invokeMethod, "System.Byte[]", "(System.Int32)");
|
||||
}
|
||||
|
||||
public byte[] decrypt(MethodDefinition method) {
|
||||
var info = getInfo(method);
|
||||
decryptedReader.BaseStream.Position = info.offset;
|
||||
return decryptedReader.ReadBytes(decryptedReader.ReadInt32());
|
||||
}
|
||||
}
|
||||
}
|
96
de4dot.code/deobfuscators/Goliath_NET/ArrayValueInliner.cs
Normal file
96
de4dot.code/deobfuscators/Goliath_NET/ArrayValueInliner.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class ArrayValueInliner : MethodReturnValueInliner {
|
||||
MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, object[], byte[]>> intDecrypters = new MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, object[], byte[]>>();
|
||||
InitializedDataCreator initializedDataCreator;
|
||||
ModuleDefinition module;
|
||||
MethodReference initializeArrayMethod;
|
||||
|
||||
class MyCallResult : CallResult {
|
||||
public MethodReference methodReference;
|
||||
public MyCallResult(Block block, int callEndIndex, MethodReference method)
|
||||
: base(block, callEndIndex) {
|
||||
this.methodReference = method;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasHandlers {
|
||||
get { return intDecrypters.Count != 0; }
|
||||
}
|
||||
|
||||
public ArrayValueInliner(ModuleDefinition module, InitializedDataCreator initializedDataCreator) {
|
||||
this.module = module;
|
||||
this.initializedDataCreator = initializedDataCreator;
|
||||
|
||||
var runtimeHelpersType = DotNetUtils.findOrCreateTypeReference(module, module.TypeSystem.Corlib as AssemblyNameReference, "System.Runtime.CompilerServices", "RuntimeHelpers", false);
|
||||
initializeArrayMethod = new MethodReference("InitializeArray", module.TypeSystem.Void, runtimeHelpersType);
|
||||
var systemArrayType = DotNetUtils.findOrCreateTypeReference(module, module.TypeSystem.Corlib as AssemblyNameReference, "System", "Array", false);
|
||||
var runtimeFieldHandleType = DotNetUtils.findOrCreateTypeReference(module, module.TypeSystem.Corlib as AssemblyNameReference, "System", "RuntimeFieldHandle", true);
|
||||
initializeArrayMethod.Parameters.Add(new ParameterDefinition(systemArrayType));
|
||||
initializeArrayMethod.Parameters.Add(new ParameterDefinition(runtimeFieldHandleType));
|
||||
}
|
||||
|
||||
public void add(MethodDefinition method, Func<MethodDefinition, object[], byte[]> handler) {
|
||||
if (method == null)
|
||||
return;
|
||||
if (intDecrypters.find(method) != null)
|
||||
throw new ApplicationException(string.Format("Handler for method {0:X8} has already been added", method.MetadataToken.ToInt32()));
|
||||
intDecrypters.add(method, handler);
|
||||
}
|
||||
|
||||
protected override void inlineReturnValues(IList<CallResult> callResults) {
|
||||
foreach (var callResult in callResults) {
|
||||
var block = callResult.block;
|
||||
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
|
||||
|
||||
var ary = (byte[])callResult.returnValue;
|
||||
int index = callResult.callStartIndex;
|
||||
block.replace(index++, num, DotNetUtils.createLdci4(ary.Length));
|
||||
block.insert(index++, Instruction.Create(OpCodes.Newarr, module.TypeSystem.Byte));
|
||||
block.insert(index++, Instruction.Create(OpCodes.Dup));
|
||||
block.insert(index++, Instruction.Create(OpCodes.Ldtoken, initializedDataCreator.create(ary)));
|
||||
block.insert(index++, Instruction.Create(OpCodes.Call, initializeArrayMethod));
|
||||
|
||||
Log.v("Decrypted array: {0} bytes", ary.Length);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void inlineAllCalls() {
|
||||
foreach (var tmp in callResults) {
|
||||
var callResult = (MyCallResult)tmp;
|
||||
var handler = intDecrypters.find(callResult.methodReference);
|
||||
callResult.returnValue = handler((MethodDefinition)callResult.methodReference, callResult.args);
|
||||
}
|
||||
}
|
||||
|
||||
protected override CallResult createCallResult(MethodReference method, Block block, int callInstrIndex) {
|
||||
if (intDecrypters.find(method) == null)
|
||||
return null;
|
||||
return new MyCallResult(block, callInstrIndex, method);
|
||||
}
|
||||
}
|
||||
}
|
301
de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs
Normal file
301
de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs
Normal file
|
@ -0,0 +1,301 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
abstract class DecrypterBase {
|
||||
protected ModuleDefinition module;
|
||||
EmbeddedResource encryptedResource;
|
||||
TypeDefinition decrypterType;
|
||||
TypeDefinition delegateType;
|
||||
TypeDefinition delegateInitType;
|
||||
protected BinaryReader decryptedReader;
|
||||
MethodDefinitionAndDeclaringTypeDict<Info> decrypterMethods = new MethodDefinitionAndDeclaringTypeDict<Info>();
|
||||
|
||||
protected class Info {
|
||||
public MethodDefinition method;
|
||||
public int offset;
|
||||
public bool referenced = false;
|
||||
public Info(MethodDefinition method, int offset) {
|
||||
this.method = method;
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Detected {
|
||||
get { return encryptedResource != null; }
|
||||
}
|
||||
|
||||
public Resource EncryptedResource {
|
||||
get { return encryptedResource; }
|
||||
}
|
||||
|
||||
public TypeDefinition Type {
|
||||
get { return decrypterType; }
|
||||
}
|
||||
|
||||
public TypeDefinition DelegateInitType {
|
||||
get { return delegateInitType ?? findDelegateInitType();}
|
||||
}
|
||||
|
||||
public TypeDefinition DelegateType {
|
||||
get { return delegateType; }
|
||||
}
|
||||
|
||||
public IEnumerable<TypeDefinition> DecrypterTypes {
|
||||
get {
|
||||
var types = new TypeDefinitionDict<TypeDefinition>();
|
||||
foreach (var info in decrypterMethods.getValues()) {
|
||||
if (info.referenced)
|
||||
types.add(info.method.DeclaringType, info.method.DeclaringType);
|
||||
}
|
||||
return types.getValues();
|
||||
}
|
||||
}
|
||||
|
||||
public DecrypterBase(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
protected Info getInfo(MethodDefinition method) {
|
||||
var info = decrypterMethods.find(method);
|
||||
if (info == null)
|
||||
return null;
|
||||
|
||||
info.referenced = true;
|
||||
return info;
|
||||
}
|
||||
|
||||
public void find() {
|
||||
foreach (var tmp in module.Resources) {
|
||||
var resource = tmp as EmbeddedResource;
|
||||
if (resource == null)
|
||||
continue;
|
||||
if (!resource.Name.EndsWith(".resources", StringComparison.Ordinal))
|
||||
continue;
|
||||
string ns, name;
|
||||
splitTypeName(resource.Name.Substring(0, resource.Name.Length - 10), out ns, out name);
|
||||
var typeRef = new TypeReference(ns, name, module, module);
|
||||
var type = DotNetUtils.getType(module, typeRef);
|
||||
if (type == null)
|
||||
continue;
|
||||
if (!checkDecrypterType(type))
|
||||
continue;
|
||||
|
||||
encryptedResource = resource;
|
||||
decrypterType = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool checkDecrypterType(TypeDefinition type);
|
||||
|
||||
void splitTypeName(string fullName, out string ns, out string name) {
|
||||
int index = fullName.LastIndexOf('.');
|
||||
if (index < 0) {
|
||||
ns = "";
|
||||
name = fullName;
|
||||
}
|
||||
else {
|
||||
ns = fullName.Substring(0, index);
|
||||
name = fullName.Substring(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
if (encryptedResource == null)
|
||||
return;
|
||||
|
||||
decryptedReader = new BinaryReader(new MemoryStream(decrypt(encryptedResource.GetResourceData())));
|
||||
|
||||
delegateType = null;
|
||||
foreach (var type in module.GetTypes()) {
|
||||
var cctor = DotNetUtils.getMethod(type, ".cctor");
|
||||
if (cctor == null)
|
||||
continue;
|
||||
|
||||
if (type.Fields.Count != 1)
|
||||
continue;
|
||||
var field = type.Fields[0];
|
||||
var tmpDelegateType = DotNetUtils.getType(module, field.FieldType);
|
||||
if (tmpDelegateType == null)
|
||||
continue;
|
||||
|
||||
if (!checkDelegateType(tmpDelegateType))
|
||||
continue;
|
||||
if (delegateType != null && delegateType != tmpDelegateType)
|
||||
continue;
|
||||
|
||||
if (!checkCctor(cctor))
|
||||
continue;
|
||||
|
||||
delegateType = tmpDelegateType;
|
||||
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.Name == ".cctor")
|
||||
continue;
|
||||
if (!method.IsStatic || method.Body == null)
|
||||
continue;
|
||||
if (method.Parameters.Count != 0)
|
||||
continue;
|
||||
if (method.MethodReturnType.ReturnType.FullName == "System.Void")
|
||||
continue;
|
||||
var info = getDecrypterInfo(method, field);
|
||||
if (info == null)
|
||||
continue;
|
||||
|
||||
decrypterMethods.add(info.method, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Info getDecrypterInfo(MethodDefinition method, FieldDefinition delegateField) {
|
||||
try {
|
||||
int index = 0;
|
||||
var instrs = method.Body.Instructions;
|
||||
if (instrs[index].OpCode.Code != Code.Ldsfld)
|
||||
return null;
|
||||
var field = instrs[index++].Operand as FieldDefinition;
|
||||
if (field != delegateField)
|
||||
return null;
|
||||
|
||||
if (!DotNetUtils.isLdcI4(instrs[index]))
|
||||
return null;
|
||||
int offset = DotNetUtils.getLdcI4Value(instrs[index++]);
|
||||
|
||||
if (instrs[index].OpCode.Code != Code.Call && instrs[index].OpCode.Code != Code.Callvirt)
|
||||
return null;
|
||||
var calledMethod = instrs[index++].Operand as MethodReference;
|
||||
if (calledMethod.Name != "Invoke")
|
||||
return null;
|
||||
|
||||
if (instrs[index].OpCode.Code == Code.Unbox_Any)
|
||||
index++;
|
||||
|
||||
if (instrs[index++].OpCode.Code != Code.Ret)
|
||||
return null;
|
||||
|
||||
return new Info(method, offset);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
bool checkCctor(MethodDefinition cctor) {
|
||||
var ldtokenType = getLdtokenType(cctor);
|
||||
if (!MemberReferenceHelper.compareTypes(ldtokenType, cctor.DeclaringType))
|
||||
return false;
|
||||
|
||||
MethodDefinition initMethod = null;
|
||||
foreach (var info in DotNetUtils.getCalledMethods(module, cctor)) {
|
||||
var method = info.Item2;
|
||||
if (DotNetUtils.isMethod(method, "System.Void", "(System.Type)")) {
|
||||
initMethod = method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (initMethod == null || initMethod.Body == null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static TypeReference getLdtokenType(MethodDefinition method) {
|
||||
if (method == null || method.Body == null)
|
||||
return null;
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.OpCode.Code != Code.Ldtoken)
|
||||
continue;
|
||||
return instr.Operand as TypeReference;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool checkDelegateType(TypeDefinition type) {
|
||||
if (!DotNetUtils.derivesFromDelegate(type))
|
||||
return false;
|
||||
var invoke = DotNetUtils.getMethod(type, "Invoke");
|
||||
if (invoke == null)
|
||||
return false;
|
||||
return checkDelegateInvokeMethod(invoke);
|
||||
}
|
||||
|
||||
protected abstract bool checkDelegateInvokeMethod(MethodDefinition invokeMethod);
|
||||
|
||||
byte[] decrypt(byte[] encryptedData) {
|
||||
const int KEY_LEN = 0x100;
|
||||
if (encryptedData.Length < KEY_LEN)
|
||||
throw new ApplicationException("Invalid encrypted data length");
|
||||
var decryptedData = new byte[encryptedData.Length - KEY_LEN];
|
||||
var pkt = module.Assembly.Name.PublicKeyToken;
|
||||
if (pkt == null || pkt.Length == 0)
|
||||
pkt = new byte[8];
|
||||
|
||||
for (int i = 0, j = 0, ki = 0; i < decryptedData.Length; i++) {
|
||||
ki = (ki + 1) % (KEY_LEN - 1);
|
||||
j = (j + encryptedData[ki] + pkt[i % 8]) % (KEY_LEN - 1);
|
||||
var tmp = encryptedData[j];
|
||||
encryptedData[j] = encryptedData[ki];
|
||||
encryptedData[ki] = tmp;
|
||||
decryptedData[i] = (byte)(encryptedData[KEY_LEN + i] ^ encryptedData[(encryptedData[j] + encryptedData[ki]) % (KEY_LEN - 1)]);
|
||||
}
|
||||
|
||||
return decryptedData;
|
||||
}
|
||||
|
||||
TypeDefinition findDelegateInitType() {
|
||||
if (delegateType == null)
|
||||
return null;
|
||||
|
||||
foreach (var type in module.Types) {
|
||||
if (type.HasProperties || type.HasEvents || type.HasFields)
|
||||
continue;
|
||||
|
||||
foreach (var method in type.Methods) {
|
||||
if (!method.IsStatic || method.IsPrivate || method.Body == null)
|
||||
continue;
|
||||
var ldtokenType = getLdtokenType(method);
|
||||
if (ldtokenType == null)
|
||||
continue;
|
||||
if (!MemberReferenceHelper.compareTypes(ldtokenType, delegateType))
|
||||
continue;
|
||||
|
||||
delegateInitType = type;
|
||||
return delegateInitType;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public IEnumerable<MethodDefinition> getMethods() {
|
||||
var list = new List<MethodDefinition>(decrypterMethods.Count);
|
||||
foreach (var info in decrypterMethods.getValues())
|
||||
list.Add(info.method);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
281
de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs
Normal file
281
de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
|
||||
public const string THE_NAME = "Goliath.NET";
|
||||
public const string THE_TYPE = "go";
|
||||
const string DEFAULT_REGEX = @"!^[A-Za-z]{1,2}(?:`\d+)?$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX;
|
||||
BoolOption inlineMethods;
|
||||
BoolOption removeInlinedMethods;
|
||||
BoolOption restoreLocals;
|
||||
BoolOption decryptIntegers;
|
||||
BoolOption decryptArrays;
|
||||
BoolOption removeAntiStrongName;
|
||||
|
||||
public DeobfuscatorInfo()
|
||||
: base(DEFAULT_REGEX) {
|
||||
inlineMethods = new BoolOption(null, makeArgName("inline"), "Inline short methods", true);
|
||||
removeInlinedMethods = new BoolOption(null, makeArgName("remove-inlined"), "Remove inlined methods", true);
|
||||
restoreLocals = new BoolOption(null, makeArgName("locals"), "Restore locals", true);
|
||||
decryptIntegers = new BoolOption(null, makeArgName("ints"), "Decrypt integers", true);
|
||||
decryptArrays = new BoolOption(null, makeArgName("arrays"), "Decrypt arrays", true);
|
||||
removeAntiStrongName = new BoolOption(null, makeArgName("sn"), "Remove anti strong name code", true);
|
||||
}
|
||||
|
||||
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 {
|
||||
RenameResourcesInCode = false,
|
||||
ValidNameRegex = validNameRegex.get(),
|
||||
InlineMethods = inlineMethods.get(),
|
||||
RemoveInlinedMethods = removeInlinedMethods.get(),
|
||||
RestoreLocals = restoreLocals.get(),
|
||||
DecryptIntegers = decryptIntegers.get(),
|
||||
DecryptArrays = decryptArrays.get(),
|
||||
RemoveAntiStrongName = removeAntiStrongName.get(),
|
||||
});
|
||||
}
|
||||
|
||||
protected override IEnumerable<Option> getOptionsInternal() {
|
||||
return new List<Option>() {
|
||||
inlineMethods,
|
||||
removeInlinedMethods,
|
||||
restoreLocals,
|
||||
decryptIntegers,
|
||||
decryptArrays,
|
||||
removeAntiStrongName,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class Deobfuscator : DeobfuscatorBase {
|
||||
Options options;
|
||||
string obfuscatorName = DeobfuscatorInfo.THE_NAME;
|
||||
|
||||
ProxyDelegateFinder proxyDelegateFinder;
|
||||
LocalsRestorer localsRestorer;
|
||||
LogicalExpressionFixer logicalExpressionFixer;
|
||||
StringDecrypter stringDecrypter;
|
||||
IntegerDecrypter integerDecrypter;
|
||||
IntegerValueInliner integerValueInliner;
|
||||
ArrayDecrypter arrayDecrypter;
|
||||
ArrayValueInliner arrayValueInliner;
|
||||
StrongNameChecker strongNameChecker;
|
||||
|
||||
bool foundGoliathAttribute = false;
|
||||
bool startedDeobfuscating = false;
|
||||
|
||||
internal class Options : OptionsBase {
|
||||
public bool InlineMethods { get; set; }
|
||||
public bool RemoveInlinedMethods { get; set; }
|
||||
public bool RestoreLocals { get; set; }
|
||||
public bool DecryptIntegers { get; set; }
|
||||
public bool DecryptArrays { get; set; }
|
||||
public bool RemoveAntiStrongName { get; set; }
|
||||
}
|
||||
|
||||
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 override bool CanInlineMethods {
|
||||
get { return startedDeobfuscating ? options.InlineMethods : true; }
|
||||
}
|
||||
|
||||
internal Deobfuscator(Options options)
|
||||
: base(options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
protected override int detectInternal() {
|
||||
int val = 0;
|
||||
|
||||
int sum = convert(foundGoliathAttribute) +
|
||||
convert(stringDecrypter.Detected) +
|
||||
convert(integerDecrypter.Detected) +
|
||||
convert(arrayDecrypter.Detected) +
|
||||
convert(strongNameChecker.Detected) +
|
||||
convert(hasMetadataStream("#GOLIATH"));
|
||||
if (sum > 0)
|
||||
val += 100 + 10 * (sum - 1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
protected override void scanForObfuscator() {
|
||||
findGoliathAttribute();
|
||||
stringDecrypter = new StringDecrypter(module);
|
||||
stringDecrypter.find();
|
||||
integerDecrypter = new IntegerDecrypter(module);
|
||||
integerDecrypter.find();
|
||||
arrayDecrypter = new ArrayDecrypter(module);
|
||||
arrayDecrypter.find();
|
||||
strongNameChecker = new StrongNameChecker(module);
|
||||
strongNameChecker.find();
|
||||
}
|
||||
|
||||
void findGoliathAttribute() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.FullName.Contains("ObfuscatedByGoliath")) {
|
||||
foundGoliathAttribute = true;
|
||||
addAttributeToBeRemoved(type, "Obfuscator attribute");
|
||||
initializeVersion(type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initializeVersion(TypeDefinition attr) {
|
||||
var s = DotNetUtils.getCustomArgAsString(getAssemblyAttribute(attr), 0);
|
||||
if (s == null)
|
||||
return;
|
||||
|
||||
var val = System.Text.RegularExpressions.Regex.Match(s, @"^Goliath \.NET Obfuscator rel\. (\d+\.\d+\.\d+)$");
|
||||
if (val.Groups.Count < 2)
|
||||
return;
|
||||
obfuscatorName = DeobfuscatorInfo.THE_NAME + " " + val.Groups[1].ToString();
|
||||
return;
|
||||
}
|
||||
|
||||
public override void deobfuscateBegin() {
|
||||
base.deobfuscateBegin();
|
||||
|
||||
proxyDelegateFinder = new ProxyDelegateFinder(module);
|
||||
proxyDelegateFinder.find();
|
||||
localsRestorer = new LocalsRestorer(module);
|
||||
if (options.RestoreLocals)
|
||||
localsRestorer.find();
|
||||
|
||||
logicalExpressionFixer = new LogicalExpressionFixer();
|
||||
stringDecrypter.initialize();
|
||||
integerDecrypter.initialize();
|
||||
arrayDecrypter.initialize();
|
||||
|
||||
if (options.DecryptIntegers) {
|
||||
integerValueInliner = new IntegerValueInliner();
|
||||
foreach (var method in integerDecrypter.getMethods()) {
|
||||
integerValueInliner.add(method, (method2, args) => {
|
||||
return integerDecrypter.decrypt(method2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (options.DecryptArrays) {
|
||||
arrayValueInliner = new ArrayValueInliner(module, initializedDataCreator);
|
||||
foreach (var method in arrayDecrypter.getMethods()) {
|
||||
arrayValueInliner.add(method, (method2, args) => {
|
||||
return arrayDecrypter.decrypt(method2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var method in stringDecrypter.getMethods()) {
|
||||
staticStringDecrypter.add(method, (method2, args) => {
|
||||
return stringDecrypter.decrypt(method2);
|
||||
});
|
||||
}
|
||||
|
||||
if (options.RemoveAntiStrongName)
|
||||
addTypeToBeRemoved(strongNameChecker.Type, "Strong name checker type");
|
||||
|
||||
startedDeobfuscating = true;
|
||||
}
|
||||
|
||||
public override void deobfuscateMethodBegin(Blocks blocks) {
|
||||
proxyDelegateFinder.deobfuscate(blocks);
|
||||
base.deobfuscateMethodBegin(blocks);
|
||||
}
|
||||
|
||||
public override void deobfuscateMethodEnd(Blocks blocks) {
|
||||
stringDecrypter.deobfuscate(blocks);
|
||||
if (integerValueInliner.HasHandlers)
|
||||
integerValueInliner.decrypt(blocks);
|
||||
if (arrayValueInliner.HasHandlers)
|
||||
arrayValueInliner.decrypt(blocks);
|
||||
if (options.RestoreLocals)
|
||||
localsRestorer.deobfuscate(blocks);
|
||||
if (options.RemoveAntiStrongName) {
|
||||
if (strongNameChecker.deobfuscate(blocks))
|
||||
Log.v("Removed strong name checker code");
|
||||
}
|
||||
logicalExpressionFixer.deobfuscate(blocks);
|
||||
base.deobfuscateMethodEnd(blocks);
|
||||
}
|
||||
|
||||
public override void deobfuscateEnd() {
|
||||
removeProxyDelegates(proxyDelegateFinder);
|
||||
removeInlinedMethods();
|
||||
addTypesToBeRemoved(localsRestorer.Types, "Method locals obfuscation type");
|
||||
|
||||
if (Operations.DecryptStrings != OpDecryptString.None) {
|
||||
removeDecrypterStuff(stringDecrypter, "String", "strings");
|
||||
addTypeToBeRemoved(stringDecrypter.StringStruct, "String struct");
|
||||
}
|
||||
if (options.DecryptIntegers)
|
||||
removeDecrypterStuff(integerDecrypter, "Integer", "integers");
|
||||
if (options.DecryptArrays)
|
||||
removeDecrypterStuff(arrayDecrypter, "Array", "arrays");
|
||||
|
||||
base.deobfuscateEnd();
|
||||
}
|
||||
|
||||
void removeDecrypterStuff(DecrypterBase decrypter, string name1, string name2) {
|
||||
addResourceToBeRemoved(decrypter.EncryptedResource, "Encrypted " + name2);
|
||||
addTypesToBeRemoved(decrypter.DecrypterTypes, name1 + " decrypter type");
|
||||
addTypeToBeRemoved(decrypter.Type, name1 + " resource decrypter type");
|
||||
if (decrypter.DelegateInitType != null) {
|
||||
addTypeToBeRemoved(decrypter.DelegateType, name1 + " resource decrypter delegate type");
|
||||
addTypeToBeRemoved(decrypter.DelegateInitType, name1 + " delegate initializer type");
|
||||
}
|
||||
}
|
||||
|
||||
void removeInlinedMethods() {
|
||||
if (!options.InlineMethods || !options.RemoveInlinedMethods)
|
||||
return;
|
||||
findAndRemoveInlinedMethods();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> getStringDecrypterMethods() {
|
||||
var list = new List<string>();
|
||||
foreach (var method in stringDecrypter.getMethods())
|
||||
list.Add(method.MetadataToken.ToInt32().ToString("X8"));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
49
de4dot.code/deobfuscators/Goliath_NET/IntegerDecrypter.cs
Normal file
49
de4dot.code/deobfuscators/Goliath_NET/IntegerDecrypter.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Mono.Cecil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class IntegerDecrypter : DecrypterBase {
|
||||
public IntegerDecrypter(ModuleDefinition module)
|
||||
: base(module) {
|
||||
}
|
||||
|
||||
static string[] requiredFields = new string[] {
|
||||
"System.Byte[]",
|
||||
"System.Collections.Generic.Dictionary`2<System.Int32,System.Object>",
|
||||
};
|
||||
protected override bool checkDecrypterType(TypeDefinition type) {
|
||||
return new FieldTypes(type).exactly(requiredFields);
|
||||
}
|
||||
|
||||
protected override bool checkDelegateInvokeMethod(MethodDefinition invokeMethod) {
|
||||
return DotNetUtils.isMethod(invokeMethod, "System.Object", "(System.Int32)");
|
||||
}
|
||||
|
||||
public int decrypt(MethodDefinition method) {
|
||||
var info = getInfo(method);
|
||||
decryptedReader.BaseStream.Position = info.offset;
|
||||
int len = decryptedReader.ReadInt32();
|
||||
return BitConverter.ToInt32(decryptedReader.ReadBytes(len), 0);
|
||||
}
|
||||
}
|
||||
}
|
74
de4dot.code/deobfuscators/Goliath_NET/IntegerValueInliner.cs
Normal file
74
de4dot.code/deobfuscators/Goliath_NET/IntegerValueInliner.cs
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class IntegerValueInliner : MethodReturnValueInliner {
|
||||
MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, object[], int>> intDecrypters = new MethodDefinitionAndDeclaringTypeDict<Func<MethodDefinition, object[], int>>();
|
||||
|
||||
class MyCallResult : CallResult {
|
||||
public MethodReference methodReference;
|
||||
public MyCallResult(Block block, int callEndIndex, MethodReference method)
|
||||
: base(block, callEndIndex) {
|
||||
this.methodReference = method;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasHandlers {
|
||||
get { return intDecrypters.Count != 0; }
|
||||
}
|
||||
|
||||
public void add(MethodDefinition method, Func<MethodDefinition, object[], int> handler) {
|
||||
if (method == null)
|
||||
return;
|
||||
if (intDecrypters.find(method) != null)
|
||||
throw new ApplicationException(string.Format("Handler for method {0:X8} has already been added", method.MetadataToken.ToInt32()));
|
||||
intDecrypters.add(method, handler);
|
||||
}
|
||||
|
||||
protected override void inlineReturnValues(IList<CallResult> callResults) {
|
||||
foreach (var callResult in callResults) {
|
||||
var block = callResult.block;
|
||||
int num = callResult.callEndIndex - callResult.callStartIndex + 1;
|
||||
|
||||
block.replace(callResult.callStartIndex, num, DotNetUtils.createLdci4((int)callResult.returnValue));
|
||||
Log.v("Decrypted integer: {0}", callResult.returnValue);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void inlineAllCalls() {
|
||||
foreach (var tmp in callResults) {
|
||||
var callResult = (MyCallResult)tmp;
|
||||
var handler = intDecrypters.find(callResult.methodReference);
|
||||
callResult.returnValue = handler((MethodDefinition)callResult.methodReference, callResult.args);
|
||||
}
|
||||
}
|
||||
|
||||
protected override CallResult createCallResult(MethodReference method, Block block, int callInstrIndex) {
|
||||
if (intDecrypters.find(method) == null)
|
||||
return null;
|
||||
return new MyCallResult(block, callInstrIndex, method);
|
||||
}
|
||||
}
|
||||
}
|
148
de4dot.code/deobfuscators/Goliath_NET/LocalsRestorer.cs
Normal file
148
de4dot.code/deobfuscators/Goliath_NET/LocalsRestorer.cs
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class LocalsRestorer {
|
||||
ModuleDefinition module;
|
||||
TypeDefinitionDict<Info> typeToInfo = new TypeDefinitionDict<Info>();
|
||||
|
||||
class Info {
|
||||
public TypeDefinition type;
|
||||
public TypeReference localType;
|
||||
public bool referenced = false;
|
||||
public Info(TypeDefinition type, TypeReference localType) {
|
||||
this.type = type;
|
||||
this.localType = localType;
|
||||
}
|
||||
}
|
||||
|
||||
public List<TypeDefinition> Types {
|
||||
get {
|
||||
var list = new List<TypeDefinition>(typeToInfo.Count);
|
||||
foreach (var info in typeToInfo.getValues()) {
|
||||
if (info.referenced)
|
||||
list.Add(info.type);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public LocalsRestorer(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public void find() {
|
||||
foreach (var type in module.GetTypes())
|
||||
initialize(type);
|
||||
}
|
||||
|
||||
void initialize(TypeDefinition type) {
|
||||
if (type.HasEvents || type.HasProperties)
|
||||
return;
|
||||
|
||||
if (!type.IsValueType)
|
||||
return;
|
||||
if (type.Methods.Count != 1)
|
||||
return;
|
||||
var ctor = type.Methods[0];
|
||||
if (ctor.Name != ".ctor" || ctor.Body == null || ctor.IsStatic)
|
||||
return;
|
||||
if (ctor.Parameters.Count != 1)
|
||||
return;
|
||||
var ctorParam = ctor.Parameters[0];
|
||||
|
||||
if (type.Fields.Count != 1)
|
||||
return;
|
||||
var typeField = type.Fields[0];
|
||||
if (typeField.IsStatic)
|
||||
return;
|
||||
if (!MemberReferenceHelper.compareTypes(ctorParam.ParameterType, typeField.FieldType))
|
||||
return;
|
||||
|
||||
typeToInfo.add(ctor.DeclaringType, new Info(ctor.DeclaringType, typeField.FieldType));
|
||||
}
|
||||
|
||||
public void deobfuscate(Blocks blocks) {
|
||||
var instrsToRemove = new List<int>();
|
||||
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
|
||||
instrsToRemove.Clear();
|
||||
var instrs = block.Instructions;
|
||||
for (int i = 0; i < instrs.Count; i++) {
|
||||
var instr = instrs[i];
|
||||
int indexToRemove;
|
||||
TypeReference type;
|
||||
VariableDefinition local = null;
|
||||
|
||||
if (instr.OpCode.Code == Code.Newobj) {
|
||||
if (i + 1 >= instrs.Count)
|
||||
continue;
|
||||
var ctor = instr.Operand as MethodReference;
|
||||
if (ctor == null || ctor.DeclaringType == null)
|
||||
continue;
|
||||
if (ctor.Name != ".ctor")
|
||||
continue;
|
||||
|
||||
var next = instrs[i + 1];
|
||||
if (!next.isStloc() && !next.isLeave() && next.OpCode.Code != Code.Pop)
|
||||
continue;
|
||||
|
||||
indexToRemove = i;
|
||||
type = ctor.DeclaringType;
|
||||
if (next.isStloc())
|
||||
local = Instr.getLocalVar(blocks.Locals, next);
|
||||
}
|
||||
else if (instr.OpCode.Code == Code.Ldfld) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
var ldloc = instrs[i - 1];
|
||||
if (!ldloc.isLdloc())
|
||||
continue;
|
||||
|
||||
var field = instr.Operand as FieldReference;
|
||||
if (field == null || field.DeclaringType == null)
|
||||
continue;
|
||||
|
||||
indexToRemove = i;
|
||||
type = field.DeclaringType;
|
||||
local = Instr.getLocalVar(blocks.Locals, ldloc);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
if (type == null)
|
||||
continue;
|
||||
var info = typeToInfo.find(type);
|
||||
if (info == null)
|
||||
continue;
|
||||
|
||||
info.referenced = true;
|
||||
instrsToRemove.Add(indexToRemove);
|
||||
if (local != null)
|
||||
local.VariableType = info.localType;
|
||||
}
|
||||
block.remove(instrsToRemove);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class LogicalExpressionFixer {
|
||||
public void deobfuscate(Blocks blocks) {
|
||||
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
|
||||
var instrs = block.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var first = instrs[i];
|
||||
var second = instrs[i + 1];
|
||||
if (first.OpCode.Code == Code.Not && second.OpCode.Code == Code.Neg) {
|
||||
// It's increment
|
||||
instrs[i] = new Instr(Instruction.Create(OpCodes.Ldc_I4_1));
|
||||
instrs[i + 1] = new Instr(Instruction.Create(OpCodes.Add));
|
||||
}
|
||||
else if (first.OpCode.Code == Code.Neg && second.OpCode.Code == Code.Not) {
|
||||
// It's decrement
|
||||
instrs[i] = new Instr(Instruction.Create(OpCodes.Ldc_I4_1));
|
||||
instrs[i + 1] = new Instr(Instruction.Create(OpCodes.Sub));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
144
de4dot.code/deobfuscators/Goliath_NET/ProxyDelegateFinder.cs
Normal file
144
de4dot.code/deobfuscators/Goliath_NET/ProxyDelegateFinder.cs
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class ProxyDelegateFinder : ProxyDelegateFinderBase {
|
||||
public ProxyDelegateFinder(ModuleDefinition module)
|
||||
: base(module) {
|
||||
}
|
||||
|
||||
class MyInfo {
|
||||
public MethodDefinition method;
|
||||
public DelegateInfo delegateInfo;
|
||||
public MyInfo(MethodDefinition method, DelegateInfo delegateInfo) {
|
||||
this.method = method;
|
||||
this.delegateInfo = delegateInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public new void find() {
|
||||
Log.v("Finding all proxy delegates");
|
||||
var infos = new List<MyInfo>();
|
||||
foreach (var type in module.GetTypes()) {
|
||||
if (type.BaseType == null || type.BaseType.FullName != "System.MulticastDelegate")
|
||||
continue;
|
||||
|
||||
infos.Clear();
|
||||
foreach (var method in type.Methods) {
|
||||
DelegateInfo info;
|
||||
if (!checkProxyMethod(method, out info))
|
||||
continue;
|
||||
infos.Add(new MyInfo(method, info));
|
||||
}
|
||||
|
||||
if (infos.Count == 0)
|
||||
continue;
|
||||
|
||||
Log.v("Found proxy delegate: {0} ({1:X8})", type, type.MetadataToken.ToUInt32());
|
||||
RemovedDelegateCreatorCalls++;
|
||||
Log.indent();
|
||||
foreach (var info in infos) {
|
||||
var di = info.delegateInfo;
|
||||
add(info.method, di.field);
|
||||
addDelegateInfo(di);
|
||||
Log.v("Field: {0}, Opcode: {1}, Method: {2} ({3:X8})", di.field.Name, di.callOpcode, di.methodRef, di.methodRef.MetadataToken.ToUInt32());
|
||||
}
|
||||
Log.deIndent();
|
||||
delegateTypesDict[type] = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool checkProxyMethod(MethodDefinition method, out DelegateInfo info) {
|
||||
info = null;
|
||||
if (!method.IsStatic || method.Body == null)
|
||||
return false;
|
||||
|
||||
var instrs = method.Body.Instructions;
|
||||
if (instrs.Count < 7)
|
||||
return false;
|
||||
|
||||
int index = 0;
|
||||
|
||||
if (instrs[index].OpCode.Code != Code.Ldsfld)
|
||||
return false;
|
||||
var field = instrs[index++].Operand as FieldDefinition;
|
||||
if (field == null || !field.IsStatic)
|
||||
return false;
|
||||
if (!MemberReferenceHelper.compareTypes(method.DeclaringType, field.DeclaringType))
|
||||
return false;
|
||||
|
||||
if (!DotNetUtils.isBrtrue(instrs[index++]))
|
||||
return false;
|
||||
if (instrs[index++].OpCode.Code != Code.Ldnull)
|
||||
return false;
|
||||
if (instrs[index].OpCode.Code != Code.Ldftn)
|
||||
return false;
|
||||
var calledMethod = instrs[index++].Operand as MethodReference;
|
||||
if (calledMethod == null)
|
||||
return false;
|
||||
if (instrs[index++].OpCode.Code != Code.Newobj)
|
||||
return false;
|
||||
if (instrs[index].OpCode.Code != Code.Stsfld)
|
||||
return false;
|
||||
if (!MemberReferenceHelper.compareFieldReference(field, instrs[index++].Operand as FieldReference))
|
||||
return false;
|
||||
if (instrs[index].OpCode.Code != Code.Ldsfld)
|
||||
return false;
|
||||
if (!MemberReferenceHelper.compareFieldReference(field, instrs[index++].Operand as FieldReference))
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < method.Parameters.Count; i++) {
|
||||
if (index >= instrs.Count)
|
||||
return false;
|
||||
if (DotNetUtils.getArgIndex(method, instrs[index++]) != i)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index + 2 > instrs.Count)
|
||||
return false;
|
||||
var call = instrs[index++];
|
||||
if (call.OpCode.Code != Code.Callvirt)
|
||||
return false;
|
||||
|
||||
if (instrs[index++].OpCode.Code != Code.Ret)
|
||||
return false;
|
||||
|
||||
info = new DelegateInfo(field, calledMethod, OpCodes.Call);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override object checkCctor(TypeDefinition type, MethodDefinition cctor) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void onFoundProxyDelegate(TypeDefinition type) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void getCallInfo(object context, FieldDefinition field, out MethodReference calledMethod, out OpCode callOpcode) {
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
116
de4dot.code/deobfuscators/Goliath_NET/StringDecrypter.cs
Normal file
116
de4dot.code/deobfuscators/Goliath_NET/StringDecrypter.cs
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class StringDecrypter : DecrypterBase {
|
||||
TypeReference delegateReturnType;
|
||||
FieldDefinition stringStructField;
|
||||
|
||||
public TypeDefinition StringStruct {
|
||||
get { return Detected && stringStructField != null ? stringStructField.DeclaringType : null; }
|
||||
}
|
||||
|
||||
public StringDecrypter(ModuleDefinition module)
|
||||
: base(module) {
|
||||
}
|
||||
|
||||
static string[] requiredFields = new string[] {
|
||||
"System.Byte[]",
|
||||
"System.Collections.Generic.Dictionary`2<System.Int32,System.String>",
|
||||
};
|
||||
protected override bool checkDecrypterType(TypeDefinition type) {
|
||||
var fields = type.Fields;
|
||||
if (fields.Count != 2)
|
||||
return false;
|
||||
|
||||
if (fields[0].FieldType.FullName != "System.Byte[]")
|
||||
return false;
|
||||
|
||||
var dict = fields[1].FieldType as GenericInstanceType;
|
||||
if (dict == null || dict.GenericArguments.Count != 2)
|
||||
return false;
|
||||
if (dict.ElementType.FullName != "System.Collections.Generic.Dictionary`2")
|
||||
return false;
|
||||
|
||||
if (dict.GenericArguments[0].FullName != "System.Int32")
|
||||
return false;
|
||||
|
||||
var garg = dict.GenericArguments[1];
|
||||
if (garg.FullName != "System.String") {
|
||||
if (!garg.IsValueType)
|
||||
return false;
|
||||
var gargType = DotNetUtils.getType(module, garg);
|
||||
if (gargType == null || !gargType.IsClass)
|
||||
return false;
|
||||
if (gargType.Fields.Count != 1)
|
||||
return false;
|
||||
var field = gargType.Fields[0];
|
||||
if (field.FieldType.FullName != "System.String")
|
||||
return false;
|
||||
delegateReturnType = gargType;
|
||||
stringStructField = field;
|
||||
}
|
||||
else {
|
||||
delegateReturnType = garg;
|
||||
stringStructField = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool checkDelegateInvokeMethod(MethodDefinition invokeMethod) {
|
||||
return DotNetUtils.isMethod(invokeMethod, delegateReturnType.FullName, "(System.Int32)");
|
||||
}
|
||||
|
||||
public string decrypt(MethodDefinition method) {
|
||||
var info = getInfo(method);
|
||||
decryptedReader.BaseStream.Position = info.offset;
|
||||
int len = decryptedReader.ReadInt32();
|
||||
return Encoding.UTF8.GetString(decryptedReader.ReadBytes(len));
|
||||
}
|
||||
|
||||
public void deobfuscate(Blocks blocks) {
|
||||
if (!Detected)
|
||||
return;
|
||||
if (stringStructField == null)
|
||||
return;
|
||||
|
||||
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
|
||||
var instrs = block.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var ldstr = instrs[i];
|
||||
if (ldstr.OpCode.Code != Code.Ldstr)
|
||||
continue;
|
||||
var ldfld = instrs[i + 1];
|
||||
if (ldfld.OpCode.Code != Code.Ldfld)
|
||||
continue;
|
||||
if (!MemberReferenceHelper.compareFieldReferenceAndDeclaringType(stringStructField, ldfld.Operand as FieldReference))
|
||||
continue;
|
||||
block.remove(i + 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
127
de4dot.code/deobfuscators/Goliath_NET/StrongNameChecker.cs
Normal file
127
de4dot.code/deobfuscators/Goliath_NET/StrongNameChecker.cs
Normal file
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Copyright (C) 2011 de4dot@gmail.com
|
||||
|
||||
This file is part of de4dot.
|
||||
|
||||
de4dot is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
de4dot is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
using de4dot.blocks;
|
||||
|
||||
namespace de4dot.code.deobfuscators.Goliath_NET {
|
||||
class StrongNameChecker {
|
||||
ModuleDefinition module;
|
||||
TypeDefinition strongNameType;
|
||||
MethodDefinition strongNameCheckMethod;
|
||||
|
||||
public bool Detected {
|
||||
get { return strongNameType != null;}
|
||||
}
|
||||
|
||||
public TypeDefinition Type {
|
||||
get { return strongNameType; }
|
||||
}
|
||||
|
||||
public MethodDefinition CheckerMethod {
|
||||
get { return strongNameCheckMethod; }
|
||||
}
|
||||
|
||||
public StrongNameChecker(ModuleDefinition module) {
|
||||
this.module = module;
|
||||
}
|
||||
|
||||
public void find() {
|
||||
foreach (var type in module.Types) {
|
||||
if (type.HasFields || type.HasEvents || type.HasProperties)
|
||||
continue;
|
||||
|
||||
var checkMethod = getAntiTamperingDetectionMethod(type);
|
||||
if (checkMethod == null)
|
||||
continue;
|
||||
|
||||
if (DotNetUtils.getMethod(type, "System.Byte[]", "(System.Reflection.Assembly)") == null)
|
||||
continue;
|
||||
if (DotNetUtils.getMethod(type, "System.String", "(System.Collections.Generic.Stack`1<System.Int32>)") == null)
|
||||
continue;
|
||||
if (DotNetUtils.getMethod(type, "System.Int32", "(System.Int32,System.Byte[])") == null)
|
||||
continue;
|
||||
|
||||
strongNameType = type;
|
||||
strongNameCheckMethod = checkMethod;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MethodDefinition getAntiTamperingDetectionMethod(TypeDefinition type) {
|
||||
var requiredLocals = new string[] {
|
||||
"System.Reflection.Assembly",
|
||||
"System.Collections.Generic.Stack`1<System.Int32>",
|
||||
};
|
||||
foreach (var method in type.Methods) {
|
||||
if (!method.IsStatic || method.Body == null)
|
||||
continue;
|
||||
if (!DotNetUtils.isMethod(method, "System.Void", "(System.Type)"))
|
||||
continue;
|
||||
if (!new LocalTypes(method).all(requiredLocals))
|
||||
continue;
|
||||
if (!hasThrow(method))
|
||||
continue;
|
||||
|
||||
return method;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static bool hasThrow(MethodDefinition method) {
|
||||
if (method == null || method.Body == null)
|
||||
return false;
|
||||
foreach (var instr in method.Body.Instructions) {
|
||||
if (instr.OpCode.Code == Code.Throw)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool deobfuscate(Blocks blocks) {
|
||||
if (blocks.Method.Name != ".cctor" && blocks.Method.Name != ".ctor")
|
||||
return false;
|
||||
foreach (var block in blocks.MethodBlocks.getAllBlocks()) {
|
||||
var instrs = block.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 2; i++) {
|
||||
var ldtoken = instrs[i];
|
||||
if (ldtoken.OpCode.Code != Code.Ldtoken)
|
||||
continue;
|
||||
|
||||
var call1 = instrs[i + 1];
|
||||
if (call1.OpCode.Code != Code.Call && call1.OpCode.Code != Code.Callvirt)
|
||||
continue;
|
||||
if (!DotNetUtils.isMethod(call1.Operand as MethodReference, "System.Type", "(System.RuntimeTypeHandle)"))
|
||||
continue;
|
||||
|
||||
var call2 = instrs[i + 2];
|
||||
if (call2.OpCode.Code != Code.Call && call2.OpCode.Code != Code.Callvirt)
|
||||
continue;
|
||||
if (!MemberReferenceHelper.compareMethodReferenceAndDeclaringType(call2.Operand as MethodReference, strongNameCheckMethod))
|
||||
continue;
|
||||
|
||||
block.remove(i, 3);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -99,8 +99,6 @@ namespace de4dot.code.deobfuscators.Unknown {
|
|||
return "CodeFort";
|
||||
if (type.FullName == "____KILL")
|
||||
return "DeployLX CodeVeil";
|
||||
if (type.FullName.Contains("ObfuscatedByGoliath"))
|
||||
return "Goliath .NET Obfuscator";
|
||||
if (type.FullName == "ZYXDNGuarder")
|
||||
return "DNGuard HVM";
|
||||
if (type.FullName == "InfaceMaxtoCode")
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace de4dot.cui {
|
|||
new de4dot.code.deobfuscators.dotNET_Reactor.v3.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.dotNET_Reactor.v4.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.Eazfuscator.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.Goliath_NET.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.SmartAssembly.DeobfuscatorInfo(),
|
||||
new de4dot.code.deobfuscators.Xenocode.DeobfuscatorInfo(),
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user