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;
|
return false;
|
||||||
if (!compare(sigInfo.ExecuteMethodThrows, info.ExecuteMethodThrows))
|
if (!compare(sigInfo.ExecuteMethodThrows, info.ExecuteMethodThrows))
|
||||||
return false;
|
return false;
|
||||||
|
if (!compare(sigInfo.ExecuteMethodPops, info.ExecuteMethodPops))
|
||||||
|
return false;
|
||||||
if (!info.hasSameFieldTypes(sigInfo.RequiredFieldTypes))
|
if (!info.hasSameFieldTypes(sigInfo.RequiredFieldTypes))
|
||||||
return false;
|
return false;
|
||||||
if (sigInfo.ExecuteMethodLocals != null && !new LocalTypes(info.ExecuteMethod).all(sigInfo.ExecuteMethodLocals))
|
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 {
|
static readonly OpCodeHandlerSigInfo sigInfo = new OpCodeHandlerSigInfo {
|
||||||
RequiredFieldTypes = new object[0],
|
RequiredFieldTypes = new object[0],
|
||||||
ExecuteMethodThrows = 1,
|
ExecuteMethodThrows = 1,
|
||||||
|
ExecuteMethodPops = 1,
|
||||||
NumStaticMethods = 0,
|
NumStaticMethods = 0,
|
||||||
NumInstanceMethods = 0,
|
NumInstanceMethods = 0,
|
||||||
NumVirtualMethods = 2,
|
NumVirtualMethods = 2,
|
||||||
|
@ -773,7 +776,7 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool detectInternal(UnknownHandlerInfo info) {
|
protected override bool detectInternal(UnknownHandlerInfo info) {
|
||||||
return info.ExecuteMethod.Body.Variables.Count == 2;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Instruction read(BinaryReader reader) {
|
public override Instruction read(BinaryReader reader) {
|
||||||
|
@ -1023,8 +1026,13 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isEmptyMethod(MethodDefinition method) {
|
static bool isEmptyMethod(MethodDefinition method) {
|
||||||
return method.Body.Instructions.Count == 1 &&
|
foreach (var instr in method.Body.Instructions) {
|
||||||
method.Body.Instructions[0].OpCode.Code == Code.Ret;
|
if (instr.OpCode.Code == Code.Ret)
|
||||||
|
return true;
|
||||||
|
if (instr.OpCode.Code != Code.Nop)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Instruction read(BinaryReader reader) {
|
public override Instruction read(BinaryReader reader) {
|
||||||
|
@ -1136,6 +1144,7 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
static readonly OpCodeHandlerSigInfo sigInfo = new OpCodeHandlerSigInfo {
|
static readonly OpCodeHandlerSigInfo sigInfo = new OpCodeHandlerSigInfo {
|
||||||
RequiredFieldTypes = new object[0],
|
RequiredFieldTypes = new object[0],
|
||||||
ExecuteMethodThrows = 1,
|
ExecuteMethodThrows = 1,
|
||||||
|
ExecuteMethodPops = 2,
|
||||||
NumStaticMethods = 0,
|
NumStaticMethods = 0,
|
||||||
NumInstanceMethods = 0,
|
NumInstanceMethods = 0,
|
||||||
NumVirtualMethods = 2,
|
NumVirtualMethods = 2,
|
||||||
|
@ -1151,7 +1160,7 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool detectInternal(UnknownHandlerInfo info) {
|
protected override bool detectInternal(UnknownHandlerInfo info) {
|
||||||
return info.ExecuteMethod.Body.Variables.Count == 3;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Instruction read(BinaryReader reader) {
|
public override Instruction read(BinaryReader reader) {
|
||||||
|
|
|
@ -25,10 +25,11 @@ using de4dot.blocks;
|
||||||
namespace de4dot.code.deobfuscators.CliSecure.vm {
|
namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
class UnknownHandlerInfo {
|
class UnknownHandlerInfo {
|
||||||
TypeDefinition type;
|
TypeDefinition type;
|
||||||
|
CsvmInfo csvmInfo;
|
||||||
FieldsInfo fieldsInfo;
|
FieldsInfo fieldsInfo;
|
||||||
MethodDefinition readMethod, executeMethod;
|
MethodDefinition readMethod, executeMethod;
|
||||||
int numStaticMethods, numInstanceMethods, numVirtualMethods, numCtors;
|
int numStaticMethods, numInstanceMethods, numVirtualMethods, numCtors;
|
||||||
int executeMethodThrows;
|
int executeMethodThrows, executeMethodPops;
|
||||||
|
|
||||||
public MethodDefinition ReadMethod {
|
public MethodDefinition ReadMethod {
|
||||||
get { return readMethod; }
|
get { return readMethod; }
|
||||||
|
@ -54,16 +55,22 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
get { return executeMethodThrows; }
|
get { return executeMethodThrows; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int ExecuteMethodPops {
|
||||||
|
get { return executeMethodPops; }
|
||||||
|
}
|
||||||
|
|
||||||
public int NumCtors {
|
public int NumCtors {
|
||||||
get { return numCtors; }
|
get { return numCtors; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnknownHandlerInfo(TypeDefinition type) {
|
public UnknownHandlerInfo(TypeDefinition type, CsvmInfo csvmInfo) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.csvmInfo = csvmInfo;
|
||||||
fieldsInfo = new FieldsInfo(type);
|
fieldsInfo = new FieldsInfo(type);
|
||||||
countMethods();
|
countMethods();
|
||||||
findOverrideMethods();
|
findOverrideMethods();
|
||||||
executeMethodThrows = countThrows(executeMethod);
|
executeMethodThrows = countThrows(executeMethod);
|
||||||
|
executeMethodPops = countPops(executeMethod);
|
||||||
}
|
}
|
||||||
|
|
||||||
void countMethods() {
|
void countMethods() {
|
||||||
|
@ -112,6 +119,20 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
return count;
|
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) {
|
public bool hasSameFieldTypes(object[] fieldTypes) {
|
||||||
return new FieldsInfo(fieldTypes).isSame(fieldsInfo);
|
return new FieldsInfo(fieldTypes).isSame(fieldsInfo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,20 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
public object[] RequiredFieldTypes { get; set; }
|
public object[] RequiredFieldTypes { get; set; }
|
||||||
public string[] ExecuteMethodLocals { get; set; }
|
public string[] ExecuteMethodLocals { get; set; }
|
||||||
public int? ExecuteMethodThrows { get; set; }
|
public int? ExecuteMethodThrows { get; set; }
|
||||||
|
public int? ExecuteMethodPops { get; set; }
|
||||||
public int? NumStaticMethods { get; set; }
|
public int? NumStaticMethods { get; set; }
|
||||||
public int? NumInstanceMethods { get; set; }
|
public int? NumInstanceMethods { get; set; }
|
||||||
public int? NumVirtualMethods { get; set; }
|
public int? NumVirtualMethods { get; set; }
|
||||||
public int? NumCtors { 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 {
|
class VmOpCodeHandlerDetector {
|
||||||
ModuleDefinition module;
|
ModuleDefinition module;
|
||||||
static readonly OpCodeHandler[] opCodeHandlerDetectors = new OpCodeHandler[] {
|
static readonly OpCodeHandler[] opCodeHandlerDetectors = new OpCodeHandler[] {
|
||||||
|
@ -87,7 +95,103 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
if (vmHandlerTypes == null)
|
if (vmHandlerTypes == null)
|
||||||
throw new ApplicationException("Could not find CSVM opcode handler types");
|
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() {
|
List<TypeDefinition> findVmHandlerTypes() {
|
||||||
|
@ -132,11 +236,11 @@ namespace de4dot.code.deobfuscators.CliSecure.vm {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void detectHandlers(List<TypeDefinition> handlerTypes) {
|
void detectHandlers(List<TypeDefinition> handlerTypes, CsvmInfo csvmInfo) {
|
||||||
opCodeHandlers = new List<OpCodeHandler>();
|
opCodeHandlers = new List<OpCodeHandler>();
|
||||||
var detected = new List<OpCodeHandler>();
|
var detected = new List<OpCodeHandler>();
|
||||||
foreach (var handlerType in handlerTypes) {
|
foreach (var handlerType in handlerTypes) {
|
||||||
var info = new UnknownHandlerInfo(handlerType);
|
var info = new UnknownHandlerInfo(handlerType, csvmInfo);
|
||||||
detected.Clear();
|
detected.Clear();
|
||||||
foreach (var opCodeHandler in opCodeHandlerDetectors) {
|
foreach (var opCodeHandler in opCodeHandlerDetectors) {
|
||||||
if (opCodeHandler.detect(info))
|
if (opCodeHandler.detect(info))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user