2012-04-06 00:06:56 +08:00
|
|
|
|
/*
|
2013-01-02 00:03:16 +08:00
|
|
|
|
Copyright (C) 2011-2013 de4dot@gmail.com
|
2012-04-06 00:06:56 +08:00
|
|
|
|
|
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2012-12-20 09:06:09 +08:00
|
|
|
|
using dnlib.DotNet;
|
|
|
|
|
using dnlib.DotNet.Emit;
|
2012-04-06 00:06:56 +08:00
|
|
|
|
using de4dot.blocks;
|
|
|
|
|
using de4dot.blocks.cflow;
|
|
|
|
|
|
2013-10-30 01:11:31 +08:00
|
|
|
|
namespace de4dot.code.deobfuscators.Agile_NET.vm.v1 {
|
2012-04-06 00:06:56 +08:00
|
|
|
|
class OpCodeHandlerSigInfo {
|
|
|
|
|
public object[] RequiredFieldTypes { get; set; }
|
|
|
|
|
public string[] ExecuteMethodLocals { get; set; }
|
|
|
|
|
public int? ExecuteMethodThrows { get; set; }
|
2012-04-24 17:33:17 +08:00
|
|
|
|
public int? ExecuteMethodPops { get; set; }
|
2012-04-06 00:06:56 +08:00
|
|
|
|
public int? NumStaticMethods { get; set; }
|
|
|
|
|
public int? NumInstanceMethods { get; set; }
|
|
|
|
|
public int? NumVirtualMethods { get; set; }
|
|
|
|
|
public int? NumCtors { get; set; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-24 17:33:17 +08:00
|
|
|
|
class CsvmInfo {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
public TypeDef StackValue { get; set; }
|
|
|
|
|
public TypeDef Stack { get; set; }
|
|
|
|
|
public MethodDef PopMethod { get; set; }
|
|
|
|
|
public MethodDef PeekMethod { get; set; }
|
2012-04-24 17:33:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
2012-04-06 00:06:56 +08:00
|
|
|
|
class VmOpCodeHandlerDetector {
|
2012-11-07 12:17:45 +08:00
|
|
|
|
ModuleDefMD module;
|
2012-04-06 00:06:56 +08:00
|
|
|
|
List<OpCodeHandler> opCodeHandlers;
|
|
|
|
|
|
|
|
|
|
public List<OpCodeHandler> Handlers {
|
|
|
|
|
get { return opCodeHandlers; }
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-07 12:17:45 +08:00
|
|
|
|
public VmOpCodeHandlerDetector(ModuleDefMD module) {
|
2012-04-06 00:06:56 +08:00
|
|
|
|
this.module = module;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
public void FindHandlers() {
|
2012-04-06 00:06:56 +08:00
|
|
|
|
if (opCodeHandlers != null)
|
|
|
|
|
return;
|
2013-01-19 20:03:57 +08:00
|
|
|
|
var vmHandlerTypes = FindVmHandlerTypes();
|
2012-04-06 00:06:56 +08:00
|
|
|
|
if (vmHandlerTypes == null)
|
|
|
|
|
throw new ApplicationException("Could not find CSVM opcode handler types");
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
DetectHandlers(vmHandlerTypes, CreateCsvmInfo());
|
2012-06-02 13:26:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
internal CsvmInfo CreateCsvmInfo() {
|
2012-04-24 17:33:17 +08:00
|
|
|
|
var csvmInfo = new CsvmInfo();
|
2013-01-19 20:03:57 +08:00
|
|
|
|
csvmInfo.StackValue = FindStackValueType();
|
|
|
|
|
csvmInfo.Stack = FindStackType(csvmInfo.StackValue);
|
|
|
|
|
InitStackTypeMethods(csvmInfo);
|
2012-06-02 13:26:21 +08:00
|
|
|
|
return csvmInfo;
|
2012-04-24 17:33:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
TypeDef FindStackValueType() {
|
2012-04-24 17:33:17 +08:00
|
|
|
|
foreach (var type in module.Types) {
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (IsStackType(type))
|
2012-04-24 17:33:17 +08:00
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
static bool IsStackType(TypeDef type) {
|
2012-04-24 17:33:17 +08:00
|
|
|
|
if (type.Fields.Count != 2)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
int enumTypes = 0;
|
|
|
|
|
int objectTypes = 0;
|
|
|
|
|
foreach (var field in type.Fields) {
|
2012-11-07 12:17:45 +08:00
|
|
|
|
var fieldType = field.FieldSig.GetFieldType().TryGetTypeDef();
|
2012-04-24 17:33:17 +08:00
|
|
|
|
if (fieldType != null && fieldType.IsEnum)
|
|
|
|
|
enumTypes++;
|
2012-11-07 12:17:45 +08:00
|
|
|
|
if (field.FieldSig.GetFieldType().GetElementType() == ElementType.Object)
|
2012-04-24 17:33:17 +08:00
|
|
|
|
objectTypes++;
|
|
|
|
|
}
|
|
|
|
|
if (enumTypes != 1 || objectTypes != 1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
TypeDef FindStackType(TypeDef stackValueType) {
|
2012-04-24 17:33:17 +08:00
|
|
|
|
foreach (var type in module.Types) {
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (IsStackType(type, stackValueType))
|
2012-04-24 17:33:17 +08:00
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
bool IsStackType(TypeDef type, TypeDef stackValueType) {
|
2012-11-17 06:50:52 +08:00
|
|
|
|
if (type.Interfaces.Count != 2)
|
2012-04-24 17:33:17 +08:00
|
|
|
|
return false;
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (!ImplementsInterface(type, "System.Collections.ICollection"))
|
2012-04-24 17:33:17 +08:00
|
|
|
|
return false;
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (!ImplementsInterface(type, "System.Collections.IEnumerable"))
|
2012-04-24 17:33:17 +08:00
|
|
|
|
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;
|
2012-11-07 12:17:45 +08:00
|
|
|
|
var fieldType = field.FieldSig.GetFieldType();
|
|
|
|
|
if (fieldType == null)
|
|
|
|
|
continue;
|
|
|
|
|
if (fieldType.IsSZArray && fieldType.Next.TryGetTypeDef() == stackValueType)
|
2012-04-24 17:33:17 +08:00
|
|
|
|
stackValueTypes++;
|
2012-11-07 12:17:45 +08:00
|
|
|
|
if (fieldType.ElementType == ElementType.I4)
|
2012-04-24 17:33:17 +08:00
|
|
|
|
int32Types++;
|
2012-11-07 12:17:45 +08:00
|
|
|
|
if (fieldType.ElementType == ElementType.Object)
|
2012-04-24 17:33:17 +08:00
|
|
|
|
objectTypes++;
|
|
|
|
|
}
|
|
|
|
|
if (stackValueTypes != 2 || int32Types != 2 || objectTypes != 1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
static bool ImplementsInterface(TypeDef type, string ifaceName) {
|
2012-11-17 06:50:52 +08:00
|
|
|
|
foreach (var iface in type.Interfaces) {
|
2012-11-07 12:17:45 +08:00
|
|
|
|
if (iface.Interface.FullName == ifaceName)
|
2012-04-24 17:33:17 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
void InitStackTypeMethods(CsvmInfo csvmInfo) {
|
2012-04-24 17:33:17 +08:00
|
|
|
|
foreach (var method in csvmInfo.Stack.Methods) {
|
2012-11-07 12:17:45 +08:00
|
|
|
|
var sig = method.MethodSig;
|
|
|
|
|
if (sig != null && sig.Params.Count == 0 && sig.RetType.TryGetTypeDef() == csvmInfo.StackValue) {
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (HasAdd(method))
|
2012-04-24 17:33:17 +08:00
|
|
|
|
csvmInfo.PopMethod = method;
|
|
|
|
|
else
|
|
|
|
|
csvmInfo.PeekMethod = method;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
static bool HasAdd(MethodDef method) {
|
2012-04-24 17:33:17 +08:00
|
|
|
|
foreach (var instr in method.Body.Instructions) {
|
|
|
|
|
if (instr.OpCode.Code == Code.Add)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2012-04-06 00:06:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
List<TypeDef> FindVmHandlerTypes() {
|
2012-04-06 00:06:56 +08:00
|
|
|
|
var requiredFields = new string[] {
|
|
|
|
|
null,
|
|
|
|
|
"System.Collections.Generic.Dictionary`2<System.UInt16,System.Type>",
|
|
|
|
|
"System.UInt16",
|
|
|
|
|
};
|
2012-04-30 04:22:43 +08:00
|
|
|
|
var cflowDeobfuscator = new CflowDeobfuscator();
|
2012-04-06 00:06:56 +08:00
|
|
|
|
foreach (var type in module.Types) {
|
2012-11-17 06:50:52 +08:00
|
|
|
|
var cctor = type.FindStaticConstructor();
|
2012-04-06 00:06:56 +08:00
|
|
|
|
if (cctor == null)
|
|
|
|
|
continue;
|
|
|
|
|
requiredFields[0] = type.FullName;
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (!new FieldTypes(type).Exactly(requiredFields))
|
2012-04-06 00:06:56 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
cflowDeobfuscator.Deobfuscate(cctor);
|
|
|
|
|
var handlers = FindVmHandlerTypes(cctor);
|
2012-04-06 00:06:56 +08:00
|
|
|
|
if (handlers.Count != 31)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return handlers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
static List<TypeDef> FindVmHandlerTypes(MethodDef method) {
|
2012-11-02 22:57:11 +08:00
|
|
|
|
var list = new List<TypeDef>();
|
2012-04-06 00:06:56 +08:00
|
|
|
|
|
|
|
|
|
foreach (var instr in method.Body.Instructions) {
|
|
|
|
|
if (instr.OpCode.Code != Code.Ldtoken)
|
|
|
|
|
continue;
|
2012-11-02 22:57:11 +08:00
|
|
|
|
var type = instr.Operand as TypeDef;
|
2012-04-06 00:06:56 +08:00
|
|
|
|
if (type == null)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
list.Add(type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
2013-01-19 20:03:57 +08:00
|
|
|
|
void DetectHandlers(List<TypeDef> handlerTypes, CsvmInfo csvmInfo) {
|
2012-04-06 00:06:56 +08:00
|
|
|
|
opCodeHandlers = new List<OpCodeHandler>();
|
|
|
|
|
var detected = new List<OpCodeHandler>();
|
2012-06-02 13:26:21 +08:00
|
|
|
|
|
2013-11-08 18:05:17 +08:00
|
|
|
|
foreach (var handlersList in OpCodeHandlers.Handlers) {
|
2012-06-02 13:26:21 +08:00
|
|
|
|
opCodeHandlers.Clear();
|
|
|
|
|
|
|
|
|
|
foreach (var handlerType in handlerTypes) {
|
|
|
|
|
var info = new UnknownHandlerInfo(handlerType, csvmInfo);
|
|
|
|
|
detected.Clear();
|
|
|
|
|
foreach (var opCodeHandler in handlersList) {
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (opCodeHandler.Detect(info))
|
2012-06-02 13:26:21 +08:00
|
|
|
|
detected.Add(opCodeHandler);
|
|
|
|
|
}
|
|
|
|
|
if (detected.Count != 1)
|
|
|
|
|
goto next;
|
|
|
|
|
opCodeHandlers.Add(detected[0]);
|
2012-04-06 00:06:56 +08:00
|
|
|
|
}
|
2013-01-19 20:03:57 +08:00
|
|
|
|
if (new List<OpCodeHandler>(Utils.Unique(opCodeHandlers)).Count == opCodeHandlers.Count)
|
2012-06-02 13:26:21 +08:00
|
|
|
|
return;
|
|
|
|
|
next: ;
|
2012-04-06 00:06:56 +08:00
|
|
|
|
}
|
2012-06-02 13:26:21 +08:00
|
|
|
|
throw new ApplicationException("Could not detect all VM opcode handlers");
|
2012-04-06 00:06:56 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|