Support Agile.NET 6.3.0.10

This commit is contained in:
de4dot 2013-11-23 22:00:13 +01:00
parent cc56b730b3
commit e2a95f6838
23 changed files with 885 additions and 1246 deletions

View File

@ -88,12 +88,10 @@
</Compile>
<Compile Include="deobfuscators\Agile_NET\vm\v2\CsvmToCilMethodConverter.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\HandlerTypeCode.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\MethodFinder.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\MethodSigInfoCreator.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandler.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandlerInfo.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandlerInfoReader.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandlerInfos.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\SigCreator.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\VmOpCode.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\v2\VmOpCodeHandlerDetector.cs" />
<Compile Include="deobfuscators\Agile_NET\vm\VmOperand.cs" />

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -25,19 +25,17 @@ using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class CompositeHandlerDetector {
readonly List<OpCodeHandler> handlers;
readonly List<MethodSigInfo> handlers;
public CompositeHandlerDetector(IList<OpCodeHandler> handlers) {
this.handlers = new List<OpCodeHandler>(handlers.Count);
OpCodeHandler nop = null;
foreach (var handler in handlers) {
if (nop == null && handler.OpCodeHandlerInfo.TypeCode == HandlerTypeCode.Nop)
nop = handler;
else
this.handlers.Add(handler);
}
if (nop != null)
this.handlers.Add(nop);
public CompositeHandlerDetector(IList<MethodSigInfo> handlers) {
this.handlers = new List<MethodSigInfo>(handlers);
this.handlers.Sort((a, b) => {
int r = b.BlockSigInfos.Count.CompareTo(a.BlockSigInfos.Count);
if (r != 0)
return r;
return b.BlockSigInfos[0].Hashes.Count.CompareTo(a.BlockSigInfos[0].Hashes.Count);
});
}
struct MatchState {
@ -51,27 +49,18 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
struct HandlerState {
public readonly HandlerMethod HandlerMethod;
public readonly IList<Block> Blocks;
public readonly List<BlockSigInfo> BlockSigInfos;
public readonly int BlockIndex;
public int InstructionIndex;
public int HashIndex;
public HandlerState(HandlerMethod handlerMethod, int blockIndex, int instructionIndex) {
this.HandlerMethod = handlerMethod;
this.Blocks = handlerMethod.Blocks.MethodBlocks.GetAllBlocks();
public HandlerState(List<BlockSigInfo> blockSigInfos, int blockIndex, int instructionIndex) {
this.BlockSigInfos = blockSigInfos;
this.BlockIndex = blockIndex;
this.InstructionIndex = instructionIndex;
}
public HandlerState(HandlerMethod handlerMethod, IList<Block> blocks, int blockIndex, int instructionIndex) {
this.HandlerMethod = handlerMethod;
this.Blocks = blocks;
this.BlockIndex = blockIndex;
this.InstructionIndex = instructionIndex;
this.HashIndex = instructionIndex;
}
public HandlerState Clone() {
return new HandlerState(HandlerMethod, Blocks, BlockIndex, InstructionIndex);
return new HandlerState(BlockSigInfos, BlockIndex, HashIndex);
}
}
@ -98,22 +87,22 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
public bool FindHandlers(CompositeOpCodeHandler composite) {
composite.OpCodeHandlerInfos.Clear();
var compositeExecState = new FindHandlerState(new HandlerState(composite.ExecMethod, 0, 0));
composite.TypeCodes.Clear();
var compositeExecState = new FindHandlerState(new HandlerState(composite.BlockSigInfos, 0, 0));
while (!compositeExecState.Done) {
var handler = FindHandlerMethod(ref compositeExecState);
if (handler == null)
return false;
composite.OpCodeHandlerInfos.Add(handler.OpCodeHandlerInfo);
composite.TypeCodes.Add(handler.TypeCode);
}
return composite.OpCodeHandlerInfos.Count != 0;
return composite.TypeCodes.Count != 0;
}
OpCodeHandler FindHandlerMethod(ref FindHandlerState findExecState) {
MethodSigInfo FindHandlerMethod(ref FindHandlerState findExecState) {
foreach (var handler in handlers) {
FindHandlerState findExecStateNew = findExecState.Clone();
if (!Matches(handler.ExecMethod, ref findExecStateNew))
if (!Matches(handler.BlockSigInfos, ref findExecStateNew))
continue;
findExecState = findExecStateNew;
@ -123,14 +112,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
Stack<MatchState> stack = new Stack<MatchState>();
bool Matches(HandlerMethod handler, ref FindHandlerState findState) {
bool Matches(List<BlockSigInfo> handler, ref FindHandlerState findState) {
HandlerState? nextState = null;
stack.Clear();
stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
while (stack.Count > 0) {
var matchState = stack.Pop();
if (matchState.CompositeState.InstructionIndex == 0) {
if (matchState.CompositeState.HashIndex == 0) {
if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
continue;
findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
@ -143,193 +132,83 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
return false;
var hblock = matchState.OtherState.Blocks[matchState.OtherState.BlockIndex];
var hinstrs = hblock.Instructions;
int hi = matchState.OtherState.InstructionIndex;
var cblock = matchState.CompositeState.Blocks[matchState.CompositeState.BlockIndex];
var cinstrs = cblock.Instructions;
int ci = matchState.CompositeState.InstructionIndex;
var hblock = matchState.OtherState.BlockSigInfos[matchState.OtherState.BlockIndex];
var hinstrs = hblock.Hashes;
int hi = matchState.OtherState.HashIndex;
var cblock = matchState.CompositeState.BlockSigInfos[matchState.CompositeState.BlockIndex];
var cinstrs = cblock.Hashes;
int ci = matchState.CompositeState.HashIndex;
if (hi < hinstrs.Count)
return false;
if (ci < cinstrs.Count) {
if (hblock.CountTargets() != 0)
if (hblock.Targets.Count != 0)
return false;
if (hblock.LastInstr.OpCode.Code == Code.Ret) {
if (hblock.EndsInRet) {
if (nextState != null)
return false;
nextState = matchState.CompositeState;
}
}
else {
if (cblock.CountTargets() != hblock.CountTargets())
if (cblock.Targets.Count != hblock.Targets.Count)
return false;
if (cblock.HasFallThrough != hblock.HasFallThrough)
return false;
if (cblock.FallThrough != null || hblock.FallThrough != null) {
if (cblock.FallThrough == null || hblock.FallThrough == null)
return false;
var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.FallThrough);
var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.FallThrough);
for (int i = 0; i < cblock.Targets.Count; i++) {
var hs = new HandlerState(handler, hblock.Targets[i], 0);
var cs = new HandlerState(findState.CompositeState.BlockSigInfos, cblock.Targets[i], 0);
stack.Push(new MatchState(hs, cs));
}
if (cblock.Targets != null || hblock.Targets != null) {
if (cblock.Targets == null || hblock.Targets == null ||
cblock.Targets.Count != hblock.Targets.Count)
return false;
for (int i = 0; i < cblock.Targets.Count; i++) {
var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.Targets[i]);
var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.Targets[i]);
stack.Push(new MatchState(hs, cs));
}
}
}
}
if (nextState == null) {
if (findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
return false;
findState.Done = true;
return true;
}
else {
if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
findState.CompositeState.InstructionIndex == nextState.Value.InstructionIndex)
findState.CompositeState.HashIndex == nextState.Value.HashIndex)
return false;
findState.CompositeState = nextState.Value;
if (findState.CompositeState.HashIndex == 0)
findState.VisitedCompositeBlocks.Remove(findState.CompositeState.BlockIndex);
return true;
}
}
static HandlerState CreateHandlerState(HandlerMethod handler, IList<Block> blocks, Block target) {
return new HandlerState(handler, blocks.IndexOf(target), 0);
}
static bool Compare(ref HandlerState handler, ref HandlerState composite) {
var hinstrs = handler.Blocks[handler.BlockIndex].Instructions;
int hi = handler.InstructionIndex;
var cinstrs = composite.Blocks[composite.BlockIndex].Instructions;
int ci = composite.InstructionIndex;
var hhashes = handler.BlockSigInfos[handler.BlockIndex].Hashes;
int hi = handler.HashIndex;
var chashes = composite.BlockSigInfos[composite.BlockIndex].Hashes;
int ci = composite.HashIndex;
while (true) {
if (hi >= hinstrs.Count && ci >= cinstrs.Count)
if (hi >= hhashes.Count && ci >= chashes.Count)
break;
if (hi >= hinstrs.Count || ci >= cinstrs.Count)
if (hi >= hhashes.Count) {
if (handler.BlockSigInfos[handler.BlockIndex].EndsInRet)
break;
}
if (hi >= hhashes.Count || ci >= chashes.Count)
return false;
var hinstr = hinstrs[hi++];
var cinstr = cinstrs[ci++];
if (hinstr.OpCode.Code == Code.Nop ||
cinstr.OpCode.Code == Code.Nop) {
if (hinstr.OpCode.Code != Code.Nop)
hi--;
if (cinstr.OpCode.Code != Code.Nop)
ci--;
continue;
}
var hhash = hhashes[hi++];
var chash = chashes[ci++];
if (hi == hinstrs.Count && hinstr.OpCode.Code == Code.Ret) {
if (cinstr.OpCode.Code != Code.Br && cinstr.OpCode.Code != Code.Ret)
ci--;
break;
}
if (hinstr.OpCode.Code != cinstr.OpCode.Code)
return false;
if (hinstr.OpCode.Code == Code.Ldfld &&
hi + 1 < hinstrs.Count && ci + 1 < cinstrs.Count) {
var hfield = hinstr.Operand as FieldDef;
var cfield = cinstr.Operand as FieldDef;
if (hfield != null && cfield != null &&
!hfield.IsStatic && !cfield.IsStatic &&
hfield.DeclaringType == handler.HandlerMethod.Method.DeclaringType &&
cfield.DeclaringType == composite.HandlerMethod.Method.DeclaringType &&
SignatureEqualityComparer.Instance.Equals(hfield.Signature, cfield.Signature)) {
cinstr = cinstrs[ci++];
hinstr = hinstrs[hi++];
if (cinstr.OpCode.Code != Code.Ldc_I4 ||
hinstr.OpCode.Code != Code.Ldc_I4)
return false;
continue;
}
}
if (!CompareOperand(hinstr.OpCode.OperandType, cinstr.Operand, hinstr.Operand))
if (chash != hhash)
return false;
}
handler.InstructionIndex = hi;
composite.InstructionIndex = ci;
handler.HashIndex = hi;
composite.HashIndex = ci;
return true;
}
static bool CompareOperand(OperandType opType, object a, object b) {
switch (opType) {
case OperandType.ShortInlineI:
return (a is byte && b is byte && (byte)a == (byte)b) ||
(a is sbyte && b is sbyte && (sbyte)a == (sbyte)b);
case OperandType.InlineI:
return a is int && b is int && (int)a == (int)b;
case OperandType.InlineI8:
return a is long && b is long && (long)a == (long)b;
case OperandType.ShortInlineR:
return a is float && b is float && (float)a == (float)b;
case OperandType.InlineR:
return a is double && b is double && (double)a == (double)b;
case OperandType.InlineField:
return FieldEqualityComparer.CompareDeclaringTypes.Equals(a as IField, b as IField);
case OperandType.InlineMethod:
return MethodEqualityComparer.CompareDeclaringTypes.Equals(a as IMethod, b as IMethod);
case OperandType.InlineSig:
return SignatureEqualityComparer.Instance.Equals(a as MethodSig, b as MethodSig);
case OperandType.InlineString:
return string.Equals(a as string, b as string);
case OperandType.InlineSwitch:
var al = a as IList<Instruction>;
var bl = b as IList<Instruction>;
return al != null && bl != null && al.Count == bl.Count;
case OperandType.InlineTok:
var fa = a as IField;
var fb = b as IField;
if (fa != null && fb != null)
return FieldEqualityComparer.CompareDeclaringTypes.Equals(fa, fb);
var ma = a as IMethod;
var mb = b as IMethod;
if (ma != null && mb != null)
return MethodEqualityComparer.CompareDeclaringTypes.Equals(ma, mb);
return TypeEqualityComparer.Instance.Equals(a as ITypeDefOrRef, b as ITypeDefOrRef);
case OperandType.InlineType:
return TypeEqualityComparer.Instance.Equals(a as ITypeDefOrRef, b as ITypeDefOrRef);
case OperandType.InlineVar:
case OperandType.ShortInlineVar:
var la = a as Local;
var lb = b as Local;
if (la != null && lb != null)
return true;
var pa = a as Parameter;
var pb = b as Parameter;
return pa != null && pb != null && pa.Index == pb.Index;
case OperandType.InlineBrTarget:
case OperandType.ShortInlineBrTarget:
case OperandType.InlineNone:
case OperandType.InlinePhi:
return true;
default:
return false;
}
}
}
}

View File

@ -23,45 +23,17 @@ using dnlib.DotNet;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class HandlerMethod {
public MethodDef Method { get; private set; }
public Blocks Blocks { get; private set; }
public HandlerMethod(MethodDef method) {
this.Method = method;
this.Blocks = new Blocks(method);
}
}
class PrimitiveHandlerMethod : HandlerMethod {
public MethodSigInfo Sig { get; set; }
public PrimitiveHandlerMethod(MethodDef method)
: base(method) {
}
}
class CompositeOpCodeHandler {
public TypeDef HandlerType { get; private set; }
public HandlerMethod ExecMethod { get; private set; }
public List<OpCodeHandlerInfo> OpCodeHandlerInfos { get; private set; }
public List<BlockSigInfo> BlockSigInfos { get; private set; }
public List<HandlerTypeCode> TypeCodes { get; private set; }
public CompositeOpCodeHandler(TypeDef handlerType, HandlerMethod execMethod) {
this.HandlerType = handlerType;
this.ExecMethod = execMethod;
this.OpCodeHandlerInfos = new List<OpCodeHandlerInfo>();
public CompositeOpCodeHandler(List<BlockSigInfo> blockSigInfos) {
this.BlockSigInfos = blockSigInfos;
this.TypeCodes = new List<HandlerTypeCode>();
}
public override string ToString() {
if (OpCodeHandlerInfos.Count == 0)
return "<nothing>";
var sb = new StringBuilder();
foreach (var handler in OpCodeHandlerInfos) {
if (sb.Length != 0)
sb.Append(", ");
sb.Append(handler.Name);
}
return sb.ToString();
return OpCodeHandlerInfo.GetCompositeName(TypeCodes);
}
}
}

View File

@ -594,45 +594,79 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
}
public bool FindUnaryOpsMethods() {
UnaryNot = FindUnaryOpMethod(Code.Not);
UnaryNeg = FindUnaryOpMethod(Code.Neg);
return UnaryNot != null && UnaryNeg != null;
UnaryNot = FindUnaryOpMethod1(Code.Not);
UnaryNeg = FindUnaryOpMethod1(Code.Neg);
if (UnaryNot != null && UnaryNeg != null)
return true;
return FindUnaryOpMethod2();
}
MethodDef FindUnaryOpMethod(Code code) {
MethodDef FindUnaryOpMethod1(Code code) {
foreach (var type in module.Types) {
if (type.BaseType != VmHandlerBaseType)
continue;
if (type.Methods.Count != 4)
continue;
foreach (var method in type.Methods) {
if (!method.HasBody || !method.IsStatic)
continue;
if (!DotNetUtils.IsMethod(method, "System.Object", "(System.Object)"))
continue;
if (CountThrows(method) != 1)
continue;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 4; i++) {
var ldarg = instrs[i];
if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
continue;
if (instrs[i + 2].OpCode.Code != code)
continue;
if (!CheckBox(instrs[i + 3], ElementType.I4))
continue;
if (!instrs[i + 4].IsStloc())
continue;
return method;
}
}
var method = FindUnaryMethod(type, code);
if (method != null)
return method;
}
return null;
}
bool FindUnaryOpMethod2() {
foreach (var type in module.Types) {
if (type.BaseType == null || type.BaseType.FullName != "System.Object")
continue;
if (type.Methods.Count != 3)
continue;
UnaryNot = FindUnaryMethod(type, Code.Not);
UnaryNeg = FindUnaryMethod(type, Code.Neg);
if (UnaryNot != null && UnaryNeg != null)
return true;
}
return false;
}
MethodDef FindUnaryMethod(TypeDef type, Code code) {
foreach (var method in type.Methods) {
if (!IsUnsaryMethod(method, code))
continue;
return method;
}
return null;
}
bool IsUnsaryMethod(MethodDef method, Code code) {
if (!method.HasBody || !method.IsStatic)
return false;
if (!DotNetUtils.IsMethod(method, "System.Object", "(System.Object)"))
return false;
if (CountThrows(method) != 1)
return false;
var instrs = method.Body.Instructions;
for (int i = 0; i < instrs.Count - 4; i++) {
var ldarg = instrs[i];
if (!ldarg.IsLdarg() || ldarg.GetParameterIndex() != 0)
continue;
if (!CheckUnboxAny(instrs[i + 1], ElementType.I4))
continue;
if (instrs[i + 2].OpCode.Code != code)
continue;
if (!CheckBox(instrs[i + 3], ElementType.I4))
continue;
if (!instrs[i + 4].IsStloc())
continue;
return true;
}
return false;
}
static int CountThrows(MethodDef method) {
if (method == null || method.Body == null)
return 0;

View File

@ -63,9 +63,9 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM1_v2 {
internal static byte[] CSVM1 {
get {
object obj = ResourceManager.GetObject("CSVM1_v2", resourceCulture);
object obj = ResourceManager.GetObject("CSVM1", resourceCulture);
return ((byte[])(obj));
}
}
@ -73,9 +73,9 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM2_v2 {
internal static byte[] CSVM2 {
get {
object obj = ResourceManager.GetObject("CSVM2_v2", resourceCulture);
object obj = ResourceManager.GetObject("CSVM2", resourceCulture);
return ((byte[])(obj));
}
}
@ -83,9 +83,19 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM3_v2 {
internal static byte[] CSVM3 {
get {
object obj = ResourceManager.GetObject("CSVM3_v2", resourceCulture);
object obj = ResourceManager.GetObject("CSVM3", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CSVM4 {
get {
object obj = ResourceManager.GetObject("CSVM4", resourceCulture);
return ((byte[])(obj));
}
}

View File

@ -117,14 +117,17 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="CSVM1_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM1_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="CSVM1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM1.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CSVM2_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM2_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<data name="CSVM2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CSVM3_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM3_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<data name="CSVM3" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM3.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CSVM4" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>CSVM4.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

View File

@ -45,11 +45,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
uint offset = 0;
for (int vmInstrIndex = 0; vmInstrIndex < numVmInstrs; vmInstrIndex++) {
var composite = opCodeDetector.Handlers[vmInstrs[vmInstrIndex]];
var handlerInfos = composite.OpCodeHandlerInfos;
IList<HandlerTypeCode> handlerInfos = composite.HandlerTypeCodes;
if (handlerInfos.Count == 0)
handlerInfos = new List<OpCodeHandlerInfo>() { new OpCodeHandlerInfo(HandlerTypeCode.Nop, null) };
handlerInfos = new HandlerTypeCode[] { HandlerTypeCode.Nop };
for (int hi = 0; hi < handlerInfos.Count; hi++) {
var instr = handlerInfoReader.Read(handlerInfos[hi].TypeCode, reader);
var instr = handlerInfoReader.Read(handlerInfos[hi], reader);
instr.Offset = offset;
offset += (uint)GetInstructionSize(instr);
SetCilToVmIndex(instr, vmInstrIndex);
@ -58,6 +58,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
instrs.Add(instr);
}
}
return instrs;
}
}

View File

@ -1,109 +0,0 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
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.Collections.Generic;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class MethodFinder {
readonly IList<OpCodeHandlerInfo> handlerInfos;
readonly PrimitiveHandlerMethod handlerMethod;
class SigState {
public readonly MethodSigInfo SigInfo;
public SigState(PrimitiveHandlerMethod handlerMethod) {
this.SigInfo = handlerMethod.Sig;
}
}
public MethodFinder(IList<OpCodeHandlerInfo> handlerInfos, PrimitiveHandlerMethod handlerMethod) {
this.handlerInfos = handlerInfos;
this.handlerMethod = handlerMethod;
}
public OpCodeHandler FindHandler() {
var handler = FindHandler(new SigState(handlerMethod));
if (handler == null)
return null;
return new OpCodeHandler(handler, handlerMethod.Method.DeclaringType, handlerMethod);
}
OpCodeHandlerInfo FindHandler(SigState execSigState) {
foreach (var handler in handlerInfos) {
if (Matches(handler.ExecSig, execSigState))
return handler;
}
return null;
}
struct MatchInfo {
public int HandlerIndex;
public int SigIndex;
public MatchInfo(int handlerIndex, int sigIndex) {
this.HandlerIndex = handlerIndex;
this.SigIndex = sigIndex;
}
}
Dictionary<int, int> sigIndexToHandlerIndex = new Dictionary<int, int>();
Dictionary<int, int> handlerIndexToSigIndex = new Dictionary<int, int>();
Stack<MatchInfo> stack = new Stack<MatchInfo>();
bool Matches(MethodSigInfo handlerSig, SigState sigState) {
stack.Clear();
sigIndexToHandlerIndex.Clear();
handlerIndexToSigIndex.Clear();
var handlerInfos = handlerSig.BlockInfos;
var sigInfos = sigState.SigInfo.BlockInfos;
stack.Push(new MatchInfo(0, 0));
while (stack.Count > 0) {
var info = stack.Pop();
int handlerIndex, sigIndex;
bool hasVisitedHandler = handlerIndexToSigIndex.TryGetValue(info.HandlerIndex, out sigIndex);
bool hasVisitedSig = sigIndexToHandlerIndex.TryGetValue(info.SigIndex, out handlerIndex);
if (hasVisitedHandler != hasVisitedSig)
return false;
if (hasVisitedHandler) {
if (handlerIndex != info.HandlerIndex || sigIndex != info.SigIndex)
return false;
continue;
}
handlerIndexToSigIndex[info.HandlerIndex] = info.SigIndex;
sigIndexToHandlerIndex[info.SigIndex] = info.HandlerIndex;
var handlerBlock = handlerInfos[info.HandlerIndex];
var sigBlock = sigInfos[info.SigIndex];
if (!handlerBlock.Equals(sigBlock))
return false;
for (int i = 0; i < handlerBlock.Targets.Count; i++) {
int handlerTargetIndex = handlerBlock.Targets[i];
int sigTargetIndex = sigBlock.Targets[i];
stack.Push(new MatchInfo(handlerTargetIndex, sigTargetIndex));
}
}
return true;
}
}
}

View File

@ -1,737 +0,0 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
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;
using System.IO;
using System.Security.Cryptography;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using dnlib.DotNet.MD;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class MethodSigInfo {
readonly List<BlockInfo> blockInfos;
public List<BlockInfo> BlockInfos {
get { return blockInfos; }
}
public MethodSigInfo() {
this.blockInfos = new List<BlockInfo>();
}
public MethodSigInfo(IEnumerable<BlockInfo> blockInfos) {
this.blockInfos = new List<BlockInfo>(blockInfos);
}
}
class BlockInfo : IEquatable<BlockInfo> {
readonly List<int> targets;
public byte[] Hash { get; set; }
public List<int> Targets {
get { return targets; }
}
public BlockInfo() {
this.targets = new List<int>();
}
public BlockInfo(byte[] hash, IEnumerable<int> targets) {
this.Hash = hash;
this.targets = new List<int>(targets);
}
public override string ToString() {
if (Hash == null)
return "<null>";
return BitConverter.ToString(Hash).Replace("-", string.Empty);
}
public bool Equals(BlockInfo other) {
return Equals(Hash, other.Hash) &&
Targets.Count == other.Targets.Count;
}
bool Equals(byte[] a, byte[] b) {
if (a == b)
return true;
if (a == null || b == null)
return false;
if (a.Length != b.Length)
return false;
for (int i = 0; i < a.Length; i++) {
if (a[i] != b[i])
return false;
}
return true;
}
}
class MethodSigInfoCreator {
MethodSigInfo methodSigInfo;
Blocks blocks;
IList<Block> allBlocks;
Dictionary<Block, BlockInfo> blockToInfo;
Dictionary<object, int> methodToId = new Dictionary<object, int>();
public void AddId(object key, int id) {
if (key != null)
methodToId[key] = id;
}
int GetId(object key) {
if (key == null)
return int.MinValue;
int id;
if (methodToId.TryGetValue(key, out id))
return id;
return int.MinValue + 1;
}
public MethodSigInfo Create(Blocks blocks) {
methodSigInfo = new MethodSigInfo();
this.blocks = blocks;
allBlocks = blocks.MethodBlocks.GetAllBlocks();
blockToInfo = new Dictionary<Block, BlockInfo>();
foreach (var block in allBlocks) {
var blockInfo = new BlockInfo();
blockToInfo[block] = blockInfo;
methodSigInfo.BlockInfos.Add(blockInfo);
}
foreach (var block in allBlocks) {
var blockInfo = blockToInfo[block];
Update(blockInfo, block);
if (block.FallThrough != null)
blockInfo.Targets.Add(allBlocks.IndexOf(block.FallThrough));
if (block.Targets != null) {
foreach (var target in block.Targets)
blockInfo.Targets.Add(allBlocks.IndexOf(target));
}
}
return methodSigInfo;
}
void Update(BlockInfo blockInfo, Block block) {
using (var hasher = MD5.Create()) {
bool emptyHash;
using (var outStream = new NullStream()) {
using (var csStream = new CryptoStream(outStream, hasher, CryptoStreamMode.Write)) {
var writer = new BinaryWriter(csStream);
Update(writer, blockInfo, block);
}
emptyHash = outStream.Length == 0;
}
if (!emptyHash)
blockInfo.Hash = hasher.Hash;
}
}
void Update(BinaryWriter writer, BlockInfo blockInfo, Block block) {
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var instr = instrs[i];
switch (instr.OpCode.Code) {
case Code.Beq_S:
case Code.Bge_S:
case Code.Bgt_S:
case Code.Ble_S:
case Code.Blt_S:
case Code.Bne_Un_S:
case Code.Bge_Un_S:
case Code.Bgt_Un_S:
case Code.Ble_Un_S:
case Code.Blt_Un_S:
case Code.Brfalse_S:
case Code.Brtrue_S:
case Code.Leave_S:
case Code.Beq:
case Code.Bge:
case Code.Bgt:
case Code.Ble:
case Code.Blt:
case Code.Bne_Un:
case Code.Bge_Un:
case Code.Bgt_Un:
case Code.Ble_Un:
case Code.Blt_Un:
case Code.Brfalse:
case Code.Brtrue:
case Code.Leave:
writer.Write((ushort)SimplifyBranch(instr.OpCode.Code));
break;
case Code.Switch:
writer.Write((ushort)instr.OpCode.Code);
writer.Write(blockInfo.Targets.Count);
break;
case Code.Br_S:
case Code.Br:
break;
case Code.Ret:
break;
case Code.Ldc_I4_M1:
case Code.Ldc_I4_0:
case Code.Ldc_I4_1:
case Code.Ldc_I4_2:
case Code.Ldc_I4_3:
case Code.Ldc_I4_4:
case Code.Ldc_I4_5:
case Code.Ldc_I4_6:
case Code.Ldc_I4_7:
case Code.Ldc_I4_8:
case Code.Ldc_I4:
case Code.Ldc_I4_S:
writer.Write((ushort)Code.Ldc_I4);
writer.Write(instr.GetLdcI4Value());
break;
case Code.Ldc_I8:
writer.Write((ushort)instr.OpCode.Code);
writer.Write((long)instr.Operand);
break;
case Code.Ldc_R4:
writer.Write((ushort)instr.OpCode.Code);
writer.Write((float)instr.Operand);
break;
case Code.Ldc_R8:
writer.Write((ushort)instr.OpCode.Code);
writer.Write((double)instr.Operand);
break;
case Code.Ldfld:
var typeField = instr.Operand as FieldDef;
bool isField = IsTypeField(typeField);
writer.Write((ushort)instr.OpCode.Code);
writer.Write(isField);
if (isField) {
if (i + 1 < instrs.Count && instrs[i + 1].IsLdcI4())
i++;
writer.Write(GetFieldId(typeField));
}
else
Write(writer, instr.Operand);
break;
case Code.Call:
case Code.Callvirt:
case Code.Newobj:
case Code.Jmp:
case Code.Ldftn:
case Code.Ldvirtftn:
case Code.Ldtoken:
case Code.Stfld:
case Code.Ldsfld:
case Code.Stsfld:
case Code.Ldflda:
case Code.Ldsflda:
case Code.Cpobj:
case Code.Ldobj:
case Code.Castclass:
case Code.Isinst:
case Code.Unbox:
case Code.Stobj:
case Code.Box:
case Code.Newarr:
case Code.Ldelema:
case Code.Ldelem:
case Code.Stelem:
case Code.Unbox_Any:
case Code.Refanyval:
case Code.Mkrefany:
case Code.Initobj:
case Code.Constrained:
case Code.Sizeof:
writer.Write((ushort)instr.OpCode.Code);
Write(writer, instr.Operand);
break;
case Code.Ldstr:
writer.Write((ushort)instr.OpCode.Code);
break;
case Code.Ldarg:
case Code.Ldarg_S:
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
writer.Write((ushort)Code.Ldarg);
writer.Write(instr.Instruction.GetParameterIndex());
break;
case Code.Ldarga:
case Code.Ldarga_S:
writer.Write((ushort)Code.Ldarga);
writer.Write(instr.Instruction.GetParameterIndex());
break;
case Code.Starg:
case Code.Starg_S:
writer.Write((ushort)Code.Starg);
writer.Write(instr.Instruction.GetParameterIndex());
break;
case Code.Ldloc:
case Code.Ldloc_S:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
writer.Write((ushort)Code.Ldloc);
break;
case Code.Ldloca:
case Code.Ldloca_S:
writer.Write((ushort)Code.Ldloca);
break;
case Code.Stloc:
case Code.Stloc_S:
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
writer.Write((ushort)Code.Stloc);
break;
case Code.Ldnull:
case Code.Throw:
case Code.Rethrow:
case Code.Ldlen:
case Code.Ckfinite:
case Code.Arglist:
case Code.Localloc:
case Code.Volatile:
case Code.Tailcall:
case Code.Cpblk:
case Code.Initblk:
case Code.Refanytype:
case Code.Readonly:
case Code.Break:
case Code.Endfinally:
case Code.Endfilter:
writer.Write((ushort)instr.OpCode.Code);
break;
case Code.Calli:
writer.Write((ushort)instr.OpCode.Code);
Write(writer, instr.Operand);
break;
case Code.Unaligned:
writer.Write((ushort)instr.OpCode.Code);
writer.Write((byte)instr.Operand);
break;
default:
break;
}
}
}
void Write(BinaryWriter writer, object op) {
var fd = op as FieldDef;
if (fd != null) {
Write(writer, fd);
return;
}
var mr = op as MemberRef;
if (mr != null) {
Write(writer, mr);
return;
}
var md = op as MethodDef;
if (md != null) {
Write(writer, md);
return;
}
var ms = op as MethodSpec;
if (ms != null) {
Write(writer, ms);
return;
}
var td = op as TypeDef;
if (td != null) {
Write(writer, td);
return;
}
var tr = op as TypeRef;
if (tr != null) {
Write(writer, tr);
return;
}
var ts = op as TypeSpec;
if (ts != null) {
Write(writer, ts);
return;
}
var fsig = op as FieldSig;
if (fsig != null) {
Write(writer, fsig);
return;
}
var msig = op as MethodSig;
if (msig != null) {
Write(writer, msig);
return;
}
var gsig = op as GenericInstMethodSig;
if (gsig != null) {
Write(writer, gsig);
return;
}
var asmRef = op as AssemblyRef;
if (asmRef != null) {
Write(writer, asmRef);
return;
}
writer.Write((byte)ObjectType.Unknown);
}
enum ObjectType : byte {
// 00..3F = Table.XXX values.
Unknown = 0x40,
TypeSig = 0x41,
FieldSig = 0x42,
MethodSig = 0x43,
GenericInstMethodSig = 0x44,
}
void Write(BinaryWriter writer, TypeSig sig) {
Write(writer, sig, 0);
}
void Write(BinaryWriter writer, TypeSig sig, int level) {
if (level++ > 20)
return;
writer.Write((byte)ObjectType.TypeSig);
var etype = sig.GetElementType();
writer.Write((byte)etype);
switch (etype) {
case ElementType.Ptr:
case ElementType.ByRef:
case ElementType.SZArray:
case ElementType.Pinned:
Write(writer, sig.Next, level);
break;
case ElementType.Array:
var arySig = (ArraySig)sig;
writer.Write(arySig.Rank);
writer.Write(arySig.Sizes.Count);
writer.Write(arySig.LowerBounds.Count);
Write(writer, sig.Next, level);
break;
case ElementType.CModReqd:
case ElementType.CModOpt:
Write(writer, ((ModifierSig)sig).Modifier);
Write(writer, sig.Next, level);
break;
case ElementType.ValueArray:
writer.Write(((ValueArraySig)sig).Size);
Write(writer, sig.Next, level);
break;
case ElementType.Module:
writer.Write(((ModuleSig)sig).Index);
Write(writer, sig.Next, level);
break;
case ElementType.GenericInst:
var gis = (GenericInstSig)sig;
Write(writer, gis.GenericType, level);
foreach (var ga in gis.GenericArguments)
Write(writer, ga, level);
Write(writer, sig.Next, level);
break;
case ElementType.FnPtr:
Write(writer, ((FnPtrSig)sig).Signature);
break;
case ElementType.Var:
case ElementType.MVar:
writer.Write(((GenericSig)sig).Number);
break;
case ElementType.ValueType:
case ElementType.Class:
Write(writer, ((TypeDefOrRefSig)sig).TypeDefOrRef);
break;
case ElementType.End:
case ElementType.Void:
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
case ElementType.I8:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.String:
case ElementType.TypedByRef:
case ElementType.I:
case ElementType.U:
case ElementType.R:
case ElementType.Object:
case ElementType.Internal:
case ElementType.Sentinel:
default:
break;
}
}
void Write(BinaryWriter writer, FieldSig sig) {
writer.Write((byte)ObjectType.FieldSig);
writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention()));
Write(writer, sig.GetFieldType());
}
void Write(BinaryWriter writer, MethodSig sig) {
writer.Write((byte)ObjectType.MethodSig);
writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention()));
Write(writer, sig.GetRetType());
foreach (var p in sig.GetParams())
Write(writer, p);
writer.Write(sig.GetParamCount());
bool hasParamsAfterSentinel = sig.GetParamsAfterSentinel() != null;
writer.Write(hasParamsAfterSentinel);
if (hasParamsAfterSentinel) {
foreach (var p in sig.GetParamsAfterSentinel())
Write(writer, p);
}
}
void Write(BinaryWriter writer, GenericInstMethodSig sig) {
writer.Write((byte)ObjectType.GenericInstMethodSig);
writer.Write((byte)(sig == null ? 0 : sig.GetCallingConvention()));
foreach (var ga in sig.GetGenericArguments())
Write(writer, ga);
}
void Write(BinaryWriter writer, FieldDef fd) {
writer.Write((byte)Table.Field);
Write(writer, fd.DeclaringType);
var attrMask = FieldAttributes.Static | FieldAttributes.InitOnly |
FieldAttributes.Literal | FieldAttributes.SpecialName |
FieldAttributes.PinvokeImpl | FieldAttributes.RTSpecialName;
writer.Write((ushort)(fd == null ? 0 : fd.Attributes & attrMask));
Write(writer, fd == null ? null : fd.Signature);
}
void Write(BinaryWriter writer, MemberRef mr) {
writer.Write((byte)Table.MemberRef);
var parent = mr == null ? null : mr.Class;
Write(writer, parent);
bool canWriteName = IsFromNonObfuscatedAssembly(parent);
writer.Write(canWriteName);
if (canWriteName)
writer.Write(mr.Name);
Write(writer, mr == null ? null : mr.Signature);
}
void Write(BinaryWriter writer, MethodDef md) {
writer.Write((byte)Table.Method);
Write(writer, md.DeclaringType);
var attrMask1 = MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask |
MethodImplAttributes.ForwardRef | MethodImplAttributes.PreserveSig |
MethodImplAttributes.InternalCall;
writer.Write((ushort)(md == null ? 0 : md.ImplAttributes & attrMask1));
var attrMask2 = MethodAttributes.Static | MethodAttributes.Virtual |
MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask |
MethodAttributes.CheckAccessOnOverride | MethodAttributes.Abstract |
MethodAttributes.SpecialName | MethodAttributes.PinvokeImpl |
MethodAttributes.UnmanagedExport | MethodAttributes.RTSpecialName;
writer.Write((ushort)(md == null ? 0 : md.Attributes & attrMask2));
Write(writer, md == null ? null : md.Signature);
writer.Write(md == null ? 0 : md.ParamDefs.Count);
writer.Write(md == null ? 0 : md.GenericParameters.Count);
writer.Write(md == null ? false : md.HasImplMap);
writer.Write(GetId(md));
}
void Write(BinaryWriter writer, MethodSpec ms) {
writer.Write((byte)Table.MethodSpec);
Write(writer, ms == null ? null : ms.Method);
Write(writer, ms == null ? null : ms.Instantiation);
}
void Write(BinaryWriter writer, TypeDef td) {
writer.Write((byte)Table.TypeDef);
Write(writer, td == null ? null : td.BaseType);
var attrMask = TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask |
TypeAttributes.Abstract | TypeAttributes.SpecialName |
TypeAttributes.Import | TypeAttributes.WindowsRuntime |
TypeAttributes.StringFormatMask | TypeAttributes.RTSpecialName;
writer.Write((uint)(td == null ? 0 : td.Attributes & attrMask));
Write(writer, td == null ? null : td.BaseType);
writer.Write(td == null ? 0 : td.GenericParameters.Count);
writer.Write(td == null ? 0 : td.Interfaces.Count);
if (td != null) {
foreach (var iface in td.Interfaces)
Write(writer, iface);
}
writer.Write(GetId(td));
}
void Write(BinaryWriter writer, TypeRef tr) {
writer.Write((byte)Table.TypeRef);
Write(writer, tr == null ? null : tr.ResolutionScope);
bool canWriteName = IsFromNonObfuscatedAssembly(tr);
writer.Write(canWriteName);
if (canWriteName) {
writer.Write(tr.Namespace);
writer.Write(tr.Name);
}
}
void Write(BinaryWriter writer, TypeSpec ts) {
writer.Write((byte)Table.TypeSpec);
Write(writer, ts == null ? null : ts.TypeSig);
}
void Write(BinaryWriter writer, AssemblyRef asmRef) {
writer.Write((byte)Table.AssemblyRef);
bool canWriteAsm = IsNonObfuscatedAssembly(asmRef);
writer.Write(canWriteAsm);
if (canWriteAsm) {
bool hasPk = !PublicKeyBase.IsNullOrEmpty2(asmRef.PublicKeyOrToken);
writer.Write(hasPk);
if (hasPk)
writer.Write(PublicKeyBase.ToPublicKeyToken(asmRef.PublicKeyOrToken).Data);
writer.Write(asmRef.Name);
writer.Write(asmRef.Culture);
}
}
static bool IsFromNonObfuscatedAssembly(IMemberRefParent mrp) {
return IsFromNonObfuscatedAssembly(mrp as TypeRef);
}
static bool IsFromNonObfuscatedAssembly(TypeRef tr) {
if (tr == null)
return false;
for (int i = 0; i < 100; i++) {
var asmRef = tr.ResolutionScope as AssemblyRef;
if (asmRef != null)
return IsNonObfuscatedAssembly(asmRef);
var tr2 = tr.ResolutionScope as TypeRef;
if (tr2 != null) {
tr = tr2;
continue;
}
break;
}
return false;
}
static bool IsNonObfuscatedAssembly(AssemblyRef asmRef) {
if (asmRef == null)
return false;
// The only external asm refs it uses...
if (asmRef.Name != "mscorlib" && asmRef.Name != "System")
return false;
return true;
}
bool IsTypeField(FieldDef fd) {
return fd != null && fd.DeclaringType == blocks.Method.DeclaringType;
}
int GetFieldId(FieldDef fd) {
if (fd == null)
return int.MinValue;
var fieldType = fd.FieldSig.GetFieldType();
if (fieldType == null)
return int.MinValue + 1;
int result = 0;
for (int i = 0; i < 100; i++) {
result += (int)fieldType.ElementType;
if (fieldType.Next == null)
break;
result += 0x100;
fieldType = fieldType.Next;
}
var td = fieldType.TryGetTypeDef();
if (td != null && td.IsEnum)
return result + 0x10000000;
return result;
}
static Code SimplifyBranch(Code code) {
switch (code) {
case Code.Beq_S: return Code.Beq;
case Code.Bge_S: return Code.Bge;
case Code.Bgt_S: return Code.Bgt;
case Code.Ble_S: return Code.Ble;
case Code.Blt_S: return Code.Blt;
case Code.Bne_Un_S: return Code.Bne_Un;
case Code.Bge_Un_S: return Code.Bge_Un;
case Code.Bgt_Un_S: return Code.Bgt_Un;
case Code.Ble_Un_S: return Code.Ble_Un;
case Code.Blt_Un_S: return Code.Blt_Un;
case Code.Br_S: return Code.Br;
case Code.Brfalse_S: return Code.Brfalse;
case Code.Brtrue_S: return Code.Brtrue;
case Code.Leave_S: return Code.Leave;
default: return code;
}
}
}
}

View File

@ -1,38 +0,0 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
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 dnlib.DotNet;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class OpCodeHandler {
public OpCodeHandlerInfo OpCodeHandlerInfo { get; private set; }
public TypeDef HandlerType { get; private set; }
public HandlerMethod ExecMethod { get; private set; }
public OpCodeHandler(OpCodeHandlerInfo opCodeHandlerInfo, TypeDef handlerType, HandlerMethod execMethod) {
this.OpCodeHandlerInfo = opCodeHandlerInfo;
this.HandlerType = handlerType;
this.ExecMethod = execMethod;
}
public override string ToString() {
return OpCodeHandlerInfo.Name;
}
}
}

View File

@ -19,24 +19,35 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class OpCodeHandlerInfo {
public HandlerTypeCode TypeCode { get; private set; }
public string Name { get; private set; }
public MethodSigInfo ExecSig { get; private set; }
public OpCodeHandlerInfo(HandlerTypeCode typeCode, MethodSigInfo execSig) {
public OpCodeHandlerInfo(HandlerTypeCode typeCode) {
this.TypeCode = typeCode;
this.Name = GetHandlerName(typeCode);
this.ExecSig = execSig;
}
public override string ToString() {
return Name;
}
static string GetHandlerName(HandlerTypeCode code) {
public static string GetCompositeName(IList<HandlerTypeCode> typeCodes) {
if (typeCodes.Count == 0)
return "<nothing>";
var sb = new StringBuilder();
foreach (var typeCode in typeCodes) {
if (sb.Length != 0)
sb.Append(", ");
sb.Append(GetHandlerName(typeCode));
}
return sb.ToString();
}
public static string GetHandlerName(HandlerTypeCode code) {
switch (code) {
case HandlerTypeCode.Add: return "add";
case HandlerTypeCode.Add_Ovf: return "add.ovf";

View File

@ -23,75 +23,61 @@ using System.IO;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
static class OpCodeHandlerInfos {
enum OpCodeHandlersFileVersion : int {
V1 = 1,
}
public static void Write(BinaryWriter writer, IList<OpCodeHandlerInfo> handlerInfos) {
WriteV1(writer, handlerInfos);
}
public static void WriteV1(BinaryWriter writer, IList<OpCodeHandlerInfo> handlerInfos) {
writer.Write((int)OpCodeHandlersFileVersion.V1);
public static void Write(BinaryWriter writer, List<MethodSigInfo> handlerInfos) {
writer.Write(1);
writer.Write(handlerInfos.Count);
foreach (var handler in handlerInfos) {
writer.Write((int)handler.TypeCode);
var infos = handler.ExecSig.BlockInfos;
writer.Write(infos.Count);
foreach (var info in infos) {
if (info.Hash == null)
writer.Write(0);
else {
writer.Write(info.Hash.Length);
writer.Write(info.Hash);
}
writer.Write(handler.BlockSigInfos.Count);
foreach (var info in handler.BlockSigInfos) {
writer.Write(info.Targets.Count);
foreach (var target in info.Targets)
writer.Write(target);
writer.Write(info.Hashes.Count);
foreach (var hash in info.Hashes)
writer.Write((uint)hash);
writer.Write(info.HasFallThrough);
writer.Write(info.EndsInRet);
}
}
}
public static List<OpCodeHandlerInfo> Read(BinaryReader reader) {
switch ((OpCodeHandlersFileVersion)reader.ReadInt32()) {
case OpCodeHandlersFileVersion.V1: return ReadV1(reader);
default: throw new ApplicationException("Invalid file version");
}
}
static List<OpCodeHandlerInfo> ReadV1(BinaryReader reader) {
public static List<MethodSigInfo> Read(BinaryReader reader) {
if (reader.ReadInt32() != 1)
throw new InvalidDataException();
int numHandlers = reader.ReadInt32();
var list = new List<OpCodeHandlerInfo>(numHandlers);
var list = new List<MethodSigInfo>(numHandlers);
for (int i = 0; i < numHandlers; i++) {
var typeCode = (HandlerTypeCode)reader.ReadInt32();
int numInfos = reader.ReadInt32();
var sigInfo = new MethodSigInfo();
for (int j = 0; j < numInfos; j++) {
var info = new BlockInfo();
info.Hash = reader.ReadBytes(reader.ReadInt32());
if (info.Hash.Length == 0)
info.Hash = null;
int numBlocks = reader.ReadInt32();
var blocks = new List<BlockSigInfo>(numBlocks);
for (int j = 0; j < numBlocks; j++) {
int numTargets = reader.ReadInt32();
var targets = new List<int>(numTargets);
for (int k = 0; k < numTargets; k++)
info.Targets.Add(reader.ReadInt32());
sigInfo.BlockInfos.Add(info);
targets.Add(reader.ReadInt32());
var numHashes = reader.ReadInt32();
var hashes = new List<BlockElementHash>(numHashes);
for (int k = 0; k < numHashes; k++)
hashes.Add((BlockElementHash)reader.ReadInt32());
var block = new BlockSigInfo(hashes, targets);
block.HasFallThrough = reader.ReadBoolean();
block.EndsInRet = reader.ReadBoolean();
blocks.Add(block);
}
list.Add(new OpCodeHandlerInfo(typeCode, sigInfo));
list.Add(new MethodSigInfo(blocks, typeCode));
}
return list;
}
public static readonly IList<OpCodeHandlerInfo>[] HandlerInfos = new IList<OpCodeHandlerInfo>[] {
ReadOpCodeHandlerInfos(CsvmResources.CSVM1_v2),
ReadOpCodeHandlerInfos(CsvmResources.CSVM2_v2),
ReadOpCodeHandlerInfos(CsvmResources.CSVM3_v2),
public static readonly IList<MethodSigInfo>[] HandlerInfos = new IList<MethodSigInfo>[] {
ReadOpCodeHandlerInfos(CsvmResources.CSVM1),
ReadOpCodeHandlerInfos(CsvmResources.CSVM2),
ReadOpCodeHandlerInfos(CsvmResources.CSVM3),
ReadOpCodeHandlerInfos(CsvmResources.CSVM4),
};
static IList<OpCodeHandlerInfo> ReadOpCodeHandlerInfos(byte[] data) {
static IList<MethodSigInfo> ReadOpCodeHandlerInfos(byte[] data) {
return OpCodeHandlerInfos.Read(new BinaryReader(new MemoryStream(data)));
}
}

View File

@ -0,0 +1,593 @@
/*
Copyright (C) 2011-2013 de4dot@gmail.com
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;
using System.Text;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
using de4dot.blocks;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class MethodSigInfo {
public HandlerTypeCode TypeCode { get; set; }
public List<BlockSigInfo> BlockSigInfos { get; private set; }
public MethodSigInfo(List<BlockSigInfo> blockSigInfos) {
this.BlockSigInfos = blockSigInfos;
}
public MethodSigInfo(List<BlockSigInfo> blockSigInfos, HandlerTypeCode typeCode) {
this.BlockSigInfos = blockSigInfos;
this.TypeCode = typeCode;
}
public override string ToString() {
return OpCodeHandlerInfo.GetHandlerName(TypeCode);
}
}
class BlockSigInfo {
readonly List<int> targets;
public List<BlockElementHash> Hashes { get; private set; }
public List<int> Targets {
get { return targets; }
}
public bool HasFallThrough { get; set; }
public bool EndsInRet { get; set; }
public BlockSigInfo() {
this.targets = new List<int>();
this.Hashes = new List<BlockElementHash>();
}
public BlockSigInfo(List<BlockElementHash> hashes, List<int> targets) {
this.Hashes = hashes;
this.targets = targets;
}
}
enum BlockElementHash : int {
}
class SigCreator {
const int BASE_INDEX = 0x40000000;
Blocks blocks;
Dictionary<object, int> objToId = new Dictionary<object, int>();
CRC32 hasher = new CRC32();
public SigCreator() {
}
public void AddId(object key, int id) {
if (key != null)
objToId[key] = id;
}
int? GetId(object key) {
if (key == null)
return null;
int id;
if (objToId.TryGetValue(key, out id))
return id;
return null;
}
public List<BlockSigInfo> Create(MethodDef method) {
blocks = new Blocks(method);
var allBlocks = blocks.MethodBlocks.GetAllBlocks();
var blockInfos = new List<BlockSigInfo>(allBlocks.Count);
foreach (var block in allBlocks) {
var blockInfo = new BlockSigInfo();
blockInfo.HasFallThrough = block.FallThrough != null;
blockInfo.EndsInRet = block.LastInstr.OpCode.Code == Code.Ret;
blockInfos.Add(blockInfo);
var instrs = block.Instructions;
for (int i = 0; i < instrs.Count; i++) {
var info = CalculateHash(instrs, ref i);
if (info != null)
blockInfo.Hashes.Add(info.Value);
}
}
for (int i = 0; i < blockInfos.Count; i++) {
var block = allBlocks[i];
var blockInfo = blockInfos[i];
if (block.FallThrough != null)
blockInfo.Targets.Add(allBlocks.IndexOf(block.FallThrough));
if (block.Targets != null) {
foreach (var target in block.Targets)
blockInfo.Targets.Add(allBlocks.IndexOf(target));
}
}
return blockInfos;
}
BlockElementHash? CalculateHash(IList<Instr> instrs, ref int index) {
hasher.Initialize();
var instr = instrs[index];
switch (instr.OpCode.Code) {
case Code.Beq:
case Code.Beq_S:
return GetHash(BASE_INDEX + 0);
case Code.Bge:
case Code.Bge_S:
return GetHash(BASE_INDEX + 1);
case Code.Bge_Un:
case Code.Bge_Un_S:
return GetHash(BASE_INDEX + 2);
case Code.Bgt:
case Code.Bgt_S:
return GetHash(BASE_INDEX + 3);
case Code.Bgt_Un:
case Code.Bgt_Un_S:
return GetHash(BASE_INDEX + 4);
case Code.Ble:
case Code.Ble_S:
return GetHash(BASE_INDEX + 5);
case Code.Ble_Un:
case Code.Ble_Un_S:
return GetHash(BASE_INDEX + 6);
case Code.Blt:
case Code.Blt_S:
return GetHash(BASE_INDEX + 7);
case Code.Blt_Un:
case Code.Blt_Un_S:
return GetHash(BASE_INDEX + 8);
case Code.Bne_Un:
case Code.Bne_Un_S:
return GetHash(BASE_INDEX + 9);
case Code.Brfalse:
case Code.Brfalse_S:
return GetHash(BASE_INDEX + 10);
case Code.Brtrue:
case Code.Brtrue_S:
return GetHash(BASE_INDEX + 11);
case Code.Switch:
return GetHash(BASE_INDEX + 12);
case Code.Ceq:
return GetHash(BASE_INDEX + 13);
case Code.Cgt:
return GetHash(BASE_INDEX + 14);
case Code.Cgt_Un:
return GetHash(BASE_INDEX + 15);
case Code.Clt:
return GetHash(BASE_INDEX + 16);
case Code.Clt_Un:
return GetHash(BASE_INDEX + 17);
case Code.Ldc_I4:
case Code.Ldc_I4_0:
case Code.Ldc_I4_1:
case Code.Ldc_I4_2:
case Code.Ldc_I4_3:
case Code.Ldc_I4_4:
case Code.Ldc_I4_5:
case Code.Ldc_I4_6:
case Code.Ldc_I4_7:
case Code.Ldc_I4_8:
case Code.Ldc_I4_M1:
case Code.Ldc_I4_S:
return GetHash(instr.GetLdcI4Value());
case Code.Ldstr:
return GetHash(instr.Operand as string);
case Code.Rethrow:
return GetHash(BASE_INDEX + 18);
case Code.Throw:
return GetHash(BASE_INDEX + 19);
case Code.Call:
case Code.Callvirt:
Hash(instr.Operand);
return (BlockElementHash)hasher.GetHash();
case Code.Ldfld:
var field = instr.Operand as FieldDef;
if (!IsTypeField(field))
return null;
if (index + 1 >= instrs.Count || !instrs[index + 1].IsLdcI4())
return null;
index++;
return GetHash(GetFieldId(field));
default:
break;
}
return null;
}
bool IsTypeField(FieldDef fd) {
return fd != null && fd.DeclaringType == blocks.Method.DeclaringType;
}
static int GetFieldId(FieldDef fd) {
if (fd == null)
return int.MinValue;
var fieldType = fd.FieldSig.GetFieldType();
if (fieldType == null)
return int.MinValue + 1;
int result = BASE_INDEX + 0x1000;
for (int i = 0; i < 100; i++) {
result += (int)fieldType.ElementType;
if (fieldType.Next == null)
break;
result += 0x100;
fieldType = fieldType.Next;
}
var td = fieldType.TryGetTypeDef();
if (td != null && td.IsEnum)
return result + 0x10000000;
return result;
}
void Hash(object op) {
var md = op as MethodDef;
if (md != null) {
Hash(md);
return;
}
var mr = op as MemberRef;
if (mr != null) {
Hash(mr);
return;
}
var td = op as TypeDef;
if (td != null) {
Hash(td);
return;
}
var tr = op as TypeRef;
if (tr != null) {
Hash(tr);
return;
}
var ts = op as TypeSpec;
if (ts != null) {
Hash(ts);
return;
}
var fsig = op as FieldSig;
if (fsig != null) {
Hash(fsig);
return;
}
var msig = op as MethodSig;
if (msig != null) {
Hash(msig);
return;
}
var gsig = op as GenericInstMethodSig;
if (gsig != null) {
Hash(gsig);
return;
}
var asmRef = op as AssemblyRef;
if (asmRef != null) {
Hash(asmRef);
return;
}
var tsig = op as TypeSig;
if (tsig != null) {
Hash(tsig);
return;
}
return;
}
void Hash(TypeSig sig) {
Hash(sig, 0);
}
void Hash(TypeSig sig, int level) {
if (sig == null)
return;
if (level++ > 20)
return;
hasher.Hash((byte)0x41);
var etype = sig.GetElementType();
hasher.Hash((byte)etype);
switch (etype) {
case ElementType.Ptr:
case ElementType.ByRef:
case ElementType.SZArray:
case ElementType.Pinned:
Hash(sig.Next, level);
break;
case ElementType.Array:
var arySig = (ArraySig)sig;
hasher.Hash(arySig.Rank);
hasher.Hash(arySig.Sizes.Count);
hasher.Hash(arySig.LowerBounds.Count);
Hash(sig.Next, level);
break;
case ElementType.CModReqd:
case ElementType.CModOpt:
Hash(((ModifierSig)sig).Modifier);
Hash(sig.Next, level);
break;
case ElementType.ValueArray:
hasher.Hash(((ValueArraySig)sig).Size);
Hash(sig.Next, level);
break;
case ElementType.Module:
hasher.Hash(((ModuleSig)sig).Index);
Hash(sig.Next, level);
break;
case ElementType.GenericInst:
var gis = (GenericInstSig)sig;
Hash(gis.GenericType, level);
foreach (var ga in gis.GenericArguments)
Hash(ga, level);
Hash(sig.Next, level);
break;
case ElementType.FnPtr:
Hash(((FnPtrSig)sig).Signature);
break;
case ElementType.Var:
case ElementType.MVar:
hasher.Hash(((GenericSig)sig).Number);
break;
case ElementType.ValueType:
case ElementType.Class:
Hash(((TypeDefOrRefSig)sig).TypeDefOrRef);
break;
case ElementType.End:
case ElementType.Void:
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
case ElementType.I8:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.String:
case ElementType.TypedByRef:
case ElementType.I:
case ElementType.U:
case ElementType.R:
case ElementType.Object:
case ElementType.Internal:
case ElementType.Sentinel:
default:
break;
}
}
void Hash(MethodDef md) {
if (md == null)
return;
var attrMask1 = MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask |
MethodImplAttributes.ForwardRef | MethodImplAttributes.PreserveSig |
MethodImplAttributes.InternalCall;
hasher.Hash((ushort)(md == null ? 0 : md.ImplAttributes & attrMask1));
var attrMask2 = MethodAttributes.Static | MethodAttributes.Virtual |
MethodAttributes.HideBySig | MethodAttributes.VtableLayoutMask |
MethodAttributes.CheckAccessOnOverride | MethodAttributes.Abstract |
MethodAttributes.SpecialName | MethodAttributes.PinvokeImpl |
MethodAttributes.UnmanagedExport | MethodAttributes.RTSpecialName;
hasher.Hash((ushort)(md.Attributes & attrMask2));
Hash(md.Signature);
hasher.Hash(md.ParamDefs.Count);
hasher.Hash(md.GenericParameters.Count);
hasher.Hash(md.HasImplMap ? 1 : 0);
var id = GetId(md);
if (id != null)
hasher.Hash(id.Value);
}
void Hash(MemberRef mr) {
if (mr == null)
return;
Hash(mr.Class);
if (IsFromNonObfuscatedAssembly(mr.Class))
Hash(mr.Name);
Hash(mr.Signature);
}
void Hash(TypeDef td) {
if (td == null)
return;
Hash(td.BaseType);
var attrMask = TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask |
TypeAttributes.Abstract | TypeAttributes.SpecialName |
TypeAttributes.Import | TypeAttributes.WindowsRuntime |
TypeAttributes.StringFormatMask | TypeAttributes.RTSpecialName;
hasher.Hash((uint)(td.Attributes & attrMask));
hasher.Hash(td.GenericParameters.Count);
hasher.Hash(td.Interfaces.Count);
foreach (var iface in td.Interfaces)
Hash(iface.Interface);
var id = GetId(td);
if (id != null)
hasher.Hash(id.Value);
}
void Hash(TypeRef tr) {
if (tr == null)
return;
Hash(tr.ResolutionScope);
if (IsFromNonObfuscatedAssembly(tr)) {
Hash(tr.Namespace);
Hash(tr.Name);
}
}
void Hash(TypeSpec ts) {
if (ts == null)
return;
Hash(ts.TypeSig);
}
void Hash(FieldSig sig) {
if (sig == null)
return;
hasher.Hash((byte)sig.GetCallingConvention());
Hash(sig.GetFieldType());
}
void Hash(MethodSig sig) {
if (sig == null)
return;
hasher.Hash((byte)sig.GetCallingConvention());
Hash(sig.GetRetType());
foreach (var p in sig.GetParams())
Hash(p);
hasher.Hash(sig.GetParamCount());
if (sig.GetParamsAfterSentinel() != null) {
foreach (var p in sig.GetParamsAfterSentinel())
Hash(p);
}
}
void Hash(GenericInstMethodSig sig) {
if (sig == null)
return;
hasher.Hash((byte)sig.GetCallingConvention());
foreach (var ga in sig.GetGenericArguments())
Hash(ga);
}
void Hash(AssemblyRef asmRef) {
if (asmRef == null)
return;
bool canWriteAsm = IsNonObfuscatedAssembly(asmRef);
hasher.Hash(canWriteAsm ? 1 : 0);
if (canWriteAsm) {
bool hasPk = !PublicKeyBase.IsNullOrEmpty2(asmRef.PublicKeyOrToken);
if (hasPk)
hasher.Hash(PublicKeyBase.ToPublicKeyToken(asmRef.PublicKeyOrToken).Data);
Hash(asmRef.Name);
Hash(asmRef.Culture);
}
}
void Hash(string s) {
if (s != null)
hasher.Hash(Encoding.UTF8.GetBytes(s));
}
BlockElementHash GetHash(int val) {
hasher.Hash(val);
return (BlockElementHash)hasher.GetHash();
}
BlockElementHash GetHash(string s) {
Hash(s);
return (BlockElementHash)hasher.GetHash();
}
static bool IsFromNonObfuscatedAssembly(IMemberRefParent mrp) {
return IsFromNonObfuscatedAssembly(mrp as TypeRef);
}
static bool IsFromNonObfuscatedAssembly(TypeRef tr) {
if (tr == null)
return false;
for (int i = 0; i < 100; i++) {
var asmRef = tr.ResolutionScope as AssemblyRef;
if (asmRef != null)
return IsNonObfuscatedAssembly(asmRef);
var tr2 = tr.ResolutionScope as TypeRef;
if (tr2 != null) {
tr = tr2;
continue;
}
break;
}
return false;
}
static bool IsNonObfuscatedAssembly(IAssembly asm) {
if (asm == null)
return false;
// The only external asm refs it uses...
if (asm.Name != "mscorlib" && asm.Name != "System")
return false;
return true;
}
}
}

View File

@ -22,23 +22,15 @@ using System.Text;
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
class VmOpCode {
public List<OpCodeHandlerInfo> OpCodeHandlerInfos { get; private set; }
public List<HandlerTypeCode> HandlerTypeCodes { get; private set; }
public VmOpCode(List<OpCodeHandlerInfo> opCodeHandlerInfos) {
this.OpCodeHandlerInfos = new List<OpCodeHandlerInfo>(opCodeHandlerInfos.Count);
this.OpCodeHandlerInfos.AddRange(opCodeHandlerInfos);
public VmOpCode(List<HandlerTypeCode> opCodeHandlerInfos) {
this.HandlerTypeCodes = new List<HandlerTypeCode>(opCodeHandlerInfos.Count);
this.HandlerTypeCodes.AddRange(opCodeHandlerInfos);
}
public override string ToString() {
if (OpCodeHandlerInfos.Count == 0)
return "<nothing>";
var sb = new StringBuilder();
foreach (var handler in OpCodeHandlerInfos) {
if (sb.Length != 0)
sb.Append(", ");
sb.Append(handler.Name);
}
return sb.ToString();
return OpCodeHandlerInfo.GetCompositeName(HandlerTypeCodes);
}
}
}

View File

@ -81,7 +81,6 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
return;
deobfuscator = new MyDeobfuscator(module);
var csvmInfo = new CsvmInfo(module);
csvmInfo.Initialize();
var vmHandlerTypes = FindVmHandlerTypes();
@ -90,9 +89,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
var composites = CreateCompositeOpCodeHandlers(csvmInfo, vmHandlerTypes);
foreach (var handlerInfos in OpCodeHandlerInfos.HandlerInfos) {
var otherHandlers = CreateOtherHandlers(csvmInfo, handlerInfos);
if (!DetectCompositeHandlers(composites, otherHandlers))
if (!DetectCompositeHandlers(composites, handlerInfos))
continue;
vmOpCodes = CreateVmOpCodes(composites);
@ -105,12 +102,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
static List<VmOpCode> CreateVmOpCodes(IList<CompositeOpCodeHandler> composites) {
var list = new List<VmOpCode>(composites.Count);
foreach (var composite in composites)
list.Add(new VmOpCode(composite.OpCodeHandlerInfos));
list.Add(new VmOpCode(composite.TypeCodes));
return list;
}
bool DetectCompositeHandlers(IEnumerable<CompositeOpCodeHandler> composites, List<OpCodeHandler> otherHandlers) {
var detector = new CompositeHandlerDetector(otherHandlers);
bool DetectCompositeHandlers(IEnumerable<CompositeOpCodeHandler> composites, IList<MethodSigInfo> handlerInfos) {
var detector = new CompositeHandlerDetector(handlerInfos);
foreach (var composite in composites) {
if (!detector.FindHandlers(composite))
return false;
@ -128,15 +125,18 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
List<CompositeOpCodeHandler> CreateCompositeOpCodeHandlers(CsvmInfo csvmInfo, List<TypeDef> handlers) {
var list = new List<CompositeOpCodeHandler>(handlers.Count);
foreach (var handler in handlers) {
var execHandler = new HandlerMethod(GetExecMethod(handler));
list.Add(new CompositeOpCodeHandler(handler, execHandler));
}
var sigCreator = CreateSigCreator(csvmInfo);
foreach (var handler in handlers)
list.Add(new CompositeOpCodeHandler(sigCreator.Create(GetExecMethod(handler))));
return list;
}
MethodDef GetExecMethod(TypeDef type) {
return GetExecMethod(deobfuscator, type);
}
static MethodDef GetExecMethod(MyDeobfuscator deobfuscator, TypeDef type) {
MethodDef readMethod, execMethod;
GetReadAndExecMethods(type, out readMethod, out execMethod);
deobfuscator.Deobfuscate(execMethod);
@ -144,8 +144,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
return execMethod;
}
static MethodSigInfoCreator CreateMethodSigInfoCreator(CsvmInfo csvmInfo) {
var creator = new MethodSigInfoCreator();
static SigCreator CreateSigCreator(CsvmInfo csvmInfo) {
var creator = new SigCreator();
creator.AddId(csvmInfo.LogicalOpShrUn, 1);
creator.AddId(csvmInfo.LogicalOpShl, 2);
@ -183,9 +183,20 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
creator.AddId(csvmInfo.LocalsGet, 30);
creator.AddId(csvmInfo.LocalsSet, 31);
AddTypeId(creator, csvmInfo.LogicalOpShrUn, 32);
AddTypeId(creator, csvmInfo.CompareLt, 33);
AddTypeId(creator, csvmInfo.ArithmeticSubOvfUn, 34);
AddTypeId(creator, csvmInfo.UnaryNot, 35);
AddTypeId(creator, csvmInfo.ArgsGet, 36);
return creator;
}
static void AddTypeId(SigCreator creator, MethodDef method, int id) {
if (method != null)
creator.AddId(method.DeclaringType, id);
}
static void GetReadAndExecMethods(TypeDef handler, out MethodDef readMethod, out MethodDef execMethod) {
readMethod = execMethod = null;
foreach (var method in handler.Methods) {
@ -270,28 +281,5 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
return list;
}
List<OpCodeHandler> CreateOtherHandlers(CsvmInfo csvmInfo, IList<OpCodeHandlerInfo> handlerInfos) {
var list = new List<OpCodeHandler>(NUM_HANDLERS);
foreach (var type in GetVmHandlerTypes(csvmInfo.VmHandlerBaseType)) {
if (list.Count == NUM_HANDLERS)
break;
var execHandler = new PrimitiveHandlerMethod(GetExecMethod(type));
execHandler.Sig = CreateMethodSigInfoCreator(csvmInfo).Create(execHandler.Blocks);
var finder = new MethodFinder(handlerInfos, execHandler);
var handler = finder.FindHandler();
if (handler == null)
continue;
list.Add(handler);
}
list.Sort((a, b) => a.OpCodeHandlerInfo.Name.ToUpperInvariant().CompareTo(b.OpCodeHandlerInfo.Name.ToUpperInvariant()));
return list;
}
}
}

View File

@ -581,6 +581,23 @@ namespace de4dot.mdecrypt {
return hModule;
}
class PatchInfo {
public int RVA;
public byte[] Data;
public byte[] Orig;
public PatchInfo(int rva, byte[] data, byte[] orig) {
this.RVA = rva;
this.Data = data;
this.Orig = orig;
}
}
static readonly PatchInfo[] patches = new PatchInfo[] {
new PatchInfo(0x000110A5, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x36, 0x3A, 0x00, 0x00 }),
new PatchInfo(0x000110AF, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0x4C, 0x3C, 0x00, 0x00 }),
new PatchInfo(0x000110AA, new byte[] { 0x33, 0xC0, 0xC2, 0x04, 0x00 }, new byte[] { 0xE9, 0xF1, 0x3A, 0x00, 0x00 }),
};
static unsafe bool PatchCM(IntPtr addr, IntPtr origValue, IntPtr newValue) {
var baseAddr = GetModuleHandle(addr);
IntPtr patchAddr;
@ -590,6 +607,45 @@ namespace de4dot.mdecrypt {
return false;
*(IntPtr*)patchAddr = newValue;
PatchRT(baseAddr);
return true;
}
[HandleProcessCorruptedStateExceptions, SecurityCritical] // Req'd on .NET 4.0
static unsafe bool PatchRT(IntPtr baseAddr) {
foreach (var info in patches) {
try {
var addr = new IntPtr(baseAddr.ToInt64() + info.RVA);
var data = new byte[info.Orig.Length];
Marshal.Copy(addr, data, 0, data.Length);
if (!Equals(data, info.Orig))
continue;
uint oldProtect;
if (!VirtualProtect(addr, info.Data.Length, PAGE_EXECUTE_READWRITE, out oldProtect))
throw new ApplicationException("Could not enable write access");
Marshal.Copy(info.Data, 0, addr, info.Data.Length);
VirtualProtect(addr, info.Data.Length, oldProtect, out oldProtect);
return true;
}
catch {
}
}
return false;
}
static bool Equals(byte[] a, byte[] b) {
if (a == b)
return true;
if (a == null || b == null)
return false;
if (a.Length != b.Length)
return false;
for (int i = 0; i < a.Length; i++) {
if (a[i] != b[i])
return false;
}
return true;
}