diff --git a/de4dot.code/de4dot.code.csproj b/de4dot.code/de4dot.code.csproj index 9f48a2e0..a56d2163 100644 --- a/de4dot.code/de4dot.code.csproj +++ b/de4dot.code/de4dot.code.csproj @@ -88,12 +88,10 @@ - - - + diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1.bin new file mode 100644 index 00000000..e32fb05e Binary files /dev/null and b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1.bin differ diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1_v2.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1_v2.bin deleted file mode 100644 index 156f0777..00000000 Binary files a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1_v2.bin and /dev/null differ diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2.bin new file mode 100644 index 00000000..e1e577a5 Binary files /dev/null and b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2.bin differ diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2_v2.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2_v2.bin deleted file mode 100644 index 81bd5ae6..00000000 Binary files a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2_v2.bin and /dev/null differ diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3.bin new file mode 100644 index 00000000..7378faf9 Binary files /dev/null and b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3.bin differ diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3_v2.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3_v2.bin deleted file mode 100644 index a86daab3..00000000 Binary files a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3_v2.bin and /dev/null differ diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM4.bin b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM4.bin new file mode 100644 index 00000000..85439b6e Binary files /dev/null and b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM4.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 9ae1debc..fc0452e6 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeHandlerDetector.cs @@ -25,19 +25,17 @@ using de4dot.blocks; namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { class CompositeHandlerDetector { - readonly List handlers; + readonly List handlers; - public CompositeHandlerDetector(IList handlers) { - this.handlers = new List(handlers.Count); - OpCodeHandler nop = null; - foreach (var handler in handlers) { - if (nop == null && handler.OpCodeHandlerInfo.TypeCode == HandlerTypeCode.Nop) - nop = handler; - else - this.handlers.Add(handler); - } - if (nop != null) - this.handlers.Add(nop); + public CompositeHandlerDetector(IList handlers) { + this.handlers = new List(handlers); + + this.handlers.Sort((a, b) => { + int r = b.BlockSigInfos.Count.CompareTo(a.BlockSigInfos.Count); + if (r != 0) + return r; + return b.BlockSigInfos[0].Hashes.Count.CompareTo(a.BlockSigInfos[0].Hashes.Count); + }); } struct MatchState { @@ -51,27 +49,18 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { } struct HandlerState { - public readonly HandlerMethod HandlerMethod; - public readonly IList Blocks; + public readonly List BlockSigInfos; public readonly int BlockIndex; - public int InstructionIndex; + public int HashIndex; - public HandlerState(HandlerMethod handlerMethod, int blockIndex, int instructionIndex) { - this.HandlerMethod = handlerMethod; - this.Blocks = handlerMethod.Blocks.MethodBlocks.GetAllBlocks(); + public HandlerState(List blockSigInfos, int blockIndex, int instructionIndex) { + this.BlockSigInfos = blockSigInfos; this.BlockIndex = blockIndex; - this.InstructionIndex = instructionIndex; - } - - public HandlerState(HandlerMethod handlerMethod, IList blocks, int blockIndex, int instructionIndex) { - this.HandlerMethod = handlerMethod; - this.Blocks = blocks; - this.BlockIndex = blockIndex; - this.InstructionIndex = instructionIndex; + this.HashIndex = instructionIndex; } public HandlerState Clone() { - return new HandlerState(HandlerMethod, Blocks, BlockIndex, InstructionIndex); + return new HandlerState(BlockSigInfos, BlockIndex, HashIndex); } } @@ -98,22 +87,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { } public bool FindHandlers(CompositeOpCodeHandler composite) { - composite.OpCodeHandlerInfos.Clear(); - var compositeExecState = new FindHandlerState(new HandlerState(composite.ExecMethod, 0, 0)); + composite.TypeCodes.Clear(); + var compositeExecState = new FindHandlerState(new HandlerState(composite.BlockSigInfos, 0, 0)); while (!compositeExecState.Done) { var handler = FindHandlerMethod(ref compositeExecState); if (handler == null) return false; - composite.OpCodeHandlerInfos.Add(handler.OpCodeHandlerInfo); + composite.TypeCodes.Add(handler.TypeCode); } - return composite.OpCodeHandlerInfos.Count != 0; + return composite.TypeCodes.Count != 0; } - OpCodeHandler FindHandlerMethod(ref FindHandlerState findExecState) { + MethodSigInfo FindHandlerMethod(ref FindHandlerState findExecState) { foreach (var handler in handlers) { FindHandlerState findExecStateNew = findExecState.Clone(); - if (!Matches(handler.ExecMethod, ref findExecStateNew)) + if (!Matches(handler.BlockSigInfos, ref findExecStateNew)) continue; findExecState = findExecStateNew; @@ -123,14 +112,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { } Stack stack = new Stack(); - bool Matches(HandlerMethod handler, ref FindHandlerState findState) { + bool Matches(List handler, ref FindHandlerState findState) { HandlerState? nextState = null; stack.Clear(); stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState)); while (stack.Count > 0) { var matchState = stack.Pop(); - if (matchState.CompositeState.InstructionIndex == 0) { + if (matchState.CompositeState.HashIndex == 0) { if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex)) continue; findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true; @@ -143,193 +132,83 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { if (!Compare(ref matchState.OtherState, ref matchState.CompositeState)) return false; - var hblock = matchState.OtherState.Blocks[matchState.OtherState.BlockIndex]; - var hinstrs = hblock.Instructions; - int hi = matchState.OtherState.InstructionIndex; - var cblock = matchState.CompositeState.Blocks[matchState.CompositeState.BlockIndex]; - var cinstrs = cblock.Instructions; - int ci = matchState.CompositeState.InstructionIndex; + var hblock = matchState.OtherState.BlockSigInfos[matchState.OtherState.BlockIndex]; + var hinstrs = hblock.Hashes; + int hi = matchState.OtherState.HashIndex; + var cblock = matchState.CompositeState.BlockSigInfos[matchState.CompositeState.BlockIndex]; + var cinstrs = cblock.Hashes; + int ci = matchState.CompositeState.HashIndex; if (hi < hinstrs.Count) return false; if (ci < cinstrs.Count) { - if (hblock.CountTargets() != 0) + if (hblock.Targets.Count != 0) return false; - if (hblock.LastInstr.OpCode.Code == Code.Ret) { + if (hblock.EndsInRet) { if (nextState != null) return false; nextState = matchState.CompositeState; } } else { - if (cblock.CountTargets() != hblock.CountTargets()) + if (cblock.Targets.Count != hblock.Targets.Count) + return false; + if (cblock.HasFallThrough != hblock.HasFallThrough) return false; - if (cblock.FallThrough != null || hblock.FallThrough != null) { - if (cblock.FallThrough == null || hblock.FallThrough == null) - return false; - var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.FallThrough); - var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.FallThrough); + for (int i = 0; i < cblock.Targets.Count; i++) { + var hs = new HandlerState(handler, hblock.Targets[i], 0); + var cs = new HandlerState(findState.CompositeState.BlockSigInfos, cblock.Targets[i], 0); stack.Push(new MatchState(hs, cs)); } - if (cblock.Targets != null || hblock.Targets != null) { - if (cblock.Targets == null || hblock.Targets == null || - cblock.Targets.Count != hblock.Targets.Count) - return false; - - for (int i = 0; i < cblock.Targets.Count; i++) { - var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.Targets[i]); - var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.Targets[i]); - stack.Push(new MatchState(hs, cs)); - } - } } } if (nextState == null) { + if (findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count) + return false; findState.Done = true; return true; } else { if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex && - findState.CompositeState.InstructionIndex == nextState.Value.InstructionIndex) + findState.CompositeState.HashIndex == nextState.Value.HashIndex) return false; findState.CompositeState = nextState.Value; + if (findState.CompositeState.HashIndex == 0) + findState.VisitedCompositeBlocks.Remove(findState.CompositeState.BlockIndex); return true; } } - static HandlerState CreateHandlerState(HandlerMethod handler, IList blocks, Block target) { - return new HandlerState(handler, blocks.IndexOf(target), 0); - } - static bool Compare(ref HandlerState handler, ref HandlerState composite) { - var hinstrs = handler.Blocks[handler.BlockIndex].Instructions; - int hi = handler.InstructionIndex; - var cinstrs = composite.Blocks[composite.BlockIndex].Instructions; - int ci = composite.InstructionIndex; + var hhashes = handler.BlockSigInfos[handler.BlockIndex].Hashes; + int hi = handler.HashIndex; + var chashes = composite.BlockSigInfos[composite.BlockIndex].Hashes; + int ci = composite.HashIndex; while (true) { - if (hi >= hinstrs.Count && ci >= cinstrs.Count) + if (hi >= hhashes.Count && ci >= chashes.Count) break; - if (hi >= hinstrs.Count || ci >= cinstrs.Count) + + if (hi >= hhashes.Count) { + if (handler.BlockSigInfos[handler.BlockIndex].EndsInRet) + break; + } + + if (hi >= hhashes.Count || ci >= chashes.Count) return false; - var hinstr = hinstrs[hi++]; - var cinstr = cinstrs[ci++]; - if (hinstr.OpCode.Code == Code.Nop || - cinstr.OpCode.Code == Code.Nop) { - if (hinstr.OpCode.Code != Code.Nop) - hi--; - if (cinstr.OpCode.Code != Code.Nop) - ci--; - continue; - } + var hhash = hhashes[hi++]; + var chash = chashes[ci++]; - if (hi == hinstrs.Count && hinstr.OpCode.Code == Code.Ret) { - if (cinstr.OpCode.Code != Code.Br && cinstr.OpCode.Code != Code.Ret) - ci--; - break; - } - - if (hinstr.OpCode.Code != cinstr.OpCode.Code) - return false; - - if (hinstr.OpCode.Code == Code.Ldfld && - hi + 1 < hinstrs.Count && ci + 1 < cinstrs.Count) { - var hfield = hinstr.Operand as FieldDef; - var cfield = cinstr.Operand as FieldDef; - if (hfield != null && cfield != null && - !hfield.IsStatic && !cfield.IsStatic && - hfield.DeclaringType == handler.HandlerMethod.Method.DeclaringType && - cfield.DeclaringType == composite.HandlerMethod.Method.DeclaringType && - SignatureEqualityComparer.Instance.Equals(hfield.Signature, cfield.Signature)) { - cinstr = cinstrs[ci++]; - hinstr = hinstrs[hi++]; - if (cinstr.OpCode.Code != Code.Ldc_I4 || - hinstr.OpCode.Code != Code.Ldc_I4) - return false; - continue; - } - } - - if (!CompareOperand(hinstr.OpCode.OperandType, cinstr.Operand, hinstr.Operand)) + if (chash != hhash) return false; } - handler.InstructionIndex = hi; - composite.InstructionIndex = ci; + handler.HashIndex = hi; + composite.HashIndex = ci; return true; } - - static bool CompareOperand(OperandType opType, object a, object b) { - switch (opType) { - case OperandType.ShortInlineI: - return (a is byte && b is byte && (byte)a == (byte)b) || - (a is sbyte && b is sbyte && (sbyte)a == (sbyte)b); - - case OperandType.InlineI: - return a is int && b is int && (int)a == (int)b; - - case OperandType.InlineI8: - return a is long && b is long && (long)a == (long)b; - - case OperandType.ShortInlineR: - return a is float && b is float && (float)a == (float)b; - - case OperandType.InlineR: - return a is double && b is double && (double)a == (double)b; - - case OperandType.InlineField: - return FieldEqualityComparer.CompareDeclaringTypes.Equals(a as IField, b as IField); - - case OperandType.InlineMethod: - return MethodEqualityComparer.CompareDeclaringTypes.Equals(a as IMethod, b as IMethod); - - case OperandType.InlineSig: - return SignatureEqualityComparer.Instance.Equals(a as MethodSig, b as MethodSig); - - case OperandType.InlineString: - return string.Equals(a as string, b as string); - - case OperandType.InlineSwitch: - var al = a as IList; - var bl = b as IList; - return al != null && bl != null && al.Count == bl.Count; - - case OperandType.InlineTok: - var fa = a as IField; - var fb = b as IField; - if (fa != null && fb != null) - return FieldEqualityComparer.CompareDeclaringTypes.Equals(fa, fb); - var ma = a as IMethod; - var mb = b as IMethod; - if (ma != null && mb != null) - return MethodEqualityComparer.CompareDeclaringTypes.Equals(ma, mb); - return TypeEqualityComparer.Instance.Equals(a as ITypeDefOrRef, b as ITypeDefOrRef); - - case OperandType.InlineType: - return TypeEqualityComparer.Instance.Equals(a as ITypeDefOrRef, b as ITypeDefOrRef); - - case OperandType.InlineVar: - case OperandType.ShortInlineVar: - var la = a as Local; - var lb = b as Local; - if (la != null && lb != null) - return true; - var pa = a as Parameter; - var pb = b as Parameter; - return pa != null && pb != null && pa.Index == pb.Index; - - case OperandType.InlineBrTarget: - case OperandType.ShortInlineBrTarget: - case OperandType.InlineNone: - case OperandType.InlinePhi: - return true; - - default: - return false; - } - } } } diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeOpCodeHandler.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeOpCodeHandler.cs index 2508d020..cc6afe0e 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeOpCodeHandler.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CompositeOpCodeHandler.cs @@ -23,45 +23,17 @@ using dnlib.DotNet; using de4dot.blocks; namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { - class HandlerMethod { - public MethodDef Method { get; private set; } - public Blocks Blocks { get; private set; } - - public HandlerMethod(MethodDef method) { - this.Method = method; - this.Blocks = new Blocks(method); - } - } - - class PrimitiveHandlerMethod : HandlerMethod { - public MethodSigInfo Sig { get; set; } - - public PrimitiveHandlerMethod(MethodDef method) - : base(method) { - } - } - class CompositeOpCodeHandler { - public TypeDef HandlerType { get; private set; } - public HandlerMethod ExecMethod { get; private set; } - public List OpCodeHandlerInfos { get; private set; } + public List BlockSigInfos { get; private set; } + public List TypeCodes { get; private set; } - public CompositeOpCodeHandler(TypeDef handlerType, HandlerMethod execMethod) { - this.HandlerType = handlerType; - this.ExecMethod = execMethod; - this.OpCodeHandlerInfos = new List(); + public CompositeOpCodeHandler(List blockSigInfos) { + this.BlockSigInfos = blockSigInfos; + this.TypeCodes = new List(); } public override string ToString() { - if (OpCodeHandlerInfos.Count == 0) - return ""; - var sb = new StringBuilder(); - foreach (var handler in OpCodeHandlerInfos) { - if (sb.Length != 0) - sb.Append(", "); - sb.Append(handler.Name); - } - return sb.ToString(); + return OpCodeHandlerInfo.GetCompositeName(TypeCodes); } } } diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs index 815cc53d..a5d1c557 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmInfo.cs @@ -594,45 +594,79 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { } public bool FindUnaryOpsMethods() { - UnaryNot = FindUnaryOpMethod(Code.Not); - UnaryNeg = FindUnaryOpMethod(Code.Neg); - return UnaryNot != null && UnaryNeg != null; + UnaryNot = FindUnaryOpMethod1(Code.Not); + UnaryNeg = FindUnaryOpMethod1(Code.Neg); + if (UnaryNot != null && UnaryNeg != null) + return true; + + return FindUnaryOpMethod2(); } - MethodDef FindUnaryOpMethod(Code code) { + MethodDef FindUnaryOpMethod1(Code code) { foreach (var type in module.Types) { if (type.BaseType != VmHandlerBaseType) continue; if (type.Methods.Count != 4) continue; - foreach (var method in type.Methods) { - if (!method.HasBody || !method.IsStatic) - continue; - if (!DotNetUtils.IsMethod(method, "System.Object", "(System.Object)")) - continue; - if (CountThrows(method) != 1) - continue; - var instrs = method.Body.Instructions; - for (int i = 0; i < instrs.Count - 4; i++) { - var ldarg = instrs[i]; - if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != 0) - continue; - if (!CheckUnboxAny(instrs[i + 1], ElementType.I4)) - continue; - if (instrs[i + 2].OpCode.Code != code) - continue; - if (!CheckBox(instrs[i + 3], ElementType.I4)) - continue; - if (!instrs[i + 4].IsStloc()) - continue; - - return method; - } - } + var method = FindUnaryMethod(type, code); + if (method != null) + return method; } return null; } + bool FindUnaryOpMethod2() { + foreach (var type in module.Types) { + if (type.BaseType == null || type.BaseType.FullName != "System.Object") + continue; + if (type.Methods.Count != 3) + continue; + + UnaryNot = FindUnaryMethod(type, Code.Not); + UnaryNeg = FindUnaryMethod(type, Code.Neg); + if (UnaryNot != null && UnaryNeg != null) + return true; + } + return false; + } + + MethodDef FindUnaryMethod(TypeDef type, Code code) { + foreach (var method in type.Methods) { + if (!IsUnsaryMethod(method, code)) + continue; + + return method; + } + return null; + } + + bool IsUnsaryMethod(MethodDef method, Code code) { + if (!method.HasBody || !method.IsStatic) + return false; + if (!DotNetUtils.IsMethod(method, "System.Object", "(System.Object)")) + return false; + if (CountThrows(method) != 1) + return false; + var instrs = method.Body.Instructions; + for (int i = 0; i < instrs.Count - 4; i++) { + var ldarg = instrs[i]; + if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != 0) + continue; + if (!CheckUnboxAny(instrs[i + 1], ElementType.I4)) + continue; + if (instrs[i + 2].OpCode.Code != code) + continue; + if (!CheckBox(instrs[i + 3], ElementType.I4)) + continue; + if (!instrs[i + 4].IsStloc()) + continue; + + return true; + } + + return false; + } + static int CountThrows(MethodDef method) { if (method == null || method.Body == null) return 0; 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 6153040b..3a090f84 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.Designer.cs @@ -63,9 +63,9 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { /// /// Looks up a localized resource of type System.Byte[]. /// - internal static byte[] CSVM1_v2 { + internal static byte[] CSVM1 { get { - object obj = ResourceManager.GetObject("CSVM1_v2", resourceCulture); + object obj = ResourceManager.GetObject("CSVM1", resourceCulture); return ((byte[])(obj)); } } @@ -73,9 +73,9 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { /// /// Looks up a localized resource of type System.Byte[]. /// - internal static byte[] CSVM2_v2 { + internal static byte[] CSVM2 { get { - object obj = ResourceManager.GetObject("CSVM2_v2", resourceCulture); + object obj = ResourceManager.GetObject("CSVM2", resourceCulture); return ((byte[])(obj)); } } @@ -83,9 +83,19 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { /// /// Looks up a localized resource of type System.Byte[]. /// - internal static byte[] CSVM3_v2 { + internal static byte[] CSVM3 { get { - object obj = ResourceManager.GetObject("CSVM3_v2", resourceCulture); + object obj = ResourceManager.GetObject("CSVM3", resourceCulture); + return ((byte[])(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Byte[]. + /// + internal static byte[] CSVM4 { + get { + object obj = ResourceManager.GetObject("CSVM4", 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 254aef83..17159be0 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmResources.resx @@ -117,14 +117,17 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - CSVM1_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + CSVM1.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - CSVM2_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + CSVM2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - CSVM3_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + CSVM3.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + CSVM4.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 3cc2f2f6..7d76cf59 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/CsvmToCilMethodConverter.cs @@ -45,11 +45,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { uint offset = 0; for (int vmInstrIndex = 0; vmInstrIndex < numVmInstrs; vmInstrIndex++) { var composite = opCodeDetector.Handlers[vmInstrs[vmInstrIndex]]; - var handlerInfos = composite.OpCodeHandlerInfos; + IList handlerInfos = composite.HandlerTypeCodes; if (handlerInfos.Count == 0) - handlerInfos = new List() { new OpCodeHandlerInfo(HandlerTypeCode.Nop, null) }; + handlerInfos = new HandlerTypeCode[] { HandlerTypeCode.Nop }; for (int hi = 0; hi < handlerInfos.Count; hi++) { - var instr = handlerInfoReader.Read(handlerInfos[hi].TypeCode, reader); + var instr = handlerInfoReader.Read(handlerInfos[hi], reader); instr.Offset = offset; offset += (uint)GetInstructionSize(instr); SetCilToVmIndex(instr, vmInstrIndex); @@ -58,6 +58,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { instrs.Add(instr); } } + return instrs; } } diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodFinder.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodFinder.cs deleted file mode 100644 index ca206830..00000000 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodFinder.cs +++ /dev/null @@ -1,109 +0,0 @@ -/* - Copyright (C) 2011-2013 de4dot@gmail.com - - This file is part of de4dot. - - de4dot is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - de4dot is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with de4dot. If not, see . -*/ - -using System.Collections.Generic; - -namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { - class MethodFinder { - readonly IList handlerInfos; - readonly PrimitiveHandlerMethod handlerMethod; - - class SigState { - public readonly MethodSigInfo SigInfo; - - public SigState(PrimitiveHandlerMethod handlerMethod) { - this.SigInfo = handlerMethod.Sig; - } - } - - public MethodFinder(IList handlerInfos, PrimitiveHandlerMethod handlerMethod) { - this.handlerInfos = handlerInfos; - this.handlerMethod = handlerMethod; - } - - public OpCodeHandler FindHandler() { - var handler = FindHandler(new SigState(handlerMethod)); - if (handler == null) - return null; - - return new OpCodeHandler(handler, handlerMethod.Method.DeclaringType, handlerMethod); - } - - OpCodeHandlerInfo FindHandler(SigState execSigState) { - foreach (var handler in handlerInfos) { - if (Matches(handler.ExecSig, execSigState)) - return handler; - } - return null; - } - - struct MatchInfo { - public int HandlerIndex; - public int SigIndex; - - public MatchInfo(int handlerIndex, int sigIndex) { - this.HandlerIndex = handlerIndex; - this.SigIndex = sigIndex; - } - } - - Dictionary sigIndexToHandlerIndex = new Dictionary(); - Dictionary handlerIndexToSigIndex = new Dictionary(); - Stack stack = new Stack(); - bool Matches(MethodSigInfo handlerSig, SigState sigState) { - stack.Clear(); - sigIndexToHandlerIndex.Clear(); - handlerIndexToSigIndex.Clear(); - var handlerInfos = handlerSig.BlockInfos; - var sigInfos = sigState.SigInfo.BlockInfos; - - stack.Push(new MatchInfo(0, 0)); - while (stack.Count > 0) { - var info = stack.Pop(); - - int handlerIndex, sigIndex; - bool hasVisitedHandler = handlerIndexToSigIndex.TryGetValue(info.HandlerIndex, out sigIndex); - bool hasVisitedSig = sigIndexToHandlerIndex.TryGetValue(info.SigIndex, out handlerIndex); - if (hasVisitedHandler != hasVisitedSig) - return false; - if (hasVisitedHandler) { - if (handlerIndex != info.HandlerIndex || sigIndex != info.SigIndex) - return false; - continue; - } - handlerIndexToSigIndex[info.HandlerIndex] = info.SigIndex; - sigIndexToHandlerIndex[info.SigIndex] = info.HandlerIndex; - - var handlerBlock = handlerInfos[info.HandlerIndex]; - var sigBlock = sigInfos[info.SigIndex]; - - if (!handlerBlock.Equals(sigBlock)) - return false; - - for (int i = 0; i < handlerBlock.Targets.Count; i++) { - int handlerTargetIndex = handlerBlock.Targets[i]; - int sigTargetIndex = sigBlock.Targets[i]; - stack.Push(new MatchInfo(handlerTargetIndex, sigTargetIndex)); - } - } - - return true; - } - } -} diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodSigInfoCreator.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodSigInfoCreator.cs deleted file mode 100644 index c311e0a9..00000000 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/MethodSigInfoCreator.cs +++ /dev/null @@ -1,737 +0,0 @@ -/* - Copyright (C) 2011-2013 de4dot@gmail.com - - This file is part of de4dot. - - de4dot is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - de4dot is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with de4dot. If not, see . -*/ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; -using dnlib.DotNet; -using dnlib.DotNet.Emit; -using dnlib.DotNet.MD; -using de4dot.blocks; - -namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { - class MethodSigInfo { - readonly List blockInfos; - - public List BlockInfos { - get { return blockInfos; } - } - - public MethodSigInfo() { - this.blockInfos = new List(); - } - - public MethodSigInfo(IEnumerable blockInfos) { - this.blockInfos = new List(blockInfos); - } - } - - class BlockInfo : IEquatable { - readonly List targets; - - public byte[] Hash { get; set; } - public List Targets { - get { return targets; } - } - - public BlockInfo() { - this.targets = new List(); - } - - public BlockInfo(byte[] hash, IEnumerable targets) { - this.Hash = hash; - this.targets = new List(targets); - } - - public override string ToString() { - if (Hash == null) - return ""; - return BitConverter.ToString(Hash).Replace("-", string.Empty); - } - - public bool Equals(BlockInfo other) { - return Equals(Hash, other.Hash) && - Targets.Count == other.Targets.Count; - } - - bool Equals(byte[] a, byte[] b) { - if (a == b) - return true; - if (a == null || b == null) - return false; - if (a.Length != b.Length) - return false; - for (int i = 0; i < a.Length; i++) { - if (a[i] != b[i]) - return false; - } - return true; - } - } - - class MethodSigInfoCreator { - MethodSigInfo methodSigInfo; - Blocks blocks; - IList allBlocks; - Dictionary blockToInfo; - Dictionary methodToId = new Dictionary(); - - public void AddId(object key, int id) { - if (key != null) - methodToId[key] = id; - } - - int GetId(object key) { - if (key == null) - return int.MinValue; - - int id; - if (methodToId.TryGetValue(key, out id)) - return id; - return int.MinValue + 1; - } - - public MethodSigInfo Create(Blocks blocks) { - methodSigInfo = new MethodSigInfo(); - - this.blocks = blocks; - allBlocks = blocks.MethodBlocks.GetAllBlocks(); - - blockToInfo = new Dictionary(); - foreach (var block in allBlocks) { - var blockInfo = new BlockInfo(); - blockToInfo[block] = blockInfo; - methodSigInfo.BlockInfos.Add(blockInfo); - } - - foreach (var block in allBlocks) { - var blockInfo = blockToInfo[block]; - Update(blockInfo, block); - if (block.FallThrough != null) - blockInfo.Targets.Add(allBlocks.IndexOf(block.FallThrough)); - if (block.Targets != null) { - foreach (var target in block.Targets) - blockInfo.Targets.Add(allBlocks.IndexOf(target)); - } - } - - return methodSigInfo; - } - - void Update(BlockInfo blockInfo, Block block) { - using (var hasher = MD5.Create()) { - bool emptyHash; - using (var outStream = new NullStream()) { - using (var csStream = new CryptoStream(outStream, hasher, CryptoStreamMode.Write)) { - var writer = new BinaryWriter(csStream); - Update(writer, blockInfo, block); - } - emptyHash = outStream.Length == 0; - } - if (!emptyHash) - blockInfo.Hash = hasher.Hash; - } - } - - void Update(BinaryWriter writer, BlockInfo blockInfo, Block block) { - var instrs = block.Instructions; - for (int i = 0; i < instrs.Count; i++) { - var instr = instrs[i]; - switch (instr.OpCode.Code) { - case Code.Beq_S: - case Code.Bge_S: - case Code.Bgt_S: - case Code.Ble_S: - case Code.Blt_S: - case Code.Bne_Un_S: - case Code.Bge_Un_S: - case Code.Bgt_Un_S: - case Code.Ble_Un_S: - case Code.Blt_Un_S: - case Code.Brfalse_S: - case Code.Brtrue_S: - case Code.Leave_S: - case Code.Beq: - case Code.Bge: - case Code.Bgt: - case Code.Ble: - case Code.Blt: - case Code.Bne_Un: - case Code.Bge_Un: - case Code.Bgt_Un: - case Code.Ble_Un: - case Code.Blt_Un: - case Code.Brfalse: - case Code.Brtrue: - case Code.Leave: - writer.Write((ushort)SimplifyBranch(instr.OpCode.Code)); - break; - - case Code.Switch: - writer.Write((ushort)instr.OpCode.Code); - writer.Write(blockInfo.Targets.Count); - break; - - case Code.Br_S: - case Code.Br: - break; - - case Code.Ret: - break; - - case Code.Ldc_I4_M1: - case Code.Ldc_I4_0: - case Code.Ldc_I4_1: - case Code.Ldc_I4_2: - case Code.Ldc_I4_3: - case Code.Ldc_I4_4: - case Code.Ldc_I4_5: - case Code.Ldc_I4_6: - case Code.Ldc_I4_7: - case Code.Ldc_I4_8: - case Code.Ldc_I4: - case Code.Ldc_I4_S: - writer.Write((ushort)Code.Ldc_I4); - writer.Write(instr.GetLdcI4Value()); - break; - - case Code.Ldc_I8: - writer.Write((ushort)instr.OpCode.Code); - writer.Write((long)instr.Operand); - break; - - case Code.Ldc_R4: - writer.Write((ushort)instr.OpCode.Code); - writer.Write((float)instr.Operand); - break; - - case Code.Ldc_R8: - writer.Write((ushort)instr.OpCode.Code); - writer.Write((double)instr.Operand); - break; - - case Code.Ldfld: - var typeField = instr.Operand as FieldDef; - bool isField = IsTypeField(typeField); - writer.Write((ushort)instr.OpCode.Code); - writer.Write(isField); - if (isField) { - if (i + 1 < instrs.Count && instrs[i + 1].IsLdcI4()) - i++; - writer.Write(GetFieldId(typeField)); - } - else - Write(writer, instr.Operand); - break; - - case Code.Call: - case Code.Callvirt: - case Code.Newobj: - case Code.Jmp: - case Code.Ldftn: - case Code.Ldvirtftn: - case Code.Ldtoken: - case Code.Stfld: - case Code.Ldsfld: - case Code.Stsfld: - case Code.Ldflda: - case Code.Ldsflda: - case Code.Cpobj: - case Code.Ldobj: - case Code.Castclass: - case Code.Isinst: - case Code.Unbox: - case Code.Stobj: - case Code.Box: - case Code.Newarr: - case Code.Ldelema: - case Code.Ldelem: - case Code.Stelem: - case Code.Unbox_Any: - case Code.Refanyval: - case Code.Mkrefany: - case Code.Initobj: - case Code.Constrained: - case Code.Sizeof: - writer.Write((ushort)instr.OpCode.Code); - Write(writer, instr.Operand); - break; - - case Code.Ldstr: - writer.Write((ushort)instr.OpCode.Code); - break; - - case Code.Ldarg: - case Code.Ldarg_S: - case Code.Ldarg_0: - case Code.Ldarg_1: - case Code.Ldarg_2: - case Code.Ldarg_3: - writer.Write((ushort)Code.Ldarg); - writer.Write(instr.Instruction.GetParameterIndex()); - break; - - case Code.Ldarga: - case Code.Ldarga_S: - writer.Write((ushort)Code.Ldarga); - writer.Write(instr.Instruction.GetParameterIndex()); - break; - - case Code.Starg: - case Code.Starg_S: - writer.Write((ushort)Code.Starg); - writer.Write(instr.Instruction.GetParameterIndex()); - break; - - case Code.Ldloc: - case Code.Ldloc_S: - case Code.Ldloc_0: - case Code.Ldloc_1: - case Code.Ldloc_2: - case Code.Ldloc_3: - writer.Write((ushort)Code.Ldloc); - break; - - case Code.Ldloca: - case Code.Ldloca_S: - writer.Write((ushort)Code.Ldloca); - break; - - case Code.Stloc: - case Code.Stloc_S: - case Code.Stloc_0: - case Code.Stloc_1: - case Code.Stloc_2: - case Code.Stloc_3: - writer.Write((ushort)Code.Stloc); - break; - - case Code.Ldnull: - case Code.Throw: - case Code.Rethrow: - case Code.Ldlen: - case Code.Ckfinite: - case Code.Arglist: - case Code.Localloc: - case Code.Volatile: - case Code.Tailcall: - case Code.Cpblk: - case Code.Initblk: - case Code.Refanytype: - case Code.Readonly: - case Code.Break: - case Code.Endfinally: - case Code.Endfilter: - writer.Write((ushort)instr.OpCode.Code); - break; - - case Code.Calli: - writer.Write((ushort)instr.OpCode.Code); - Write(writer, instr.Operand); - break; - - case Code.Unaligned: - writer.Write((ushort)instr.OpCode.Code); - writer.Write((byte)instr.Operand); - break; - - default: - break; - } - } - } - - void Write(BinaryWriter writer, object op) { - var fd = op as FieldDef; - if (fd != null) { - Write(writer, fd); - return; - } - - var mr = op as MemberRef; - if (mr != null) { - Write(writer, mr); - return; - } - - var md = op as MethodDef; - if (md != null) { - Write(writer, md); - return; - } - - var ms = op as MethodSpec; - if (ms != null) { - Write(writer, ms); - return; - } - - var td = op as TypeDef; - if (td != null) { - Write(writer, td); - return; - } - - var tr = op as TypeRef; - if (tr != null) { - Write(writer, tr); - return; - } - - var ts = op as TypeSpec; - if (ts != null) { - Write(writer, ts); - return; - } - - var fsig = op as FieldSig; - if (fsig != null) { - Write(writer, fsig); - return; - } - - var msig = op as MethodSig; - if (msig != null) { - Write(writer, msig); - return; - } - - var gsig = op as GenericInstMethodSig; - if (gsig != null) { - Write(writer, gsig); - return; - } - - var asmRef = op as AssemblyRef; - if (asmRef != null) { - Write(writer, asmRef); - return; - } - - writer.Write((byte)ObjectType.Unknown); - } - - enum ObjectType : byte { - // 00..3F = Table.XXX values. - Unknown = 0x40, - TypeSig = 0x41, - FieldSig = 0x42, - MethodSig = 0x43, - GenericInstMethodSig = 0x44, - } - - void Write(BinaryWriter writer, TypeSig sig) { - Write(writer, sig, 0); - } - - void Write(BinaryWriter writer, TypeSig sig, int level) { - if (level++ > 20) - return; - - writer.Write((byte)ObjectType.TypeSig); - var etype = sig.GetElementType(); - writer.Write((byte)etype); - switch (etype) { - case ElementType.Ptr: - case ElementType.ByRef: - case ElementType.SZArray: - case ElementType.Pinned: - Write(writer, sig.Next, level); - break; - - case ElementType.Array: - var arySig = (ArraySig)sig; - writer.Write(arySig.Rank); - writer.Write(arySig.Sizes.Count); - writer.Write(arySig.LowerBounds.Count); - Write(writer, sig.Next, level); - break; - - case ElementType.CModReqd: - case ElementType.CModOpt: - Write(writer, ((ModifierSig)sig).Modifier); - Write(writer, sig.Next, level); - break; - - case ElementType.ValueArray: - writer.Write(((ValueArraySig)sig).Size); - Write(writer, sig.Next, level); - break; - - case ElementType.Module: - writer.Write(((ModuleSig)sig).Index); - Write(writer, sig.Next, level); - break; - - case ElementType.GenericInst: - var gis = (GenericInstSig)sig; - Write(writer, gis.GenericType, level); - foreach (var ga in gis.GenericArguments) - Write(writer, ga, level); - Write(writer, sig.Next, level); - break; - - case ElementType.FnPtr: - Write(writer, ((FnPtrSig)sig).Signature); - break; - - case ElementType.Var: - case ElementType.MVar: - writer.Write(((GenericSig)sig).Number); - break; - - case ElementType.ValueType: - case ElementType.Class: - Write(writer, ((TypeDefOrRefSig)sig).TypeDefOrRef); - break; - - case ElementType.End: - case ElementType.Void: - case ElementType.Boolean: - case ElementType.Char: - case ElementType.I1: - case ElementType.U1: - case ElementType.I2: - case ElementType.U2: - case ElementType.I4: - case ElementType.U4: - case ElementType.I8: - case ElementType.U8: - case ElementType.R4: - case ElementType.R8: - case ElementType.String: - case ElementType.TypedByRef: - case ElementType.I: - case ElementType.U: - case ElementType.R: - case ElementType.Object: - case ElementType.Internal: - case ElementType.Sentinel: - default: - break; - } - } - - void Write(BinaryWriter writer, FieldSig sig) { - writer.Write((byte)ObjectType.FieldSig); - writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention())); - Write(writer, sig.GetFieldType()); - } - - void Write(BinaryWriter writer, MethodSig sig) { - writer.Write((byte)ObjectType.MethodSig); - writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention())); - Write(writer, sig.GetRetType()); - foreach (var p in sig.GetParams()) - Write(writer, p); - writer.Write(sig.GetParamCount()); - bool hasParamsAfterSentinel = sig.GetParamsAfterSentinel() != null; - writer.Write(hasParamsAfterSentinel); - if (hasParamsAfterSentinel) { - foreach (var p in sig.GetParamsAfterSentinel()) - Write(writer, p); - } - } - - void Write(BinaryWriter writer, GenericInstMethodSig sig) { - writer.Write((byte)ObjectType.GenericInstMethodSig); - writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention())); - foreach (var ga in sig.GetGenericArguments()) - Write(writer, ga); - } - - void Write(BinaryWriter writer, FieldDef fd) { - writer.Write((byte)Table.Field); - Write(writer, fd.DeclaringType); - var attrMask = FieldAttributes.Static | FieldAttributes.InitOnly | - FieldAttributes.Literal | FieldAttributes.SpecialName | - FieldAttributes.PinvokeImpl | FieldAttributes.RTSpecialName; - writer.Write((ushort)(fd == null ? 0 : fd.Attributes & attrMask)); - Write(writer, fd == null ? null : fd.Signature); - } - - void Write(BinaryWriter writer, MemberRef mr) { - writer.Write((byte)Table.MemberRef); - var parent = mr == null ? null : mr.Class; - Write(writer, parent); - bool canWriteName = IsFromNonObfuscatedAssembly(parent); - writer.Write(canWriteName); - if (canWriteName) - writer.Write(mr.Name); - Write(writer, mr == null ? null : mr.Signature); - } - - void Write(BinaryWriter writer, MethodDef md) { - writer.Write((byte)Table.Method); - Write(writer, md.DeclaringType); - var attrMask1 = MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask | - MethodImplAttributes.ForwardRef | MethodImplAttributes.PreserveSig | - MethodImplAttributes.InternalCall; - writer.Write((ushort)(md == null ? 0 : md.ImplAttributes & attrMask1)); - var attrMask2 = MethodAttributes.Static | MethodAttributes.Virtual | - MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask | - MethodAttributes.CheckAccessOnOverride | MethodAttributes.Abstract | - MethodAttributes.SpecialName | MethodAttributes.PinvokeImpl | - MethodAttributes.UnmanagedExport | MethodAttributes.RTSpecialName; - writer.Write((ushort)(md == null ? 0 : md.Attributes & attrMask2)); - Write(writer, md == null ? null : md.Signature); - writer.Write(md == null ? 0 : md.ParamDefs.Count); - writer.Write(md == null ? 0 : md.GenericParameters.Count); - writer.Write(md == null ? false : md.HasImplMap); - writer.Write(GetId(md)); - } - - void Write(BinaryWriter writer, MethodSpec ms) { - writer.Write((byte)Table.MethodSpec); - Write(writer, ms == null ? null : ms.Method); - Write(writer, ms == null ? null : ms.Instantiation); - } - - void Write(BinaryWriter writer, TypeDef td) { - writer.Write((byte)Table.TypeDef); - Write(writer, td == null ? null : td.BaseType); - var attrMask = TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask | - TypeAttributes.Abstract | TypeAttributes.SpecialName | - TypeAttributes.Import | TypeAttributes.WindowsRuntime | - TypeAttributes.StringFormatMask | TypeAttributes.RTSpecialName; - writer.Write((uint)(td == null ? 0 : td.Attributes & attrMask)); - Write(writer, td == null ? null : td.BaseType); - writer.Write(td == null ? 0 : td.GenericParameters.Count); - writer.Write(td == null ? 0 : td.Interfaces.Count); - if (td != null) { - foreach (var iface in td.Interfaces) - Write(writer, iface); - } - writer.Write(GetId(td)); - } - - void Write(BinaryWriter writer, TypeRef tr) { - writer.Write((byte)Table.TypeRef); - Write(writer, tr == null ? null : tr.ResolutionScope); - bool canWriteName = IsFromNonObfuscatedAssembly(tr); - writer.Write(canWriteName); - if (canWriteName) { - writer.Write(tr.Namespace); - writer.Write(tr.Name); - } - } - - void Write(BinaryWriter writer, TypeSpec ts) { - writer.Write((byte)Table.TypeSpec); - Write(writer, ts == null ? null : ts.TypeSig); - } - - void Write(BinaryWriter writer, AssemblyRef asmRef) { - writer.Write((byte)Table.AssemblyRef); - - bool canWriteAsm = IsNonObfuscatedAssembly(asmRef); - writer.Write(canWriteAsm); - if (canWriteAsm) { - bool hasPk = !PublicKeyBase.IsNullOrEmpty2(asmRef.PublicKeyOrToken); - writer.Write(hasPk); - if (hasPk) - writer.Write(PublicKeyBase.ToPublicKeyToken(asmRef.PublicKeyOrToken).Data); - writer.Write(asmRef.Name); - writer.Write(asmRef.Culture); - } - } - - static bool IsFromNonObfuscatedAssembly(IMemberRefParent mrp) { - return IsFromNonObfuscatedAssembly(mrp as TypeRef); - } - - static bool IsFromNonObfuscatedAssembly(TypeRef tr) { - if (tr == null) - return false; - - for (int i = 0; i < 100; i++) { - var asmRef = tr.ResolutionScope as AssemblyRef; - if (asmRef != null) - return IsNonObfuscatedAssembly(asmRef); - - var tr2 = tr.ResolutionScope as TypeRef; - if (tr2 != null) { - tr = tr2; - continue; - } - - break; - } - - return false; - } - - static bool IsNonObfuscatedAssembly(AssemblyRef asmRef) { - if (asmRef == null) - return false; - // The only external asm refs it uses... - if (asmRef.Name != "mscorlib" && asmRef.Name != "System") - return false; - - return true; - } - - bool IsTypeField(FieldDef fd) { - return fd != null && fd.DeclaringType == blocks.Method.DeclaringType; - } - - int GetFieldId(FieldDef fd) { - if (fd == null) - return int.MinValue; - var fieldType = fd.FieldSig.GetFieldType(); - if (fieldType == null) - return int.MinValue + 1; - - int result = 0; - for (int i = 0; i < 100; i++) { - result += (int)fieldType.ElementType; - if (fieldType.Next == null) - break; - result += 0x100; - fieldType = fieldType.Next; - } - - var td = fieldType.TryGetTypeDef(); - if (td != null && td.IsEnum) - return result + 0x10000000; - return result; - } - - static Code SimplifyBranch(Code code) { - switch (code) { - case Code.Beq_S: return Code.Beq; - case Code.Bge_S: return Code.Bge; - case Code.Bgt_S: return Code.Bgt; - case Code.Ble_S: return Code.Ble; - case Code.Blt_S: return Code.Blt; - case Code.Bne_Un_S: return Code.Bne_Un; - case Code.Bge_Un_S: return Code.Bge_Un; - case Code.Bgt_Un_S: return Code.Bgt_Un; - case Code.Ble_Un_S: return Code.Ble_Un; - case Code.Blt_Un_S: return Code.Blt_Un; - case Code.Br_S: return Code.Br; - case Code.Brfalse_S: return Code.Brfalse; - case Code.Brtrue_S: return Code.Brtrue; - case Code.Leave_S: return Code.Leave; - default: return code; - } - } - } -} diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandler.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandler.cs deleted file mode 100644 index 606d1f68..00000000 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandler.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2011-2013 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.vm.v2 { - class OpCodeHandler { - public OpCodeHandlerInfo OpCodeHandlerInfo { get; private set; } - public TypeDef HandlerType { get; private set; } - public HandlerMethod ExecMethod { get; private set; } - - public OpCodeHandler(OpCodeHandlerInfo opCodeHandlerInfo, TypeDef handlerType, HandlerMethod execMethod) { - this.OpCodeHandlerInfo = opCodeHandlerInfo; - this.HandlerType = handlerType; - this.ExecMethod = execMethod; - } - - public override string ToString() { - return OpCodeHandlerInfo.Name; - } - } -} diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfo.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfo.cs index d7d3d48d..1d07cf95 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfo.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfo.cs @@ -19,24 +19,35 @@ using System; using System.Collections.Generic; +using System.Text; namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { class OpCodeHandlerInfo { public HandlerTypeCode TypeCode { get; private set; } public string Name { get; private set; } - public MethodSigInfo ExecSig { get; private set; } - public OpCodeHandlerInfo(HandlerTypeCode typeCode, MethodSigInfo execSig) { + public OpCodeHandlerInfo(HandlerTypeCode typeCode) { this.TypeCode = typeCode; this.Name = GetHandlerName(typeCode); - this.ExecSig = execSig; } public override string ToString() { return Name; } - static string GetHandlerName(HandlerTypeCode code) { + public static string GetCompositeName(IList typeCodes) { + if (typeCodes.Count == 0) + return ""; + var sb = new StringBuilder(); + foreach (var typeCode in typeCodes) { + if (sb.Length != 0) + sb.Append(", "); + sb.Append(GetHandlerName(typeCode)); + } + return sb.ToString(); + } + + public static string GetHandlerName(HandlerTypeCode code) { switch (code) { case HandlerTypeCode.Add: return "add"; case HandlerTypeCode.Add_Ovf: return "add.ovf"; diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfos.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfos.cs index 13165b97..a78753b8 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfos.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/OpCodeHandlerInfos.cs @@ -23,75 +23,61 @@ using System.IO; namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { static class OpCodeHandlerInfos { - enum OpCodeHandlersFileVersion : int { - V1 = 1, - } - - public static void Write(BinaryWriter writer, IList handlerInfos) { - WriteV1(writer, handlerInfos); - } - - public static void WriteV1(BinaryWriter writer, IList handlerInfos) { - writer.Write((int)OpCodeHandlersFileVersion.V1); + public static void Write(BinaryWriter writer, List handlerInfos) { + writer.Write(1); writer.Write(handlerInfos.Count); foreach (var handler in handlerInfos) { writer.Write((int)handler.TypeCode); - var infos = handler.ExecSig.BlockInfos; - writer.Write(infos.Count); - foreach (var info in infos) { - if (info.Hash == null) - writer.Write(0); - else { - writer.Write(info.Hash.Length); - writer.Write(info.Hash); - } + writer.Write(handler.BlockSigInfos.Count); + foreach (var info in handler.BlockSigInfos) { writer.Write(info.Targets.Count); foreach (var target in info.Targets) writer.Write(target); + writer.Write(info.Hashes.Count); + foreach (var hash in info.Hashes) + writer.Write((uint)hash); + writer.Write(info.HasFallThrough); + writer.Write(info.EndsInRet); } } } - public static List Read(BinaryReader reader) { - switch ((OpCodeHandlersFileVersion)reader.ReadInt32()) { - case OpCodeHandlersFileVersion.V1: return ReadV1(reader); - default: throw new ApplicationException("Invalid file version"); - } - } - - static List ReadV1(BinaryReader reader) { + public static List Read(BinaryReader reader) { + if (reader.ReadInt32() != 1) + throw new InvalidDataException(); int numHandlers = reader.ReadInt32(); - var list = new List(numHandlers); + var list = new List(numHandlers); for (int i = 0; i < numHandlers; i++) { var typeCode = (HandlerTypeCode)reader.ReadInt32(); - int numInfos = reader.ReadInt32(); - var sigInfo = new MethodSigInfo(); - for (int j = 0; j < numInfos; j++) { - var info = new BlockInfo(); - - info.Hash = reader.ReadBytes(reader.ReadInt32()); - if (info.Hash.Length == 0) - info.Hash = null; - + int numBlocks = reader.ReadInt32(); + var blocks = new List(numBlocks); + for (int j = 0; j < numBlocks; j++) { int numTargets = reader.ReadInt32(); + var targets = new List(numTargets); for (int k = 0; k < numTargets; k++) - info.Targets.Add(reader.ReadInt32()); - - sigInfo.BlockInfos.Add(info); + targets.Add(reader.ReadInt32()); + var numHashes = reader.ReadInt32(); + var hashes = new List(numHashes); + for (int k = 0; k < numHashes; k++) + hashes.Add((BlockElementHash)reader.ReadInt32()); + var block = new BlockSigInfo(hashes, targets); + block.HasFallThrough = reader.ReadBoolean(); + block.EndsInRet = reader.ReadBoolean(); + blocks.Add(block); } - - list.Add(new OpCodeHandlerInfo(typeCode, sigInfo)); + list.Add(new MethodSigInfo(blocks, typeCode)); } return list; } - public static readonly IList[] HandlerInfos = new IList[] { - ReadOpCodeHandlerInfos(CsvmResources.CSVM1_v2), - ReadOpCodeHandlerInfos(CsvmResources.CSVM2_v2), - ReadOpCodeHandlerInfos(CsvmResources.CSVM3_v2), + public static readonly IList[] HandlerInfos = new IList[] { + ReadOpCodeHandlerInfos(CsvmResources.CSVM1), + ReadOpCodeHandlerInfos(CsvmResources.CSVM2), + ReadOpCodeHandlerInfos(CsvmResources.CSVM3), + ReadOpCodeHandlerInfos(CsvmResources.CSVM4), }; - static IList ReadOpCodeHandlerInfos(byte[] data) { + static IList ReadOpCodeHandlerInfos(byte[] data) { return OpCodeHandlerInfos.Read(new BinaryReader(new MemoryStream(data))); } } diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/SigCreator.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/SigCreator.cs new file mode 100644 index 00000000..0206b16f --- /dev/null +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/SigCreator.cs @@ -0,0 +1,593 @@ +/* + Copyright (C) 2011-2013 de4dot@gmail.com + + This file is part of de4dot. + + de4dot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + de4dot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with de4dot. If not, see . +*/ + +using System; +using System.Collections.Generic; +using System.Text; +using dnlib.DotNet; +using dnlib.DotNet.Emit; +using de4dot.blocks; + +namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { + class MethodSigInfo { + public HandlerTypeCode TypeCode { get; set; } + public List BlockSigInfos { get; private set; } + + public MethodSigInfo(List blockSigInfos) { + this.BlockSigInfos = blockSigInfos; + } + + public MethodSigInfo(List blockSigInfos, HandlerTypeCode typeCode) { + this.BlockSigInfos = blockSigInfos; + this.TypeCode = typeCode; + } + + public override string ToString() { + return OpCodeHandlerInfo.GetHandlerName(TypeCode); + } + } + + class BlockSigInfo { + readonly List targets; + + public List Hashes { get; private set; } + public List Targets { + get { return targets; } + } + public bool HasFallThrough { get; set; } + public bool EndsInRet { get; set; } + + public BlockSigInfo() { + this.targets = new List(); + this.Hashes = new List(); + } + + public BlockSigInfo(List hashes, List targets) { + this.Hashes = hashes; + this.targets = targets; + } + } + + enum BlockElementHash : int { + } + + class SigCreator { + const int BASE_INDEX = 0x40000000; + Blocks blocks; + Dictionary objToId = new Dictionary(); + CRC32 hasher = new CRC32(); + + public SigCreator() { + } + + public void AddId(object key, int id) { + if (key != null) + objToId[key] = id; + } + + int? GetId(object key) { + if (key == null) + return null; + + int id; + if (objToId.TryGetValue(key, out id)) + return id; + return null; + } + + public List Create(MethodDef method) { + blocks = new Blocks(method); + var allBlocks = blocks.MethodBlocks.GetAllBlocks(); + + var blockInfos = new List(allBlocks.Count); + foreach (var block in allBlocks) { + var blockInfo = new BlockSigInfo(); + blockInfo.HasFallThrough = block.FallThrough != null; + blockInfo.EndsInRet = block.LastInstr.OpCode.Code == Code.Ret; + blockInfos.Add(blockInfo); + var instrs = block.Instructions; + for (int i = 0; i < instrs.Count; i++) { + var info = CalculateHash(instrs, ref i); + if (info != null) + blockInfo.Hashes.Add(info.Value); + } + } + + for (int i = 0; i < blockInfos.Count; i++) { + var block = allBlocks[i]; + var blockInfo = blockInfos[i]; + + if (block.FallThrough != null) + blockInfo.Targets.Add(allBlocks.IndexOf(block.FallThrough)); + if (block.Targets != null) { + foreach (var target in block.Targets) + blockInfo.Targets.Add(allBlocks.IndexOf(target)); + } + } + + return blockInfos; + } + + BlockElementHash? CalculateHash(IList instrs, ref int index) { + hasher.Initialize(); + var instr = instrs[index]; + switch (instr.OpCode.Code) { + case Code.Beq: + case Code.Beq_S: + return GetHash(BASE_INDEX + 0); + + case Code.Bge: + case Code.Bge_S: + return GetHash(BASE_INDEX + 1); + + case Code.Bge_Un: + case Code.Bge_Un_S: + return GetHash(BASE_INDEX + 2); + + case Code.Bgt: + case Code.Bgt_S: + return GetHash(BASE_INDEX + 3); + + case Code.Bgt_Un: + case Code.Bgt_Un_S: + return GetHash(BASE_INDEX + 4); + + case Code.Ble: + case Code.Ble_S: + return GetHash(BASE_INDEX + 5); + + case Code.Ble_Un: + case Code.Ble_Un_S: + return GetHash(BASE_INDEX + 6); + + case Code.Blt: + case Code.Blt_S: + return GetHash(BASE_INDEX + 7); + + case Code.Blt_Un: + case Code.Blt_Un_S: + return GetHash(BASE_INDEX + 8); + + case Code.Bne_Un: + case Code.Bne_Un_S: + return GetHash(BASE_INDEX + 9); + + case Code.Brfalse: + case Code.Brfalse_S: + return GetHash(BASE_INDEX + 10); + + case Code.Brtrue: + case Code.Brtrue_S: + return GetHash(BASE_INDEX + 11); + + case Code.Switch: + return GetHash(BASE_INDEX + 12); + + case Code.Ceq: + return GetHash(BASE_INDEX + 13); + + case Code.Cgt: + return GetHash(BASE_INDEX + 14); + + case Code.Cgt_Un: + return GetHash(BASE_INDEX + 15); + + case Code.Clt: + return GetHash(BASE_INDEX + 16); + + case Code.Clt_Un: + return GetHash(BASE_INDEX + 17); + + case Code.Ldc_I4: + case Code.Ldc_I4_0: + case Code.Ldc_I4_1: + case Code.Ldc_I4_2: + case Code.Ldc_I4_3: + case Code.Ldc_I4_4: + case Code.Ldc_I4_5: + case Code.Ldc_I4_6: + case Code.Ldc_I4_7: + case Code.Ldc_I4_8: + case Code.Ldc_I4_M1: + case Code.Ldc_I4_S: + return GetHash(instr.GetLdcI4Value()); + + case Code.Ldstr: + return GetHash(instr.Operand as string); + + case Code.Rethrow: + return GetHash(BASE_INDEX + 18); + + case Code.Throw: + return GetHash(BASE_INDEX + 19); + + case Code.Call: + case Code.Callvirt: + Hash(instr.Operand); + return (BlockElementHash)hasher.GetHash(); + + case Code.Ldfld: + var field = instr.Operand as FieldDef; + if (!IsTypeField(field)) + return null; + if (index + 1 >= instrs.Count || !instrs[index + 1].IsLdcI4()) + return null; + index++; + return GetHash(GetFieldId(field)); + + default: + break; + } + return null; + } + + bool IsTypeField(FieldDef fd) { + return fd != null && fd.DeclaringType == blocks.Method.DeclaringType; + } + + static int GetFieldId(FieldDef fd) { + if (fd == null) + return int.MinValue; + var fieldType = fd.FieldSig.GetFieldType(); + if (fieldType == null) + return int.MinValue + 1; + + int result = BASE_INDEX + 0x1000; + for (int i = 0; i < 100; i++) { + result += (int)fieldType.ElementType; + if (fieldType.Next == null) + break; + result += 0x100; + fieldType = fieldType.Next; + } + + var td = fieldType.TryGetTypeDef(); + if (td != null && td.IsEnum) + return result + 0x10000000; + return result; + } + + void Hash(object op) { + var md = op as MethodDef; + if (md != null) { + Hash(md); + return; + } + + var mr = op as MemberRef; + if (mr != null) { + Hash(mr); + return; + } + + var td = op as TypeDef; + if (td != null) { + Hash(td); + return; + } + + var tr = op as TypeRef; + if (tr != null) { + Hash(tr); + return; + } + + var ts = op as TypeSpec; + if (ts != null) { + Hash(ts); + return; + } + + var fsig = op as FieldSig; + if (fsig != null) { + Hash(fsig); + return; + } + + var msig = op as MethodSig; + if (msig != null) { + Hash(msig); + return; + } + + var gsig = op as GenericInstMethodSig; + if (gsig != null) { + Hash(gsig); + return; + } + + var asmRef = op as AssemblyRef; + if (asmRef != null) { + Hash(asmRef); + return; + } + + var tsig = op as TypeSig; + if (tsig != null) { + Hash(tsig); + return; + } + + return; + } + + void Hash(TypeSig sig) { + Hash(sig, 0); + } + + void Hash(TypeSig sig, int level) { + if (sig == null) + return; + if (level++ > 20) + return; + + hasher.Hash((byte)0x41); + var etype = sig.GetElementType(); + hasher.Hash((byte)etype); + switch (etype) { + case ElementType.Ptr: + case ElementType.ByRef: + case ElementType.SZArray: + case ElementType.Pinned: + Hash(sig.Next, level); + break; + + case ElementType.Array: + var arySig = (ArraySig)sig; + hasher.Hash(arySig.Rank); + hasher.Hash(arySig.Sizes.Count); + hasher.Hash(arySig.LowerBounds.Count); + Hash(sig.Next, level); + break; + + case ElementType.CModReqd: + case ElementType.CModOpt: + Hash(((ModifierSig)sig).Modifier); + Hash(sig.Next, level); + break; + + case ElementType.ValueArray: + hasher.Hash(((ValueArraySig)sig).Size); + Hash(sig.Next, level); + break; + + case ElementType.Module: + hasher.Hash(((ModuleSig)sig).Index); + Hash(sig.Next, level); + break; + + case ElementType.GenericInst: + var gis = (GenericInstSig)sig; + Hash(gis.GenericType, level); + foreach (var ga in gis.GenericArguments) + Hash(ga, level); + Hash(sig.Next, level); + break; + + case ElementType.FnPtr: + Hash(((FnPtrSig)sig).Signature); + break; + + case ElementType.Var: + case ElementType.MVar: + hasher.Hash(((GenericSig)sig).Number); + break; + + case ElementType.ValueType: + case ElementType.Class: + Hash(((TypeDefOrRefSig)sig).TypeDefOrRef); + break; + + case ElementType.End: + case ElementType.Void: + case ElementType.Boolean: + case ElementType.Char: + case ElementType.I1: + case ElementType.U1: + case ElementType.I2: + case ElementType.U2: + case ElementType.I4: + case ElementType.U4: + case ElementType.I8: + case ElementType.U8: + case ElementType.R4: + case ElementType.R8: + case ElementType.String: + case ElementType.TypedByRef: + case ElementType.I: + case ElementType.U: + case ElementType.R: + case ElementType.Object: + case ElementType.Internal: + case ElementType.Sentinel: + default: + break; + } + } + + void Hash(MethodDef md) { + if (md == null) + return; + + var attrMask1 = MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask | + MethodImplAttributes.ForwardRef | MethodImplAttributes.PreserveSig | + MethodImplAttributes.InternalCall; + hasher.Hash((ushort)(md == null ? 0 : md.ImplAttributes & attrMask1)); + var attrMask2 = MethodAttributes.Static | MethodAttributes.Virtual | + MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask | + MethodAttributes.CheckAccessOnOverride | MethodAttributes.Abstract | + MethodAttributes.SpecialName | MethodAttributes.PinvokeImpl | + MethodAttributes.UnmanagedExport | MethodAttributes.RTSpecialName; + hasher.Hash((ushort)(md.Attributes & attrMask2)); + Hash(md.Signature); + hasher.Hash(md.ParamDefs.Count); + hasher.Hash(md.GenericParameters.Count); + hasher.Hash(md.HasImplMap ? 1 : 0); + + var id = GetId(md); + if (id != null) + hasher.Hash(id.Value); + } + + void Hash(MemberRef mr) { + if (mr == null) + return; + + Hash(mr.Class); + if (IsFromNonObfuscatedAssembly(mr.Class)) + Hash(mr.Name); + Hash(mr.Signature); + } + + void Hash(TypeDef td) { + if (td == null) + return; + + Hash(td.BaseType); + var attrMask = TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask | + TypeAttributes.Abstract | TypeAttributes.SpecialName | + TypeAttributes.Import | TypeAttributes.WindowsRuntime | + TypeAttributes.StringFormatMask | TypeAttributes.RTSpecialName; + hasher.Hash((uint)(td.Attributes & attrMask)); + hasher.Hash(td.GenericParameters.Count); + hasher.Hash(td.Interfaces.Count); + foreach (var iface in td.Interfaces) + Hash(iface.Interface); + var id = GetId(td); + if (id != null) + hasher.Hash(id.Value); + } + + void Hash(TypeRef tr) { + if (tr == null) + return; + + Hash(tr.ResolutionScope); + if (IsFromNonObfuscatedAssembly(tr)) { + Hash(tr.Namespace); + Hash(tr.Name); + } + } + + void Hash(TypeSpec ts) { + if (ts == null) + return; + + Hash(ts.TypeSig); + } + + void Hash(FieldSig sig) { + if (sig == null) + return; + + hasher.Hash((byte)sig.GetCallingConvention()); + Hash(sig.GetFieldType()); + } + + void Hash(MethodSig sig) { + if (sig == null) + return; + + hasher.Hash((byte)sig.GetCallingConvention()); + Hash(sig.GetRetType()); + foreach (var p in sig.GetParams()) + Hash(p); + hasher.Hash(sig.GetParamCount()); + if (sig.GetParamsAfterSentinel() != null) { + foreach (var p in sig.GetParamsAfterSentinel()) + Hash(p); + } + } + + void Hash(GenericInstMethodSig sig) { + if (sig == null) + return; + + hasher.Hash((byte)sig.GetCallingConvention()); + foreach (var ga in sig.GetGenericArguments()) + Hash(ga); + } + + void Hash(AssemblyRef asmRef) { + if (asmRef == null) + return; + + bool canWriteAsm = IsNonObfuscatedAssembly(asmRef); + hasher.Hash(canWriteAsm ? 1 : 0); + if (canWriteAsm) { + bool hasPk = !PublicKeyBase.IsNullOrEmpty2(asmRef.PublicKeyOrToken); + if (hasPk) + hasher.Hash(PublicKeyBase.ToPublicKeyToken(asmRef.PublicKeyOrToken).Data); + Hash(asmRef.Name); + Hash(asmRef.Culture); + } + } + + void Hash(string s) { + if (s != null) + hasher.Hash(Encoding.UTF8.GetBytes(s)); + } + + BlockElementHash GetHash(int val) { + hasher.Hash(val); + return (BlockElementHash)hasher.GetHash(); + } + + BlockElementHash GetHash(string s) { + Hash(s); + return (BlockElementHash)hasher.GetHash(); + } + + static bool IsFromNonObfuscatedAssembly(IMemberRefParent mrp) { + return IsFromNonObfuscatedAssembly(mrp as TypeRef); + } + + static bool IsFromNonObfuscatedAssembly(TypeRef tr) { + if (tr == null) + return false; + + for (int i = 0; i < 100; i++) { + var asmRef = tr.ResolutionScope as AssemblyRef; + if (asmRef != null) + return IsNonObfuscatedAssembly(asmRef); + + var tr2 = tr.ResolutionScope as TypeRef; + if (tr2 != null) { + tr = tr2; + continue; + } + + break; + } + + return false; + } + + static bool IsNonObfuscatedAssembly(IAssembly asm) { + if (asm == null) + return false; + + // The only external asm refs it uses... + if (asm.Name != "mscorlib" && asm.Name != "System") + return false; + + return true; + } + } +} diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCode.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCode.cs index bb1fdd85..10bc1beb 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCode.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCode.cs @@ -22,23 +22,15 @@ using System.Text; namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { class VmOpCode { - public List OpCodeHandlerInfos { get; private set; } + public List HandlerTypeCodes { get; private set; } - public VmOpCode(List opCodeHandlerInfos) { - this.OpCodeHandlerInfos = new List(opCodeHandlerInfos.Count); - this.OpCodeHandlerInfos.AddRange(opCodeHandlerInfos); + public VmOpCode(List opCodeHandlerInfos) { + this.HandlerTypeCodes = new List(opCodeHandlerInfos.Count); + this.HandlerTypeCodes.AddRange(opCodeHandlerInfos); } public override string ToString() { - if (OpCodeHandlerInfos.Count == 0) - return ""; - var sb = new StringBuilder(); - foreach (var handler in OpCodeHandlerInfos) { - if (sb.Length != 0) - sb.Append(", "); - sb.Append(handler.Name); - } - return sb.ToString(); + return OpCodeHandlerInfo.GetCompositeName(HandlerTypeCodes); } } } diff --git a/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCodeHandlerDetector.cs b/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCodeHandlerDetector.cs index ea234c72..c5e56d55 100644 --- a/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCodeHandlerDetector.cs +++ b/de4dot.code/deobfuscators/Agile_NET/vm/v2/VmOpCodeHandlerDetector.cs @@ -81,7 +81,6 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { return; deobfuscator = new MyDeobfuscator(module); - var csvmInfo = new CsvmInfo(module); csvmInfo.Initialize(); var vmHandlerTypes = FindVmHandlerTypes(); @@ -90,9 +89,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { var composites = CreateCompositeOpCodeHandlers(csvmInfo, vmHandlerTypes); foreach (var handlerInfos in OpCodeHandlerInfos.HandlerInfos) { - var otherHandlers = CreateOtherHandlers(csvmInfo, handlerInfos); - - if (!DetectCompositeHandlers(composites, otherHandlers)) + if (!DetectCompositeHandlers(composites, handlerInfos)) continue; vmOpCodes = CreateVmOpCodes(composites); @@ -105,12 +102,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { static List CreateVmOpCodes(IList composites) { var list = new List(composites.Count); foreach (var composite in composites) - list.Add(new VmOpCode(composite.OpCodeHandlerInfos)); + list.Add(new VmOpCode(composite.TypeCodes)); return list; } - bool DetectCompositeHandlers(IEnumerable composites, List otherHandlers) { - var detector = new CompositeHandlerDetector(otherHandlers); + bool DetectCompositeHandlers(IEnumerable composites, IList handlerInfos) { + var detector = new CompositeHandlerDetector(handlerInfos); foreach (var composite in composites) { if (!detector.FindHandlers(composite)) return false; @@ -128,15 +125,18 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { List CreateCompositeOpCodeHandlers(CsvmInfo csvmInfo, List handlers) { var list = new List(handlers.Count); - foreach (var handler in handlers) { - var execHandler = new HandlerMethod(GetExecMethod(handler)); - list.Add(new CompositeOpCodeHandler(handler, execHandler)); - } + var sigCreator = CreateSigCreator(csvmInfo); + foreach (var handler in handlers) + list.Add(new CompositeOpCodeHandler(sigCreator.Create(GetExecMethod(handler)))); return list; } MethodDef GetExecMethod(TypeDef type) { + return GetExecMethod(deobfuscator, type); + } + + static MethodDef GetExecMethod(MyDeobfuscator deobfuscator, TypeDef type) { MethodDef readMethod, execMethod; GetReadAndExecMethods(type, out readMethod, out execMethod); deobfuscator.Deobfuscate(execMethod); @@ -144,8 +144,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { return execMethod; } - static MethodSigInfoCreator CreateMethodSigInfoCreator(CsvmInfo csvmInfo) { - var creator = new MethodSigInfoCreator(); + static SigCreator CreateSigCreator(CsvmInfo csvmInfo) { + var creator = new SigCreator(); creator.AddId(csvmInfo.LogicalOpShrUn, 1); creator.AddId(csvmInfo.LogicalOpShl, 2); @@ -183,9 +183,20 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { creator.AddId(csvmInfo.LocalsGet, 30); creator.AddId(csvmInfo.LocalsSet, 31); + AddTypeId(creator, csvmInfo.LogicalOpShrUn, 32); + AddTypeId(creator, csvmInfo.CompareLt, 33); + AddTypeId(creator, csvmInfo.ArithmeticSubOvfUn, 34); + AddTypeId(creator, csvmInfo.UnaryNot, 35); + AddTypeId(creator, csvmInfo.ArgsGet, 36); + return creator; } + static void AddTypeId(SigCreator creator, MethodDef method, int id) { + if (method != null) + creator.AddId(method.DeclaringType, id); + } + static void GetReadAndExecMethods(TypeDef handler, out MethodDef readMethod, out MethodDef execMethod) { readMethod = execMethod = null; foreach (var method in handler.Methods) { @@ -270,28 +281,5 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 { return list; } - - List CreateOtherHandlers(CsvmInfo csvmInfo, IList handlerInfos) { - var list = new List(NUM_HANDLERS); - - foreach (var type in GetVmHandlerTypes(csvmInfo.VmHandlerBaseType)) { - if (list.Count == NUM_HANDLERS) - break; - - var execHandler = new PrimitiveHandlerMethod(GetExecMethod(type)); - execHandler.Sig = CreateMethodSigInfoCreator(csvmInfo).Create(execHandler.Blocks); - - var finder = new MethodFinder(handlerInfos, execHandler); - var handler = finder.FindHandler(); - if (handler == null) - continue; - - list.Add(handler); - } - - list.Sort((a, b) => a.OpCodeHandlerInfo.Name.ToUpperInvariant().CompareTo(b.OpCodeHandlerInfo.Name.ToUpperInvariant())); - - return list; - } } } diff --git a/de4dot.mdecrypt/DynamicMethodsDecrypter.cs b/de4dot.mdecrypt/DynamicMethodsDecrypter.cs index 9d40208c..8e41c1b6 100644 --- a/de4dot.mdecrypt/DynamicMethodsDecrypter.cs +++ b/de4dot.mdecrypt/DynamicMethodsDecrypter.cs @@ -581,6 +581,23 @@ namespace de4dot.mdecrypt { return hModule; } + class PatchInfo { + public int RVA; + public byte[] Data; + public byte[] Orig; + + public PatchInfo(int rva, byte[] data, byte[] orig) { + this.RVA = rva; + this.Data = data; + this.Orig = orig; + } + } + static readonly PatchInfo[] patches = new PatchInfo[] { + 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 }), + }; + static unsafe bool PatchCM(IntPtr addr, IntPtr origValue, IntPtr newValue) { var baseAddr = GetModuleHandle(addr); IntPtr patchAddr; @@ -590,6 +607,45 @@ namespace de4dot.mdecrypt { return false; *(IntPtr*)patchAddr = newValue; + PatchRT(baseAddr); + return true; + } + + [HandleProcessCorruptedStateExceptions, SecurityCritical] // Req'd on .NET 4.0 + static unsafe bool PatchRT(IntPtr baseAddr) { + foreach (var info in patches) { + try { + var addr = new IntPtr(baseAddr.ToInt64() + info.RVA); + + var data = new byte[info.Orig.Length]; + Marshal.Copy(addr, data, 0, data.Length); + if (!Equals(data, info.Orig)) + continue; + + uint oldProtect; + if (!VirtualProtect(addr, info.Data.Length, PAGE_EXECUTE_READWRITE, out oldProtect)) + throw new ApplicationException("Could not enable write access"); + Marshal.Copy(info.Data, 0, addr, info.Data.Length); + VirtualProtect(addr, info.Data.Length, oldProtect, out oldProtect); + return true; + } + catch { + } + } + return false; + } + + static bool Equals(byte[] a, byte[] b) { + if (a == b) + return true; + if (a == null || b == null) + return false; + if (a.Length != b.Length) + return false; + for (int i = 0; i < a.Length; i++) { + if (a[i] != b[i]) + return false; + } return true; }