diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index c09a92d9..42f7b6f6 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -115,6 +115,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/de4dot.code/deobfuscators/Goliath_NET/ArrayDecrypter.cs b/de4dot.code/deobfuscators/Goliath_NET/ArrayDecrypter.cs
new file mode 100644
index 00000000..ccf986c4
--- /dev/null
+++ b/de4dot.code/deobfuscators/Goliath_NET/ArrayDecrypter.cs
@@ -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 .
+*/
+
+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",
+ };
+ 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());
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Goliath_NET/ArrayValueInliner.cs b/de4dot.code/deobfuscators/Goliath_NET/ArrayValueInliner.cs
new file mode 100644
index 00000000..8889dc73
--- /dev/null
+++ b/de4dot.code/deobfuscators/Goliath_NET/ArrayValueInliner.cs
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2011 de4dot@gmail.com
+
+ This file is part of de4dot.
+
+ de4dot is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ de4dot is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with de4dot. If not, see .
+*/
+
+using System;
+using System.Collections.Generic;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using de4dot.blocks;
+
+namespace de4dot.code.deobfuscators.Goliath_NET {
+ class ArrayValueInliner : MethodReturnValueInliner {
+ MethodDefinitionAndDeclaringTypeDict> intDecrypters = new MethodDefinitionAndDeclaringTypeDict>();
+ 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 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 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);
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs b/de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs
new file mode 100644
index 00000000..d3731224
--- /dev/null
+++ b/de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs
@@ -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 .
+*/
+
+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 decrypterMethods = new MethodDefinitionAndDeclaringTypeDict();
+
+ 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 DecrypterTypes {
+ get {
+ var types = new TypeDefinitionDict();
+ 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 getMethods() {
+ var list = new List(decrypterMethods.Count);
+ foreach (var info in decrypterMethods.getValues())
+ list.Add(info.method);
+ return list;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs
new file mode 100644
index 00000000..c92bc1b1
--- /dev/null
+++ b/de4dot.code/deobfuscators/Goliath_NET/Deobfuscator.cs
@@ -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 .
+*/
+
+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