diff --git a/AssemblyData/Properties/AssemblyInfo.cs b/AssemblyData/Properties/AssemblyInfo.cs index f6cdc24d..27f8b583 100644 --- a/AssemblyData/Properties/AssemblyInfo.cs +++ b/AssemblyData/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.8.6.3405")] -[assembly: AssemblyFileVersion("1.8.6.3405")] +[assembly: AssemblyVersion("1.8.7.3405")] +[assembly: AssemblyFileVersion("1.8.7.3405")] diff --git a/AssemblyServer-x64/Properties/AssemblyInfo.cs b/AssemblyServer-x64/Properties/AssemblyInfo.cs index e1ae73ac..347ddd9c 100644 --- a/AssemblyServer-x64/Properties/AssemblyInfo.cs +++ b/AssemblyServer-x64/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.8.6.3405")] -[assembly: AssemblyFileVersion("1.8.6.3405")] +[assembly: AssemblyVersion("1.8.7.3405")] +[assembly: AssemblyFileVersion("1.8.7.3405")] diff --git a/AssemblyServer/Properties/AssemblyInfo.cs b/AssemblyServer/Properties/AssemblyInfo.cs index 8c13053a..47997de1 100644 --- a/AssemblyServer/Properties/AssemblyInfo.cs +++ b/AssemblyServer/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.8.6.3405")] -[assembly: AssemblyFileVersion("1.8.6.3405")] +[assembly: AssemblyVersion("1.8.7.3405")] +[assembly: AssemblyFileVersion("1.8.7.3405")] diff --git a/Test.Rename.Dll/Properties/AssemblyInfo.cs b/Test.Rename.Dll/Properties/AssemblyInfo.cs index fcb57a9e..5923486a 100644 --- a/Test.Rename.Dll/Properties/AssemblyInfo.cs +++ b/Test.Rename.Dll/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.8.6.3405")] -[assembly: AssemblyFileVersion("1.8.6.3405")] +[assembly: AssemblyVersion("1.8.7.3405")] +[assembly: AssemblyFileVersion("1.8.7.3405")] diff --git a/Test.Rename/Properties/AssemblyInfo.cs b/Test.Rename/Properties/AssemblyInfo.cs index 70ee8769..0bbf3a93 100644 --- a/Test.Rename/Properties/AssemblyInfo.cs +++ b/Test.Rename/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.8.6.3405")] -[assembly: AssemblyFileVersion("1.8.6.3405")] +[assembly: AssemblyVersion("1.8.7.3405")] +[assembly: AssemblyFileVersion("1.8.7.3405")] diff --git a/blocks/DotNetUtils.cs b/blocks/DotNetUtils.cs index 4d136dd9..1ac93a93 100644 --- a/blocks/DotNetUtils.cs +++ b/blocks/DotNetUtils.cs @@ -462,11 +462,23 @@ namespace de4dot.blocks { } public static MethodDefinition getMethod(ModuleDefinition module, MethodReference method) { + if (method == null) + return null; + return getMethod(module, method, method.DeclaringType); + } + + public static MethodDefinition getMethod2(ModuleDefinition module, MethodReference method) { + if (method == null) + return null; + return getMethod(module, method, method.DeclaringType.GetElementType()); + } + + static MethodDefinition getMethod(ModuleDefinition module, MethodReference method, TypeReference declaringType) { if (method == null) return null; if (method is MethodDefinition) return (MethodDefinition)method; - return getMethod(getType(module, method.DeclaringType), method); + return getMethod(getType(module, declaringType), method); } public static MethodDefinition getMethod(TypeDefinition type, string returnType, string parameters) { diff --git a/blocks/Properties/AssemblyInfo.cs b/blocks/Properties/AssemblyInfo.cs index 1c9315df..532676d3 100644 --- a/blocks/Properties/AssemblyInfo.cs +++ b/blocks/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.8.6.3405")] -[assembly: AssemblyFileVersion("1.8.6.3405")] +[assembly: AssemblyVersion("1.8.7.3405")] +[assembly: AssemblyFileVersion("1.8.7.3405")] diff --git a/cecil b/cecil index e420b072..ce087fb8 160000 --- a/cecil +++ b/cecil @@ -1 +1 @@ -Subproject commit e420b072ae91a28f4f79e505194076d62b52587d +Subproject commit ce087fb87af13b15d4abc552b3927024accf023a diff --git a/de4dot-x64/Properties/AssemblyInfo.cs b/de4dot-x64/Properties/AssemblyInfo.cs index 8a647cbe..9dd9c4be 100644 --- a/de4dot-x64/Properties/AssemblyInfo.cs +++ b/de4dot-x64/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.8.6.3405")] -[assembly: AssemblyFileVersion("1.8.6.3405")] +[assembly: AssemblyVersion("1.8.7.3405")] +[assembly: AssemblyFileVersion("1.8.7.3405")] diff --git a/de4dot.code/ObfuscatedFile.cs b/de4dot.code/ObfuscatedFile.cs index 15c38078..e120a1ef 100644 --- a/de4dot.code/ObfuscatedFile.cs +++ b/de4dot.code/ObfuscatedFile.cs @@ -731,7 +731,11 @@ namespace de4dot.code { } void ISimpleDeobfuscator.deobfuscate(MethodDefinition method) { - if (check(method, SimpleDeobFlags.HasDeobfuscated)) + ((ISimpleDeobfuscator)this).deobfuscate(method, false); + } + + void ISimpleDeobfuscator.deobfuscate(MethodDefinition method, bool force) { + if (!force && check(method, SimpleDeobFlags.HasDeobfuscated)) return; deobfuscate(method, "Deobfuscating control flow", (blocks) => { diff --git a/de4dot.code/Properties/AssemblyInfo.cs b/de4dot.code/Properties/AssemblyInfo.cs index b3f1f083..e98db1fc 100644 --- a/de4dot.code/Properties/AssemblyInfo.cs +++ b/de4dot.code/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.8.6.3405")] -[assembly: AssemblyFileVersion("1.8.6.3405")] +[assembly: AssemblyVersion("1.8.7.3405")] +[assembly: AssemblyFileVersion("1.8.7.3405")] diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index eadd896d..e53e1bdd 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -70,6 +70,14 @@ + + + + + + + + diff --git a/de4dot.code/deobfuscators/Blowfish.cs b/de4dot.code/deobfuscators/Blowfish.cs index 6dff1461..02cde9f4 100644 --- a/de4dot.code/deobfuscators/Blowfish.cs +++ b/de4dot.code/deobfuscators/Blowfish.cs @@ -318,6 +318,22 @@ namespace de4dot.code.deobfuscators { } } + public void encrypt_LE(byte[] data) { + for (int i = 0; i + 8 <= data.Length; i += 8) { + uint xl = BitConverter.ToUInt32(data, i); + uint xr = BitConverter.ToUInt32(data, i + 4); + encrypt(ref xl, ref xr); + data[i] = (byte)xl; + data[i + 1] = (byte)(xl >> 8); + data[i + 2] = (byte)(xl >> 16); + data[i + 3] = (byte)(xl >> 24); + data[i + 4] = (byte)xr; + data[i + 5] = (byte)(xr >> 8); + data[i + 6] = (byte)(xr >> 16); + data[i + 7] = (byte)(xr >> 24); + } + } + public void encrypt(byte[] data) { for (int i = 0; i + 8 <= data.Length; i += 8) { uint xl = (uint)((data[i] << 24) | (data[i + 1] << 16) | (data[i + 2] << 8) | data[i + 3]); @@ -347,6 +363,22 @@ namespace de4dot.code.deobfuscators { rxl = xr ^ P[17]; } + public void decrypt_LE(byte[] data) { + for (int i = 0; i + 8 <= data.Length; i += 8) { + uint xl = BitConverter.ToUInt32(data, i); + uint xr = BitConverter.ToUInt32(data, i + 4); + decrypt(ref xl, ref xr); + data[i] = (byte)xl; + data[i + 1] = (byte)(xl >> 8); + data[i + 2] = (byte)(xl >> 16); + data[i + 3] = (byte)(xl >> 24); + data[i + 4] = (byte)xr; + data[i + 5] = (byte)(xr >> 8); + data[i + 6] = (byte)(xr >> 16); + data[i + 7] = (byte)(xr >> 24); + } + } + public void decrypt(byte[] data) { for (int i = 0; i + 8 <= data.Length; i += 8) { uint xl = (uint)((data[i] << 24) | (data[i + 1] << 16) | (data[i + 2] << 8) | data[i + 3]); diff --git a/de4dot.code/deobfuscators/DeepSea/ArrayBlockDeobfuscator.cs b/de4dot.code/deobfuscators/DeepSea/ArrayBlockDeobfuscator.cs index ac100559..79bf6340 100644 --- a/de4dot.code/deobfuscators/DeepSea/ArrayBlockDeobfuscator.cs +++ b/de4dot.code/deobfuscators/DeepSea/ArrayBlockDeobfuscator.cs @@ -20,73 +20,17 @@ using System.Collections.Generic; using Mono.Cecil; using Mono.Cecil.Cil; -using Mono.Cecil.Metadata; using de4dot.blocks; using de4dot.blocks.cflow; namespace de4dot.code.deobfuscators.DeepSea { class ArrayBlockDeobfuscator : BlockDeobfuscator { - ModuleDefinition module; - FieldDefinitionAndDeclaringTypeDict fieldToInfo = new FieldDefinitionAndDeclaringTypeDict(); - Dictionary localToInfo = new Dictionary(); + ArrayBlockState arrayBlockState; + Dictionary localToInfo = new Dictionary(); DsConstantsReader constantsReader; - class FieldInfo { - public readonly FieldDefinition field; - public readonly FieldDefinition arrayInitField; - public readonly byte[] array; - - public FieldInfo(FieldDefinition field, FieldDefinition arrayInitField) { - this.field = field; - this.arrayInitField = arrayInitField; - this.array = (byte[])arrayInitField.InitialValue.Clone(); - } - } - - public bool Detected { - get { return fieldToInfo.Count != 0; } - } - - public ArrayBlockDeobfuscator(ModuleDefinition module) { - this.module = module; - } - - public void init() { - initializeArrays(DotNetUtils.getModuleTypeCctor(module)); - } - - void initializeArrays(MethodDefinition method) { - if (method == null || method.Body == null) - return; - - var instructions = method.Body.Instructions; - for (int i = 0; i < instructions.Count; i++) { - var ldci4 = instructions[i]; - if (!DotNetUtils.isLdcI4(ldci4)) - continue; - i++; - var instrs = DotNetUtils.getInstructions(instructions, i, OpCodes.Newarr, OpCodes.Dup, OpCodes.Ldtoken, OpCodes.Call, OpCodes.Stsfld); - if (instrs == null) - continue; - - var arrayType = instrs[0].Operand as TypeReference; - if (arrayType == null || arrayType.EType != ElementType.U1) - continue; - - var arrayInitField = instrs[2].Operand as FieldDefinition; - if (arrayInitField == null || arrayInitField.InitialValue == null || arrayInitField.InitialValue.Length == 0) - continue; - - var calledMethod = instrs[3].Operand as MethodReference; - if (calledMethod == null || calledMethod.FullName != "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") - continue; - - var targetField = instrs[4].Operand as FieldDefinition; - if (targetField == null) - continue; - - fieldToInfo.add(targetField, new FieldInfo(targetField, arrayInitField)); - } + public ArrayBlockDeobfuscator(ArrayBlockState arrayBlockState) { + this.arrayBlockState = arrayBlockState; } public override void deobfuscateBegin(Blocks blocks) { @@ -107,7 +51,7 @@ namespace de4dot.code.deobfuscators.DeepSea { if (!stloc.isStloc()) continue; - var info = fieldToInfo.find((FieldReference)ldsfld.Operand); + var info = arrayBlockState.getFieldInfo((FieldReference)ldsfld.Operand); if (info == null) continue; var local = DotNetUtils.getLocalVar(blocks.Locals, stloc.Instruction); @@ -158,7 +102,7 @@ namespace de4dot.code.deobfuscators.DeepSea { var local = DotNetUtils.getLocalVar(blocks.Locals, ldloc.Instruction); if (local == null) return false; - FieldInfo info; + ArrayBlockState.FieldInfo info; if (!localToInfo.TryGetValue(local, out info)) return false; @@ -183,7 +127,7 @@ namespace de4dot.code.deobfuscators.DeepSea { var ldsfld = instrs[i]; if (ldsfld.OpCode.Code != Code.Ldsfld) return false; - var info = fieldToInfo.find(ldsfld.Operand as FieldReference); + var info = arrayBlockState.getFieldInfo(ldsfld.Operand as FieldReference); if (info == null) return false; @@ -209,7 +153,7 @@ namespace de4dot.code.deobfuscators.DeepSea { var ldsfld = instrs[i]; if (ldsfld.OpCode.Code != Code.Ldsfld) return false; - var info = fieldToInfo.find(ldsfld.Operand as FieldReference); + var info = arrayBlockState.getFieldInfo(ldsfld.Operand as FieldReference); if (info == null) return false; @@ -237,90 +181,5 @@ namespace de4dot.code.deobfuscators.DeepSea { return constantsReader; return constantsReader = new DsConstantsReader(block.Instructions); } - - public IEnumerable cleanUp() { - var removedFields = new List(); - var moduleCctor = DotNetUtils.getModuleTypeCctor(module); - if (moduleCctor == null) - return removedFields; - var moduleCctorBlocks = new Blocks(moduleCctor); - - var keep = findFieldsToKeep(); - foreach (var fieldInfo in fieldToInfo.getValues()) { - if (keep.ContainsKey(fieldInfo)) - continue; - if (removeInitCode(moduleCctorBlocks, fieldInfo)) { - removedFields.Add(fieldInfo.field); - removedFields.Add(fieldInfo.arrayInitField); - } - fieldInfo.arrayInitField.InitialValue = new byte[1]; - fieldInfo.arrayInitField.FieldType = module.TypeSystem.Byte; - } - - IList allInstructions; - IList allExceptionHandlers; - moduleCctorBlocks.getCode(out allInstructions, out allExceptionHandlers); - DotNetUtils.restoreBody(moduleCctorBlocks.Method, allInstructions, allExceptionHandlers); - return removedFields; - } - - bool removeInitCode(Blocks blocks, FieldInfo info) { - bool removedSomething = false; - foreach (var block in blocks.MethodBlocks.getAllBlocks()) { - var instrs = block.Instructions; - for (int i = 0; i < instrs.Count - 5; i++) { - var ldci4 = instrs[i]; - if (!ldci4.isLdcI4()) - continue; - if (instrs[i + 1].OpCode.Code != Code.Newarr) - continue; - if (instrs[i + 2].OpCode.Code != Code.Dup) - continue; - var ldtoken = instrs[i + 3]; - if (ldtoken.OpCode.Code != Code.Ldtoken) - continue; - if (ldtoken.Operand != info.arrayInitField) - continue; - var call = instrs[i + 4]; - if (call.OpCode.Code != Code.Call) - continue; - var calledMethod = call.Operand as MethodReference; - if (calledMethod == null || calledMethod.FullName != "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") - continue; - var stsfld = instrs[i + 5]; - if (stsfld.OpCode.Code != Code.Stsfld) - continue; - if (stsfld.Operand != info.field) - continue; - block.remove(i, 6); - i--; - removedSomething = true; - } - } - return removedSomething; - } - - Dictionary findFieldsToKeep() { - var keep = new Dictionary(); - foreach (var type in module.GetTypes()) { - foreach (var method in type.Methods) { - if (type == DotNetUtils.getModuleType(module) && method.Name == ".cctor") - continue; - if (method.Body == null) - continue; - - foreach (var instr in method.Body.Instructions) { - var field = instr.Operand as FieldReference; - if (field == null) - continue; - var fieldInfo = fieldToInfo.find(field); - if (fieldInfo == null) - continue; - keep[fieldInfo] = true; - } - } - } - return keep; - } } } diff --git a/de4dot.code/deobfuscators/DeepSea/ArrayBlockState.cs b/de4dot.code/deobfuscators/DeepSea/ArrayBlockState.cs new file mode 100644 index 00000000..383129ee --- /dev/null +++ b/de4dot.code/deobfuscators/DeepSea/ArrayBlockState.cs @@ -0,0 +1,190 @@ +/* + 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 . +*/ + +using System.Collections.Generic; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Metadata; +using de4dot.blocks; + +namespace de4dot.code.deobfuscators.DeepSea { + class ArrayBlockState { + ModuleDefinition module; + FieldDefinitionAndDeclaringTypeDict fieldToInfo = new FieldDefinitionAndDeclaringTypeDict(); + + public class FieldInfo { + public readonly FieldDefinition field; + public readonly FieldDefinition arrayInitField; + public readonly byte[] array; + + public FieldInfo(FieldDefinition field, FieldDefinition arrayInitField) { + this.field = field; + this.arrayInitField = arrayInitField; + this.array = (byte[])arrayInitField.InitialValue.Clone(); + } + } + + public bool Detected { + get { return fieldToInfo.Count != 0; } + } + + public ArrayBlockState(ModuleDefinition module) { + this.module = module; + } + + public void init(ISimpleDeobfuscator simpleDeobfuscator) { + initializeArrays(simpleDeobfuscator, DotNetUtils.getModuleTypeCctor(module)); + } + + void initializeArrays(ISimpleDeobfuscator simpleDeobfuscator, MethodDefinition method) { + if (method == null || method.Body == null) + return; + while (initializeArrays2(simpleDeobfuscator, method)) { + } + } + + bool initializeArrays2(ISimpleDeobfuscator simpleDeobfuscator, MethodDefinition method) { + bool foundField = false; + simpleDeobfuscator.deobfuscate(method, true); + var instructions = method.Body.Instructions; + for (int i = 0; i < instructions.Count; i++) { + var ldci4 = instructions[i]; + if (!DotNetUtils.isLdcI4(ldci4)) + continue; + i++; + var instrs = DotNetUtils.getInstructions(instructions, i, OpCodes.Newarr, OpCodes.Dup, OpCodes.Ldtoken, OpCodes.Call, OpCodes.Stsfld); + if (instrs == null) + continue; + + var arrayType = instrs[0].Operand as TypeReference; + if (arrayType == null || arrayType.EType != ElementType.U1) + continue; + + var arrayInitField = instrs[2].Operand as FieldDefinition; + if (arrayInitField == null || arrayInitField.InitialValue == null || arrayInitField.InitialValue.Length == 0) + continue; + + var calledMethod = instrs[3].Operand as MethodReference; + if (calledMethod == null || calledMethod.FullName != "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") + continue; + + var targetField = instrs[4].Operand as FieldDefinition; + if (targetField == null) + continue; + + if (fieldToInfo.find(targetField) == null) { + fieldToInfo.add(targetField, new FieldInfo(targetField, arrayInitField)); + foundField = true; + } + } + return foundField; + } + + public FieldInfo getFieldInfo(FieldReference fieldRef) { + if (fieldRef == null) + return null; + return fieldToInfo.find(fieldRef); + } + + public IEnumerable cleanUp() { + var removedFields = new List(); + var moduleCctor = DotNetUtils.getModuleTypeCctor(module); + if (moduleCctor == null) + return removedFields; + var moduleCctorBlocks = new Blocks(moduleCctor); + + var keep = findFieldsToKeep(); + foreach (var fieldInfo in fieldToInfo.getValues()) { + if (keep.ContainsKey(fieldInfo)) + continue; + if (removeInitCode(moduleCctorBlocks, fieldInfo)) { + removedFields.Add(fieldInfo.field); + removedFields.Add(fieldInfo.arrayInitField); + } + fieldInfo.arrayInitField.InitialValue = new byte[1]; + fieldInfo.arrayInitField.FieldType = module.TypeSystem.Byte; + } + + IList allInstructions; + IList allExceptionHandlers; + moduleCctorBlocks.getCode(out allInstructions, out allExceptionHandlers); + DotNetUtils.restoreBody(moduleCctorBlocks.Method, allInstructions, allExceptionHandlers); + return removedFields; + } + + bool removeInitCode(Blocks blocks, FieldInfo info) { + bool removedSomething = false; + foreach (var block in blocks.MethodBlocks.getAllBlocks()) { + var instrs = block.Instructions; + for (int i = 0; i < instrs.Count - 5; i++) { + var ldci4 = instrs[i]; + if (!ldci4.isLdcI4()) + continue; + if (instrs[i + 1].OpCode.Code != Code.Newarr) + continue; + if (instrs[i + 2].OpCode.Code != Code.Dup) + continue; + var ldtoken = instrs[i + 3]; + if (ldtoken.OpCode.Code != Code.Ldtoken) + continue; + if (ldtoken.Operand != info.arrayInitField) + continue; + var call = instrs[i + 4]; + if (call.OpCode.Code != Code.Call) + continue; + var calledMethod = call.Operand as MethodReference; + if (calledMethod == null || calledMethod.FullName != "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") + continue; + var stsfld = instrs[i + 5]; + if (stsfld.OpCode.Code != Code.Stsfld) + continue; + if (stsfld.Operand != info.field) + continue; + block.remove(i, 6); + i--; + removedSomething = true; + } + } + return removedSomething; + } + + Dictionary findFieldsToKeep() { + var keep = new Dictionary(); + foreach (var type in module.GetTypes()) { + foreach (var method in type.Methods) { + if (type == DotNetUtils.getModuleType(module) && method.Name == ".cctor") + continue; + if (method.Body == null) + continue; + + foreach (var instr in method.Body.Instructions) { + var field = instr.Operand as FieldReference; + if (field == null) + continue; + var fieldInfo = fieldToInfo.find(field); + if (fieldInfo == null) + continue; + keep[fieldInfo] = true; + } + } + } + return keep; + } + } +} diff --git a/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs b/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs index 7eac25c9..00f82d86 100644 --- a/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/DeepSea/Deobfuscator.cs @@ -88,7 +88,7 @@ namespace de4dot.code.deobfuscators.DeepSea { ResourceResolver resourceResolver; AssemblyResolver assemblyResolver; FieldsRestorer fieldsRestorer; - ArrayBlockDeobfuscator arrayBlockDeobfuscator; + ArrayBlockState arrayBlockState; internal class Options : OptionsBase { public bool InlineMethods { get; set; } @@ -127,8 +127,8 @@ namespace de4dot.code.deobfuscators.DeepSea { List getBlocksDeobfuscators() { var list = new List(); - if (arrayBlockDeobfuscator.Detected) - list.Add(arrayBlockDeobfuscator); + if (arrayBlockState != null && arrayBlockState.Detected) + list.Add(new ArrayBlockDeobfuscator(arrayBlockState)); if (!startedDeobfuscating || options.CastDeobfuscation) list.Add(new CastDeobfuscator()); return list; @@ -158,8 +158,8 @@ namespace de4dot.code.deobfuscators.DeepSea { protected override void scanForObfuscator() { staticStringInliner.UseUnknownArgs = true; - arrayBlockDeobfuscator = new ArrayBlockDeobfuscator(module); - arrayBlockDeobfuscator.init(); + arrayBlockState = new ArrayBlockState(module); + arrayBlockState.init(DeobfuscatedFile); stringDecrypter = new StringDecrypter(module); stringDecrypter.find(DeobfuscatedFile); resourceResolver = new ResourceResolver(module, DeobfuscatedFile, this); @@ -278,7 +278,7 @@ done: stringDecrypter.cleanup(); } - addFieldsToBeRemoved(arrayBlockDeobfuscator.cleanUp(), "Control flow obfuscation array"); + addFieldsToBeRemoved(arrayBlockState.cleanUp(), "Control flow obfuscation array"); base.deobfuscateEnd(); } diff --git a/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs b/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs index df8dd39c..6648e6fe 100644 --- a/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs +++ b/de4dot.code/deobfuscators/DeepSea/ResolverBase.cs @@ -90,6 +90,7 @@ namespace de4dot.code.deobfuscators.DeepSea { } bool checkResolverInitMethodDesktop(MethodDefinition resolverInitMethod) { + simpleDeobfuscator.deobfuscate(resolverInitMethod); if (!checkResolverInitMethodInternal(resolverInitMethod)) return false; diff --git a/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs b/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs index f8c623fa..aeeeb64a 100644 --- a/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs +++ b/de4dot.code/deobfuscators/DeepSea/ResourceResolver.cs @@ -123,6 +123,8 @@ namespace de4dot.code.deobfuscators.DeepSea { var calledMethod = instr.Operand as MethodDefinition; if (calledMethod == null) continue; + if (getLdtokenField(calledMethod) == null) + continue; var args = DsUtils.getArgValues(instrs, i); if (args == null) continue; diff --git a/de4dot.code/deobfuscators/DeepSea/StringDecrypter.cs b/de4dot.code/deobfuscators/DeepSea/StringDecrypter.cs index 3eb6a3f7..0399f891 100644 --- a/de4dot.code/deobfuscators/DeepSea/StringDecrypter.cs +++ b/de4dot.code/deobfuscators/DeepSea/StringDecrypter.cs @@ -127,6 +127,29 @@ namespace de4dot.code.deobfuscators.DeepSea { return false; } + static void removeInitializeArrayCall(MethodDefinition method, FieldDefinition field) { + var instrs = method.Body.Instructions; + for (int i = 0; i < instrs.Count - 1; i++) { + var ldtoken = instrs[i]; + if (ldtoken.OpCode.Code != Code.Ldtoken) + continue; + if (ldtoken.Operand != field) + continue; + + var call = instrs[i + 1]; + if (call.OpCode.Code != Code.Call) + continue; + var calledMethod = call.Operand as MethodReference; + if (calledMethod == null) + continue; + if (calledMethod.ToString() != "System.Void System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(System.Array,System.RuntimeFieldHandle)") + continue; + + instrs[i] = Instruction.Create(OpCodes.Pop); + instrs[i + 1] = Instruction.Create(OpCodes.Nop); + } + } + class DecrypterInfo41 : IDecrypterInfo { MethodDefinition cctor; int magic; @@ -358,6 +381,7 @@ namespace de4dot.code.deobfuscators.DeepSea { public void cleanup() { arrayInfo.initField.InitialValue = new byte[1]; arrayInfo.initField.FieldType = arrayInfo.initField.Module.TypeSystem.Byte; + removeInitializeArrayCall(cctor, arrayInfo.initField); } } @@ -516,6 +540,7 @@ namespace de4dot.code.deobfuscators.DeepSea { public void cleanup() { encryptedDataField.InitialValue = new byte[1]; encryptedDataField.FieldType = encryptedDataField.Module.TypeSystem.Byte; + removeInitializeArrayCall(cctor, encryptedDataField); } } diff --git a/de4dot.code/deobfuscators/ISimpleDeobfuscator.cs b/de4dot.code/deobfuscators/ISimpleDeobfuscator.cs index 527bcf3d..6b028100 100644 --- a/de4dot.code/deobfuscators/ISimpleDeobfuscator.cs +++ b/de4dot.code/deobfuscators/ISimpleDeobfuscator.cs @@ -22,6 +22,7 @@ using Mono.Cecil; namespace de4dot.code.deobfuscators { public interface ISimpleDeobfuscator { void deobfuscate(MethodDefinition method); + void deobfuscate(MethodDefinition method, bool force); void decryptStrings(MethodDefinition method, IDeobfuscator deob); } } diff --git a/de4dot.code/deobfuscators/MaxtoCode/CryptDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/CryptDecrypter.cs new file mode 100644 index 00000000..7cdfa911 --- /dev/null +++ b/de4dot.code/deobfuscators/MaxtoCode/CryptDecrypter.cs @@ -0,0 +1,375 @@ +/* + 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 . +*/ + +using System; + +namespace de4dot.code.deobfuscators.MaxtoCode { + class CryptDecrypter { + byte[] key; + + static readonly byte[] sbox = new byte[8 * 8 * 8] { + 14, 4, 13, 1, 2, 15, 11, 8, + 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, + 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, + 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, + 5, 11, 3, 14, 10, 0, 6, 13, + 15, 1, 8, 14, 6, 11, 3, 4, + 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, + 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, + 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, + 11, 6, 7, 12, 0, 5, 14, 9, + 10, 0, 9, 14, 6, 3, 15, 5, + 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, + 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, + 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, + 4, 15, 14, 3, 11, 5, 2, 12, + 7, 13, 14, 3, 0, 6, 9, 10, + 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, + 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, + 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, + 9, 4, 5, 11, 12, 7, 2, 14, + 2, 12, 4, 1, 7, 10, 11, 6, + 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, + 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, + 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, + 6, 15, 0, 9, 10, 4, 5, 3, + 12, 1, 10, 15, 9, 2, 6, 8, + 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, + 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, + 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, + 11, 14, 1, 7, 6, 0, 8, 13, + 4, 11, 2, 14, 15, 0, 8, 13, + 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, + 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, + 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, + 9, 5, 0, 15, 14, 2, 3, 12, + 13, 2, 8, 4, 6, 15, 11, 1, + 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, + 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, + 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, + 15, 12, 9, 0, 3, 5, 6, 11, + }; + static readonly byte[] perm = new byte[32] { + 16, 7, 20, 21, 29, 12, 28, 17, + 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, + 19, 13, 30, 6, 22, 11, 4, 25, + }; + static readonly byte[] esel = new byte[48] { + 32, 1, 2, 3, 4, 5, 4, 5, + 6, 7, 8, 9, 8, 9, 10, 11, + 12, 13, 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, 20, 21, + 22, 23, 24, 25, 24, 25, 26, 27, + 28, 29, 28, 29, 30, 31, 32, 1, + }; + static readonly byte[] ip = new byte[64] { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + }; + static readonly byte[] final = new byte[64] { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, + }; + static readonly byte[] pc1 = new byte[56] { + 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, + 59, 51, 43, 35, 27, 19, 11, 3, + 60, 52, 44, 36, 63, 55, 47, 39, + 31, 23, 15, 7, 62, 54, 46, 38, + 30, 22, 14, 6, 61, 53, 45, 37, + 29, 21, 13, 5, 28, 20, 12, 4, + }; + static readonly byte[] pc2 = new byte[48] { + 14, 17, 11, 24, 1, 5, 3, 28, + 15, 6, 21, 10, 23, 19, 12, 4, + 26, 8, 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, 30, 40, + 51, 45, 33, 48, 44, 49, 39, 56, + 34, 53, 46, 42, 50, 36, 29, 32, + }; + static readonly byte[] rots = new byte[16] { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, + }; + + struct Bits { + readonly byte[] byteBits; + + public static Bits fromBytes(byte[] bytes) { + return fromBytes(bytes, 0, bytes.Length * 8); + } + + public static Bits fromBytes(byte[] bytes, int index, int numBits) { + return new Bits(bytes, index, numBits); + } + + public static Bits fromByteBits(byte[] byteBits1, byte[] byteBits2) { + return new Bits(byteBits1, byteBits2); + } + + public static Bits fromByteBits(byte[] byteBits) { + return fromByteBits(byteBits, 0, byteBits.Length); + } + + public static Bits fromByteBits(byte[] byteBits, int index, int numBits) { + var bits = new Bits(numBits); + for (int i = 0; i < numBits; i++) + bits.byteBits[i] = byteBits[index + i]; + return bits; + } + + public byte this[int index] { + get { return byteBits[index]; } + } + + public byte[] ByteBits { + get { return byteBits; } + } + + Bits(int numBits) { + this.byteBits = new byte[numBits]; + } + + Bits(byte[] bytes1, byte[] bytes2) { + this.byteBits = concat(bytes1, bytes2); + } + + Bits(byte[] bytes, int index, int numBits) { + this.byteBits = toByteBits(bytes, index, numBits); + } + + static byte[] toByteBits(byte[] bytes, int index, int numBits) { + var byteBits = new byte[numBits]; + for (int i = 0; i < numBits; i++) { + int j = i / 8; + int k = i & 7; + byteBits[i] = (byte)(((bytes[index + j] >> k) & 1) != 0 ? 1 : 0); + } + return byteBits; + } + + static byte[] concat(byte[] bytes1, byte[] bytes2) { + var bytes = new byte[bytes1.Length + bytes2.Length]; + Array.Copy(bytes1, 0, bytes, 0, bytes1.Length); + Array.Copy(bytes2, 0, bytes, bytes1.Length, bytes2.Length); + return bytes; + } + + public Bits transpose(byte[] bits) { + var result = new Bits(bits.Length); + for (int i = 0; i < bits.Length; i++) + result.byteBits[i] = byteBits[bits[i] - 1]; + return result; + } + + public void rol() { + if (byteBits.Length == 0) + return; + var first = byteBits[0]; + for (int i = 1; i < byteBits.Length; i++) + byteBits[i - 1] = byteBits[i]; + byteBits[byteBits.Length - 1] = first; + } + + public void rol(int num) { + for (int i = 0; i < num; i++) + rol(); + } + + public Bits extract(int index, int numBits) { + return fromByteBits(byteBits, index, numBits); + } + + public void toBits(byte[] dest, int index) { + var bits = toBits(); + Array.Copy(bits, 0, dest, index, bits.Length); + } + + public byte[] toBits() { + var bits = new byte[(byteBits.Length + 7) / 8]; + for (int i = 0; i < bits.Length; i++) { + byte val = 0; + for (int j = i * 8, k = 1; j < byteBits.Length; j++, k <<= 1) { + if (byteBits[j] != 0) + val |= (byte)k; + } + bits[i] = val; + } + return bits; + } + + public Bits clone() { + return fromByteBits(byteBits, 0, byteBits.Length); + } + + public void set(int destIndex, Bits other) { + for (int i = 0; i < other.byteBits.Length; i++) + byteBits[destIndex + i] = other.byteBits[i]; + } + + public void xor(Bits other) { + if (byteBits.Length != other.byteBits.Length) + throw new ArgumentException("other"); + for (int i = 0; i < byteBits.Length; i++) + byteBits[i] ^= other.byteBits[i]; + } + + public void copyTo(byte[] dest, int index) { + for (int i = 0; i < byteBits.Length; i++) + dest[index + i] = byteBits[i]; + } + } + + public CryptDecrypter(byte[] key) { + if (key.Length <= 8) + throw new ArgumentException("Invalid size", "key"); + this.key = key; + } + + public static byte[] decrypt(byte[] key, byte[] encrypted) { + return new CryptDecrypter(key).decrypt(encrypted); + } + + byte[] decrypt(byte[] encrypted) { + if (encrypted.Length % 8 != 0) + throw new ArgumentException("encrypted"); + var key1 = createKey(key, 0); + var key2 = createKey(key, 8); + + var decrypted = new byte[encrypted.Length]; + int count = encrypted.Length / 8; + for (int i = 0; i < count; i++) { + var buf = new byte[8]; + Array.Copy(encrypted, i * 8, buf, 0, buf.Length); + buf = decrypt(buf, key1, true); + buf = decrypt(buf, key2, false); + buf = decrypt(buf, key1, true); + Array.Copy(buf, 0, decrypted, i * 8, buf.Length); + } + + return decrypted; + } + + byte[] decrypt(byte[] data, Bits key, bool flag) { + var bits = Bits.fromBytes(data).transpose(ip); + + if (flag) { + for (int i = 0, ki = key.ByteBits.Length - 48; i < 16; i++, ki -= 48) { + var oldBits = bits.extract(0, 32); + var tmp = decrypt(oldBits.clone(), key.extract(ki, 48)); + tmp.xor(bits.extract(32, 32)); + bits.set(32, oldBits); + bits.set(0, tmp); + } + } + else { + for (int i = 0, ki = 0; i < 16; i++, ki += 48) { + var oldBits = bits.extract(32, 32); + var tmp = decrypt(oldBits.clone(), key.extract(ki, 48)); + tmp.xor(bits.extract(0, 32)); + bits.set(0, oldBits); + bits.set(32, tmp); + } + } + + bits = bits.transpose(final); + return bits.toBits(); + } + + Bits decrypt(Bits data, Bits key) { + var newData = data.clone().transpose(esel); + newData.xor(key); + return Bits.fromByteBits(getSbox(newData)).transpose(perm); + } + + byte[] getSbox(Bits data) { + var sboxByteBits = new byte[32]; + + for (int i = 0; i < 8; i++) { + int di = i * 6; + int index = (data[di + 0] << 5) + (data[di + 5] << 4) + (data[di + 1] << 3) + + (data[di + 2] << 2) + (data[di + 3] << 1) + data[di + 4] + i * 64; + Bits.fromBytes(sbox, index, 4).copyTo(sboxByteBits, i * 4); + } + + return sboxByteBits; + } + + static Bits createKey(byte[] data, int index) { + Bits key1, key2; + createKeys(data, index, out key1, out key2); + byte[] newKey = new byte[16 * 6]; + byte[] tmpData = new byte[28 * 2]; + for (int i = 0; i < 16; i++) { + int rolCount = rots[i]; + key1.rol(rolCount); + key2.rol(rolCount); + Bits.fromByteBits(key1.ByteBits, key2.ByteBits).transpose(pc2).toBits(newKey, i * 6); + } + return Bits.fromBytes(newKey); + } + + static void createKeys(byte[] data, int index, out Bits key1, out Bits key2) { + var tmpKey = new byte[8]; + int len = Math.Min(tmpKey.Length, data.Length - index); + if (len == 0) + throw new ArgumentException("data"); + Array.Copy(data, index, tmpKey, 0, len); + var bits = Bits.fromBytes(tmpKey).transpose(pc1); + key1 = Bits.fromByteBits(bits.ByteBits, 0, 28); + key2 = Bits.fromByteBits(bits.ByteBits, 28, 28); + } + } +} diff --git a/de4dot.code/deobfuscators/MaxtoCode/Decrypter6.cs b/de4dot.code/deobfuscators/MaxtoCode/Decrypter6.cs new file mode 100644 index 00000000..59479bee --- /dev/null +++ b/de4dot.code/deobfuscators/MaxtoCode/Decrypter6.cs @@ -0,0 +1,123 @@ +/* + 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 . +*/ + +using System; + +namespace de4dot.code.deobfuscators.MaxtoCode { + class Decrypter6 { + readonly uint[] key; + readonly byte[] gen1 = new byte[0x100]; + readonly byte[] gen2 = new byte[0x100]; + readonly byte[] gen3 = new byte[0x100]; + readonly byte[] gen4 = new byte[0x100]; + static readonly byte[] d1 = new byte[16] { 14, 4, 13, 21, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 }; + static readonly byte[] d2 = new byte[16] { 15, 1, 8, 14, 6, 11, 3, 4, 30, 7, 2, 13, 12, 0, 5, 10 }; + static readonly byte[] d3 = new byte[16] { 10, 0, 9, 14, 6, 3, 15, 5, 23, 13, 12, 7, 11, 4, 2, 8 }; + static readonly byte[] d4 = new byte[16] { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 }; + static readonly byte[] d5 = new byte[16] { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 }; + static readonly byte[] d6 = new byte[16] { 12, 1, 10, 15, 9, 2, 6, 8, 2, 13, 3, 4, 14, 7, 5, 11 }; + static readonly byte[] d7 = new byte[16] { 4, 11, 12, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 }; + static readonly byte[] d8 = new byte[16] { 13, 2, 8, 14, 6, 7, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 }; + + public static byte[] decrypt(byte[] key, byte[] encrypted) { + return new Decrypter6(key).decrypt(encrypted); + } + + Decrypter6(byte[] key) { + if (key.Length != 32) + throw new ArgumentException("Invalid key size", "key"); + this.key = new uint[8]; + Buffer.BlockCopy(key, 0, this.key, 0, key.Length); + initialize(); + } + + byte[] decrypt(byte[] encrypted) { + if ((encrypted.Length & 7) != 0) + throw new ArgumentException("Invalid data length", "encrypted"); + var decrypted = new byte[encrypted.Length]; + + int count = decrypted.Length / 8; + for (int i = 0; i < count; i++) { + uint x, y; + decrypt(BitConverter.ToUInt32(encrypted, i * 8), BitConverter.ToUInt32(encrypted, i * 8 + 4), out x, out y); + for (int j = 1; j < 100; j++) + decrypt(x, y, out x, out y); + writeUInt32(decrypted, i * 8, x); + writeUInt32(decrypted, i * 8 + 4, y); + } + + return decrypted; + } + + static void writeUInt32(byte[] data, int index, uint value) { + data[index] = (byte)value; + data[index + 1] = (byte)(value >> 8); + data[index + 2] = (byte)(value >> 16); + data[index + 3] = (byte)(value >> 24); + } + + void initialize() { + for (int i = 0; i < 0x100; i++) { + gen1[i] = (byte)((d1[i / 16] << 4) | d2[i & 0x0F]); + gen2[i] = (byte)((d3[i / 16] << 4) | d4[i & 0x0F]); + gen3[i] = (byte)((d5[i / 16] << 4) | d6[i & 0x0F]); + gen4[i] = (byte)((d7[i / 16] << 4) | d8[i & 0x0F]); + } + } + + void decrypt(uint i0, uint i1, out uint o0, out uint o1) { + uint x = i0; + uint y = decrypt(x + key[0]); + y ^= i1; + x ^= decrypt(y + key[1]); + y ^= decrypt(x + key[2]); + x ^= decrypt(y + key[3]); + y ^= decrypt(x + key[4]); + x ^= decrypt(y + key[5]); + y ^= decrypt(x + key[6]); + x ^= decrypt(y + key[7]); + + for (int i = 0; i < 3; i++) { + y ^= decrypt(x + key[7]); + x ^= decrypt(y + key[6]); + y ^= decrypt(x + key[5]); + x ^= decrypt(y + key[4]); + y ^= decrypt(x + key[3]); + x ^= decrypt(y + key[2]); + y ^= decrypt(x + key[1]); + x ^= decrypt(y + key[0]); + } + + o0 = y; + o1 = x; + } + + uint decrypt(uint val) { + uint x = (uint)((gen1[(byte)(val >> 24)] << 24) | + (gen2[(byte)(val >> 16)] << 16) | + (gen3[(byte)(val >> 8)] << 8) | + gen4[(byte)val]); + return ror(x, 21); + } + + static uint ror(uint val, int n) { + return (val << (32 - n)) + (val >> n); + } + } +} diff --git a/de4dot.code/deobfuscators/MaxtoCode/DecrypterInfo.cs b/de4dot.code/deobfuscators/MaxtoCode/DecrypterInfo.cs new file mode 100644 index 00000000..d15c2509 --- /dev/null +++ b/de4dot.code/deobfuscators/MaxtoCode/DecrypterInfo.cs @@ -0,0 +1,38 @@ +/* + 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 . +*/ + +using de4dot.PE; + +namespace de4dot.code.deobfuscators.MaxtoCode { + class DecrypterInfo { + public readonly MainType mainType; + public readonly PeImage peImage; + public readonly PeHeader peHeader; + public readonly McKey mcKey; + public readonly byte[] fileData; + + public DecrypterInfo(MainType mainType, byte[] fileData) { + this.mainType = mainType; + this.peImage = new PeImage(fileData); + this.peHeader = new PeHeader(mainType, peImage); + this.mcKey = new McKey(peImage, peHeader); + this.fileData = fileData; + } + } +} diff --git a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs index 3fd51171..38e643fe 100644 --- a/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs +++ b/de4dot.code/deobfuscators/MaxtoCode/Deobfuscator.cs @@ -17,7 +17,9 @@ along with de4dot. If not, see . */ +using System; using System.Collections.Generic; +using System.Text; using Mono.Cecil; using Mono.MyStuff; @@ -26,8 +28,11 @@ namespace de4dot.code.deobfuscators.MaxtoCode { public const string THE_NAME = "MaxtoCode"; public const string THE_TYPE = "mc"; const string DEFAULT_REGEX = @"!^[oO01l]+$&" + DeobfuscatorBase.DEFAULT_VALID_NAME_REGEX; + IntOption stringCodePage; + public DeobfuscatorInfo() : base(DEFAULT_REGEX) { + stringCodePage = new IntOption(null, makeArgName("cp"), "String code page", 936); } public override string Name { @@ -42,15 +47,25 @@ namespace de4dot.code.deobfuscators.MaxtoCode { return new Deobfuscator(new Deobfuscator.Options { RenameResourcesInCode = false, ValidNameRegex = validNameRegex.get(), + StringCodePage = stringCodePage.get(), }); } + + protected override IEnumerable