From eebb831c4b09952f76222edcdfce2ea9139329cc Mon Sep 17 00:00:00 2001 From: de4dot Date: Tue, 24 Apr 2012 11:33:17 +0200 Subject: [PATCH] Update CSVM opcode handler detection code --- .../CliSecure/vm/OpCodeHandler.cs | 17 ++- .../CliSecure/vm/UnknownHandlerInfo.cs | 25 +++- .../CliSecure/vm/VmOpCodeHandlerDetector.cs | 110 +++++++++++++++++- 3 files changed, 143 insertions(+), 9 deletions(-) diff --git a/de4dot.code/deobfuscators/CliSecure/vm/OpCodeHandler.cs b/de4dot.code/deobfuscators/CliSecure/vm/OpCodeHandler.cs index 71750c3e..3ce34f01 100644 --- a/de4dot.code/deobfuscators/CliSecure/vm/OpCodeHandler.cs +++ b/de4dot.code/deobfuscators/CliSecure/vm/OpCodeHandler.cs @@ -45,6 +45,8 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { return false; if (!compare(sigInfo.ExecuteMethodThrows, info.ExecuteMethodThrows)) return false; + if (!compare(sigInfo.ExecuteMethodPops, info.ExecuteMethodPops)) + return false; if (!info.hasSameFieldTypes(sigInfo.RequiredFieldTypes)) return false; if (sigInfo.ExecuteMethodLocals != null && !new LocalTypes(info.ExecuteMethod).all(sigInfo.ExecuteMethodLocals)) @@ -758,6 +760,7 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { static readonly OpCodeHandlerSigInfo sigInfo = new OpCodeHandlerSigInfo { RequiredFieldTypes = new object[0], ExecuteMethodThrows = 1, + ExecuteMethodPops = 1, NumStaticMethods = 0, NumInstanceMethods = 0, NumVirtualMethods = 2, @@ -773,7 +776,7 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { } protected override bool detectInternal(UnknownHandlerInfo info) { - return info.ExecuteMethod.Body.Variables.Count == 2; + return true; } public override Instruction read(BinaryReader reader) { @@ -1023,8 +1026,13 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { } static bool isEmptyMethod(MethodDefinition method) { - return method.Body.Instructions.Count == 1 && - method.Body.Instructions[0].OpCode.Code == Code.Ret; + foreach (var instr in method.Body.Instructions) { + if (instr.OpCode.Code == Code.Ret) + return true; + if (instr.OpCode.Code != Code.Nop) + break; + } + return false; } public override Instruction read(BinaryReader reader) { @@ -1136,6 +1144,7 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { static readonly OpCodeHandlerSigInfo sigInfo = new OpCodeHandlerSigInfo { RequiredFieldTypes = new object[0], ExecuteMethodThrows = 1, + ExecuteMethodPops = 2, NumStaticMethods = 0, NumInstanceMethods = 0, NumVirtualMethods = 2, @@ -1151,7 +1160,7 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { } protected override bool detectInternal(UnknownHandlerInfo info) { - return info.ExecuteMethod.Body.Variables.Count == 3; + return true; } public override Instruction read(BinaryReader reader) { diff --git a/de4dot.code/deobfuscators/CliSecure/vm/UnknownHandlerInfo.cs b/de4dot.code/deobfuscators/CliSecure/vm/UnknownHandlerInfo.cs index a8592266..3a7b43f4 100644 --- a/de4dot.code/deobfuscators/CliSecure/vm/UnknownHandlerInfo.cs +++ b/de4dot.code/deobfuscators/CliSecure/vm/UnknownHandlerInfo.cs @@ -25,10 +25,11 @@ using de4dot.blocks; namespace de4dot.code.deobfuscators.CliSecure.vm { class UnknownHandlerInfo { TypeDefinition type; + CsvmInfo csvmInfo; FieldsInfo fieldsInfo; MethodDefinition readMethod, executeMethod; int numStaticMethods, numInstanceMethods, numVirtualMethods, numCtors; - int executeMethodThrows; + int executeMethodThrows, executeMethodPops; public MethodDefinition ReadMethod { get { return readMethod; } @@ -54,16 +55,22 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { get { return executeMethodThrows; } } + public int ExecuteMethodPops { + get { return executeMethodPops; } + } + public int NumCtors { get { return numCtors; } } - public UnknownHandlerInfo(TypeDefinition type) { + public UnknownHandlerInfo(TypeDefinition type, CsvmInfo csvmInfo) { this.type = type; + this.csvmInfo = csvmInfo; fieldsInfo = new FieldsInfo(type); countMethods(); findOverrideMethods(); executeMethodThrows = countThrows(executeMethod); + executeMethodPops = countPops(executeMethod); } void countMethods() { @@ -112,6 +119,20 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { return count; } + int countPops(MethodDefinition method) { + int count = 0; + foreach (var instr in method.Body.Instructions) { + if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt) + continue; + var calledMethod = instr.Operand as MethodReference; + if (!MemberReferenceHelper.compareMethodReferenceAndDeclaringType(calledMethod, csvmInfo.PopMethod)) + continue; + + count++; + } + return count; + } + public bool hasSameFieldTypes(object[] fieldTypes) { return new FieldsInfo(fieldTypes).isSame(fieldsInfo); } diff --git a/de4dot.code/deobfuscators/CliSecure/vm/VmOpCodeHandlerDetector.cs b/de4dot.code/deobfuscators/CliSecure/vm/VmOpCodeHandlerDetector.cs index 3e8c23c4..6542e2f9 100644 --- a/de4dot.code/deobfuscators/CliSecure/vm/VmOpCodeHandlerDetector.cs +++ b/de4dot.code/deobfuscators/CliSecure/vm/VmOpCodeHandlerDetector.cs @@ -29,12 +29,20 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { public object[] RequiredFieldTypes { get; set; } public string[] ExecuteMethodLocals { get; set; } public int? ExecuteMethodThrows { get; set; } + public int? ExecuteMethodPops { get; set; } public int? NumStaticMethods { get; set; } public int? NumInstanceMethods { get; set; } public int? NumVirtualMethods { get; set; } public int? NumCtors { get; set; } } + class CsvmInfo { + public TypeDefinition StackValue { get; set; } + public TypeDefinition Stack { get; set; } + public MethodDefinition PopMethod { get; set; } + public MethodDefinition PeekMethod { get; set; } + } + class VmOpCodeHandlerDetector { ModuleDefinition module; static readonly OpCodeHandler[] opCodeHandlerDetectors = new OpCodeHandler[] { @@ -87,7 +95,103 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { if (vmHandlerTypes == null) throw new ApplicationException("Could not find CSVM opcode handler types"); - detectHandlers(vmHandlerTypes); + var csvmInfo = new CsvmInfo(); + csvmInfo.StackValue = findStackValueType(); + csvmInfo.Stack = findStackType(csvmInfo.StackValue); + initStackTypeMethods(csvmInfo); + + detectHandlers(vmHandlerTypes, csvmInfo); + } + + TypeDefinition findStackValueType() { + foreach (var type in module.Types) { + if (isStackType(type)) + return type; + } + return null; + } + + static bool isStackType(TypeDefinition type) { + if (type.Fields.Count != 2) + return false; + + int enumTypes = 0; + int objectTypes = 0; + foreach (var field in type.Fields) { + var fieldType = field.FieldType as TypeDefinition; + if (fieldType != null && fieldType.IsEnum) + enumTypes++; + if (field.FieldType.FullName == "System.Object") + objectTypes++; + } + if (enumTypes != 1 || objectTypes != 1) + return false; + + return true; + } + + TypeDefinition findStackType(TypeDefinition stackValueType) { + foreach (var type in module.Types) { + if (isStackType(type, stackValueType)) + return type; + } + return null; + } + + bool isStackType(TypeDefinition type, TypeDefinition stackValueType) { + if (type.Interfaces.Count != 2) + return false; + if (!implementsInterface(type, "System.Collections.ICollection")) + return false; + if (!implementsInterface(type, "System.Collections.IEnumerable")) + return false; + if (type.NestedTypes.Count == 0) + return false; + + int stackValueTypes = 0; + int int32Types = 0; + int objectTypes = 0; + foreach (var field in type.Fields) { + if (field.IsLiteral) + continue; + if (field.FieldType is ArrayType && ((ArrayType)field.FieldType).ElementType == stackValueType) + stackValueTypes++; + if (field.FieldType.FullName == "System.Int32") + int32Types++; + if (field.FieldType.FullName == "System.Object") + objectTypes++; + } + if (stackValueTypes != 2 || int32Types != 2 || objectTypes != 1) + return false; + + return true; + } + + static bool implementsInterface(TypeDefinition type, string ifaceName) { + foreach (var iface in type.Interfaces) { + if (iface.FullName == ifaceName) + return true; + } + return false; + } + + void initStackTypeMethods(CsvmInfo csvmInfo) { + foreach (var method in csvmInfo.Stack.Methods) { + if (method.Parameters.Count == 0 && method.MethodReturnType.ReturnType == csvmInfo.StackValue) { + if (hasAdd(method)) + csvmInfo.PopMethod = method; + else + csvmInfo.PeekMethod = method; + } + } + } + + static bool hasAdd(MethodDefinition method) { + foreach (var instr in method.Body.Instructions) { + if (instr.OpCode.Code == Code.Add) + return true; + } + return false; } List findVmHandlerTypes() { @@ -132,11 +236,11 @@ namespace de4dot.code.deobfuscators.CliSecure.vm { return list; } - void detectHandlers(List handlerTypes) { + void detectHandlers(List handlerTypes, CsvmInfo csvmInfo) { opCodeHandlers = new List(); var detected = new List(); foreach (var handlerType in handlerTypes) { - var info = new UnknownHandlerInfo(handlerType); + var info = new UnknownHandlerInfo(handlerType, csvmInfo); detected.Clear(); foreach (var opCodeHandler in opCodeHandlerDetectors) { if (opCodeHandler.detect(info))