diff --git a/.gitmodules b/.gitmodules
index f2f13f7a..31197a77 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
[submodule "dnlib"]
path = dnlib
- url = git@bitbucket.org:0xd4d/dnlib.git
+ url = git@github.com:0xd4d/dnlib.git
diff --git a/AssemblyData/Properties/AssemblyInfo.cs b/AssemblyData/Properties/AssemblyInfo.cs
index c13cb77c..66113581 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("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/AssemblyServer-CLR20-x64/Properties/AssemblyInfo.cs b/AssemblyServer-CLR20-x64/Properties/AssemblyInfo.cs
index 885556ce..44833b42 100644
--- a/AssemblyServer-CLR20-x64/Properties/AssemblyInfo.cs
+++ b/AssemblyServer-CLR20-x64/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/AssemblyServer-CLR20/Properties/AssemblyInfo.cs b/AssemblyServer-CLR20/Properties/AssemblyInfo.cs
index ad310d96..11597cc7 100644
--- a/AssemblyServer-CLR20/Properties/AssemblyInfo.cs
+++ b/AssemblyServer-CLR20/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/AssemblyServer-CLR40-x64/Properties/AssemblyInfo.cs b/AssemblyServer-CLR40-x64/Properties/AssemblyInfo.cs
index 655bdd3a..8b008978 100644
--- a/AssemblyServer-CLR40-x64/Properties/AssemblyInfo.cs
+++ b/AssemblyServer-CLR40-x64/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/AssemblyServer-CLR40/Properties/AssemblyInfo.cs b/AssemblyServer-CLR40/Properties/AssemblyInfo.cs
index 953e469f..23148956 100644
--- a/AssemblyServer-CLR40/Properties/AssemblyInfo.cs
+++ b/AssemblyServer-CLR40/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/AssemblyServer-x64/Properties/AssemblyInfo.cs b/AssemblyServer-x64/Properties/AssemblyInfo.cs
index 76ca6b81..88329d74 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("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/AssemblyServer/Properties/AssemblyInfo.cs b/AssemblyServer/Properties/AssemblyInfo.cs
index f3040761..a710db94 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("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/LICENSE.de4dot.txt b/LICENSE.de4dot.txt
index 7f5a9468..b8822f03 100644
--- a/LICENSE.de4dot.txt
+++ b/LICENSE.de4dot.txt
@@ -17,6 +17,6 @@
along with de4dot. If not, see .
-Official site: https://bitbucket.org/0xd4d/de4dot
+Official site: https://github.com/0xd4d/de4dot
See the file COPYING for more details.
diff --git a/LICENSE.dnlib.txt b/LICENSE.dnlib.txt
index aafeb7bc..89b254d3 100644
--- a/LICENSE.dnlib.txt
+++ b/LICENSE.dnlib.txt
@@ -21,4 +21,4 @@
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-Official site: https://bitbucket.org/0xd4d/dnlib
+Official site: https://github.com/0xd4d/dnlib
diff --git a/Test.Rename.Dll/Properties/AssemblyInfo.cs b/Test.Rename.Dll/Properties/AssemblyInfo.cs
index c469fe85..530ec319 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("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/Test.Rename/Properties/AssemblyInfo.cs b/Test.Rename/Properties/AssemblyInfo.cs
index 0b60d049..66842afd 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("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/de4dot-x64/Properties/AssemblyInfo.cs b/de4dot-x64/Properties/AssemblyInfo.cs
index 13667790..5f9cf404 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("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/de4dot.blocks/DotNetUtils.cs b/de4dot.blocks/DotNetUtils.cs
index 89bd176d..88ad2712 100644
--- a/de4dot.blocks/DotNetUtils.cs
+++ b/de4dot.blocks/DotNetUtils.cs
@@ -174,9 +174,9 @@ namespace de4dot.blocks {
public static bool IsPinvokeMethod(MethodDef method, string dll, string funcName) {
if (method == null)
return false;
- if (method.ImplMap == null || method.ImplMap.Name.String != funcName)
+ if (method.ImplMap == null)
return false;
- return GetDllName(dll).Equals(GetDllName(method.ImplMap.Module.Name.String), StringComparison.OrdinalIgnoreCase);
+ return method.ImplMap.IsPinvokeMethod(dll, funcName);
}
public static MethodDef GetMethod(ModuleDefMD module, IMethod method) {
diff --git a/de4dot.blocks/GenericArgsSubstitutor.cs b/de4dot.blocks/GenericArgsSubstitutor.cs
index 17d83e66..77e6b95a 100644
--- a/de4dot.blocks/GenericArgsSubstitutor.cs
+++ b/de4dot.blocks/GenericArgsSubstitutor.cs
@@ -19,6 +19,7 @@
using System.Collections.Generic;
using dnlib.DotNet;
+using dnlib.Threading;
namespace de4dot.blocks {
public struct GenericArgsSubstitutor {
@@ -291,7 +292,7 @@ namespace de4dot.blocks {
newSig.Params.Add(Create2(sig.Params[i]));
newSig.GenParamCount = sig.GenParamCount;
if (sig.ParamsAfterSentinel != null) {
- newSig.ParamsAfterSentinel = new List();
+ newSig.ParamsAfterSentinel = ThreadSafeListCreator.Create();
for (int i = 0; i < sig.ParamsAfterSentinel.Count; i++)
newSig.ParamsAfterSentinel.Add(Create2(sig.ParamsAfterSentinel[i]));
}
diff --git a/de4dot.blocks/Properties/AssemblyInfo.cs b/de4dot.blocks/Properties/AssemblyInfo.cs
index b05b48f5..3fca2b8e 100644
--- a/de4dot.blocks/Properties/AssemblyInfo.cs
+++ b/de4dot.blocks/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/de4dot.blocks/cflow/BranchEmulator.cs b/de4dot.blocks/cflow/BranchEmulator.cs
index 3e3f71a1..8d9269b9 100644
--- a/de4dot.blocks/cflow/BranchEmulator.cs
+++ b/de4dot.blocks/cflow/BranchEmulator.cs
@@ -95,6 +95,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareEq((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareEq((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareEq((Real8Value)val1, (Real8Value)val2));
else if (val1.IsNull() && val2.IsNull())
return EmulateBranch(2, true);
else
@@ -109,6 +111,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareNeq((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareNeq((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareNeq((Real8Value)val1, (Real8Value)val2));
else if (val1.IsNull() && val2.IsNull())
return EmulateBranch(2, false);
else
@@ -123,6 +127,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareGe((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareGe((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareGe((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@@ -135,6 +141,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareGe_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareGe_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareGe_Un((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@@ -147,6 +155,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareGt((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareGt((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareGt((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@@ -159,6 +169,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareGt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareGt_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareGt_Un((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@@ -171,6 +183,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareLe((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareLe((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareLe((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@@ -183,6 +197,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareLe_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareLe_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareLe_Un((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@@ -195,6 +211,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareLt((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareLt((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareLt((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@@ -207,6 +225,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(2, Int32Value.CompareLt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
return EmulateBranch(2, Int64Value.CompareLt_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ return EmulateBranch(2, Real8Value.CompareLt_Un((Real8Value)val1, (Real8Value)val2));
else
return false;
}
@@ -218,6 +238,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(1, Int32Value.CompareFalse((Int32Value)val1));
else if (val1.IsInt64())
return EmulateBranch(1, Int64Value.CompareFalse((Int64Value)val1));
+ else if (val1.IsReal8())
+ return EmulateBranch(1, Real8Value.CompareFalse((Real8Value)val1));
else if (val1.IsNull())
return EmulateBranch(1, true);
else if (val1.IsObject() || val1.IsString())
@@ -233,6 +255,8 @@ namespace de4dot.blocks.cflow {
return EmulateBranch(1, Int32Value.CompareTrue((Int32Value)val1));
else if (val1.IsInt64())
return EmulateBranch(1, Int64Value.CompareTrue((Int64Value)val1));
+ else if (val1.IsReal8())
+ return EmulateBranch(1, Real8Value.CompareTrue((Real8Value)val1));
else if (val1.IsNull())
return EmulateBranch(1, false);
else if (val1.IsObject() || val1.IsString())
diff --git a/de4dot.blocks/cflow/ConstantsFolder.cs b/de4dot.blocks/cflow/ConstantsFolder.cs
index a740fa45..b5227acf 100644
--- a/de4dot.blocks/cflow/ConstantsFolder.cs
+++ b/de4dot.blocks/cflow/ConstantsFolder.cs
@@ -70,6 +70,96 @@ namespace de4dot.blocks.cflow {
case Code.Ldloca_S:
instructionEmulator.MakeLocalUnknown((Local)instr.Operand);
break;
+
+ case Code.Add:
+ case Code.Add_Ovf:
+ case Code.Add_Ovf_Un:
+ case Code.And:
+ case Code.Ceq:
+ case Code.Cgt:
+ case Code.Cgt_Un:
+ case Code.Clt:
+ case Code.Clt_Un:
+ case Code.Conv_I:
+ case Code.Conv_I1:
+ case Code.Conv_I2:
+ case Code.Conv_I4:
+ case Code.Conv_I8:
+ case Code.Conv_Ovf_I:
+ case Code.Conv_Ovf_I_Un:
+ case Code.Conv_Ovf_I1:
+ case Code.Conv_Ovf_I1_Un:
+ case Code.Conv_Ovf_I2:
+ case Code.Conv_Ovf_I2_Un:
+ case Code.Conv_Ovf_I4:
+ case Code.Conv_Ovf_I4_Un:
+ case Code.Conv_Ovf_I8:
+ case Code.Conv_Ovf_I8_Un:
+ case Code.Conv_Ovf_U:
+ case Code.Conv_Ovf_U_Un:
+ case Code.Conv_Ovf_U1:
+ case Code.Conv_Ovf_U1_Un:
+ case Code.Conv_Ovf_U2:
+ case Code.Conv_Ovf_U2_Un:
+ case Code.Conv_Ovf_U4:
+ case Code.Conv_Ovf_U4_Un:
+ case Code.Conv_Ovf_U8:
+ case Code.Conv_Ovf_U8_Un:
+ case Code.Conv_R_Un:
+ case Code.Conv_R4:
+ case Code.Conv_R8:
+ case Code.Conv_U:
+ case Code.Conv_U1:
+ case Code.Conv_U2:
+ case Code.Conv_U4:
+ case Code.Conv_U8:
+ case Code.Div:
+ case Code.Div_Un:
+ case Code.Dup:
+ case Code.Mul:
+ case Code.Mul_Ovf:
+ case Code.Mul_Ovf_Un:
+ case Code.Neg:
+ case Code.Not:
+ case Code.Or:
+ case Code.Rem:
+ case Code.Rem_Un:
+ case Code.Shl:
+ case Code.Shr:
+ case Code.Shr_Un:
+ case Code.Sub:
+ case Code.Sub_Ovf:
+ case Code.Sub_Ovf_Un:
+ case Code.Xor:
+ if (i + 1 < instrs.Count && instrs[i + 1].OpCode.Code == Code.Pop)
+ break;
+ if (!VerifyValidArgs(instr.Instruction))
+ break;
+ instructionEmulator.Emulate(instr.Instruction);
+ var tos = instructionEmulator.Peek();
+ Instruction newInstr = null;
+ if (tos.IsInt32()) {
+ var val = (Int32Value)tos;
+ if (val.AllBitsValid())
+ newInstr = Instruction.CreateLdcI4(val.Value);
+ }
+ else if (tos.IsInt64()) {
+ var val = (Int64Value)tos;
+ if (val.AllBitsValid())
+ newInstr = OpCodes.Ldc_I8.ToInstruction(val.Value);
+ }
+ else if (tos.IsReal8()) {
+ var val = (Real8Value)tos;
+ if (val.IsValid)
+ newInstr = GetLoadRealInstruction(val.Value);
+ }
+ if (newInstr != null) {
+ block.Insert(i + 1, Instruction.Create(OpCodes.Pop));
+ block.Insert(i + 2, newInstr);
+ i += 2;
+ modified = true;
+ }
+ continue;
}
try {
@@ -84,6 +174,53 @@ namespace de4dot.blocks.cflow {
return modified;
}
+ bool VerifyValidArgs(Instruction instr) {
+ int pushes, pops;
+ instr.CalculateStackUsage(out pushes, out pops);
+ if (pops < 0)
+ return false;
+
+ bool retVal;
+ Value val2, val1;
+ switch (pops) {
+ case 0:
+ return true;
+
+ case 1:
+ val1 = instructionEmulator.Pop();
+ retVal = VerifyValidArg(val1);
+ instructionEmulator.Push(val1);
+ return retVal;
+
+ case 2:
+ val2 = instructionEmulator.Pop();
+ val1 = instructionEmulator.Pop();
+ retVal = VerifyValidArg(val2) && VerifyValidArg(val1);
+ instructionEmulator.Push(val1);
+ instructionEmulator.Push(val2);
+ return retVal;
+ }
+
+ return false;
+ }
+
+ static bool VerifyValidArg(Value value) {
+ if (value.IsInt32())
+ return ((Int32Value)value).AllBitsValid();
+ if (value.IsInt64())
+ return ((Int64Value)value).AllBitsValid();
+ if (value.IsReal8())
+ return ((Real8Value)value).IsValid;
+ return false;
+ }
+
+ static Instruction GetLoadRealInstruction(double value) {
+ var floatVal = (float)value;
+ if (floatVal == value || double.IsNaN(value))
+ return OpCodes.Ldc_R4.ToInstruction(floatVal);
+ return OpCodes.Ldc_R8.ToInstruction(value);
+ }
+
bool FixLoadInstruction(Block block, int index, Value value) {
if (value.IsInt32()) {
var intValue = (Int32Value)value;
diff --git a/de4dot.blocks/cflow/InstructionEmulator.cs b/de4dot.blocks/cflow/InstructionEmulator.cs
index f42bdff6..447812b5 100644
--- a/de4dot.blocks/cflow/InstructionEmulator.cs
+++ b/de4dot.blocks/cflow/InstructionEmulator.cs
@@ -52,8 +52,12 @@ namespace de4dot.blocks.cflow {
}
public void Initialize(MethodDef method, bool emulateFromFirstInstruction) {
- this.parameterDefs = method.Parameters;
- this.localDefs = method.Body.Variables;
+ Initialize(method, method.Parameters, method.Body.Variables, method.Body.InitLocals, emulateFromFirstInstruction);
+ }
+
+ public void Initialize(MethodDef method, IList methodParameters, IList methodLocals, bool initLocals, bool emulateFromFirstInstruction) {
+ this.parameterDefs = methodParameters;
+ this.localDefs = methodLocals;
valueStack.Initialize();
protectedStackValues.Clear();
@@ -75,7 +79,7 @@ namespace de4dot.blocks.cflow {
args.Clear();
args.AddRange(cached_args);
locals.Clear();
- locals.AddRange(method.Body.InitLocals && emulateFromFirstInstruction ? cached_zeroed_locals : cached_locals);
+ locals.AddRange(initLocals && emulateFromFirstInstruction ? cached_zeroed_locals : cached_locals);
}
public void SetProtected(Value value) {
@@ -429,9 +433,9 @@ namespace de4dot.blocks.cflow {
case Code.Unbox:
- case Code.Conv_R_Un:
- case Code.Conv_R4:
- case Code.Conv_R8:
+ case Code.Conv_R_Un:Emulate_Conv_R_Un(instr); break;
+ case Code.Conv_R4: Emulate_Conv_R4(instr); break;
+ case Code.Conv_R8: Emulate_Conv_R8(instr); break;
case Code.Arglist:
case Code.Beq:
@@ -782,6 +786,36 @@ namespace de4dot.blocks.cflow {
}
}
+ void Emulate_Conv_R_Un(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_R_Un((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_R_Un((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_R_Un((Real8Value)val1)); break;
+ default: valueStack.Push(Real8Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_R4(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_R4((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_R4((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_R4((Real8Value)val1)); break;
+ default: valueStack.Push(Real8Value.CreateUnknown()); break;
+ }
+ }
+
+ void Emulate_Conv_R8(Instruction instr) {
+ var val1 = valueStack.Pop();
+ switch (val1.valueType) {
+ case ValueType.Int32: valueStack.Push(Int32Value.Conv_R8((Int32Value)val1)); break;
+ case ValueType.Int64: valueStack.Push(Int64Value.Conv_R8((Int64Value)val1)); break;
+ case ValueType.Real8: valueStack.Push(Real8Value.Conv_R8((Real8Value)val1)); break;
+ default: valueStack.Push(Real8Value.CreateUnknown()); break;
+ }
+ }
+
void Emulate_Add(Instruction instr) {
var val2 = valueStack.Pop();
var val1 = valueStack.Pop();
@@ -1064,6 +1098,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Ceq((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Ceq((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Ceq((Real8Value)val1, (Real8Value)val2));
else if (val1.IsNull() && val2.IsNull())
valueStack.Push(Int32Value.One);
else
@@ -1078,6 +1114,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Cgt((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Cgt((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Cgt((Real8Value)val1, (Real8Value)val2));
else
valueStack.Push(Int32Value.CreateUnknownBool());
}
@@ -1090,6 +1128,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Cgt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Cgt_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Cgt_Un((Real8Value)val1, (Real8Value)val2));
else
valueStack.Push(Int32Value.CreateUnknownBool());
}
@@ -1102,6 +1142,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Clt((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Clt((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Clt((Real8Value)val1, (Real8Value)val2));
else
valueStack.Push(Int32Value.CreateUnknownBool());
}
@@ -1114,6 +1156,8 @@ namespace de4dot.blocks.cflow {
valueStack.Push(Int32Value.Clt_Un((Int32Value)val1, (Int32Value)val2));
else if (val1.IsInt64() && val2.IsInt64())
valueStack.Push(Int64Value.Clt_Un((Int64Value)val1, (Int64Value)val2));
+ else if (val1.IsReal8() && val2.IsReal8())
+ valueStack.Push(Real8Value.Clt_Un((Real8Value)val1, (Real8Value)val2));
else
valueStack.Push(Int32Value.CreateUnknownBool());
}
diff --git a/de4dot.blocks/cflow/Int32Value.cs b/de4dot.blocks/cflow/Int32Value.cs
index 0fb8d400..bdb60482 100644
--- a/de4dot.blocks/cflow/Int32Value.cs
+++ b/de4dot.blocks/cflow/Int32Value.cs
@@ -331,6 +331,24 @@ namespace de4dot.blocks.cflow {
return new Int64Value((long)(uint)a.Value, a.ValidMask | (Int64Value.NO_UNKNOWN_BITS << 32));
}
+ public static Real8Value Conv_R_Un(Int32Value a) {
+ if (a.AllBitsValid())
+ return new Real8Value((float)(uint)a.Value);
+ return Real8Value.CreateUnknown();
+ }
+
+ public static Real8Value Conv_R4(Int32Value a) {
+ if (a.AllBitsValid())
+ return new Real8Value((float)(int)a.Value);
+ return Real8Value.CreateUnknown();
+ }
+
+ public static Real8Value Conv_R8(Int32Value a) {
+ if (a.AllBitsValid())
+ return new Real8Value((double)(int)a.Value);
+ return Real8Value.CreateUnknown();
+ }
+
public static Int32Value Add(Int32Value a, Int32Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int32Value(a.Value + b.Value);
@@ -556,7 +574,7 @@ namespace de4dot.blocks.cflow {
return new Int32Value((int)((uint)a.Value >> shift), validMask);
}
- static Int32Value Create(Bool3 b) {
+ public static Int32Value Create(Bool3 b) {
switch (b) {
case Bool3.False: return Zero;
case Bool3.True: return One;
diff --git a/de4dot.blocks/cflow/Int64Value.cs b/de4dot.blocks/cflow/Int64Value.cs
index 2ead373c..20303704 100644
--- a/de4dot.blocks/cflow/Int64Value.cs
+++ b/de4dot.blocks/cflow/Int64Value.cs
@@ -224,6 +224,24 @@ namespace de4dot.blocks.cflow {
return a;
}
+ public static Real8Value Conv_R_Un(Int64Value a) {
+ if (a.AllBitsValid())
+ return new Real8Value((float)(ulong)a.Value);
+ return Real8Value.CreateUnknown();
+ }
+
+ public static Real8Value Conv_R4(Int64Value a) {
+ if (a.AllBitsValid())
+ return new Real8Value((float)(long)a.Value);
+ return Real8Value.CreateUnknown();
+ }
+
+ public static Real8Value Conv_R8(Int64Value a) {
+ if (a.AllBitsValid())
+ return new Real8Value((double)(long)a.Value);
+ return Real8Value.CreateUnknown();
+ }
+
public static Int64Value Add(Int64Value a, Int64Value b) {
if (a.AllBitsValid() && b.AllBitsValid())
return new Int64Value(a.Value + b.Value);
@@ -449,32 +467,24 @@ namespace de4dot.blocks.cflow {
return new Int64Value((long)((ulong)a.Value >> shift), validMask);
}
- static Int32Value Create(Bool3 b) {
- switch (b) {
- case Bool3.False: return Int32Value.Zero;
- case Bool3.True: return Int32Value.One;
- default: return Int32Value.CreateUnknownBool();
- }
- }
-
public static Int32Value Ceq(Int64Value a, Int64Value b) {
- return Create(CompareEq(a, b));
+ return Int32Value.Create(CompareEq(a, b));
}
public static Int32Value Cgt(Int64Value a, Int64Value b) {
- return Create(CompareGt(a, b));
+ return Int32Value.Create(CompareGt(a, b));
}
public static Int32Value Cgt_Un(Int64Value a, Int64Value b) {
- return Create(CompareGt_Un(a, b));
+ return Int32Value.Create(CompareGt_Un(a, b));
}
public static Int32Value Clt(Int64Value a, Int64Value b) {
- return Create(CompareLt(a, b));
+ return Int32Value.Create(CompareLt(a, b));
}
public static Int32Value Clt_Un(Int64Value a, Int64Value b) {
- return Create(CompareLt_Un(a, b));
+ return Int32Value.Create(CompareLt_Un(a, b));
}
public static Bool3 CompareEq(Int64Value a, Int64Value b) {
diff --git a/de4dot.blocks/cflow/Real8Value.cs b/de4dot.blocks/cflow/Real8Value.cs
index 77206e5a..f7e17a35 100644
--- a/de4dot.blocks/cflow/Real8Value.cs
+++ b/de4dot.blocks/cflow/Real8Value.cs
@@ -168,6 +168,100 @@ namespace de4dot.blocks.cflow {
return Int64Value.CreateUnknown();
}
+ public static Real8Value Conv_R_Un(Real8Value a) {
+ return CreateUnknown();
+ }
+
+ public static Real8Value Conv_R4(Real8Value a) {
+ if (a.IsValid)
+ return new Real8Value((float)a.Value);
+ return CreateUnknown();
+ }
+
+ public static Real8Value Conv_R8(Real8Value a) {
+ return a;
+ }
+
+ public static Int32Value Ceq(Real8Value a, Real8Value b) {
+ return Int32Value.Create(CompareEq(a, b));
+ }
+
+ public static Int32Value Cgt(Real8Value a, Real8Value b) {
+ return Int32Value.Create(CompareGt(a, b));
+ }
+
+ public static Int32Value Cgt_Un(Real8Value a, Real8Value b) {
+ return Int32Value.Create(CompareGt_Un(a, b));
+ }
+
+ public static Int32Value Clt(Real8Value a, Real8Value b) {
+ return Int32Value.Create(CompareLt(a, b));
+ }
+
+ public static Int32Value Clt_Un(Real8Value a, Real8Value b) {
+ return Int32Value.Create(CompareLt_Un(a, b));
+ }
+
+ public static Bool3 CompareEq(Real8Value a, Real8Value b) {
+ if (a.IsValid && b.IsValid)
+ return a.Value == b.Value ? Bool3.True : Bool3.False;
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 CompareNeq(Real8Value a, Real8Value b) {
+ if (a.IsValid && b.IsValid)
+ return a.Value != b.Value ? Bool3.True : Bool3.False;
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 CompareGt(Real8Value a, Real8Value b) {
+ if (a.IsValid && b.IsValid)
+ return a.Value > b.Value ? Bool3.True : Bool3.False;
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 CompareGt_Un(Real8Value a, Real8Value b) {
+ return Bool3.Unknown; //TODO:
+ }
+
+ public static Bool3 CompareGe(Real8Value a, Real8Value b) {
+ if (a.IsValid && b.IsValid)
+ return a.Value >= b.Value ? Bool3.True : Bool3.False;
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 CompareGe_Un(Real8Value a, Real8Value b) {
+ return Bool3.Unknown; //TODO:
+ }
+
+ public static Bool3 CompareLe(Real8Value a, Real8Value b) {
+ if (a.IsValid && b.IsValid)
+ return a.Value <= b.Value ? Bool3.True : Bool3.False;
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 CompareLe_Un(Real8Value a, Real8Value b) {
+ return Bool3.Unknown; //TODO:
+ }
+
+ public static Bool3 CompareLt(Real8Value a, Real8Value b) {
+ if (a.IsValid && b.IsValid)
+ return a.Value < b.Value ? Bool3.True : Bool3.False;
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 CompareLt_Un(Real8Value a, Real8Value b) {
+ return Bool3.Unknown; //TODO:
+ }
+
+ public static Bool3 CompareTrue(Real8Value a) {
+ return Bool3.Unknown;
+ }
+
+ public static Bool3 CompareFalse(Real8Value a) {
+ return Bool3.Unknown;
+ }
+
public override string ToString() {
if (!IsValid)
return "";
diff --git a/de4dot.code/DumpedMethodsRestorer.cs b/de4dot.code/DumpedMethodsRestorer.cs
index ffd17f25..b7e8224c 100644
--- a/de4dot.code/DumpedMethodsRestorer.cs
+++ b/de4dot.code/DumpedMethodsRestorer.cs
@@ -61,15 +61,14 @@ namespace de4dot.code {
return false;
}
- public bool HasMethodBody(uint rid) {
- return GetDumpedMethod(rid) != null;
- }
-
- public MethodBody GetMethodBody(uint rid, RVA rva, IList parameters) {
+ public bool GetMethodBody(uint rid, RVA rva, IList parameters, GenericParamContext gpContext, out MethodBody methodBody) {
var dm = GetDumpedMethod(rid);
- if (dm == null)
- return null;
- return MethodBodyReader.CreateCilBody(module, dm.code, dm.extraSections, parameters, dm.mhFlags, dm.mhMaxStack, dm.mhCodeSize, dm.mhLocalVarSigTok);
+ if (dm == null) {
+ methodBody = null;
+ return false;
+ }
+ methodBody = MethodBodyReader.CreateCilBody(module, dm.code, dm.extraSections, parameters, dm.mhFlags, dm.mhMaxStack, dm.mhCodeSize, dm.mhLocalVarSigTok, gpContext);
+ return true;
}
}
}
diff --git a/de4dot.code/Properties/AssemblyInfo.cs b/de4dot.code/Properties/AssemblyInfo.cs
index 84584d69..625f0921 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("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj
index 4787d149..62ec8193 100644
--- a/de4dot.code/de4dot.code.csproj
+++ b/de4dot.code/de4dot.code.csproj
@@ -73,6 +73,7 @@
+
diff --git a/de4dot.code/deobfuscators/Agile_NET/CliSecureRtType.cs b/de4dot.code/deobfuscators/Agile_NET/CliSecureRtType.cs
index 391869e3..96d06c58 100644
--- a/de4dot.code/deobfuscators/Agile_NET/CliSecureRtType.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/CliSecureRtType.cs
@@ -29,7 +29,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
TypeDef cliSecureRtType;
MethodDef postInitializeMethod;
MethodDef initializeMethod;
- MethodDef stringDecrypterMethod;
+ Dictionary stringDecrypterInfos = new Dictionary();
MethodDef loadMethod;
bool foundSig;
@@ -41,8 +41,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
get { return cliSecureRtType; }
}
- public MethodDef StringDecrypterMethod {
- get { return stringDecrypterMethod; }
+ public IEnumerable StringDecrypterInfos {
+ get { return stringDecrypterInfos.Keys; }
}
public MethodDef PostInitializeMethod {
@@ -66,7 +66,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
cliSecureRtType = Lookup(oldOne.cliSecureRtType, "Could not find CliSecureRt type");
postInitializeMethod = Lookup(oldOne.postInitializeMethod, "Could not find postInitializeMethod method");
initializeMethod = Lookup(oldOne.initializeMethod, "Could not find initializeMethod method");
- stringDecrypterMethod = Lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod method");
+ foreach (var info in oldOne.stringDecrypterInfos.Keys) {
+ var m = Lookup(info.Method, "Could not find string decrypter method");
+ var f = Lookup(info.Field, "Could not find string decrypter field");
+ stringDecrypterInfos[new StringDecrypterInfo(m, f)] = true;
+ }
loadMethod = Lookup(oldOne.loadMethod, "Could not find loadMethod method");
foundSig = oldOne.foundSig;
}
@@ -100,11 +104,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (!HasInitializeMethod(type, "_Initialize") && !HasInitializeMethod(type, "_Initialize64"))
continue;
- stringDecrypterMethod = FindStringDecrypterMethod(type);
initializeMethod = calledMethod;
postInitializeMethod = FindMethod(type, "System.Void", "PostInitialize", "()");
loadMethod = FindMethod(type, "System.IntPtr", "Load", "()");
cliSecureRtType = type;
+ FindStringDecrypters();
return true;
}
}
@@ -112,6 +116,15 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return false;
}
+ void FindStringDecrypters() {
+ AddStringDecrypterMethod(FindStringDecrypterMethod(cliSecureRtType));
+ }
+
+ void AddStringDecrypterMethod(MethodDef method) {
+ if (method != null)
+ stringDecrypterInfos[new StringDecrypterInfo(method)] = true;
+ }
+
static string[] requiredFields6 = new string[] {
"System.Byte[]",
};
@@ -134,7 +147,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (cs == null)
continue;
- stringDecrypterMethod = cs;
+ AddStringDecrypterMethod(cs);
cliSecureRtType = type;
return true;
}
@@ -208,7 +221,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
continue;
cliSecureRtType = type;
- stringDecrypterMethod = cs;
+ AddStringDecrypterMethod(cs);
return;
}
}
diff --git a/de4dot.code/deobfuscators/Agile_NET/Deobfuscator.cs b/de4dot.code/deobfuscators/Agile_NET/Deobfuscator.cs
index fd577753..a3e6a3f9 100644
--- a/de4dot.code/deobfuscators/Agile_NET/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/Deobfuscator.cs
@@ -180,7 +180,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
FindCliSecureAttribute();
cliSecureRtType = new CliSecureRtType(module);
cliSecureRtType.Find(ModuleBytes);
- stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterMethod);
+ stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterInfos);
stringDecrypter.Find();
resourceDecrypter = new ResourceDecrypter(module);
resourceDecrypter.Find();
@@ -246,7 +246,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
base.DeobfuscateBegin();
cliSecureRtType.FindStringDecrypterMethod();
- stringDecrypter.Method = cliSecureRtType.StringDecrypterMethod;
+ stringDecrypter.AddDecrypterInfos(cliSecureRtType.StringDecrypterInfos);
+ stringDecrypter.Initialize();
AddAttributesToBeRemoved(cliSecureAttributes, "Obfuscator attribute");
@@ -265,7 +266,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
proxyCallFixer.Find();
- staticStringInliner.Add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
+ foreach (var info in stringDecrypter.StringDecrypterInfos)
+ staticStringInliner.Add(info.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
DeobfuscatedFile.StringDecryptersAdded();
if (options.DecryptMethods) {
@@ -295,6 +297,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
public override void DeobfuscateMethodEnd(Blocks blocks) {
+ if (Operations.DecryptStrings != OpDecryptString.None)
+ stringDecrypter.Deobfuscate(blocks);
proxyCallFixer.Deobfuscate(blocks);
RemoveStackFrameHelperCode(blocks);
base.DeobfuscateMethodEnd(blocks);
@@ -310,8 +314,14 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
if (CanRemoveStringDecrypterType) {
AddTypeToBeRemoved(stringDecrypter.Type, "String decrypter type");
+ foreach (var info in stringDecrypter.StringDecrypterInfos) {
+ if (info.Method.DeclaringType != cliSecureRtType.Type)
+ AddMethodToBeRemoved(info.Method, "String decrypter method");
+ if (info.Field != null && info.Field.DeclaringType != stringDecrypter.Type)
+ AddFieldToBeRemoved(info.Field, "String decrypter field");
+ }
if (options.DecryptMethods)
- AddTypeToBeRemoved(cliSecureRtType.Type, "Obfuscator type");
+ AddTypeToBeRemoved(cliSecureRtType.Type ?? stringDecrypter.KeyArrayFieldType, "Obfuscator type");
}
if (options.DecryptMethods) {
AddResources("Obfuscator protection files");
@@ -327,8 +337,8 @@ namespace de4dot.code.deobfuscators.Agile_NET {
public override IEnumerable GetStringDecrypterMethods() {
var list = new List();
- if (stringDecrypter.Method != null)
- list.Add(stringDecrypter.Method.MDToken.ToInt32());
+ foreach (var info in stringDecrypter.StringDecrypterInfos)
+ list.Add(info.Method.MDToken.ToInt32());
return list;
}
diff --git a/de4dot.code/deobfuscators/Agile_NET/ResourceDecrypter.cs b/de4dot.code/deobfuscators/Agile_NET/ResourceDecrypter.cs
index c696f508..e1854f9c 100644
--- a/de4dot.code/deobfuscators/Agile_NET/ResourceDecrypter.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/ResourceDecrypter.cs
@@ -62,10 +62,15 @@ namespace de4dot.code.deobfuscators.Agile_NET {
FindResourceType();
}
- static readonly string[] requiredFields = new string[] {
+ static readonly string[] requiredFields1 = new string[] {
"System.Reflection.Assembly",
"System.String[]",
};
+ static readonly string[] requiredFields2 = new string[] {
+ "System.Reflection.Assembly",
+ "System.String[]",
+ "System.Collections.Hashtable",
+ };
void FindResourceType() {
var cctor = DotNetUtils.GetModuleTypeCctor(module);
if (cctor == null)
@@ -77,7 +82,9 @@ namespace de4dot.code.deobfuscators.Agile_NET {
if (!DotNetUtils.IsMethod(calledMethod, "System.Void", "()"))
continue;
var type = calledMethod.DeclaringType;
- if (!new FieldTypes(type).Exactly(requiredFields))
+ var fieldTypes = new FieldTypes(type);
+ if (!fieldTypes.Exactly(requiredFields1) &&
+ !fieldTypes.Exactly(requiredFields2))
continue;
var resolveHandler = DotNetUtils.GetMethod(type, "System.Reflection.Assembly", "(System.Object,System.ResolveEventArgs)");
diff --git a/de4dot.code/deobfuscators/Agile_NET/StringDecrypter.cs b/de4dot.code/deobfuscators/Agile_NET/StringDecrypter.cs
index 91bf919f..d9d975d8 100644
--- a/de4dot.code/deobfuscators/Agile_NET/StringDecrypter.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/StringDecrypter.cs
@@ -18,38 +18,53 @@
*/
using System;
+using System.Collections.Generic;
using System.Text;
using dnlib.DotNet;
+using dnlib.DotNet.Emit;
+using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET {
class StringDecrypter {
ModuleDefMD module;
TypeDef stringDecrypterType;
- MethodDef stringDecrypterMethod;
+ FieldDef keyInitField;
+ FieldDef keyArrayField;
+ Dictionary stringDecrypterInfos = new Dictionary();
byte[] stringDecrypterKey;
public bool Detected {
- get { return stringDecrypterMethod != null; }
+ get { return stringDecrypterInfos.Count != 0; }
}
public TypeDef Type {
get { return stringDecrypterType; }
}
- public MethodDef Method {
- get { return stringDecrypterMethod; }
- set { stringDecrypterMethod = value; }
+ public TypeDef KeyArrayFieldType {
+ get { return keyArrayField == null ? null : keyArrayField.DeclaringType; }
}
- public StringDecrypter(ModuleDefMD module, MethodDef stringDecrypterMethod) {
+ public IEnumerable StringDecrypterInfos {
+ get { return stringDecrypterInfos.Keys; }
+ }
+
+ public StringDecrypter(ModuleDefMD module, IEnumerable stringDecrypterMethods) {
this.module = module;
- this.stringDecrypterMethod = stringDecrypterMethod;
+ foreach (var sdm in stringDecrypterMethods)
+ this.stringDecrypterInfos[sdm] = true;
}
public StringDecrypter(ModuleDefMD module, StringDecrypter oldOne) {
this.module = module;
stringDecrypterType = Lookup(oldOne.stringDecrypterType, "Could not find stringDecrypterType");
- stringDecrypterMethod = Lookup(oldOne.stringDecrypterMethod, "Could not find stringDecrypterMethod");
+ keyInitField = Lookup(oldOne.keyInitField, "Could not find key init field");
+ keyArrayField = Lookup(oldOne.keyArrayField, "Could not find key array field");
+ foreach (var info in oldOne.stringDecrypterInfos.Keys) {
+ var m = Lookup(info.Method, "Could not find string decrypter method");
+ var f = Lookup(info.Field, "Could not find string decrypter field");
+ stringDecrypterInfos[new StringDecrypterInfo(m, f)] = true;
+ }
stringDecrypterKey = oldOne.stringDecrypterKey;
}
@@ -57,6 +72,11 @@ namespace de4dot.code.deobfuscators.Agile_NET {
return DeobUtils.Lookup(module, def, errorMessage);
}
+ public void AddDecrypterInfos(IEnumerable infos) {
+ foreach (var info in infos)
+ stringDecrypterInfos[info] = true;
+ }
+
public void Find() {
stringDecrypterKey = new byte[1] { 0xFF };
foreach (var type in module.Types) {
@@ -64,6 +84,7 @@ namespace de4dot.code.deobfuscators.Agile_NET {
stringDecrypterType = type;
foreach (var field in type.Fields) {
if (field.FullName == " ::345" || field.FullName == "/D234 ::345") {
+ keyInitField = field;
stringDecrypterKey = field.InitialValue;
break;
}
@@ -73,6 +94,121 @@ namespace de4dot.code.deobfuscators.Agile_NET {
}
}
+ public void Initialize() {
+ if (keyInitField == null)
+ return;
+
+ foreach (var type in module.Types) {
+ var cctor = type.FindStaticConstructor();
+ if (cctor == null)
+ continue;
+ keyArrayField = GetKeyArrayField(cctor, keyInitField);
+ if (keyArrayField != null)
+ break;
+ }
+ if (keyArrayField == null)
+ return;
+
+ foreach (var type in module.GetTypes()) {
+ FieldDef field;
+ var method = FindStringDecrypters(type, keyArrayField, out field);
+ if (method == null)
+ continue;
+
+ stringDecrypterInfos[new StringDecrypterInfo(method, field)] = true;
+ }
+ }
+
+ static FieldDef GetKeyArrayField(MethodDef method, FieldDef keyInitField) {
+ if (method == null || method.Body == null)
+ return null;
+ var instrs = method.Body.Instructions;
+ for (int i = 0; i < instrs.Count; i++) {
+ if (instrs[i].OpCode.Code != Code.Ldtoken)
+ continue;
+
+ i++;
+ for (; i < instrs.Count; i++) {
+ var instr = instrs[i];
+ if (instr.OpCode.Code != Code.Stsfld)
+ continue;
+ var field = instr.Operand as FieldDef;
+ if (field == null || !field.IsStatic || field.DeclaringType != method.DeclaringType)
+ continue;
+ if (field.FieldSig.GetFieldType().GetFullName() != "System.Byte[]")
+ continue;
+ return field;
+ }
+ }
+ return null;
+ }
+
+ static MethodDef FindStringDecrypters(TypeDef type, FieldDef keyArrayField, out FieldDef field) {
+ FieldDef foundField = null;
+ foreach (var method in type.Methods) {
+ if (!method.IsAssembly || !method.IsStatic)
+ continue;
+ if (!DotNetUtils.IsMethod(method, "System.String", "(System.String)"))
+ continue;
+ if (!method.HasBody)
+ continue;
+
+ bool accessedArrayField = false;
+ foreach (var instr in method.Body.Instructions) {
+ var f = instr.Operand as FieldDef;
+ accessedArrayField |= f == keyArrayField;
+ if (f == null || f == keyArrayField || f == foundField)
+ continue;
+ if (DotNetUtils.DerivesFromDelegate(f.DeclaringType))
+ continue;
+ if (f.FieldSig.GetFieldType().GetFullName() != "System.Collections.Hashtable" ||
+ foundField != null)
+ goto exit;
+ foundField = f;
+ }
+ if (!accessedArrayField)
+ continue;
+
+ field = foundField;
+ return method;
+ }
+
+exit: ;
+ field = null;
+ return null;
+ }
+
+ public void Deobfuscate(Blocks blocks) {
+ if (!blocks.Method.IsStaticConstructor)
+ return;
+
+ var decrypterFields = new Dictionary(stringDecrypterInfos.Count);
+ foreach (var info in stringDecrypterInfos.Keys) {
+ if (info.Field != null)
+ decrypterFields[info.Field] = true;
+ }
+
+ foreach (var block in blocks.MethodBlocks.GetAllBlocks()) {
+ var instrs = block.Instructions;
+ for (int i = instrs.Count - 2; i >= 0; i--) {
+ var newobj = instrs[i];
+ if (newobj.OpCode.Code != Code.Newobj)
+ continue;
+ var ctor = newobj.Operand as IMethod;
+ if (ctor == null || ctor.FullName != "System.Void System.Collections.Hashtable::.ctor()")
+ continue;
+ var stsfld = instrs[i + 1];
+ if (stsfld.OpCode.Code != Code.Stsfld)
+ continue;
+ var field = stsfld.Operand as FieldDef;
+ if (field == null || !decrypterFields.ContainsKey(field))
+ continue;
+
+ block.Remove(i, 2);
+ }
+ }
+ }
+
public string Decrypt(string es) {
if (stringDecrypterKey == null)
throw new ApplicationException("Trying to decrypt strings when stringDecrypterKey is null (could not find it!)");
diff --git a/de4dot.code/deobfuscators/Agile_NET/StringDecrypterInfo.cs b/de4dot.code/deobfuscators/Agile_NET/StringDecrypterInfo.cs
new file mode 100644
index 00000000..52dac2fb
--- /dev/null
+++ b/de4dot.code/deobfuscators/Agile_NET/StringDecrypterInfo.cs
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2011-2014 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 dnlib.DotNet;
+
+namespace de4dot.code.deobfuscators.Agile_NET {
+ class StringDecrypterInfo {
+ public readonly MethodDef Method;
+ public readonly FieldDef Field;
+
+ public StringDecrypterInfo(MethodDef method)
+ : this(method, null) {
+ }
+
+ public StringDecrypterInfo(MethodDef method, FieldDef field) {
+ this.Method = method;
+ this.Field = field;
+ }
+
+ public override int GetHashCode() {
+ int hash = 0;
+ if (Method != null)
+ hash ^= Method.GetHashCode();
+ if (Field != null)
+ hash ^= Field.GetHashCode();
+ return hash;
+ }
+
+ public override bool Equals(object obj) {
+ var other = obj as StringDecrypterInfo;
+ return other != null &&
+ Method == other.Method &&
+ Field == other.Field;
+ }
+ }
+}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverterBase.cs b/de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverterBase.cs
index b9726049..3ee297b9 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverterBase.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/CsvmToCilMethodConverterBase.cs
@@ -232,13 +232,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (numLocals < 0)
throw new ApplicationException("Invalid number of locals");
+ var gpContext = GenericParamContext.Create(cilMethod);
for (int i = 0; i < numLocals; i++)
- locals.Add(new Local(ReadTypeRef(reader)));
+ locals.Add(new Local(ReadTypeRef(reader, gpContext)));
return locals;
}
- TypeSig ReadTypeRef(BinaryReader reader) {
+ TypeSig ReadTypeRef(BinaryReader reader, GenericParamContext gpContext) {
var etype = (ElementType)reader.ReadInt32();
switch (etype) {
case ElementType.Void: return module.CorLibTypes.Void;
@@ -263,12 +264,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
case ElementType.ValueType:
case ElementType.Var:
case ElementType.MVar:
- return (module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef).ToTypeSig();
+ return (module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef).ToTypeSig();
case ElementType.GenericInst:
etype = (ElementType)reader.ReadInt32();
if (etype == ElementType.ValueType)
- return (module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef).ToTypeSig();
+ return (module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef).ToTypeSig();
// ElementType.Class
return module.CorLibTypes.Object;
@@ -299,6 +300,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
if (numExceptions < 0)
throw new ApplicationException("Invalid number of exception handlers");
+ var gpContext = GenericParamContext.Create(cilMethod);
for (int i = 0; i < numExceptions; i++) {
var eh = new ExceptionHandler((ExceptionHandlerType)reader.ReadInt32());
eh.TryStart = GetInstruction(reader.ReadInt32());
@@ -306,7 +308,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm {
eh.HandlerStart = GetInstruction(reader.ReadInt32());
eh.HandlerEnd = GetInstructionEnd(reader.ReadInt32());
if (eh.HandlerType == ExceptionHandlerType.Catch)
- eh.CatchType = module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ eh.CatchType = module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
else if (eh.HandlerType == ExceptionHandlerType.Filter)
eh.FilterStart = GetInstruction(reader.ReadInt32());
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v1/CsvmToCilMethodConverter.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/CsvmToCilMethodConverter.cs
index ac039506..c50eedde 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v1/CsvmToCilMethodConverter.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/CsvmToCilMethodConverter.cs
@@ -34,12 +34,13 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
}
protected override List ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
+ var gpContext = GenericParamContext.Create(cilMethod);
var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
var instrs = new List();
uint offset = 0;
while (reader.BaseStream.Position < reader.BaseStream.Length) {
int vmOpCode = reader.ReadUInt16();
- var instr = opCodeDetector.Handlers[vmOpCode].Read(reader, module);
+ var instr = opCodeDetector.Handlers[vmOpCode].Read(reader, module, gpContext);
instr.Offset = offset;
offset += (uint)GetInstructionSize(instr);
SetCilToVmIndex(instr, instrs.Count);
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandler.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandler.cs
index 81475049..4c8b5407 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandler.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v1/OpCodeHandler.cs
@@ -29,7 +29,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
public string Name { get; set; }
public OpCodeHandlerSigInfo OpCodeHandlerSigInfo { get; set; }
public Predicate Check { get; set; }
- public Func Read { get; set; }
+ public Func Read { get; set; }
public bool Detect(UnknownHandlerInfo info) {
var sigInfo = OpCodeHandlerSigInfo;
@@ -68,7 +68,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
}
static partial class OpCodeHandlers {
- static Instruction arithmetic_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction arithmetic_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Add.ToInstruction();
case 1: return OpCodes.Add_Ovf.ToInstruction();
@@ -91,22 +91,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Type System.Reflection.Module::ResolveType(System.Int32)");
}
- static Instruction newarr_read(BinaryReader reader, IInstructionOperandResolver resolver) {
- return new Instruction(OpCodes.Newarr, resolver.ResolveToken(reader.ReadUInt32()));
+ static Instruction newarr_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
+ return new Instruction(OpCodes.Newarr, resolver.ResolveToken(reader.ReadUInt32(), gpContext));
}
- static Instruction box_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction box_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Box; break;
case 1: instr.OpCode = OpCodes.Unbox_Any; break;
default: throw new ApplicationException("Invalid opcode");
}
- instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
+ instr.Operand = resolver.ResolveToken(reader.ReadUInt32(), gpContext);
return instr;
}
- static Instruction call_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction call_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Newobj; break;
@@ -114,22 +114,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
case 2: instr.OpCode = OpCodes.Callvirt; break;
default: throw new ApplicationException("Invalid opcode");
}
- instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
+ instr.Operand = resolver.ResolveToken(reader.ReadUInt32(), gpContext);
return instr;
}
- static Instruction cast_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction cast_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
var instr = new Instruction();
switch (reader.ReadByte()) {
case 0: instr.OpCode = OpCodes.Castclass; break;
case 1: instr.OpCode = OpCodes.Isinst; break;
default: throw new ApplicationException("Invalid opcode");
}
- instr.Operand = resolver.ResolveToken(reader.ReadUInt32());
+ instr.Operand = resolver.ResolveToken(reader.ReadUInt32(), gpContext);
return instr;
}
- static Instruction compare_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction compare_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
int type = reader.ReadByte();
Instruction instr = new Instruction();
switch (type) {
@@ -202,7 +202,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
new InstructionInfo1 { Type = 11, Second = true, Third = true, OpCode = OpCodes.Conv_Ovf_U_Un },
new InstructionInfo1 { Type = 12, Second = true, Third = true, OpCode = OpCodes.Conv_R_Un },
};
- static Instruction convert_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction convert_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
byte type = reader.ReadByte();
bool second = reader.ReadBoolean();
bool third = reader.ReadBoolean();
@@ -221,7 +221,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return instr;
}
- static Instruction dup_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction dup_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Dup.ToInstruction();
case 1: return OpCodes.Pop.ToInstruction();
@@ -259,7 +259,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
new InstructionInfo2 { First = true, Second = true, Value = 28, OpCode = OpCodes.Ldelem_Ref },
new InstructionInfo2 { First = true, Second = false, Value = 0, OpCode = OpCodes.Ldelem },
};
- static Instruction ldelem_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldelem_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
Instruction instr = null;
bool first = reader.ReadBoolean();
bool second = reader.ReadBoolean();
@@ -273,7 +273,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
if (second)
instr = new Instruction(info.OpCode);
else
- instr = new Instruction(info.OpCode, resolver.ResolveToken((uint)value));
+ instr = new Instruction(info.OpCode, resolver.ResolveToken((uint)value, gpContext));
break;
}
if (instr == null)
@@ -286,13 +286,13 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags)");
}
- static Instruction endfinally_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction endfinally_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Endfinally.ToInstruction();
}
- static Instruction ldfld_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldfld_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
byte b = reader.ReadByte();
- var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
+ var field = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
switch (b) {
case 0: return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsfld, OpCodes.Ldfld, field));
case 1: return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsflda, OpCodes.Ldflda, field));
@@ -301,11 +301,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
}
}
- static Instruction initobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
- return new Instruction(OpCodes.Initobj, resolver.ResolveToken(reader.ReadUInt32()));
+ static Instruction initobj_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
+ return new Instruction(OpCodes.Initobj, resolver.ResolveToken(reader.ReadUInt32(), gpContext));
}
- static Instruction ldloc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldloc_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
bool isLdarg = reader.ReadBoolean();
ushort index = reader.ReadUInt16();
@@ -322,7 +322,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return instr;
}
- static Instruction ldloca_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldloca_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
Instruction instr = new Instruction();
if (reader.ReadBoolean()) {
instr.OpCode = OpCodes.Ldarga;
@@ -336,19 +336,19 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return instr;
}
- static Instruction ldelema_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldelema_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Ldelema, null);
}
- static Instruction ldlen_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldlen_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Ldlen.ToInstruction();
}
- static Instruction ldobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldobj_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Ldobj, null);
}
- static Instruction ldstr_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldstr_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Ldstr.ToInstruction(reader.ReadString());
}
@@ -356,8 +356,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MemberInfo System.Reflection.Module::ResolveMember(System.Int32)");
}
- static Instruction ldtoken_read(BinaryReader reader, IInstructionOperandResolver resolver) {
- return new Instruction(OpCodes.Ldtoken, resolver.ResolveToken(reader.ReadUInt32()));
+ static Instruction ldtoken_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
+ return new Instruction(OpCodes.Ldtoken, resolver.ResolveToken(reader.ReadUInt32(), gpContext));
}
static bool leave_check(UnknownHandlerInfo info) {
@@ -366,12 +366,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
!DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MemberInfo System.Reflection.Module::ResolveMember(System.Int32)");
}
- static Instruction leave_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction leave_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
int displacement = reader.ReadInt32();
return new Instruction(OpCodes.Leave, new TargetDisplOperand(displacement));
}
- static Instruction ldc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldc_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch ((ElementType)reader.ReadByte()) {
case ElementType.I4: return Instruction.CreateLdcI4(reader.ReadInt32());
case ElementType.I8: return OpCodes.Ldc_I8.ToInstruction(reader.ReadInt64());
@@ -382,24 +382,24 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
}
}
- static Instruction ldftn_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ldftn_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
byte code = reader.ReadByte();
uint token = reader.ReadUInt32();
switch (code) {
case 0:
- return new Instruction(OpCodes.Ldftn, resolver.ResolveToken(token));
+ return new Instruction(OpCodes.Ldftn, resolver.ResolveToken(token, gpContext));
case 1:
reader.ReadInt32(); // token of newobj .ctor
- return new Instruction(OpCodes.Ldvirtftn, resolver.ResolveToken(token));
+ return new Instruction(OpCodes.Ldvirtftn, resolver.ResolveToken(token, gpContext));
default:
throw new ApplicationException("Invalid opcode");
}
}
- static Instruction logical_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction logical_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch (reader.ReadByte()) {
case 0: return OpCodes.And.ToInstruction();
case 1: return OpCodes.Or.ToInstruction();
@@ -425,7 +425,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return false;
}
- static Instruction nop_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction nop_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Nop.ToInstruction();
}
@@ -433,7 +433,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodBase System.Reflection.Module::ResolveMethod(System.Int32)");
}
- static Instruction ret_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction ret_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
reader.ReadInt32(); // token of current method
return OpCodes.Ret.ToInstruction();
}
@@ -442,11 +442,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return info.ExecuteMethod.Body.Variables.Count == 0;
}
- static Instruction rethrow_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction rethrow_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Rethrow.ToInstruction();
}
- static Instruction stloc_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction stloc_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
bool isStarg = reader.ReadBoolean();
ushort index = reader.ReadUInt16();
@@ -464,11 +464,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return instr;
}
- static Instruction stobj_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction stobj_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return new Instruction(OpCodes.Stobj, null);
}
- static Instruction switch_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction switch_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
int numTargets = reader.ReadInt32();
int[] targetDispls = new int[numTargets];
for (int i = 0; i < targetDispls.Length; i++)
@@ -480,11 +480,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
return !DotNetUtils.CallsMethod(info.ExecuteMethod, "System.Reflection.MethodInfo System.Type::GetMethod(System.String,System.Reflection.BindingFlags)");
}
- static Instruction throw_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction throw_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
return OpCodes.Throw.ToInstruction();
}
- static Instruction neg_read(BinaryReader reader, IInstructionOperandResolver resolver) {
+ static Instruction neg_read(BinaryReader reader, IInstructionOperandResolver resolver, GenericParamContext gpContext) {
switch (reader.ReadByte()) {
case 0: return OpCodes.Neg.ToInstruction();
case 1: return OpCodes.Not.ToInstruction();
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM5.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM5.bin
new file mode 100644
index 00000000..1177d7fc
Binary files /dev/null and b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM5.bin differ
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs
index 56900000..1dec73de 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs
@@ -53,10 +53,10 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
public readonly int BlockIndex;
public int HashIndex;
- public HandlerState(List blockSigInfos, int blockIndex, int instructionIndex) {
+ public HandlerState(List blockSigInfos, int blockIndex, int hashIndex) {
this.BlockSigInfos = blockSigInfos;
this.BlockIndex = blockIndex;
- this.HashIndex = instructionIndex;
+ this.HashIndex = hashIndex;
}
public HandlerState Clone() {
@@ -164,6 +164,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
}
+ if (nextState == null && findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
+ nextState = GetNextHandlerState(ref findState);
if (nextState == null) {
if (findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
return false;
@@ -181,6 +183,16 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
}
+ static HandlerState? GetNextHandlerState(ref FindHandlerState findState) {
+ for (int i = 0; i < findState.CompositeState.BlockSigInfos.Count; i++) {
+ if (findState.VisitedCompositeBlocks.ContainsKey(i))
+ continue;
+ return new HandlerState(findState.CompositeState.BlockSigInfos, i, 0);
+ }
+
+ return null;
+ }
+
static bool Compare(ref HandlerState handler, ref HandlerState composite) {
var hhashes = handler.BlockSigInfos[handler.BlockIndex].Hashes;
int hi = handler.HashIndex;
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs
index 11ebea38..488f3e14 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs
@@ -81,7 +81,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
foreach (var type in module.Types) {
if (!type.IsPublic || !type.IsAbstract)
continue;
- if (type.HasFields || type.HasProperties || type.HasEvents)
+ if (type.HasProperties || type.HasEvents)
continue;
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
continue;
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs
index 3a090f84..bea0bf1c 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
-// Runtime Version:4.0.30319.18052
+// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -99,5 +99,15 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
return ((byte[])(obj));
}
}
+
+ ///
+ /// Looks up a localized resource of type System.Byte[].
+ ///
+ internal static byte[] CSVM5 {
+ get {
+ object obj = ResourceManager.GetObject("CSVM5", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
}
}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx
index 17159be0..3a91280c 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx
@@ -130,4 +130,8 @@
CSVM4.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ CSVM5.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
\ No newline at end of file
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs
index 9c25af10..b63d8c3c 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs
@@ -35,7 +35,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
protected override List ReadInstructions(MethodDef cilMethod, CsvmMethodData csvmMethod) {
var reader = new BinaryReader(new MemoryStream(csvmMethod.Instructions));
var instrs = new List();
- var handlerInfoReader = new OpCodeHandlerInfoReader(module);
+ var gpContext = GenericParamContext.Create(cilMethod);
+ var handlerInfoReader = new OpCodeHandlerInfoReader(module, gpContext);
int numVmInstrs = reader.ReadInt32();
var vmInstrs = new ushort[numVmInstrs];
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfoReader.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfoReader.cs
index dd92c2bc..f61c9691 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfoReader.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfoReader.cs
@@ -27,9 +27,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class OpCodeHandlerInfoReader {
IInstructionOperandResolver resolver;
Dictionary> readHandlers;
+ readonly GenericParamContext gpContext;
- public OpCodeHandlerInfoReader(IInstructionOperandResolver resolver) {
+ public OpCodeHandlerInfoReader(IInstructionOperandResolver resolver, GenericParamContext gpContext) {
this.resolver = resolver;
+ this.gpContext = gpContext;
this.readHandlers = new Dictionary> {
{ HandlerTypeCode.Add, Handler_Add },
{ HandlerTypeCode.Add_Ovf, Handler_Add_Ovf },
@@ -176,7 +178,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Box(BinaryReader reader) {
- var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Box.ToInstruction(type);
}
@@ -193,17 +195,17 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Call(BinaryReader reader) {
- var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
+ var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Call.ToInstruction(method);
}
Instruction Handler_Callvirt(BinaryReader reader) {
- var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
+ var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Callvirt.ToInstruction(method);
}
Instruction Handler_Castclass(BinaryReader reader) {
- var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Castclass.ToInstruction(type);
}
@@ -312,12 +314,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Initobj(BinaryReader reader) {
- var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Initobj.ToInstruction(type);
}
Instruction Handler_Isinst(BinaryReader reader) {
- var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Isinst.ToInstruction(type);
}
@@ -349,17 +351,17 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Ldfld_Ldsfld(BinaryReader reader) {
- var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
+ var field = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsfld, OpCodes.Ldfld, field));
}
Instruction Handler_Ldflda_Ldsflda(BinaryReader reader) {
- var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
+ var field = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Ldsflda, OpCodes.Ldflda, field));
}
Instruction Handler_Ldftn(BinaryReader reader) {
- var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
+ var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Ldftn.ToInstruction(method);
}
@@ -384,12 +386,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Ldtoken(BinaryReader reader) {
- var member = resolver.ResolveToken(reader.ReadUInt32()) as ITokenOperand;
+ var member = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITokenOperand;
return OpCodes.Ldtoken.ToInstruction(member);
}
Instruction Handler_Ldvirtftn(BinaryReader reader) {
- var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
+ var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
reader.ReadUInt32();
return OpCodes.Ldvirtftn.ToInstruction(method);
}
@@ -415,12 +417,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Newarr(BinaryReader reader) {
- var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Newarr.ToInstruction(type);
}
Instruction Handler_Newobj(BinaryReader reader) {
- var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
+ var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Newobj.ToInstruction(method);
}
@@ -449,7 +451,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Ret(BinaryReader reader) {
- var method = resolver.ResolveToken(reader.ReadUInt32()) as IMethod;
+ var method = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
return OpCodes.Ret.ToInstruction();
}
@@ -478,7 +480,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Stfld_Stsfld(BinaryReader reader) {
- var field = resolver.ResolveToken(reader.ReadUInt32()) as IField;
+ var field = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
return new Instruction(null, new FieldInstructionOperand(OpCodes.Stsfld, OpCodes.Stfld, field));
}
@@ -517,7 +519,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Instruction Handler_Unbox_Any(BinaryReader reader) {
- var type = resolver.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ var type = resolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
return OpCodes.Unbox_Any.ToInstruction(type);
}
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfos.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfos.cs
index f70dc4aa..37fa316d 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfos.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfos.cs
@@ -75,6 +75,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
ReadOpCodeHandlerInfos(CsvmResources.CSVM2),
ReadOpCodeHandlerInfos(CsvmResources.CSVM3),
ReadOpCodeHandlerInfos(CsvmResources.CSVM4),
+ ReadOpCodeHandlerInfos(CsvmResources.CSVM5),
};
static IList ReadOpCodeHandlerInfos(byte[] data) {
diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCodeHandlerDetector.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCodeHandlerDetector.cs
index a6431820..220044a3 100644
--- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCodeHandlerDetector.cs
+++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCodeHandlerDetector.cs
@@ -33,11 +33,13 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
public MyDeobfuscator(ModuleDefMD module) {
cliSecureRtType = new CliSecureRtType(module);
cliSecureRtType.Find(null);
- stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterMethod);
+ stringDecrypter = new StringDecrypter(module, cliSecureRtType.StringDecrypterInfos);
stringDecrypter.Find();
cliSecureRtType.FindStringDecrypterMethod();
- stringDecrypter.Method = cliSecureRtType.StringDecrypterMethod;
- staticStringInliner.Add(stringDecrypter.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
+ stringDecrypter.AddDecrypterInfos(cliSecureRtType.StringDecrypterInfos);
+ stringDecrypter.Initialize();
+ foreach (var info in stringDecrypter.StringDecrypterInfos)
+ staticStringInliner.Add(info.Method, (method, gim, args) => stringDecrypter.Decrypt((string)args[0]));
}
void RestoreMethod(Blocks blocks) {
@@ -252,7 +254,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
if (cctor == null)
continue;
requiredFields[0] = type.FullName;
- if (!new FieldTypes(type).Exactly(requiredFields))
+ var fieldTypes = new FieldTypes(type);
+ if (!fieldTypes.All(requiredFields))
continue;
cflowDeobfuscator.Deobfuscate(cctor);
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/AntiDebugger.cs b/de4dot.code/deobfuscators/CryptoObfuscator/AntiDebugger.cs
index c77115c0..5d0a84f5 100644
--- a/de4dot.code/deobfuscators/CryptoObfuscator/AntiDebugger.cs
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/AntiDebugger.cs
@@ -70,7 +70,8 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
!ContainsString(method, "run under") &&
!ContainsString(method, "run with") &&
!ContainsString(method, "started under") &&
- !ContainsString(method, "{0} detected"))
+ !ContainsString(method, "{0} detected") &&
+ !ContainsString(method, "{0} found"))
continue;
antiDebuggerType = type;
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/MethodBodyReader.cs b/de4dot.code/deobfuscators/CryptoObfuscator/MethodBodyReader.cs
index 760ffcd3..4273dc8c 100644
--- a/de4dot.code/deobfuscators/CryptoObfuscator/MethodBodyReader.cs
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/MethodBodyReader.cs
@@ -28,6 +28,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
class MethodBodyReader : MethodBodyReaderBase {
ModuleDefMD module;
ushort maxStackSize;
+ GenericParamContext gpContext;
public MethodBodyReader(ModuleDefMD module, IBinaryReader reader)
: base(reader) {
@@ -35,6 +36,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
public void Read(MethodDef method) {
+ this.gpContext = GenericParamContext.Create(method);
this.parameters = method.Parameters;
SetLocals(GetLocals(method));
@@ -58,15 +60,15 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
protected override IField ReadInlineField(Instruction instr) {
- return module.ResolveToken(reader.ReadUInt32()) as IField;
+ return module.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
}
protected override IMethod ReadInlineMethod(Instruction instr) {
- return module.ResolveToken(reader.ReadUInt32()) as IMethod;
+ return module.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
}
protected override MethodSig ReadInlineSig(Instruction instr) {
- var sas = module.ResolveStandAloneSig(MDToken.ToRID(reader.ReadUInt32()));
+ var sas = module.ResolveStandAloneSig(MDToken.ToRID(reader.ReadUInt32()), gpContext);
return sas == null ? null : sas.MethodSig;
}
@@ -75,11 +77,11 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
protected override ITokenOperand ReadInlineTok(Instruction instr) {
- return module.ResolveToken(reader.ReadUInt32()) as ITokenOperand;
+ return module.ResolveToken(reader.ReadUInt32(), gpContext) as ITokenOperand;
}
protected override ITypeDefOrRef ReadInlineType(Instruction instr) {
- return module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ return module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
}
void ReadExceptionHandlers(int numExceptionHandlers) {
@@ -101,7 +103,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
switch (eh.HandlerType) {
case ExceptionHandlerType.Catch:
- eh.CatchType = module.ResolveToken(reader.ReadUInt32()) as ITypeDefOrRef;
+ eh.CatchType = module.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
break;
case ExceptionHandlerType.Filter:
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/ProxyCallFixer.cs b/de4dot.code/deobfuscators/CryptoObfuscator/ProxyCallFixer.cs
index b296ff6c..d8ff5395 100644
--- a/de4dot.code/deobfuscators/CryptoObfuscator/ProxyCallFixer.cs
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/ProxyCallFixer.cs
@@ -110,7 +110,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
MethodDef GetProxyCreateMethod(TypeDef type) {
if (DotNetUtils.FindFieldType(type, "System.ModuleHandle", true) == null)
return null;
- if (type.Fields.Count < 1 || type.Fields.Count > 18)
+ if (type.Fields.Count < 1 || type.Fields.Count > 20)
return null;
MethodDef createMethod = null;
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/ResourceDecrypter.cs b/de4dot.code/deobfuscators/CryptoObfuscator/ResourceDecrypter.cs
index b4288131..3449cc90 100644
--- a/de4dot.code/deobfuscators/CryptoObfuscator/ResourceDecrypter.cs
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/ResourceDecrypter.cs
@@ -157,7 +157,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
foreach (var method in GetDecrypterMethods(type)) {
if (method == null)
continue;
- if (!new LocalTypes(method).Exactly(requiredLocals_sl))
+ if (!new LocalTypes(method).All(requiredLocals_sl))
continue;
resourceDecrypterType = type;
@@ -180,6 +180,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
}
static bool CheckFlipBits(MethodDef method) {
+ int nots = 0;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
var ldloc = instrs[i];
@@ -189,14 +190,11 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
if (local == null || local.Type.GetElementType().GetPrimitiveSize() < 0)
continue;
- var not = instrs[i + 1];
- if (not.OpCode.Code != Code.Not)
- continue;
-
- return true;
+ if (instrs[i + 1].OpCode.Code == Code.Not)
+ nots++;
}
- return false;
+ return (nots & 1) == 1;
}
bool UpdateFlags(MethodDef method, ISimpleDeobfuscator simpleDeobfuscator) {
diff --git a/de4dot.code/deobfuscators/CryptoObfuscator/TamperDetection.cs b/de4dot.code/deobfuscators/CryptoObfuscator/TamperDetection.cs
index 1a44a36a..79392332 100644
--- a/de4dot.code/deobfuscators/CryptoObfuscator/TamperDetection.cs
+++ b/de4dot.code/deobfuscators/CryptoObfuscator/TamperDetection.cs
@@ -84,7 +84,7 @@ namespace de4dot.code.deobfuscators.CryptoObfuscator {
if (!method.IsStatic || !DotNetUtils.IsMethod(method, "System.Void", "()"))
return false;
- if (type.Methods.Count < 3 || type.Methods.Count > 27)
+ if (type.Methods.Count < 3 || type.Methods.Count > 31)
return false;
if (DotNetUtils.GetPInvokeMethod(type, "mscoree", "StrongNameSignatureVerificationEx") != null) {
}
diff --git a/de4dot.code/deobfuscators/Dotfuscator/Deobfuscator.cs b/de4dot.code/deobfuscators/Dotfuscator/Deobfuscator.cs
index c5f3c319..0f95125f 100644
--- a/de4dot.code/deobfuscators/Dotfuscator/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/Dotfuscator/Deobfuscator.cs
@@ -25,7 +25,7 @@ namespace de4dot.code.deobfuscators.Dotfuscator {
public class DeobfuscatorInfo : DeobfuscatorInfoBase {
public const string THE_NAME = "Dotfuscator";
public const string THE_TYPE = "df";
- const string DEFAULT_REGEX = @"!^[a-z][a-z0-9]{0,2}$&!^A_[0-9]+$&" + DeobfuscatorBase.DEFAULT_ASIAN_VALID_NAME_REGEX;
+ const string DEFAULT_REGEX = @"!^(?:eval_)?[a-z][a-z0-9]{0,2}$&!^A_[0-9]+$&" + DeobfuscatorBase.DEFAULT_ASIAN_VALID_NAME_REGEX;
public DeobfuscatorInfo()
: base(DEFAULT_REGEX) {
}
diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/DynocodeService.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/DynocodeService.cs
index 06371ab5..31cdb538 100644
--- a/de4dot.code/deobfuscators/Eazfuscator_NET/DynocodeService.cs
+++ b/de4dot.code/deobfuscators/Eazfuscator_NET/DynocodeService.cs
@@ -31,8 +31,10 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
public const int MSG_CALL_MOVE_NEXT = 4;
Module reflObfModule;
- IEnumerable ienumerable = null;
- IEnumerator ienumerator = null;
+ object ienumerable = null;
+ object ienumerator = null;
+ MethodInfo mi_get_Current;
+ MethodInfo mi_MoveNext;
[CreateUserGenericService]
public static IUserGenericService Create() {
@@ -72,7 +74,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
var ctor = reflObfModule.ResolveMethod((int)ctorToken) as ConstructorInfo;
if (ctor == null)
throw new ApplicationException(string.Format("Invalid ctor with token: {0:X8}", ctorToken));
- ienumerable = (IEnumerable)ctor.Invoke(args);
+ ienumerable = ctor.Invoke(args);
}
void WriteEnumerableField(uint fieldToken, object value) {
@@ -83,15 +85,74 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
}
void CreateEnumerator() {
- ienumerator = ienumerable.GetEnumerator();
+ foreach (var method in ienumerable.GetType().GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
+ if (method.GetParameters().Length != 0)
+ continue;
+ var retType = method.ReturnType;
+ if (!retType.IsGenericType)
+ continue;
+ var genArgs = retType.GetGenericArguments();
+ if (genArgs.Length != 1)
+ continue;
+ if (genArgs[0] != typeof(int))
+ continue;
+ if (!FindEnumeratorMethods(retType))
+ continue;
+
+ ienumerator = method.Invoke(ienumerable, null);
+ return;
+ }
+
+ throw new ApplicationException("No GetEnumerator() method found");
+ }
+
+ bool FindEnumeratorMethods(Type type) {
+ mi_get_Current = null;
+ mi_MoveNext = null;
+
+ foreach (var method in ienumerable.GetType().GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
+ if (Is_get_Current(method)) {
+ if (mi_get_Current != null)
+ return false;
+ mi_get_Current = method;
+ continue;
+ }
+
+ if (Is_MoveNext(method)) {
+ if (mi_MoveNext != null)
+ return false;
+ mi_MoveNext = method;
+ continue;
+ }
+ }
+
+ return mi_get_Current != null && mi_MoveNext != null;
+ }
+
+ static bool Is_get_Current(MethodInfo method) {
+ if (method.GetParameters().Length != 0)
+ return false;
+ if (method.ReturnType != typeof(int))
+ return false;
+
+ return true;
+ }
+
+ static bool Is_MoveNext(MethodInfo method) {
+ if (method.GetParameters().Length != 0)
+ return false;
+ if (method.ReturnType != typeof(bool))
+ return false;
+
+ return true;
}
int CallGetCurrent() {
- return ienumerator.Current;
+ return (int)mi_get_Current.Invoke(ienumerator, null);
}
bool CallMoveNext() {
- return ienumerator.MoveNext();
+ return (bool)mi_MoveNext.Invoke(ienumerator, null);
}
public void Dispose() {
diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs
index da60a999..a16c6729 100644
--- a/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs
+++ b/de4dot.code/deobfuscators/Eazfuscator_NET/StringDecrypter.cs
@@ -80,7 +80,7 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
}
public int? ValidStringDecrypterValue {
- get { return validStringDecrypterValue;}
+ get { return validStringDecrypterValue; }
}
public TypeDef Type {
@@ -696,8 +696,8 @@ done: ;
if (initValue2 == null || !initValue2.AllBitsValid())
return false;
- int loopStart = GetIndexOfCall(instrs, index, leaveIndex, "System.Int32 System.Collections.Generic.IEnumerator`1::get_Current()");
- int loopEnd = GetIndexOfCall(instrs, loopStart, leaveIndex, "System.Boolean System.Collections.IEnumerator::MoveNext()");
+ int loopStart = GetIndexOfCall(instrs, index, leaveIndex, "System.Int32", "()");
+ int loopEnd = GetIndexOfCall(instrs, loopStart, leaveIndex, "System.Boolean", "()");
if (loopStart < 0 || loopEnd < 0)
return false;
loopStart++;
@@ -720,7 +720,7 @@ done: ;
return true;
}
- static int GetIndexOfCall(IList instrs, int startIndex, int endIndex, string fullMethodName) {
+ static int GetIndexOfCall(IList instrs, int startIndex, int endIndex, string returnType, string parameters) {
if (startIndex < 0 || endIndex < 0)
return -1;
for (int i = startIndex; i < endIndex; i++) {
@@ -728,7 +728,7 @@ done: ;
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt)
continue;
var method = instr.Operand as IMethod;
- if (method == null || method.FullName != fullMethodName)
+ if (!DotNetUtils.IsMethod(method, returnType, parameters))
continue;
return i;
diff --git a/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs b/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs
index 980d9d03..9e6e6e73 100644
--- a/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs
+++ b/de4dot.code/deobfuscators/Eazfuscator_NET/VersionDetector.cs
@@ -722,13 +722,85 @@ namespace de4dot.code.deobfuscators.Eazfuscator_NET {
decryptStringMethod.Body.ExceptionHandlers.Count >= 2 &&
new LocalTypes(decryptStringMethod).All(locals35) &&
CheckTypeFields2(fields35)) {
- return "3.5 - 4.1";
+ return "3.5 - 4.2";
+ }
+
+ /////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////
+
+ var fields43 = new string[] {
+ GetNestedTypeName(0),
+ GetNestedTypeName(1),
+ "System.Byte[]",
+ "System.Int16",
+ "System.Int32",
+ "System.Byte[]",
+ "System.Int32",
+ "System.Int32",
+ GetNestedTypeName(2),
+ };
+ var locals43 = CreateLocalsArray(
+ "System.Boolean",
+ "System.Byte",
+ "System.Byte[]",
+ "System.Char[]",
+ FindEnumeratorName(decryptStringMethod),
+ GetNestedTypeName(0),
+ "System.Diagnostics.StackFrame",
+ "System.Diagnostics.StackTrace",
+ "System.Int16",
+ "System.Int32",
+ "System.Int64",
+ "System.IO.Stream",
+ "System.Reflection.Assembly",
+ "System.Reflection.AssemblyName",
+ "System.Reflection.MethodBase",
+ "System.String",
+ "System.Text.StringBuilder",
+ "System.Type"
+ );
+ var olocals43 = CreateLocalsArray(
+ "System.Int32"
+ );
+ if (otherMethods.Count == 1 &&
+ decryptStringType.NestedTypes.Count == 3 &&
+ DotNetUtils.IsMethod(otherMethods[0], "System.Void", "(System.Byte[],System.Int32,System.Byte[])") &&
+ otherMethods[0].IsPrivate &&
+ otherMethods[0].IsStatic &&
+ new LocalTypes(otherMethods[0]).Exactly(olocals43) &&
+ decryptStringMethod.IsNoInlining &&
+ decryptStringMethod.IsAssembly &&
+ !decryptStringMethod.IsSynchronized &&
+ decryptStringMethod.Body.MaxStack >= 1 &&
+ decryptStringMethod.Body.MaxStack <= 8 &&
+ decryptStringMethod.Body.ExceptionHandlers.Count >= 2 &&
+ new LocalTypes(decryptStringMethod).All(locals43) &&
+ CheckTypeFields2(fields43)) {
+ return "4.3";
}
}
return null;
}
+ static string FindEnumeratorName(MethodDef method) {
+ foreach (var local in method.Body.Variables) {
+ var gis = local.Type as GenericInstSig;
+ if (gis == null)
+ continue;
+ if (gis.FullName == "System.Collections.Generic.IEnumerator`1")
+ continue;
+ if (gis.GenericArguments.Count != 1)
+ continue;
+ if (gis.GenericArguments[0].GetFullName() != "System.Int32")
+ continue;
+
+ return gis.FullName;
+ }
+ return null;
+ }
+
TypeDef GetNestedType(int n) {
var type = stringDecrypter.Type;
diff --git a/de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs b/de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs
index a63d5078..ba4cc0b4 100644
--- a/de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs
+++ b/de4dot.code/deobfuscators/Goliath_NET/DecrypterBase.cs
@@ -57,7 +57,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET {
}
public TypeDef DelegateInitType {
- get { return delegateInitType ?? FindDelegateInitType();}
+ get { return delegateInitType ?? FindDelegateInitType(); }
}
public TypeDef DelegateType {
diff --git a/de4dot.code/deobfuscators/Goliath_NET/StrongNameChecker.cs b/de4dot.code/deobfuscators/Goliath_NET/StrongNameChecker.cs
index 402afab8..e647d0aa 100644
--- a/de4dot.code/deobfuscators/Goliath_NET/StrongNameChecker.cs
+++ b/de4dot.code/deobfuscators/Goliath_NET/StrongNameChecker.cs
@@ -28,7 +28,7 @@ namespace de4dot.code.deobfuscators.Goliath_NET {
MethodDef strongNameCheckMethod;
public bool Detected {
- get { return strongNameType != null;}
+ get { return strongNameType != null; }
}
public TypeDef Type {
diff --git a/de4dot.code/deobfuscators/ILProtector/Deobfuscator.cs b/de4dot.code/deobfuscators/ILProtector/Deobfuscator.cs
index ca1cd63c..3ee9ce6a 100644
--- a/de4dot.code/deobfuscators/ILProtector/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/ILProtector/Deobfuscator.cs
@@ -122,7 +122,6 @@ namespace de4dot.code.deobfuscators.ILProtector {
bool emailMe = false;
foreach (var info in mainType.RuntimeFileInfos) {
var version = info.GetVersion();
- emailMe |= version == null && System.IO.File.Exists(info.PathName);
emailMe |= version != null && version == new Version(1, 0, 7, 0);
Logger.v("Version: {0} ({1})", version == null ? "UNKNOWN" : version.ToString(), info.PathName);
}
diff --git a/de4dot.code/deobfuscators/ILProtector/DynamicMethodsDecrypter.cs b/de4dot.code/deobfuscators/ILProtector/DynamicMethodsDecrypter.cs
index e6dec7b4..b90f1731 100644
--- a/de4dot.code/deobfuscators/ILProtector/DynamicMethodsDecrypter.cs
+++ b/de4dot.code/deobfuscators/ILProtector/DynamicMethodsDecrypter.cs
@@ -40,6 +40,50 @@ namespace de4dot.code.deobfuscators.ILProtector {
IDecrypter decrypter;
bool methodReaderHasDelegateTypeFlag;
+ static class CodeAllocator {
+ [DllImport("kernel32")]
+ static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, uint flProtect);
+
+ const uint PAGE_EXECUTE_READWRITE = 0x40;
+ const uint MEM_COMMIT = 0x00001000;
+ const int ALIGNMENT = 0x10;
+
+ static IntPtr currentPage;
+ static int nextOffset;
+ static int pageSize;
+
+ public static IntPtr Allocate(byte[] code) {
+ if (code == null || code.Length == 0)
+ return IntPtr.Zero;
+
+ var addr = Allocate(code.Length);
+ Marshal.Copy(code, 0, addr, code.Length);
+ return addr;
+ }
+
+ public static IntPtr Allocate(int size) {
+ if (size <= 0)
+ return IntPtr.Zero;
+
+ size = (size + ALIGNMENT - 1) & ~(ALIGNMENT - 1);
+ if (nextOffset + size > pageSize)
+ AllocNewPage(size);
+
+ var data = new IntPtr(currentPage.ToInt64() + nextOffset);
+ nextOffset += size;
+ return data;
+ }
+
+ static void AllocNewPage(int size) {
+ size = (size + 0xFFF) & ~0xFFF;
+ currentPage = VirtualAlloc(IntPtr.Zero, new UIntPtr((uint)size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ if (currentPage == IntPtr.Zero)
+ throw new ApplicationException("VirtualAlloc() failed");
+ pageSize = size;
+ nextOffset = 0;
+ }
+ }
+
interface IDecrypter {
byte[] Decrypt(int methodId, uint rid);
}
@@ -323,7 +367,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
pDecryptCallback = new IntPtr(p + IntPtr.Size * 40);
}
- IntPtr GetStateAddr(object obj) {
+ public static IntPtr GetStateAddr(object obj) {
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
foreach (var fi in obj.GetType().GetFields(flags)) {
if (fi.FieldType == typeof(IntPtr))
@@ -335,7 +379,6 @@ namespace de4dot.code.deobfuscators.ILProtector {
public byte[] Decrypt(int methodId, uint rid) {
decryptedData = null;
currentILBytes = dmd.reflectionModule.ResolveMethod(0x06000000 + (int)rid).GetMethodBody().GetILAsByteArray();
-
invoker.DynamicInvoke(new object[1] { methodId });
return decryptedData;
}
@@ -358,7 +401,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
public unsafe DecrypterV2_0_12_0(DynamicMethodsDecrypter dmd)
: base(dmd) {
getCallerMethodAsILByteArrayDelegate = GetCallerMethodAsILByteArray;
- decryptCallbackDelegate = MyDecryptCallback;
+ decryptCallbackDelegate = DecryptCallback;
*(IntPtr*)pGetILBytes = Marshal.GetFunctionPointerForDelegate(getCallerMethodAsILByteArrayDelegate);
*(IntPtr*)pDecryptCallback = Marshal.GetFunctionPointerForDelegate(decryptCallbackDelegate);
@@ -368,7 +411,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
return currentILBytes;
}
- unsafe bool MyDecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId) {
+ unsafe bool DecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId) {
SaveDecryptedData(pMethodCode, methodSize);
return true;
}
@@ -386,7 +429,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
public unsafe DecrypterV2_0_12_3(DynamicMethodsDecrypter dmd)
: base(dmd) {
getCallerMethodAsILByteArrayDelegate = GetCallerMethodAsILByteArray;
- decryptCallbackDelegate = MyDecryptCallback;
+ decryptCallbackDelegate = DecryptCallback;
*(IntPtr*)pGetILBytes = Marshal.GetFunctionPointerForDelegate(getCallerMethodAsILByteArrayDelegate);
*(IntPtr*)pDecryptCallback = Marshal.GetFunctionPointerForDelegate(decryptCallbackDelegate);
@@ -396,12 +439,176 @@ namespace de4dot.code.deobfuscators.ILProtector {
return currentILBytes;
}
- unsafe bool MyDecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId, IntPtr e) {
+ unsafe bool DecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId, IntPtr e) {
SaveDecryptedData(pMethodCode, methodSize);
return true;
}
}
+ abstract class DecrypterV2_0_13_0_Base : IDecrypter {
+ protected readonly DynamicMethodsDecrypter dmd;
+ protected byte[] currentILBytes;
+ byte[] decryptedData;
+ readonly Delegate invoker;
+
+ readonly GetCallerMethodAsILByteArrayDelegate getCallerMethodAsILByteArrayDelegate;
+ readonly DecryptCallbackDelegate decryptCallbackDelegate;
+ readonly IgnoreDelegate ignoreDelegate;
+
+ [DllImport("kernel32")]
+ static extern bool GetModuleHandleEx(uint dwFlags, IntPtr lpModuleName, out IntPtr phModule);
+
+ [return: MarshalAs(UnmanagedType.SafeArray)]
+ delegate byte[] GetCallerMethodAsILByteArrayDelegate(IntPtr a, int skipFrames, ref int flags, IntPtr d);
+ unsafe delegate bool DecryptCallbackDelegate(IntPtr a, byte* pMethodCode, int methodSize, int methodId, IntPtr e);
+ delegate IntPtr IgnoreDelegate(IntPtr a, IntPtr b);
+
+ public unsafe DecrypterV2_0_13_0_Base(DynamicMethodsDecrypter dmd) {
+ this.dmd = dmd;
+ this.invoker = (Delegate)dmd.invokerFieldInfo.GetValue(null);
+
+ byte* p = (byte*)DecrypterBaseV2_0_12_x.GetStateAddr(invoker.Target);
+ byte* pis = GetAddr(*(byte**)p);
+ p = *(byte**)pis;
+ byte* pam = *(byte**)(p + IntPtr.Size * 2);
+ p = *(byte**)(p + ((Environment.Version.Major - 2) / 2 * IntPtr.Size));
+ p += IntPtr.Size * 8 + 0x18;
+ p = LookUp(p, AppDomain.CurrentDomain.Id);
+ p = *(byte**)(p + IntPtr.Size * 16 + 0x18);
+ byte* pd = p + IntPtr.Size * 2;
+ p = *(byte**)(p + IntPtr.Size * 13);
+
+ getCallerMethodAsILByteArrayDelegate = GetCallerMethodAsILByteArray;
+ decryptCallbackDelegate = DecryptCallback;
+ ignoreDelegate = IgnoreMethod;
+
+ byte* pm = p + 0x28 * IntPtr.Size;
+ *(IntPtr*)(p + 0x29 * IntPtr.Size) = Marshal.GetFunctionPointerForDelegate(getCallerMethodAsILByteArrayDelegate);
+ *(IntPtr*)(p + 0x2A * IntPtr.Size) = Marshal.GetFunctionPointerForDelegate(decryptCallbackDelegate);
+ if (IntPtr.Size == 4)
+ *(IntPtr*)(p + 0x2B * IntPtr.Size) = Marshal.GetFunctionPointerForDelegate(ignoreDelegate);
+ InitCode(GetModuleHandle(pis), pam, pd, pm);
+ }
+
+ static unsafe byte* GetModuleHandle(byte* addr) {
+ IntPtr hModule;
+ if (!GetModuleHandleEx(4, new IntPtr(addr), out hModule))
+ throw new ApplicationException("GetModuleHandleEx() failed");
+ return (byte*)hModule;
+ }
+
+ protected unsafe abstract void InitCode(byte* ba, byte* pam, byte* pd, byte* pm);
+
+ static unsafe byte* GetAddr(byte* p) {
+ if (IntPtr.Size == 4) {
+ for (int i = 0; i < 20; i++, p++) {
+ if (*p == 0xA1)
+ return *(byte**)(p + 1);
+ }
+ }
+ else {
+ for (int i = 0; i < 20; i++, p++)
+ if (*p == 0x4C && p[1] == 0x8B && p[2] == 0x15)
+ return p + 7 + *(int*)(p + 3);
+ }
+ return null;
+ }
+
+ static unsafe byte* LookUp(byte* p, int key) {
+ p = *(byte**)(p + IntPtr.Size);
+ p = *(byte**)(p + IntPtr.Size);
+
+ int f1 = 0;
+ int f2 = IntPtr.Size * 2;
+ int f3 = IntPtr.Size * 3;
+ int f4 = IntPtr.Size * 4;
+ int f5 = IntPtr.Size * 5 + 1;
+
+ byte* res = null;
+ while (true) {
+ if (*(p + f5) != 0)
+ break;
+ int k = *(int*)(p + f3);
+ if (k < key)
+ p = *(byte**)(p + f2);
+ else {
+ res = p;
+ p = *(byte**)(p + f1);
+ }
+ }
+ return *(byte**)(res + f4);
+ }
+
+ byte[] aryDummy = new byte[7];
+ IntPtr dummy;
+ public unsafe byte[] Decrypt(int methodId, uint rid) {
+ fixed (byte* p = &aryDummy[0]) {
+ dummy = new IntPtr(p);
+ decryptedData = null;
+ currentILBytes = dmd.reflectionModule.ResolveMethod(0x06000000 + (int)rid).GetMethodBody().GetILAsByteArray();
+ invoker.DynamicInvoke(new object[1] { methodId });
+ }
+ dummy = IntPtr.Zero;
+ return decryptedData;
+ }
+
+ byte[] GetCallerMethodAsILByteArray(IntPtr a, int skipFrames, ref int flags, IntPtr d) {
+ flags = 2;
+ return currentILBytes;
+ }
+
+ unsafe bool DecryptCallback(IntPtr a, byte* pMethodCode, int methodSize, int methodId, IntPtr e) {
+ decryptedData = new byte[methodSize];
+ Marshal.Copy(new IntPtr(pMethodCode), decryptedData, 0, decryptedData.Length);
+ return true;
+ }
+
+ IntPtr IgnoreMethod(IntPtr a, IntPtr b) {
+ return dummy;
+ }
+ }
+
+ class DecrypterV2_0_13_0 : DecrypterV2_0_13_0_Base {
+ public unsafe DecrypterV2_0_13_0(DynamicMethodsDecrypter dmd)
+ : base(dmd) {
+ }
+
+ static readonly byte[] initCode_x86 = new byte[] {
+ 0x8B, 0xCC, 0x8B, 0x41, 0x04, 0xFF, 0x71, 0x10,
+ 0xFF, 0x71, 0x0C, 0xFF, 0x71, 0x08, 0xFF, 0x51,
+ 0x14, 0xC2, 0x14, 0x00,
+ };
+ unsafe delegate void InitCode32Delegate(byte* pppam, byte* m, IntPtr s, byte* pd, byte* f);
+ unsafe delegate void InitCode64Delegate(byte* pppam, byte* m, IntPtr s, byte* pd);
+ protected unsafe override void InitCode(byte* ba, byte* pam, byte* pd, byte* pm) {
+ byte* ppam = (byte*)&pam;
+ byte* pppam = (byte*)&ppam;
+ if (IntPtr.Size == 4) {
+ var del = (InitCode32Delegate)Marshal.GetDelegateForFunctionPointer(CodeAllocator.Allocate(initCode_x86), typeof(InitCode32Delegate));
+ del(pppam, pm, new IntPtr(IntPtr.Size * 4), pd, ba + 0x00012500);
+ }
+ else {
+ var del = (InitCode64Delegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(ba + 0x00014CF0), typeof(InitCode64Delegate));
+ del(pppam, pm, new IntPtr(IntPtr.Size * 4), pd);
+ }
+ }
+ }
+
+ class DecrypterV2_0_13_1 : DecrypterV2_0_13_0_Base {
+ public unsafe DecrypterV2_0_13_1(DynamicMethodsDecrypter dmd)
+ : base(dmd) {
+ }
+
+ unsafe delegate void InitCodeDelegate(byte* pppam, byte* m, IntPtr s, byte* pd);
+ protected unsafe override void InitCode(byte* ba, byte* pam, byte* pd, byte* pm) {
+ int rva = IntPtr.Size == 4 ? 0x00013650 : 0x00016B50;
+ var del = (InitCodeDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(ba + rva), typeof(InitCodeDelegate));
+ byte* ppam = (byte*)&pam;
+ byte* pppam = (byte*)&ppam;
+ del(pppam, pm, new IntPtr(IntPtr.Size * 4), pd);
+ }
+ }
+
public bool MethodReaderHasDelegateTypeFlag {
get { return methodReaderHasDelegateTypeFlag; }
}
@@ -456,9 +663,13 @@ namespace de4dot.code.deobfuscators.ILProtector {
methodReaderHasDelegateTypeFlag = true;
if (version < new Version(2, 0, 12, 3))
- return CreateDecrypterV2_0_12_0();
- if (version < new Version(2, 0, 12, 4))
- return CreateDecrypterV2_0_12_3();
+ return new DecrypterV2_0_12_0(this);
+ if (version == new Version(2, 0, 12, 3))
+ return new DecrypterV2_0_12_3(this);
+ if (version == new Version(2, 0, 13, 0))
+ return new DecrypterV2_0_13_0(this);
+ if (version == new Version(2, 0, 13, 1))
+ return new DecrypterV2_0_13_1(this);
return null;
}
@@ -503,14 +714,6 @@ namespace de4dot.code.deobfuscators.ILProtector {
return new DecrypterV2_0_9_0(this, delegateField);
}
- IDecrypter CreateDecrypterV2_0_12_0() {
- return new DecrypterV2_0_12_0(this);
- }
-
- IDecrypter CreateDecrypterV2_0_12_3() {
- return new DecrypterV2_0_12_3(this);
- }
-
static readonly byte[] ilpPublicKeyToken = new byte[8] { 0x20, 0x12, 0xD3, 0xC0, 0x55, 0x1F, 0xE0, 0x3D };
static Assembly GetProtectAssembly() {
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) {
diff --git a/de4dot.code/deobfuscators/ILProtector/MethodReader.cs b/de4dot.code/deobfuscators/ILProtector/MethodReader.cs
index 700cdaf5..a20345ee 100644
--- a/de4dot.code/deobfuscators/ILProtector/MethodReader.cs
+++ b/de4dot.code/deobfuscators/ILProtector/MethodReader.cs
@@ -32,6 +32,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
MethodFlags flags;
TypeDef delegateType;
bool hasDelegateTypeFlag;
+ GenericParamContext gpContext;
[Flags]
enum MethodFlags {
@@ -76,7 +77,8 @@ namespace de4dot.code.deobfuscators.ILProtector {
this.module = module;
}
- public void Read() {
+ public void Read(MethodDef method) {
+ gpContext = GenericParamContext.Create(method);
flags = (MethodFlags)reader.ReadByte();
if (HasDelegateType) {
delegateType = Resolve(ReadTypeToken());
@@ -108,7 +110,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
}
T Resolve(int token) {
- return (T)module.ResolveToken(token);
+ return (T)module.ResolveToken(token, gpContext);
}
int ReadTypeToken() {
@@ -182,7 +184,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
var token = reader.ReadUInt32();
if (MDToken.ToTable(token) != Table.StandAloneSig)
return null;
- var sas = module.ResolveStandAloneSig(MDToken.ToRID(token));
+ var sas = module.ResolveStandAloneSig(MDToken.ToRID(token), gpContext);
return sas == null ? null : sas.MethodSig;
}
diff --git a/de4dot.code/deobfuscators/ILProtector/MethodsDecrypterBase.cs b/de4dot.code/deobfuscators/ILProtector/MethodsDecrypterBase.cs
index 8b27224a..6bda873d 100644
--- a/de4dot.code/deobfuscators/ILProtector/MethodsDecrypterBase.cs
+++ b/de4dot.code/deobfuscators/ILProtector/MethodsDecrypterBase.cs
@@ -87,7 +87,7 @@ namespace de4dot.code.deobfuscators.ILProtector {
methodInfos.Remove(methodId.Value);
var methodReader = new MethodReader(module, methodInfo.data, parameters);
methodReader.HasDelegateTypeFlag = MethodReaderHasDelegateTypeFlag;
- methodReader.Read();
+ methodReader.Read(method);
RestoreMethod(method, methodReader);
if (methodReader.DelegateType != null)
diff --git a/de4dot.code/deobfuscators/ILProtector/RuntimeFileInfo.cs b/de4dot.code/deobfuscators/ILProtector/RuntimeFileInfo.cs
index 2cef7981..4f9eff07 100644
--- a/de4dot.code/deobfuscators/ILProtector/RuntimeFileInfo.cs
+++ b/de4dot.code/deobfuscators/ILProtector/RuntimeFileInfo.cs
@@ -64,6 +64,8 @@ namespace de4dot.code.deobfuscators.ILProtector {
new VersionInfo(new Version(2, 0, 12, 0), new byte[] { 0x63, 0x8B, 0x5C, 0xE9, 0x89, 0x83, 0x57, 0x9D, 0xDC, 0xC3, 0xBD, 0xD9, 0xDB, 0x54, 0xBE, 0x66 }),
new VersionInfo(new Version(2, 0, 12, 2), new byte[] { 0xD5, 0x46, 0x38, 0xC7, 0x48, 0xF6, 0x3C, 0x1C, 0x1E, 0x7F, 0x3B, 0x7B, 0x5B, 0xE0, 0x49, 0x46 }),
new VersionInfo(new Version(2, 0, 12, 3), new byte[] { 0x35, 0xA3, 0x53, 0xE9, 0x9E, 0x30, 0x6E, 0x9C, 0x0F, 0x46, 0x20, 0x9A, 0x91, 0xD2, 0x95, 0x18 }),
+ new VersionInfo(new Version(2, 0, 13, 0), new byte[] { 0x66, 0x21, 0xA1, 0x1F, 0x8F, 0x4A, 0xD2, 0xF8, 0x68, 0xEE, 0xD5, 0xD9, 0xC8, 0xB8, 0x17, 0xC7 }),
+ new VersionInfo(new Version(2, 0, 13, 1), new byte[] { 0xDF, 0x7A, 0xBF, 0x8B, 0xAD, 0x2B, 0x94, 0x6F, 0x37, 0xD9, 0x4B, 0xFC, 0x42, 0x7F, 0x0B, 0x37 }),
};
static readonly VersionInfo[] versionInfo64 = new VersionInfo[] {
@@ -89,6 +91,8 @@ namespace de4dot.code.deobfuscators.ILProtector {
new VersionInfo(new Version(2, 0, 12, 0), new byte[] { 0x5F, 0x42, 0xA5, 0x6C, 0x19, 0xC6, 0x73, 0x9E, 0xE6, 0x74, 0x62, 0x3B, 0x8A, 0x51, 0xBB, 0x93 }),
new VersionInfo(new Version(2, 0, 12, 2), new byte[] { 0x10, 0x91, 0xED, 0x05, 0x9C, 0x31, 0x0B, 0x63, 0x76, 0xD7, 0x4A, 0xEC, 0xDE, 0x99, 0x6D, 0xD0 }),
new VersionInfo(new Version(2, 0, 12, 3), new byte[] { 0x38, 0x86, 0xE0, 0xBF, 0xC6, 0x64, 0xB9, 0xA0, 0x07, 0xED, 0xDB, 0x02, 0x40, 0xD0, 0x57, 0xE8 }),
+ new VersionInfo(new Version(2, 0, 13, 0), new byte[] { 0xF0, 0x13, 0xC4, 0x6F, 0x31, 0x0F, 0x61, 0xEA, 0x89, 0x1E, 0x8A, 0x95, 0x8C, 0xBE, 0x2E, 0x44 }),
+ new VersionInfo(new Version(2, 0, 13, 1), new byte[] { 0xD4, 0x71, 0x75, 0xE2, 0xB1, 0xA5, 0xAE, 0xF5, 0x32, 0xD7, 0x72, 0xDE, 0x93, 0xDC, 0x0B, 0x68 }),
};
public RuntimeFileInfo(MethodDef protectMethod) {
diff --git a/de4dot.code/deobfuscators/MaxtoCode/EncryptionInfos.cs b/de4dot.code/deobfuscators/MaxtoCode/EncryptionInfos.cs
index d1f4808d..28c2dd99 100644
--- a/de4dot.code/deobfuscators/MaxtoCode/EncryptionInfos.cs
+++ b/de4dot.code/deobfuscators/MaxtoCode/EncryptionInfos.cs
@@ -112,6 +112,11 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
},
// 526BC020
// 526BDD12
+ // 5296E242
+ // 52B2B2A3
+ // 52B3043C
+ // 53172907
+ // 531729C4
new EncryptionInfo {
MagicLo = 0x9A683B87,
MagicHi = 0x928ECDA3,
@@ -177,6 +182,11 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
// 5166DB4F
// 526BC020
// 526BDD12
+ // 5296E242
+ // 52B2B2A3
+ // 52B3043C
+ // 53172907
+ // 531729C4
new EncryptionInfo {
MagicLo = 0x1A731B13,
MagicHi = 0x1723891F,
diff --git a/de4dot.code/deobfuscators/MaxtoCode/MethodsDecrypter.cs b/de4dot.code/deobfuscators/MaxtoCode/MethodsDecrypter.cs
index 92c01b54..a3eedb04 100644
--- a/de4dot.code/deobfuscators/MaxtoCode/MethodsDecrypter.cs
+++ b/de4dot.code/deobfuscators/MaxtoCode/MethodsDecrypter.cs
@@ -194,6 +194,10 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v5, Decrypt2_v2, Decrypt3_v6, Decrypt1_v9, Decrypt6, Decrypt8_v8, Decrypt9_v9, Decrypt7, Decrypt5 }, new uint[] { 0x513D4492, 0x5113E277 }));
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt3_v6, Decrypt2_v2, Decrypt4_v8, Decrypt1_v10, Decrypt8_v9, Decrypt9_v10, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x526BDD12 }));
decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt1_v10, Decrypt4_v8, Decrypt2_v2, Decrypt3_v6, Decrypt6, Decrypt8_v9, Decrypt9_v10, Decrypt7, Decrypt5 }, new uint[] { 0x526BC020 }));
+ decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt3_v7, Decrypt2_v6, Decrypt4_v9, Decrypt1_v11, Decrypt8_v10, Decrypt11_v1, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x5296E242, 0x52B3043C }));
+ decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt4_v10, Decrypt1_v12, Decrypt3_v8, Decrypt2_v7, Decrypt6, Decrypt8_v11, Decrypt9_v11, Decrypt7, Decrypt5 }, new uint[] { 0x531729C4 }));
+ decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt1_v13, Decrypt4_v11, Decrypt2_v8, Decrypt3_v9, Decrypt6, Decrypt8_v11, Decrypt9_v12, Decrypt7, Decrypt5 }, new uint[] { 0x52B2B2A3 }));
+ decrypters.Add(new Decrypter(new DecryptFunc[] { Decrypt2_v9, Decrypt3_v10, Decrypt1_v10, Decrypt4_v12, Decrypt8_v12, Decrypt9_v13, Decrypt6, Decrypt7, Decrypt5 }, new uint[] { 0x53172907 }));
break;
case EncryptionVersion.Unknown:
@@ -404,6 +408,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt1(encrypted, 0x11, 0x11, 0x400);
}
+ byte[] Decrypt1_v11(byte[] encrypted) {
+ return Decrypt1(encrypted, 0x13, 0x13, 0x400);
+ }
+
+ byte[] Decrypt1_v12(byte[] encrypted) {
+ return Decrypt1(encrypted, 0x12, 0x12, 0x200);
+ }
+
+ byte[] Decrypt1_v13(byte[] encrypted) {
+ return Decrypt1(encrypted, 0x11, 0x11, 0x200);
+ }
+
byte[] Decrypt1(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
var decrypted = new byte[encrypted.Length];
for (int i = 0, ki = keyStart; i < decrypted.Length; i++) {
@@ -434,6 +450,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt2(encrypted, 0x00FA + 0x63);
}
+ byte[] Decrypt2_v6(byte[] encrypted) {
+ return Decrypt2(encrypted, 0x00FA + 0x0B);
+ }
+
+ byte[] Decrypt2_v7(byte[] encrypted) {
+ return Decrypt2(encrypted, 0x00FA + 0x0E);
+ }
+
+ byte[] Decrypt2_v8(byte[] encrypted) {
+ return Decrypt2(encrypted, 0x00FA + 0x0D);
+ }
+
+ byte[] Decrypt2_v9(byte[] encrypted) {
+ return Decrypt2(encrypted, 0x00FA + 0x0C);
+ }
+
byte[] Decrypt2(byte[] encrypted, int offset) {
if ((encrypted.Length & 7) != 0)
throw new ApplicationException("Invalid encryption #2 length");
@@ -481,6 +513,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt3(encrypted, 0x015E + 0x7F);
}
+ byte[] Decrypt3_v7(byte[] encrypted) {
+ return Decrypt3(encrypted, 0x015E + 0x0D);
+ }
+
+ byte[] Decrypt3_v8(byte[] encrypted) {
+ return Decrypt3(encrypted, 0x015E + 0x0F);
+ }
+
+ byte[] Decrypt3_v9(byte[] encrypted) {
+ return Decrypt3(encrypted, 0x015E + 0x12);
+ }
+
+ byte[] Decrypt3_v10(byte[] encrypted) {
+ return Decrypt3(encrypted, 0x015E + 0x0E);
+ }
+
static readonly byte[] decrypt3Shifts = new byte[16] { 5, 11, 14, 21, 6, 20, 17, 29, 4, 10, 3, 2, 7, 1, 26, 18 };
byte[] Decrypt3(byte[] encrypted, int offset) {
if ((encrypted.Length & 7) != 0)
@@ -542,6 +590,22 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt4(encrypted, 9, 9, 0x100);
}
+ byte[] Decrypt4_v9(byte[] encrypted) {
+ return Decrypt4(encrypted, 0x0B, 0x0B, 0x150);
+ }
+
+ byte[] Decrypt4_v10(byte[] encrypted) {
+ return Decrypt4(encrypted, 0x10, 0x10, 0x120);
+ }
+
+ byte[] Decrypt4_v11(byte[] encrypted) {
+ return Decrypt4(encrypted, 0x0F, 0x0E, 0x120);
+ }
+
+ byte[] Decrypt4_v12(byte[] encrypted) {
+ return Decrypt4(encrypted, 0x0C, 0x0C, 0x150);
+ }
+
byte[] Decrypt4(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
var decrypted = new byte[encrypted.Length / 3 * 2 + 1];
@@ -599,6 +663,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt8(encrypted, 0xA, 0xA, 0x600);
}
+ byte[] Decrypt8_v10(byte[] encrypted) {
+ return Decrypt8(encrypted, 0x14, 0x14, 0x600);
+ }
+
+ byte[] Decrypt8_v11(byte[] encrypted) {
+ return Decrypt8(encrypted, 0x19, 0x19, 0x500);
+ }
+
+ byte[] Decrypt8_v12(byte[] encrypted) {
+ return Decrypt8(encrypted, 0x14, 0x14, 0x600);
+ }
+
byte[] Decrypt8(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
var decrypted = new byte[encrypted.Length];
int ki = keyStart;
@@ -636,6 +712,18 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return Decrypt9(encrypted, 5, 5, 0x510);
}
+ byte[] Decrypt9_v11(byte[] encrypted) {
+ return Decrypt9(encrypted, 0x19, 0x19, 0x500);
+ }
+
+ byte[] Decrypt9_v12(byte[] encrypted) {
+ return Decrypt9(encrypted, 0x19, 0x19, 0x500);
+ }
+
+ byte[] Decrypt9_v13(byte[] encrypted) {
+ return Decrypt9(encrypted, 5, 5, 0x510);
+ }
+
byte[] Decrypt9(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
var decrypted = new byte[encrypted.Length];
int ki = keyStart;
@@ -695,6 +783,38 @@ namespace de4dot.code.deobfuscators.MaxtoCode {
return dest;
}
+ byte[] Decrypt11_v1(byte[] encrypted) {
+ return Decrypt11(encrypted, 5, 5, 0x510);
+ }
+
+ byte[] Decrypt11(byte[] encrypted, int keyStart, int keyReset, int keyEnd) {
+ byte[] dest = new byte[encrypted.Length];
+
+ for (int i = 0, ki = keyStart; i < encrypted.Length; i++, ki++) {
+ if (ki >= keyEnd)
+ ki = keyStart;
+
+ byte b;
+ switch (i % 3) {
+ case 0:
+ dest[i] = (byte)(encrypted[i] ^ mcKey.ReadByte(ki));
+ break;
+
+ case 1:
+ b = (byte)(encrypted[i] ^ mcKey.ReadByte(ki));
+ dest[i] = (byte)((b << 4) | (b >> 4));
+ break;
+
+ case 2:
+ b = encrypted[i];
+ dest[i] = (byte)((b << 4) | (b >> 4));
+ break;
+ }
+ }
+
+ return dest;
+ }
+
byte[] blowfishKey;
byte[] GetBlowfishKey() {
if (blowfishKey != null)
diff --git a/de4dot.code/deobfuscators/MethodsDecrypter.cs b/de4dot.code/deobfuscators/MethodsDecrypter.cs
index fd5bdd11..8db05e0e 100644
--- a/de4dot.code/deobfuscators/MethodsDecrypter.cs
+++ b/de4dot.code/deobfuscators/MethodsDecrypter.cs
@@ -17,6 +17,8 @@
along with de4dot. If not, see .
*/
+using System;
+using System.Runtime.Remoting;
using dnlib.DotNet;
using AssemblyData;
using de4dot.code.AssemblyClient;
@@ -30,6 +32,20 @@ namespace de4dot.code.deobfuscators {
}
public static DumpedMethods Decrypt(ServerClrVersion serverVersion, string filename, byte[] moduleCctorBytes) {
+ Exception lastEx = null;
+ for (int i = 0; i < 5; i++) {
+ try {
+ return Decrypt2(serverVersion, filename, moduleCctorBytes);
+ }
+ catch (RemotingException ex) {
+ lastEx = ex;
+ continue;
+ }
+ }
+ throw lastEx;
+ }
+
+ static DumpedMethods Decrypt2(ServerClrVersion serverVersion, string filename, byte[] moduleCctorBytes) {
using (var client = new NewProcessAssemblyClientFactory(serverVersion).Create(AssemblyServiceType.MethodDecrypter)) {
client.Connect();
client.WaitConnected();
diff --git a/de4dot.code/deobfuscators/ProxyCallFixerBase.cs b/de4dot.code/deobfuscators/ProxyCallFixerBase.cs
index 2a14920d..238e91c8 100644
--- a/de4dot.code/deobfuscators/ProxyCallFixerBase.cs
+++ b/de4dot.code/deobfuscators/ProxyCallFixerBase.cs
@@ -155,14 +155,15 @@ namespace de4dot.code.deobfuscators {
});
}
- protected static bool FixProxyCalls(Dictionary> removeInfos) {
+ protected bool FixProxyCalls(MethodDef method, Dictionary> removeInfos) {
+ var gpContext = GenericParamContext.Create(method);
foreach (var block in removeInfos.Keys) {
var list = removeInfos[block];
var removeIndexes = new List(list.Count);
foreach (var info in list) {
if (info.IsCall) {
var opcode = info.DelegateInfo.callOpcode;
- var newInstr = Instruction.Create(opcode, info.DelegateInfo.methodRef);
+ var newInstr = Instruction.Create(opcode, ReResolve(info.DelegateInfo.methodRef, gpContext));
block.Replace(info.Index, 1, newInstr);
}
else
@@ -174,6 +175,12 @@ namespace de4dot.code.deobfuscators {
return removeInfos.Count > 0;
}
+
+ IMethod ReResolve(IMethod method, GenericParamContext gpContext) {
+ if (method.IsMethodSpec || method.IsMemberRef)
+ method = module.ResolveToken(method.MDToken.Raw, gpContext) as IMethod ?? method;
+ return method;
+ }
}
// Fixes proxy calls that call the delegate inline in the code, eg.:
@@ -279,7 +286,7 @@ namespace de4dot.code.deobfuscators {
}
}
- return FixProxyCalls(removeInfos);
+ return FixProxyCalls(blocks.Method, removeInfos);
}
protected virtual BlockInstr FindProxyCall(DelegateInfo di, Block block, int index) {
@@ -481,7 +488,7 @@ namespace de4dot.code.deobfuscators {
}
}
- return FixProxyCalls(removeInfos);
+ return FixProxyCalls(blocks.Method, removeInfos);
}
}
diff --git a/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs b/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs
index b4c9b6b3..560d5c7e 100644
--- a/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/SmartAssembly/Deobfuscator.cs
@@ -239,7 +239,7 @@ namespace de4dot.code.deobfuscators.SmartAssembly {
var attrs2 = new Dictionary();
foreach (var cattr in cattrs) {
- if (!DotNetUtils.IsMethod(cattr.Constructor as IMethod, "System.Void", "(System.Int32)"))
+ if (!DotNetUtils.IsMethod(cattr.Constructor, "System.Void", "(System.Int32)"))
continue;
var attrType = cattr.AttributeType as TypeDef;
if (attrType == null)
diff --git a/de4dot.code/deobfuscators/Spices_Net/ResourceNamesRestorer.cs b/de4dot.code/deobfuscators/Spices_Net/ResourceNamesRestorer.cs
index 37553866..40846bca 100644
--- a/de4dot.code/deobfuscators/Spices_Net/ResourceNamesRestorer.cs
+++ b/de4dot.code/deobfuscators/Spices_Net/ResourceNamesRestorer.cs
@@ -17,6 +17,7 @@
along with de4dot. If not, see .
*/
+using System;
using System.Collections.Generic;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
@@ -83,12 +84,40 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return true;
}
- public void RenameResources() {
- if (resourceManagerType == null && componentResourceManagerType == null)
- return;
+ class ResourceDictionary {
+ struct Key {
+ public readonly uint hash;
+ public readonly string ns;
+ public Key(uint hash, string ns) {
+ this.hash = hash;
+ this.ns = ns;
+ }
- var numToResource = new Dictionary(module.Resources.Count);
- foreach (var resource in module.Resources) {
+ public override int GetHashCode() {
+ return (int)(hash ^ ns.GetHashCode());
+ }
+
+ public override bool Equals(object obj) {
+ if (!(obj is Key))
+ return false;
+ var other = (Key)obj;
+ return hash == other.hash &&
+ ns == other.ns;
+ }
+
+ public override string ToString() {
+ if (ns == string.Empty)
+ return string.Format("{0}", hash);
+ return string.Format("{0}.{1}", ns, hash);
+ }
+ }
+ Dictionary resources = new Dictionary();
+
+ public int Count {
+ get { return resources.Count; }
+ }
+
+ public bool Add(Resource resource) {
var name = resource.Name.String;
int index = name.LastIndexOf('.');
string ext;
@@ -98,35 +127,55 @@ namespace de4dot.code.deobfuscators.Spices_Net {
ext = name.Substring(index + 1);
uint extNum;
if (!uint.TryParse(ext, out extNum))
- continue;
- numToResource[extNum] = resource;
+ return false;
+ var ns = index < 0 ? string.Empty : name.Substring(0, index);
+
+ resources.Add(new Key(extNum, ns), resource);
+ return true;
}
+ public Resource GetAndRemove(uint hash, string ns) {
+ var key = new Key(hash, ns);
+ Resource resource;
+ if (resources.TryGetValue(key, out resource))
+ resources.Remove(key);
+ return resource;
+ }
+ }
+
+ public void RenameResources() {
+ if (resourceManagerType == null && componentResourceManagerType == null)
+ return;
+
+ var rsrcDict = new ResourceDictionary();
+ foreach (var resource in module.Resources)
+ rsrcDict.Add(resource);
+
if (module.Assembly != null)
- Rename(numToResource, "", module.Assembly.Name + ".g");
+ Rename(rsrcDict, "", module.Assembly.Name + ".g");
foreach (var type in callsResourceManager.Keys)
- Rename(numToResource, type);
+ Rename(rsrcDict, type);
- if (numToResource.Count != 0) {
+ if (rsrcDict.Count != 0) {
foreach (var type in module.GetTypes()) {
- if (numToResource.Count == 0)
+ if (rsrcDict.Count == 0)
break;
if (!IsWinFormType(type))
continue;
- Rename(numToResource, type);
+ Rename(rsrcDict, type);
}
}
- if (numToResource.Count != 0) {
+ if (rsrcDict.Count != 0) {
foreach (var type in module.GetTypes()) {
- if (numToResource.Count == 0)
+ if (rsrcDict.Count == 0)
break;
- Rename(numToResource, type);
+ Rename(rsrcDict, type);
}
}
- if (numToResource.Count != 0)
+ if (rsrcDict.Count != 0)
Logger.e("Couldn't restore all renamed resource names");
}
@@ -151,18 +200,17 @@ namespace de4dot.code.deobfuscators.Spices_Net {
return false;
}
- static bool Rename(Dictionary numToResource, TypeDef type) {
- return Rename(numToResource, "", type.FullName) ||
- Rename(numToResource, "", type.FullName + ".g") ||
- Rename(numToResource, type.Namespace, type.Name) ||
- Rename(numToResource, type.Namespace, type.Name + ".g");
+ static bool Rename(ResourceDictionary rsrcDict, TypeDef type) {
+ if (!IsWinFormType(type) && Rename(rsrcDict, "", type.FullName))
+ return true;
+ return Rename(rsrcDict, type.Namespace, type.Name);
}
- static bool Rename(Dictionary numToResource, string ns, string name) {
+ static bool Rename(ResourceDictionary rsrcDict, string ns, string name) {
var resourceName = name + ".resources";
uint hash = GetResourceHash(resourceName);
- Resource resource;
- if (!numToResource.TryGetValue(hash, out resource))
+ var resource = rsrcDict.GetAndRemove(hash, ns);
+ if (resource == null)
return false;
int index = resource.Name.String.LastIndexOf('.');
@@ -176,13 +224,12 @@ namespace de4dot.code.deobfuscators.Spices_Net {
newName = resourceNamespace + "." + resourceName;
}
if (resourceNamespace != ns)
- return false;
+ throw new ApplicationException("Invalid resource namespace");
Logger.v("Restoring resource name: '{0}' => '{1}'",
Utils.RemoveNewlines(resource.Name),
Utils.RemoveNewlines(newName));
resource.Name = newName;
- numToResource.Remove(hash);
return true;
}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v4/Deobfuscator.cs b/de4dot.code/deobfuscators/dotNET_Reactor/v4/Deobfuscator.cs
index eccc159e..9e46e331 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v4/Deobfuscator.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor/v4/Deobfuscator.cs
@@ -333,6 +333,9 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
break;
}
+ if (methodsDecrypter.DecrypterTypeVersion != DnrDecrypterType.V1)
+ return DeobfuscatorInfo.THE_NAME;
+
if (methodsDecrypter.Method == null) {
if (minVer >= 3800)
return DeobfuscatorInfo.THE_NAME + " >= 3.8";
@@ -361,6 +364,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
bool compileMethodHasConstant_0x70000000 = DeobUtils.HasInteger(compileMethod, 0x70000000); // 4.0-4.1
DeobfuscatedFile.Deobfuscate(methodsDecrypter.Method);
bool hasCorEnableProfilingString = FindString(methodsDecrypter.Method, "Cor_Enable_Profiling"); // 4.1-4.4
+ bool hasCatchString = FindString(methodsDecrypter.Method, "catch: "); // <= 4.7
if (compileMethodHasConstant_0x70000000) {
if (hasCorEnableProfilingString)
@@ -368,7 +372,6 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return DeobfuscatorInfo.THE_NAME + " 4.0";
}
if (!hasCorEnableProfilingString) {
- // 4.x or 4.5 - 4.6
bool callsReverse = DotNetUtils.CallsMethod(methodsDecrypter.Method, "System.Void System.Array::Reverse(System.Array)");
if (!callsReverse)
return DeobfuscatorInfo.THE_NAME + " 4.0 - 4.4";
@@ -382,7 +385,9 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
case 10:
if (!hasSymmetricAlgorithm)
return DeobfuscatorInfo.THE_NAME + " 4.6";
- return DeobfuscatorInfo.THE_NAME + " 4.7";
+ if (hasCatchString)
+ return DeobfuscatorInfo.THE_NAME + " 4.7";
+ return DeobfuscatorInfo.THE_NAME + " 4.8";
}
}
else {
@@ -392,7 +397,9 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
case 9:
if (!hasSymmetricAlgorithm)
return DeobfuscatorInfo.THE_NAME + " 4.6";
- return DeobfuscatorInfo.THE_NAME + " 4.7";
+ if (hasCatchString)
+ return DeobfuscatorInfo.THE_NAME + " 4.7";
+ return DeobfuscatorInfo.THE_NAME + " 4.8";
}
}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v4/EncryptedResource.cs b/de4dot.code/deobfuscators/dotNET_Reactor/v4/EncryptedResource.cs
index 4ea0301a..285ed802 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v4/EncryptedResource.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor/v4/EncryptedResource.cs
@@ -24,13 +24,24 @@ using System.Security.Cryptography;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
+using de4dot.blocks.cflow;
namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
+ enum DnrDecrypterType {
+ Unknown,
+ V1,
+ V2,
+ }
+
class EncryptedResource {
ModuleDefMD module;
MethodDef resourceDecrypterMethod;
EmbeddedResource encryptedDataResource;
- byte[] key, iv;
+ IDecrypter decrypter;
+
+ public DnrDecrypterType DecrypterTypeVersion {
+ get { return decrypter == null ? DnrDecrypterType.Unknown : decrypter.DecrypterType; }
+ }
public TypeDef Type {
get { return resourceDecrypterMethod == null ? null : resourceDecrypterMethod.DeclaringType; }
@@ -58,8 +69,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
resourceDecrypterMethod = Lookup(oldOne.resourceDecrypterMethod, "Could not find resource decrypter method");
if (oldOne.encryptedDataResource != null)
encryptedDataResource = DotNetUtils.GetResource(module, oldOne.encryptedDataResource.Name.String) as EmbeddedResource;
- key = oldOne.key;
- iv = oldOne.iv;
+ this.decrypter = oldOne.decrypter;
if (encryptedDataResource == null && oldOne.encryptedDataResource != null)
throw new ApplicationException("Could not initialize EncryptedResource");
@@ -69,30 +79,12 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return DeobUtils.Lookup(module, def, errorMessage);
}
- public bool CouldBeResourceDecrypter(MethodDef method, IEnumerable additionalTypes) {
+ public bool CouldBeResourceDecrypter(MethodDef method, IList additionalTypes) {
return CouldBeResourceDecrypter(method, additionalTypes, true);
}
- public bool CouldBeResourceDecrypter(MethodDef method, IEnumerable additionalTypes, bool checkResource) {
- if (!method.IsStatic)
- return false;
- if (method.Body == null)
- return false;
-
- var localTypes = new LocalTypes(method);
- var requiredTypes = new List {
- "System.Byte[]",
- "System.IO.BinaryReader",
- "System.IO.MemoryStream",
- "System.Security.Cryptography.CryptoStream",
- "System.Security.Cryptography.ICryptoTransform",
- };
- requiredTypes.AddRange(additionalTypes);
- if (!localTypes.All(requiredTypes))
- return false;
- if (!localTypes.Exists("System.Security.Cryptography.RijndaelManaged") &&
- !localTypes.Exists("System.Security.Cryptography.AesManaged") &&
- !localTypes.Exists("System.Security.Cryptography.SymmetricAlgorithm"))
+ public bool CouldBeResourceDecrypter(MethodDef method, IList additionalTypes, bool checkResource) {
+ if (GetDecrypterType(method, additionalTypes) == DnrDecrypterType.Unknown)
return false;
if (checkResource && FindMethodsDecrypterResource(method) == null)
@@ -101,6 +93,24 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return true;
}
+ public DnrDecrypterType GuessDecrypterType() {
+ return GetDecrypterType(resourceDecrypterMethod, null);
+ }
+
+ static DnrDecrypterType GetDecrypterType(MethodDef method, IList additionalTypes) {
+ if (method == null || !method.IsStatic || method.Body == null)
+ return DnrDecrypterType.Unknown;
+
+ if (additionalTypes == null)
+ additionalTypes = new string[0];
+ var localTypes = new LocalTypes(method);
+ if (DecrypterV1.CouldBeResourceDecrypter(method, localTypes, additionalTypes))
+ return DnrDecrypterType.V1;
+ else if (DecrypterV2.CouldBeResourceDecrypter(method, localTypes, additionalTypes))
+ return DnrDecrypterType.V2;
+ return DnrDecrypterType.Unknown;
+ }
+
public void Initialize(ISimpleDeobfuscator simpleDeobfuscator) {
if (resourceDecrypterMethod == null)
return;
@@ -111,10 +121,10 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (encryptedDataResource == null)
return;
- key = ArrayFinder.GetInitializedByteArray(resourceDecrypterMethod, 32);
+ var key = ArrayFinder.GetInitializedByteArray(resourceDecrypterMethod, 32);
if (key == null)
throw new ApplicationException("Could not find resource decrypter key");
- iv = ArrayFinder.GetInitializedByteArray(resourceDecrypterMethod, 16);
+ var iv = ArrayFinder.GetInitializedByteArray(resourceDecrypterMethod, 16);
if (iv == null)
throw new ApplicationException("Could not find resource decrypter IV");
if (NeedReverse())
@@ -126,6 +136,13 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
iv[i * 2 + 1] = publicKeyToken.Data[i];
}
}
+
+ var decrypterType = GetDecrypterType(resourceDecrypterMethod, new string[0]);
+ switch (decrypterType) {
+ case DnrDecrypterType.V1: decrypter = new DecrypterV1(iv, key); break;
+ case DnrDecrypterType.V2: decrypter = new DecrypterV2(iv, key, resourceDecrypterMethod); break;
+ default: throw new ApplicationException("Unknown decrypter type");
+ }
}
static int[] pktIndexes = new int[16] { 1, 0, 3, 1, 5, 2, 7, 3, 9, 4, 11, 5, 13, 6, 15, 7 };
@@ -162,22 +179,244 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
return null;
}
- public byte[] Decrypt() {
- if (encryptedDataResource == null || key == null || iv == null)
- throw new ApplicationException("Can't decrypt resource");
-
- return DeobUtils.AesDecrypt(encryptedDataResource.GetResourceData(), key, iv);
+ interface IDecrypter {
+ DnrDecrypterType DecrypterType { get; }
+ byte[] Decrypt(EmbeddedResource resource);
+ byte[] Encrypt(byte[] data);
}
- public byte[] Encrypt(byte[] data) {
- if (key == null || iv == null)
- throw new ApplicationException("Can't encrypt resource");
+ class DecrypterV1 : IDecrypter {
+ readonly byte[] key, iv;
- using (var aes = new RijndaelManaged { Mode = CipherMode.CBC }) {
- using (var transform = aes.CreateEncryptor(key, iv)) {
- return transform.TransformFinalBlock(data, 0, data.Length);
+ public DnrDecrypterType DecrypterType {
+ get { return DnrDecrypterType.V1; }
+ }
+
+ public DecrypterV1(byte[] iv, byte[] key) {
+ this.iv = iv;
+ this.key = key;
+ }
+
+ public static bool CouldBeResourceDecrypter(MethodDef method, LocalTypes localTypes, IList additionalTypes) {
+ var requiredTypes = new List {
+ "System.Byte[]",
+ "System.IO.BinaryReader",
+ "System.IO.MemoryStream",
+ "System.Security.Cryptography.CryptoStream",
+ "System.Security.Cryptography.ICryptoTransform",
+ };
+ requiredTypes.AddRange(additionalTypes);
+ if (!localTypes.All(requiredTypes))
+ return false;
+ if (!localTypes.Exists("System.Security.Cryptography.RijndaelManaged") &&
+ !localTypes.Exists("System.Security.Cryptography.AesManaged") &&
+ !localTypes.Exists("System.Security.Cryptography.SymmetricAlgorithm"))
+ return false;
+
+ return true;
+ }
+
+ public byte[] Decrypt(EmbeddedResource resource) {
+ return DeobUtils.AesDecrypt(resource.GetResourceData(), key, iv);
+ }
+
+ public byte[] Encrypt(byte[] data) {
+ using (var aes = new RijndaelManaged { Mode = CipherMode.CBC }) {
+ using (var transform = aes.CreateEncryptor(key, iv)) {
+ return transform.TransformFinalBlock(data, 0, data.Length);
+ }
}
}
}
+
+ class DecrypterV2 : IDecrypter {
+ readonly byte[] key, iv;
+ readonly MethodDef method;
+ List instructions;
+ readonly List locals;
+ readonly InstructionEmulator instrEmulator = new InstructionEmulator();
+ Local emuLocal;
+
+ public DnrDecrypterType DecrypterType {
+ get { return DnrDecrypterType.V2; }
+ }
+
+ public DecrypterV2(byte[] iv, byte[] key, MethodDef method) {
+ this.iv = iv;
+ this.key = key;
+ this.method = method;
+ this.locals = new List(method.Body.Variables);
+ if (!Initialize())
+ throw new ApplicationException("Could not initialize decrypter");
+ }
+
+ public static bool CouldBeResourceDecrypter(MethodDef method, LocalTypes localTypes, IList additionalTypes) {
+ var requiredTypes = new List {
+ "System.UInt32",
+ "System.String",
+ "System.Int32",
+ "System.Byte[]",
+ "System.IO.BinaryReader",
+ };
+ requiredTypes.AddRange(additionalTypes);
+ if (!localTypes.All(requiredTypes))
+ return false;
+
+ return true;
+ }
+
+ bool Initialize() {
+ for (int i = 0; i < iv.Length; i++)
+ key[i] ^= iv[i];
+
+ var origInstrs = method.Body.Instructions;
+
+ int emuStartIndex;
+ if (!FindStart(origInstrs, out emuStartIndex, out emuLocal))
+ return false;
+ int emuEndIndex;
+ if (!FindEnd(origInstrs, emuStartIndex, out emuEndIndex))
+ return false;
+
+ int count = emuEndIndex - emuStartIndex + 1;
+ instructions = new List(count);
+ for (int i = 0; i < count; i++)
+ instructions.Add(origInstrs[emuStartIndex + i].Clone());
+
+ return true;
+ }
+
+ bool FindStart(IList instrs, out int startIndex, out Local tmpLocal) {
+ for (int i = 0; i + 8 < instrs.Count; i++) {
+ if (instrs[i].OpCode.Code != Code.Conv_U)
+ continue;
+ if (instrs[i + 1].OpCode.Code != Code.Ldelem_U1)
+ continue;
+ if (instrs[i + 2].OpCode.Code != Code.Or)
+ continue;
+ if (CheckLocal(instrs[i + 3], false) == null)
+ continue;
+ Local local;
+ if ((local = CheckLocal(instrs[i + 4], true)) == null)
+ continue;
+ if (CheckLocal(instrs[i + 5], true) == null)
+ continue;
+ if (instrs[i + 6].OpCode.Code != Code.Add)
+ continue;
+ if (CheckLocal(instrs[i + 7], false) != local)
+ continue;
+ var instr = instrs[i + 8];
+ int newStartIndex = i + 8;
+ if (instr.IsBr()) {
+ instr = instr.Operand as Instruction;
+ newStartIndex = instrs.IndexOf(instr);
+ }
+ if (newStartIndex < 0 || instr == null)
+ continue;
+ if (CheckLocal(instr, true) != local)
+ continue;
+
+ startIndex = newStartIndex;
+ tmpLocal = local;
+ return true;
+ }
+
+ startIndex = 0;
+ tmpLocal = null;
+ return false;
+ }
+
+ bool FindEnd(IList instrs, int startIndex, out int endIndex) {
+ for (int i = startIndex; i < instrs.Count; i++) {
+ var instr = instrs[i];
+ if (instr.OpCode.FlowControl != FlowControl.Next)
+ break;
+ if (instr.IsStloc() && instr.GetLocal(locals) == emuLocal) {
+ endIndex = i - 1;
+ return true;
+ }
+ }
+
+ endIndex = 0;
+ return false;
+ }
+
+ Local CheckLocal(Instruction instr, bool isLdloc) {
+ if (isLdloc && !instr.IsLdloc())
+ return null;
+ else if (!isLdloc && !instr.IsStloc())
+ return null;
+
+ return instr.GetLocal(locals);
+ }
+
+ public byte[] Decrypt(EmbeddedResource resource) {
+ var encrypted = resource.GetResourceData();
+ var decrypted = new byte[encrypted.Length];
+
+ uint sum = 0;
+ for (int i = 0; i < encrypted.Length; i += 4) {
+ sum = CalculateMagic(sum + ReadUInt32(key, i % key.Length));
+ WriteUInt32(decrypted, i, sum ^ ReadUInt32(encrypted, i));
+ }
+
+ return decrypted;
+ }
+
+ uint CalculateMagic(uint input) {
+ instrEmulator.Initialize(method, method.Parameters, locals, method.Body.InitLocals, false);
+ instrEmulator.SetLocal(emuLocal, new Int32Value((int)input));
+
+ foreach (var instr in instructions)
+ instrEmulator.Emulate(instr);
+
+ var tos = instrEmulator.Pop() as Int32Value;
+ if (tos == null || !tos.AllBitsValid())
+ throw new ApplicationException("Couldn't calculate magic value");
+ return (uint)tos.Value;
+ }
+
+ static uint ReadUInt32(byte[] ary, int index) {
+ int sizeLeft = ary.Length - index;
+ if (sizeLeft >= 4)
+ return BitConverter.ToUInt32(ary, index);
+ switch (sizeLeft) {
+ case 1: return ary[index];
+ case 2: return (uint)(ary[index] | (ary[index + 1] << 8));
+ case 3: return (uint)(ary[index] | (ary[index + 1] << 8) | (ary[index + 2] << 16));
+ default: throw new ApplicationException("Can't read data");
+ }
+ }
+
+ static void WriteUInt32(byte[] ary, int index, uint value) {
+ int sizeLeft = ary.Length - index;
+ if (sizeLeft >= 1)
+ ary[index] = (byte)value;
+ if (sizeLeft >= 2)
+ ary[index + 1] = (byte)(value >> 8);
+ if (sizeLeft >= 3)
+ ary[index + 2] = (byte)(value >> 16);
+ if (sizeLeft >= 4)
+ ary[index + 3] = (byte)(value >> 24);
+ }
+
+ public byte[] Encrypt(byte[] data) {
+ //TODO: Support re-encryption
+ Logger.e("Re-encryption is not supported. Assembly will probably crash at runtime.");
+ return (byte[])data.Clone();
+ }
+ }
+
+ public byte[] Decrypt() {
+ if (encryptedDataResource == null || decrypter == null)
+ throw new ApplicationException("Can't decrypt resource");
+ return decrypter.Decrypt(encryptedDataResource);
+ }
+
+ public byte[] Encrypt(byte[] data) {
+ if (decrypter == null)
+ throw new ApplicationException("Can't encrypt resource");
+ return decrypter.Encrypt(data);
+ }
}
}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v4/MetadataTokenObfuscator.cs b/de4dot.code/deobfuscators/dotNET_Reactor/v4/MetadataTokenObfuscator.cs
index 825580d2..9c3a8cd9 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v4/MetadataTokenObfuscator.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor/v4/MetadataTokenObfuscator.cs
@@ -76,6 +76,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (type == null)
return;
+ var gpContext = GenericParamContext.Create(blocks.Method);
foreach (var block in blocks.MethodBlocks.GetAllBlocks()) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count - 1; i++) {
@@ -98,7 +99,7 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
uint token = (uint)(int)instrs[i].Operand;
instrs[i] = new Instr(OpCodes.Nop.ToInstruction());
- instrs[i + 1] = new Instr(new Instruction(OpCodes.Ldtoken, module.ResolveToken(token) as ITokenOperand));
+ instrs[i + 1] = new Instr(new Instruction(OpCodes.Ldtoken, module.ResolveToken(token, gpContext) as ITokenOperand));
}
}
}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v4/MethodsDecrypter.cs b/de4dot.code/deobfuscators/dotNET_Reactor/v4/MethodsDecrypter.cs
index fedb2f96..b0801aa3 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v4/MethodsDecrypter.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor/v4/MethodsDecrypter.cs
@@ -57,6 +57,10 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
get { return encryptedResource.Resource; }
}
+ public DnrDecrypterType DecrypterTypeVersion {
+ get { return encryptedResource.GuessDecrypterType(); }
+ }
+
public MethodsDecrypter(ModuleDefMD module) {
this.module = module;
this.encryptedResource = new EncryptedResource(module);
@@ -301,10 +305,10 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (instructions[i].OpCode.Code != Code.Ldind_I8)
continue;
var ldci4 = instructions[i + 1];
- if (!ldci4.IsLdcI4())
- continue;
-
- return ldci4.GetLdcI4Value();
+ if (ldci4.IsLdcI4())
+ return ldci4.GetLdcI4Value();
+ if (ldci4.OpCode.Code == Code.Ldc_I8)
+ return (long)ldci4.Operand;
}
return 0;
}
diff --git a/de4dot.code/deobfuscators/dotNET_Reactor/v4/ResourceResolver.cs b/de4dot.code/deobfuscators/dotNET_Reactor/v4/ResourceResolver.cs
index b4f83831..a747dabc 100644
--- a/de4dot.code/deobfuscators/dotNET_Reactor/v4/ResourceResolver.cs
+++ b/de4dot.code/deobfuscators/dotNET_Reactor/v4/ResourceResolver.cs
@@ -70,21 +70,37 @@ namespace de4dot.code.deobfuscators.dotNET_Reactor.v4 {
if (!DotNetUtils.IsMethod(method, "System.Reflection.Assembly", "(System.Object,System.ResolveEventArgs)") &&
!DotNetUtils.IsMethod(method, "System.Reflection.Assembly", "(System.Object,System.Object)"))
continue;
- if (!encryptedResource.CouldBeResourceDecrypter(method, additionalTypes, false))
+ var initMethod = GetResourceDecrypterInitMethod(method, additionalTypes, false);
+ if (initMethod == null)
continue;
- encryptedResource.Method = method;
+ encryptedResource.Method = initMethod;
return;
}
}
}
+ MethodDef GetResourceDecrypterInitMethod(MethodDef method, string[] additionalTypes, bool checkResource) {
+ if (encryptedResource.CouldBeResourceDecrypter(method, additionalTypes, checkResource))
+ return method;
+
+ foreach (var calledMethod in DotNetUtils.GetCalledMethods(module, method)) {
+ if (!DotNetUtils.IsMethod(calledMethod, "System.Void", "()"))
+ continue;
+ if (encryptedResource.CouldBeResourceDecrypter(calledMethod, additionalTypes, checkResource))
+ return calledMethod;
+ }
+
+ return null;
+ }
+
bool CheckFields(IList fields) {
- if (fields.Count != 3)
+ if (fields.Count != 3 && fields.Count != 4)
return false;
+ int numBools = fields.Count == 3 ? 1 : 2;
var fieldTypes = new FieldTypes(fields);
- if (fieldTypes.Count("System.Boolean") != 1)
+ if (fieldTypes.Count("System.Boolean") != numBools)
return false;
if (fieldTypes.Count("System.Object") == 2)
return true;
diff --git a/de4dot.code/renamer/DerivedFrom.cs b/de4dot.code/renamer/DerivedFrom.cs
index fefc1b8e..abe4ddc4 100644
--- a/de4dot.code/renamer/DerivedFrom.cs
+++ b/de4dot.code/renamer/DerivedFrom.cs
@@ -40,6 +40,12 @@ namespace de4dot.code.renamer {
}
public bool Check(MTypeDef type) {
+ return Check(type, 0);
+ }
+
+ public bool Check(MTypeDef type, int recurseCount) {
+ if (recurseCount >= 100)
+ return false;
if (results.ContainsKey(type))
return results[type];
@@ -53,7 +59,7 @@ namespace de4dot.code.renamer {
val = false;
}
else
- val = Check(type.baseType.typeDef);
+ val = Check(type.baseType.typeDef, recurseCount + 1);
results[type] = val;
return val;
diff --git a/de4dot.code/renamer/ExistingNames.cs b/de4dot.code/renamer/ExistingNames.cs
index 5f4e1287..a0716f7d 100644
--- a/de4dot.code/renamer/ExistingNames.cs
+++ b/de4dot.code/renamer/ExistingNames.cs
@@ -62,6 +62,8 @@ namespace de4dot.code.renamer {
}
public void Merge(ExistingNames other) {
+ if (this == other)
+ return;
foreach (var key in other.allNames.Keys)
allNames[key] = true;
}
diff --git a/de4dot.code/renamer/Renamer.cs b/de4dot.code/renamer/Renamer.cs
index 28d1d7d9..0a72cb7c 100644
--- a/de4dot.code/renamer/Renamer.cs
+++ b/de4dot.code/renamer/Renamer.cs
@@ -1520,6 +1520,29 @@ namespace de4dot.code.renamer {
return null;
}
+ internal static ITypeDefOrRef GetScopeType(TypeSig typeSig) {
+ if (typeSig == null)
+ return null;
+ var scopeType = typeSig.ScopeType;
+ if (scopeType != null)
+ return scopeType;
+
+ for (int i = 0; i < 100; i++) {
+ var nls = typeSig as NonLeafSig;
+ if (nls == null)
+ break;
+ typeSig = nls.Next;
+ }
+
+ switch (typeSig.GetElementType()) {
+ case ElementType.MVar:
+ case ElementType.Var:
+ return new TypeSpecUser(typeSig);
+ default:
+ return null;
+ }
+ }
+
string GetNewPropertyNamePrefix(MethodNameGroup group) {
const string defaultVal = "Prop_";
@@ -1527,7 +1550,7 @@ namespace de4dot.code.renamer {
if (propType == null)
return defaultVal;
- var elementType = propType.ScopeType.ToTypeSig(false).RemovePinnedAndModifiers();
+ var elementType = GetScopeType(propType).ToTypeSig(false).RemovePinnedAndModifiers();
if (propType is GenericInstSig || elementType is GenericSig)
return defaultVal;
diff --git a/de4dot.code/renamer/TypeNames.cs b/de4dot.code/renamer/TypeNames.cs
index 05ab7a0d..0a9adc28 100644
--- a/de4dot.code/renamer/TypeNames.cs
+++ b/de4dot.code/renamer/TypeNames.cs
@@ -44,7 +44,7 @@ namespace de4dot.code.renamer {
string prefix = GetPrefix(typeRef);
- var elementType = typeRef.ScopeType;
+ var elementType = Renamer.GetScopeType(typeRef);
if (elementType == null && IsFnPtrSig(typeRef))
return fnPtrNameCreator.Create();
if (IsGenericParam(elementType))
@@ -113,6 +113,8 @@ namespace de4dot.code.renamer {
protected abstract string FixName(string prefix, string name);
public virtual TypeNames Merge(TypeNames other) {
+ if (this == other)
+ return this;
foreach (var pair in other.typeNames) {
NameCreator nc;
if (typeNames.TryGetValue(pair.Key, out nc))
diff --git a/de4dot.code/renamer/VariableNameState.cs b/de4dot.code/renamer/VariableNameState.cs
index 4e2ea22d..029c433d 100644
--- a/de4dot.code/renamer/VariableNameState.cs
+++ b/de4dot.code/renamer/VariableNameState.cs
@@ -61,6 +61,8 @@ namespace de4dot.code.renamer {
}
public VariableNameState Merge(VariableNameState other) {
+ if (this == other)
+ return this;
existingVariableNames.Merge(other.existingVariableNames);
existingMethodNames.Merge(other.existingMethodNames);
existingPropertyNames.Merge(other.existingPropertyNames);
diff --git a/de4dot.code/renamer/asmmodules/MemberRefFinder.cs b/de4dot.code/renamer/asmmodules/MemberRefFinder.cs
index 3aeff2a9..71425395 100644
--- a/de4dot.code/renamer/asmmodules/MemberRefFinder.cs
+++ b/de4dot.code/renamer/asmmodules/MemberRefFinder.cs
@@ -285,9 +285,44 @@ namespace de4dot.code.renamer.asmmodules {
void Add(DeclSecurity decl) {
if (decl == null)
return;
+ Add(decl.SecurityAttributes);
Add(decl.CustomAttributes);
}
+ void Add(IEnumerable secAttrs) {
+ if (secAttrs == null)
+ return;
+ foreach (var secAttr in secAttrs)
+ Add(secAttr);
+ }
+
+ void Add(SecurityAttribute secAttr) {
+ if (secAttr == null)
+ return;
+ Add(secAttr.AttributeType);
+ Add(secAttr.NamedArguments);
+ }
+
+ void Add(ITypeDefOrRef tdr) {
+ var td = tdr as TypeDef;
+ if (td != null) {
+ Add(td);
+ return;
+ }
+
+ var tr = tdr as TypeRef;
+ if (tr != null) {
+ Add(tr);
+ return;
+ }
+
+ var ts = tdr as TypeSpec;
+ if (ts != null) {
+ Add(ts);
+ return;
+ }
+ }
+
void Add(IEnumerable eds) {
if (eds == null)
return;
@@ -326,6 +361,7 @@ namespace de4dot.code.renamer.asmmodules {
Add(fd.CustomAttributes);
Add(fd.Signature);
Add(fd.DeclaringType);
+ Add(fd.MarshalType);
}
void Add(IEnumerable gps) {
@@ -489,6 +525,22 @@ namespace de4dot.code.renamer.asmmodules {
return;
Add(pd.DeclaringMethod);
Add(pd.CustomAttributes);
+ Add(pd.MarshalType);
+ }
+
+ void Add(MarshalType mt) {
+ if (mt == null)
+ return;
+
+ switch (mt.NativeType) {
+ case NativeType.SafeArray:
+ Add(((SafeArrayMarshalType)mt).UserDefinedSubType);
+ break;
+
+ case NativeType.CustomMarshaler:
+ Add(((CustomMarshalType)mt).CustomMarshaler);
+ break;
+ }
}
void Add(IEnumerable mos) {
diff --git a/de4dot.cui/Program.cs b/de4dot.cui/Program.cs
index 54610085..44885e47 100644
--- a/de4dot.cui/Program.cs
+++ b/de4dot.cui/Program.cs
@@ -74,7 +74,7 @@ namespace de4dot.cui {
Logger.n("");
Logger.n("de4dot v{0} Copyright (C) 2011-2014 de4dot@gmail.com", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version);
- Logger.n("Latest version and source code: https://bitbucket.org/0xd4d/de4dot");
+ Logger.n("Latest version and source code: https://github.com/0xd4d/de4dot");
Logger.n("");
var options = new FilesDeobfuscator.Options();
diff --git a/de4dot.cui/Properties/AssemblyInfo.cs b/de4dot.cui/Properties/AssemblyInfo.cs
index b208b36e..981bd097 100644
--- a/de4dot.cui/Properties/AssemblyInfo.cs
+++ b/de4dot.cui/Properties/AssemblyInfo.cs
@@ -30,7 +30,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
[assembly: InternalsVisibleTo("de4dot, PublicKey=00240000048000009400000006020000002400005253413100040000010001007b5ffd8f48f1397cd4e21c9e30a5cb36b2c013d6f20688c90e3f0c2d24e6d67cbeea7a6ec3faf9ba081f3d6b6fbe389677adbb8337d3a16187cd13b16a34008a22b89089da41c4a08fd35615c77de0827adcca6d49b08c0ed3e0404a1c44b7d083be614acb1779e4fb275e14427f3687f375d03f3b465c8a6cdeebd1f8c7f4ea")]
[assembly: InternalsVisibleTo("de4dot-x64, PublicKey=00240000048000009400000006020000002400005253413100040000010001007b5ffd8f48f1397cd4e21c9e30a5cb36b2c013d6f20688c90e3f0c2d24e6d67cbeea7a6ec3faf9ba081f3d6b6fbe389677adbb8337d3a16187cd13b16a34008a22b89089da41c4a08fd35615c77de0827adcca6d49b08c0ed3e0404a1c44b7d083be614acb1779e4fb275e14427f3687f375d03f3b465c8a6cdeebd1f8c7f4ea")]
diff --git a/de4dot.mdecrypt/DynamicMethodsDecrypter.cs b/de4dot.mdecrypt/DynamicMethodsDecrypter.cs
index 24fa5816..58557ff5 100644
--- a/de4dot.mdecrypt/DynamicMethodsDecrypter.cs
+++ b/de4dot.mdecrypt/DynamicMethodsDecrypter.cs
@@ -596,6 +596,9 @@ namespace de4dot.mdecrypt {
new PatchInfo(0x000110A5, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x36, 0x3A, 0x00, 0x00 }),
new PatchInfo(0x000110AF, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x4C, 0x3C, 0x00, 0x00 }),
new PatchInfo(0x000110AA, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0xF1, 0x3A, 0x00, 0x00 }),
+ new PatchInfo(0x00011019, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x12, 0x4B, 0x00, 0x00 }),
+ new PatchInfo(0x00011019, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x02, 0x4B, 0x00, 0x00 }),
+ new PatchInfo(0x00011019, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0xA2, 0x4B, 0x00, 0x00 }),
};
static unsafe bool PatchCM(IntPtr addr, IntPtr origValue, IntPtr newValue) {
diff --git a/de4dot.mdecrypt/Properties/AssemblyInfo.cs b/de4dot.mdecrypt/Properties/AssemblyInfo.cs
index a148ef31..0a392fad 100644
--- a/de4dot.mdecrypt/Properties/AssemblyInfo.cs
+++ b/de4dot.mdecrypt/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/de4dot/Properties/AssemblyInfo.cs b/de4dot/Properties/AssemblyInfo.cs
index aea00aa1..27c485e3 100644
--- a/de4dot/Properties/AssemblyInfo.cs
+++ b/de4dot/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("3.0.3.3405")]
-[assembly: AssemblyFileVersion("3.0.3.3405")]
+[assembly: AssemblyVersion("3.1.41592.3405")]
+[assembly: AssemblyFileVersion("3.1.41592.3405")]
diff --git a/dnlib b/dnlib
index d854e20b..4abc5988 160000
--- a/dnlib
+++ b/dnlib
@@ -1 +1 @@
-Subproject commit d854e20b2d4245245efc19e676e6862cdbd162f6
+Subproject commit 4abc5988d3cc4e8ae4cb7ac77f3018ffb54200c7