Update CSVM opcode handler detection code
This commit is contained in:
parent
88d7607d10
commit
eebb831c4b
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Reference in New Issue
Block a user