Update CSVM opcode handler detection code

This commit is contained in:
de4dot 2012-04-24 11:33:17 +02:00
parent 88d7607d10
commit eebb831c4b
3 changed files with 143 additions and 9 deletions

View File

@ -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) {

View File

@ -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);
}

View File

@ -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<TypeDefinition> findVmHandlerTypes() {
@ -132,11 +236,11 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
return list;
}
void detectHandlers(List<TypeDefinition> handlerTypes) {
void detectHandlers(List<TypeDefinition> handlerTypes, CsvmInfo csvmInfo) {
opCodeHandlers = new List<OpCodeHandler>();
var detected = new List<OpCodeHandler>();
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))