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