Support Agile.NET 6.3.0.10
This commit is contained in:
parent
cc56b730b3
commit
e2a95f6838
|
@ -88,12 +88,10 @@
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="deobfuscators\Agile_NET\vm\v2\CsvmToCilMethodConverter.cs" />
|
<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\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\OpCodeHandlerInfo.cs" />
|
||||||
<Compile Include="deobfuscators\Agile_NET\vm\v2\OpCodeHandlerInfoReader.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\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\VmOpCode.cs" />
|
||||||
<Compile Include="deobfuscators\Agile_NET\vm\v2\VmOpCodeHandlerDetector.cs" />
|
<Compile Include="deobfuscators\Agile_NET\vm\v2\VmOpCodeHandlerDetector.cs" />
|
||||||
<Compile Include="deobfuscators\Agile_NET\vm\VmOperand.cs" />
|
<Compile Include="deobfuscators\Agile_NET\vm\VmOperand.cs" />
|
||||||
|
|
BIN
de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1.bin
Normal file
BIN
de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM1.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2.bin
Normal file
BIN
de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM2.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3.bin
Normal file
BIN
de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM3.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM4.bin
Normal file
BIN
de4dot.code/deobfuscators/Agile_NET/vm/v2/CSVM4.bin
Normal file
Binary file not shown.
|
@ -25,19 +25,17 @@ using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
class CompositeHandlerDetector {
|
class CompositeHandlerDetector {
|
||||||
readonly List<OpCodeHandler> handlers;
|
readonly List<MethodSigInfo> handlers;
|
||||||
|
|
||||||
public CompositeHandlerDetector(IList<OpCodeHandler> handlers) {
|
public CompositeHandlerDetector(IList<MethodSigInfo> handlers) {
|
||||||
this.handlers = new List<OpCodeHandler>(handlers.Count);
|
this.handlers = new List<MethodSigInfo>(handlers);
|
||||||
OpCodeHandler nop = null;
|
|
||||||
foreach (var handler in handlers) {
|
this.handlers.Sort((a, b) => {
|
||||||
if (nop == null && handler.OpCodeHandlerInfo.TypeCode == HandlerTypeCode.Nop)
|
int r = b.BlockSigInfos.Count.CompareTo(a.BlockSigInfos.Count);
|
||||||
nop = handler;
|
if (r != 0)
|
||||||
else
|
return r;
|
||||||
this.handlers.Add(handler);
|
return b.BlockSigInfos[0].Hashes.Count.CompareTo(a.BlockSigInfos[0].Hashes.Count);
|
||||||
}
|
});
|
||||||
if (nop != null)
|
|
||||||
this.handlers.Add(nop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MatchState {
|
struct MatchState {
|
||||||
|
@ -51,27 +49,18 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HandlerState {
|
struct HandlerState {
|
||||||
public readonly HandlerMethod HandlerMethod;
|
public readonly List<BlockSigInfo> BlockSigInfos;
|
||||||
public readonly IList<Block> Blocks;
|
|
||||||
public readonly int BlockIndex;
|
public readonly int BlockIndex;
|
||||||
public int InstructionIndex;
|
public int HashIndex;
|
||||||
|
|
||||||
public HandlerState(HandlerMethod handlerMethod, int blockIndex, int instructionIndex) {
|
public HandlerState(List<BlockSigInfo> blockSigInfos, int blockIndex, int instructionIndex) {
|
||||||
this.HandlerMethod = handlerMethod;
|
this.BlockSigInfos = blockSigInfos;
|
||||||
this.Blocks = handlerMethod.Blocks.MethodBlocks.GetAllBlocks();
|
|
||||||
this.BlockIndex = blockIndex;
|
this.BlockIndex = blockIndex;
|
||||||
this.InstructionIndex = instructionIndex;
|
this.HashIndex = instructionIndex;
|
||||||
}
|
|
||||||
|
|
||||||
public HandlerState(HandlerMethod handlerMethod, IList<Block> blocks, int blockIndex, int instructionIndex) {
|
|
||||||
this.HandlerMethod = handlerMethod;
|
|
||||||
this.Blocks = blocks;
|
|
||||||
this.BlockIndex = blockIndex;
|
|
||||||
this.InstructionIndex = instructionIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HandlerState Clone() {
|
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) {
|
public bool FindHandlers(CompositeOpCodeHandler composite) {
|
||||||
composite.OpCodeHandlerInfos.Clear();
|
composite.TypeCodes.Clear();
|
||||||
var compositeExecState = new FindHandlerState(new HandlerState(composite.ExecMethod, 0, 0));
|
var compositeExecState = new FindHandlerState(new HandlerState(composite.BlockSigInfos, 0, 0));
|
||||||
while (!compositeExecState.Done) {
|
while (!compositeExecState.Done) {
|
||||||
var handler = FindHandlerMethod(ref compositeExecState);
|
var handler = FindHandlerMethod(ref compositeExecState);
|
||||||
if (handler == null)
|
if (handler == null)
|
||||||
return false;
|
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) {
|
foreach (var handler in handlers) {
|
||||||
FindHandlerState findExecStateNew = findExecState.Clone();
|
FindHandlerState findExecStateNew = findExecState.Clone();
|
||||||
if (!Matches(handler.ExecMethod, ref findExecStateNew))
|
if (!Matches(handler.BlockSigInfos, ref findExecStateNew))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
findExecState = findExecStateNew;
|
findExecState = findExecStateNew;
|
||||||
|
@ -123,14 +112,14 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
Stack<MatchState> stack = new Stack<MatchState>();
|
Stack<MatchState> stack = new Stack<MatchState>();
|
||||||
bool Matches(HandlerMethod handler, ref FindHandlerState findState) {
|
bool Matches(List<BlockSigInfo> handler, ref FindHandlerState findState) {
|
||||||
HandlerState? nextState = null;
|
HandlerState? nextState = null;
|
||||||
stack.Clear();
|
stack.Clear();
|
||||||
stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
|
stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
|
||||||
while (stack.Count > 0) {
|
while (stack.Count > 0) {
|
||||||
var matchState = stack.Pop();
|
var matchState = stack.Pop();
|
||||||
|
|
||||||
if (matchState.CompositeState.InstructionIndex == 0) {
|
if (matchState.CompositeState.HashIndex == 0) {
|
||||||
if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
|
if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
|
||||||
continue;
|
continue;
|
||||||
findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
|
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))
|
if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var hblock = matchState.OtherState.Blocks[matchState.OtherState.BlockIndex];
|
var hblock = matchState.OtherState.BlockSigInfos[matchState.OtherState.BlockIndex];
|
||||||
var hinstrs = hblock.Instructions;
|
var hinstrs = hblock.Hashes;
|
||||||
int hi = matchState.OtherState.InstructionIndex;
|
int hi = matchState.OtherState.HashIndex;
|
||||||
var cblock = matchState.CompositeState.Blocks[matchState.CompositeState.BlockIndex];
|
var cblock = matchState.CompositeState.BlockSigInfos[matchState.CompositeState.BlockIndex];
|
||||||
var cinstrs = cblock.Instructions;
|
var cinstrs = cblock.Hashes;
|
||||||
int ci = matchState.CompositeState.InstructionIndex;
|
int ci = matchState.CompositeState.HashIndex;
|
||||||
if (hi < hinstrs.Count)
|
if (hi < hinstrs.Count)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ci < cinstrs.Count) {
|
if (ci < cinstrs.Count) {
|
||||||
if (hblock.CountTargets() != 0)
|
if (hblock.Targets.Count != 0)
|
||||||
return false;
|
return false;
|
||||||
if (hblock.LastInstr.OpCode.Code == Code.Ret) {
|
if (hblock.EndsInRet) {
|
||||||
if (nextState != null)
|
if (nextState != null)
|
||||||
return false;
|
return false;
|
||||||
nextState = matchState.CompositeState;
|
nextState = matchState.CompositeState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (cblock.CountTargets() != hblock.CountTargets())
|
if (cblock.Targets.Count != hblock.Targets.Count)
|
||||||
return false;
|
return false;
|
||||||
if (cblock.FallThrough != null || hblock.FallThrough != null) {
|
if (cblock.HasFallThrough != hblock.HasFallThrough)
|
||||||
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);
|
|
||||||
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;
|
return false;
|
||||||
|
|
||||||
for (int i = 0; i < cblock.Targets.Count; i++) {
|
for (int i = 0; i < cblock.Targets.Count; i++) {
|
||||||
var hs = CreateHandlerState(handler, matchState.OtherState.Blocks, hblock.Targets[i]);
|
var hs = new HandlerState(handler, hblock.Targets[i], 0);
|
||||||
var cs = CreateHandlerState(findState.CompositeState.HandlerMethod, findState.CompositeState.Blocks, cblock.Targets[i]);
|
var cs = new HandlerState(findState.CompositeState.BlockSigInfos, cblock.Targets[i], 0);
|
||||||
stack.Push(new MatchState(hs, cs));
|
stack.Push(new MatchState(hs, cs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (nextState == null) {
|
if (nextState == null) {
|
||||||
|
if (findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
|
||||||
|
return false;
|
||||||
findState.Done = true;
|
findState.Done = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
|
if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
|
||||||
findState.CompositeState.InstructionIndex == nextState.Value.InstructionIndex)
|
findState.CompositeState.HashIndex == nextState.Value.HashIndex)
|
||||||
return false;
|
return false;
|
||||||
findState.CompositeState = nextState.Value;
|
findState.CompositeState = nextState.Value;
|
||||||
|
if (findState.CompositeState.HashIndex == 0)
|
||||||
|
findState.VisitedCompositeBlocks.Remove(findState.CompositeState.BlockIndex);
|
||||||
return true;
|
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) {
|
static bool Compare(ref HandlerState handler, ref HandlerState composite) {
|
||||||
var hinstrs = handler.Blocks[handler.BlockIndex].Instructions;
|
var hhashes = handler.BlockSigInfos[handler.BlockIndex].Hashes;
|
||||||
int hi = handler.InstructionIndex;
|
int hi = handler.HashIndex;
|
||||||
var cinstrs = composite.Blocks[composite.BlockIndex].Instructions;
|
var chashes = composite.BlockSigInfos[composite.BlockIndex].Hashes;
|
||||||
int ci = composite.InstructionIndex;
|
int ci = composite.HashIndex;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (hi >= hinstrs.Count && ci >= cinstrs.Count)
|
if (hi >= hhashes.Count && ci >= chashes.Count)
|
||||||
break;
|
break;
|
||||||
if (hi >= hinstrs.Count || ci >= cinstrs.Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var hinstr = hinstrs[hi++];
|
if (hi >= hhashes.Count) {
|
||||||
var cinstr = cinstrs[ci++];
|
if (handler.BlockSigInfos[handler.BlockIndex].EndsInRet)
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hi == hinstrs.Count && hinstr.OpCode.Code == Code.Ret) {
|
|
||||||
if (cinstr.OpCode.Code != Code.Br && cinstr.OpCode.Code != Code.Ret)
|
|
||||||
ci--;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hinstr.OpCode.Code != cinstr.OpCode.Code)
|
if (hi >= hhashes.Count || ci >= chashes.Count)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (hinstr.OpCode.Code == Code.Ldfld &&
|
var hhash = hhashes[hi++];
|
||||||
hi + 1 < hinstrs.Count && ci + 1 < cinstrs.Count) {
|
var chash = chashes[ci++];
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.InstructionIndex = hi;
|
handler.HashIndex = hi;
|
||||||
composite.InstructionIndex = ci;
|
composite.HashIndex = ci;
|
||||||
return true;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,45 +23,17 @@ using dnlib.DotNet;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
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 {
|
class CompositeOpCodeHandler {
|
||||||
public TypeDef HandlerType { get; private set; }
|
public List<BlockSigInfo> BlockSigInfos { get; private set; }
|
||||||
public HandlerMethod ExecMethod { get; private set; }
|
public List<HandlerTypeCode> TypeCodes { get; private set; }
|
||||||
public List<OpCodeHandlerInfo> OpCodeHandlerInfos { get; private set; }
|
|
||||||
|
|
||||||
public CompositeOpCodeHandler(TypeDef handlerType, HandlerMethod execMethod) {
|
public CompositeOpCodeHandler(List<BlockSigInfo> blockSigInfos) {
|
||||||
this.HandlerType = handlerType;
|
this.BlockSigInfos = blockSigInfos;
|
||||||
this.ExecMethod = execMethod;
|
this.TypeCodes = new List<HandlerTypeCode>();
|
||||||
this.OpCodeHandlerInfos = new List<OpCodeHandlerInfo>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
if (OpCodeHandlerInfos.Count == 0)
|
return OpCodeHandlerInfo.GetCompositeName(TypeCodes);
|
||||||
return "<nothing>";
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
foreach (var handler in OpCodeHandlerInfos) {
|
|
||||||
if (sb.Length != 0)
|
|
||||||
sb.Append(", ");
|
|
||||||
sb.Append(handler.Name);
|
|
||||||
}
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,24 +594,59 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool FindUnaryOpsMethods() {
|
public bool FindUnaryOpsMethods() {
|
||||||
UnaryNot = FindUnaryOpMethod(Code.Not);
|
UnaryNot = FindUnaryOpMethod1(Code.Not);
|
||||||
UnaryNeg = FindUnaryOpMethod(Code.Neg);
|
UnaryNeg = FindUnaryOpMethod1(Code.Neg);
|
||||||
return UnaryNot != null && UnaryNeg != null;
|
if (UnaryNot != null && UnaryNeg != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return FindUnaryOpMethod2();
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodDef FindUnaryOpMethod(Code code) {
|
MethodDef FindUnaryOpMethod1(Code code) {
|
||||||
foreach (var type in module.Types) {
|
foreach (var type in module.Types) {
|
||||||
if (type.BaseType != VmHandlerBaseType)
|
if (type.BaseType != VmHandlerBaseType)
|
||||||
continue;
|
continue;
|
||||||
if (type.Methods.Count != 4)
|
if (type.Methods.Count != 4)
|
||||||
continue;
|
continue;
|
||||||
|
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) {
|
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)
|
if (!method.HasBody || !method.IsStatic)
|
||||||
continue;
|
return false;
|
||||||
if (!DotNetUtils.IsMethod(method, "System.Object", "(System.Object)"))
|
if (!DotNetUtils.IsMethod(method, "System.Object", "(System.Object)"))
|
||||||
continue;
|
return false;
|
||||||
if (CountThrows(method) != 1)
|
if (CountThrows(method) != 1)
|
||||||
continue;
|
return false;
|
||||||
var instrs = method.Body.Instructions;
|
var instrs = method.Body.Instructions;
|
||||||
for (int i = 0; i < instrs.Count - 4; i++) {
|
for (int i = 0; i < instrs.Count - 4; i++) {
|
||||||
var ldarg = instrs[i];
|
var ldarg = instrs[i];
|
||||||
|
@ -626,11 +661,10 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
if (!instrs[i + 4].IsStloc())
|
if (!instrs[i + 4].IsStloc())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return method;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
return false;
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CountThrows(MethodDef method) {
|
static int CountThrows(MethodDef method) {
|
||||||
|
|
|
@ -63,9 +63,9 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Byte[].
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static byte[] CSVM1_v2 {
|
internal static byte[] CSVM1 {
|
||||||
get {
|
get {
|
||||||
object obj = ResourceManager.GetObject("CSVM1_v2", resourceCulture);
|
object obj = ResourceManager.GetObject("CSVM1", resourceCulture);
|
||||||
return ((byte[])(obj));
|
return ((byte[])(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,9 +73,9 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Byte[].
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static byte[] CSVM2_v2 {
|
internal static byte[] CSVM2 {
|
||||||
get {
|
get {
|
||||||
object obj = ResourceManager.GetObject("CSVM2_v2", resourceCulture);
|
object obj = ResourceManager.GetObject("CSVM2", resourceCulture);
|
||||||
return ((byte[])(obj));
|
return ((byte[])(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,9 +83,19 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Byte[].
|
/// Looks up a localized resource of type System.Byte[].
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static byte[] CSVM3_v2 {
|
internal static byte[] CSVM3 {
|
||||||
get {
|
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));
|
return ((byte[])(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,14 +117,17 @@
|
||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
<data name="CSVM1_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="CSVM1" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>CSVM1_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>CSVM1.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CSVM2_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="CSVM2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>CSVM2_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>CSVM2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="CSVM3_v2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="CSVM3" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>CSVM3_v2.bin;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<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>
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -45,11 +45,11 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
uint offset = 0;
|
uint offset = 0;
|
||||||
for (int vmInstrIndex = 0; vmInstrIndex < numVmInstrs; vmInstrIndex++) {
|
for (int vmInstrIndex = 0; vmInstrIndex < numVmInstrs; vmInstrIndex++) {
|
||||||
var composite = opCodeDetector.Handlers[vmInstrs[vmInstrIndex]];
|
var composite = opCodeDetector.Handlers[vmInstrs[vmInstrIndex]];
|
||||||
var handlerInfos = composite.OpCodeHandlerInfos;
|
IList<HandlerTypeCode> handlerInfos = composite.HandlerTypeCodes;
|
||||||
if (handlerInfos.Count == 0)
|
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++) {
|
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;
|
instr.Offset = offset;
|
||||||
offset += (uint)GetInstructionSize(instr);
|
offset += (uint)GetInstructionSize(instr);
|
||||||
SetCilToVmIndex(instr, vmInstrIndex);
|
SetCilToVmIndex(instr, vmInstrIndex);
|
||||||
|
@ -58,6 +58,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
instrs.Add(instr);
|
instrs.Add(instr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return instrs;
|
return instrs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,24 +19,35 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
class OpCodeHandlerInfo {
|
class OpCodeHandlerInfo {
|
||||||
public HandlerTypeCode TypeCode { get; private set; }
|
public HandlerTypeCode TypeCode { get; private set; }
|
||||||
public string Name { 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.TypeCode = typeCode;
|
||||||
this.Name = GetHandlerName(typeCode);
|
this.Name = GetHandlerName(typeCode);
|
||||||
this.ExecSig = execSig;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
return Name;
|
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) {
|
switch (code) {
|
||||||
case HandlerTypeCode.Add: return "add";
|
case HandlerTypeCode.Add: return "add";
|
||||||
case HandlerTypeCode.Add_Ovf: return "add.ovf";
|
case HandlerTypeCode.Add_Ovf: return "add.ovf";
|
||||||
|
|
|
@ -23,75 +23,61 @@ using System.IO;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
static class OpCodeHandlerInfos {
|
static class OpCodeHandlerInfos {
|
||||||
enum OpCodeHandlersFileVersion : int {
|
public static void Write(BinaryWriter writer, List<MethodSigInfo> handlerInfos) {
|
||||||
V1 = 1,
|
writer.Write(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);
|
|
||||||
writer.Write(handlerInfos.Count);
|
writer.Write(handlerInfos.Count);
|
||||||
foreach (var handler in handlerInfos) {
|
foreach (var handler in handlerInfos) {
|
||||||
writer.Write((int)handler.TypeCode);
|
writer.Write((int)handler.TypeCode);
|
||||||
var infos = handler.ExecSig.BlockInfos;
|
writer.Write(handler.BlockSigInfos.Count);
|
||||||
writer.Write(infos.Count);
|
foreach (var info in handler.BlockSigInfos) {
|
||||||
foreach (var info in infos) {
|
|
||||||
if (info.Hash == null)
|
|
||||||
writer.Write(0);
|
|
||||||
else {
|
|
||||||
writer.Write(info.Hash.Length);
|
|
||||||
writer.Write(info.Hash);
|
|
||||||
}
|
|
||||||
writer.Write(info.Targets.Count);
|
writer.Write(info.Targets.Count);
|
||||||
foreach (var target in info.Targets)
|
foreach (var target in info.Targets)
|
||||||
writer.Write(target);
|
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) {
|
public static List<MethodSigInfo> Read(BinaryReader reader) {
|
||||||
switch ((OpCodeHandlersFileVersion)reader.ReadInt32()) {
|
if (reader.ReadInt32() != 1)
|
||||||
case OpCodeHandlersFileVersion.V1: return ReadV1(reader);
|
throw new InvalidDataException();
|
||||||
default: throw new ApplicationException("Invalid file version");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<OpCodeHandlerInfo> ReadV1(BinaryReader reader) {
|
|
||||||
int numHandlers = reader.ReadInt32();
|
int numHandlers = reader.ReadInt32();
|
||||||
var list = new List<OpCodeHandlerInfo>(numHandlers);
|
var list = new List<MethodSigInfo>(numHandlers);
|
||||||
for (int i = 0; i < numHandlers; i++) {
|
for (int i = 0; i < numHandlers; i++) {
|
||||||
var typeCode = (HandlerTypeCode)reader.ReadInt32();
|
var typeCode = (HandlerTypeCode)reader.ReadInt32();
|
||||||
int numInfos = reader.ReadInt32();
|
int numBlocks = reader.ReadInt32();
|
||||||
var sigInfo = new MethodSigInfo();
|
var blocks = new List<BlockSigInfo>(numBlocks);
|
||||||
for (int j = 0; j < numInfos; j++) {
|
for (int j = 0; j < numBlocks; j++) {
|
||||||
var info = new BlockInfo();
|
|
||||||
|
|
||||||
info.Hash = reader.ReadBytes(reader.ReadInt32());
|
|
||||||
if (info.Hash.Length == 0)
|
|
||||||
info.Hash = null;
|
|
||||||
|
|
||||||
int numTargets = reader.ReadInt32();
|
int numTargets = reader.ReadInt32();
|
||||||
|
var targets = new List<int>(numTargets);
|
||||||
for (int k = 0; k < numTargets; k++)
|
for (int k = 0; k < numTargets; k++)
|
||||||
info.Targets.Add(reader.ReadInt32());
|
targets.Add(reader.ReadInt32());
|
||||||
|
var numHashes = reader.ReadInt32();
|
||||||
sigInfo.BlockInfos.Add(info);
|
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 MethodSigInfo(blocks, typeCode));
|
||||||
list.Add(new OpCodeHandlerInfo(typeCode, sigInfo));
|
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly IList<OpCodeHandlerInfo>[] HandlerInfos = new IList<OpCodeHandlerInfo>[] {
|
public static readonly IList<MethodSigInfo>[] HandlerInfos = new IList<MethodSigInfo>[] {
|
||||||
ReadOpCodeHandlerInfos(CsvmResources.CSVM1_v2),
|
ReadOpCodeHandlerInfos(CsvmResources.CSVM1),
|
||||||
ReadOpCodeHandlerInfos(CsvmResources.CSVM2_v2),
|
ReadOpCodeHandlerInfos(CsvmResources.CSVM2),
|
||||||
ReadOpCodeHandlerInfos(CsvmResources.CSVM3_v2),
|
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)));
|
return OpCodeHandlerInfos.Read(new BinaryReader(new MemoryStream(data)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
593
de4dot.code/deobfuscators/Agile_NET/vm/v2/SigCreator.cs
Normal file
593
de4dot.code/deobfuscators/Agile_NET/vm/v2/SigCreator.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,23 +22,15 @@ using System.Text;
|
||||||
|
|
||||||
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
class VmOpCode {
|
class VmOpCode {
|
||||||
public List<OpCodeHandlerInfo> OpCodeHandlerInfos { get; private set; }
|
public List<HandlerTypeCode> HandlerTypeCodes { get; private set; }
|
||||||
|
|
||||||
public VmOpCode(List<OpCodeHandlerInfo> opCodeHandlerInfos) {
|
public VmOpCode(List<HandlerTypeCode> opCodeHandlerInfos) {
|
||||||
this.OpCodeHandlerInfos = new List<OpCodeHandlerInfo>(opCodeHandlerInfos.Count);
|
this.HandlerTypeCodes = new List<HandlerTypeCode>(opCodeHandlerInfos.Count);
|
||||||
this.OpCodeHandlerInfos.AddRange(opCodeHandlerInfos);
|
this.HandlerTypeCodes.AddRange(opCodeHandlerInfos);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString() {
|
||||||
if (OpCodeHandlerInfos.Count == 0)
|
return OpCodeHandlerInfo.GetCompositeName(HandlerTypeCodes);
|
||||||
return "<nothing>";
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
foreach (var handler in OpCodeHandlerInfos) {
|
|
||||||
if (sb.Length != 0)
|
|
||||||
sb.Append(", ");
|
|
||||||
sb.Append(handler.Name);
|
|
||||||
}
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,6 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
deobfuscator = new MyDeobfuscator(module);
|
deobfuscator = new MyDeobfuscator(module);
|
||||||
|
|
||||||
var csvmInfo = new CsvmInfo(module);
|
var csvmInfo = new CsvmInfo(module);
|
||||||
csvmInfo.Initialize();
|
csvmInfo.Initialize();
|
||||||
var vmHandlerTypes = FindVmHandlerTypes();
|
var vmHandlerTypes = FindVmHandlerTypes();
|
||||||
|
@ -90,9 +89,7 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
|
|
||||||
var composites = CreateCompositeOpCodeHandlers(csvmInfo, vmHandlerTypes);
|
var composites = CreateCompositeOpCodeHandlers(csvmInfo, vmHandlerTypes);
|
||||||
foreach (var handlerInfos in OpCodeHandlerInfos.HandlerInfos) {
|
foreach (var handlerInfos in OpCodeHandlerInfos.HandlerInfos) {
|
||||||
var otherHandlers = CreateOtherHandlers(csvmInfo, handlerInfos);
|
if (!DetectCompositeHandlers(composites, handlerInfos))
|
||||||
|
|
||||||
if (!DetectCompositeHandlers(composites, otherHandlers))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
vmOpCodes = CreateVmOpCodes(composites);
|
vmOpCodes = CreateVmOpCodes(composites);
|
||||||
|
@ -105,12 +102,12 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
static List<VmOpCode> CreateVmOpCodes(IList<CompositeOpCodeHandler> composites) {
|
static List<VmOpCode> CreateVmOpCodes(IList<CompositeOpCodeHandler> composites) {
|
||||||
var list = new List<VmOpCode>(composites.Count);
|
var list = new List<VmOpCode>(composites.Count);
|
||||||
foreach (var composite in composites)
|
foreach (var composite in composites)
|
||||||
list.Add(new VmOpCode(composite.OpCodeHandlerInfos));
|
list.Add(new VmOpCode(composite.TypeCodes));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DetectCompositeHandlers(IEnumerable<CompositeOpCodeHandler> composites, List<OpCodeHandler> otherHandlers) {
|
bool DetectCompositeHandlers(IEnumerable<CompositeOpCodeHandler> composites, IList<MethodSigInfo> handlerInfos) {
|
||||||
var detector = new CompositeHandlerDetector(otherHandlers);
|
var detector = new CompositeHandlerDetector(handlerInfos);
|
||||||
foreach (var composite in composites) {
|
foreach (var composite in composites) {
|
||||||
if (!detector.FindHandlers(composite))
|
if (!detector.FindHandlers(composite))
|
||||||
return false;
|
return false;
|
||||||
|
@ -128,15 +125,18 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
List<CompositeOpCodeHandler> CreateCompositeOpCodeHandlers(CsvmInfo csvmInfo, List<TypeDef> handlers) {
|
List<CompositeOpCodeHandler> CreateCompositeOpCodeHandlers(CsvmInfo csvmInfo, List<TypeDef> handlers) {
|
||||||
var list = new List<CompositeOpCodeHandler>(handlers.Count);
|
var list = new List<CompositeOpCodeHandler>(handlers.Count);
|
||||||
|
|
||||||
foreach (var handler in handlers) {
|
var sigCreator = CreateSigCreator(csvmInfo);
|
||||||
var execHandler = new HandlerMethod(GetExecMethod(handler));
|
foreach (var handler in handlers)
|
||||||
list.Add(new CompositeOpCodeHandler(handler, execHandler));
|
list.Add(new CompositeOpCodeHandler(sigCreator.Create(GetExecMethod(handler))));
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodDef GetExecMethod(TypeDef type) {
|
MethodDef GetExecMethod(TypeDef type) {
|
||||||
|
return GetExecMethod(deobfuscator, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MethodDef GetExecMethod(MyDeobfuscator deobfuscator, TypeDef type) {
|
||||||
MethodDef readMethod, execMethod;
|
MethodDef readMethod, execMethod;
|
||||||
GetReadAndExecMethods(type, out readMethod, out execMethod);
|
GetReadAndExecMethods(type, out readMethod, out execMethod);
|
||||||
deobfuscator.Deobfuscate(execMethod);
|
deobfuscator.Deobfuscate(execMethod);
|
||||||
|
@ -144,8 +144,8 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
return execMethod;
|
return execMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MethodSigInfoCreator CreateMethodSigInfoCreator(CsvmInfo csvmInfo) {
|
static SigCreator CreateSigCreator(CsvmInfo csvmInfo) {
|
||||||
var creator = new MethodSigInfoCreator();
|
var creator = new SigCreator();
|
||||||
|
|
||||||
creator.AddId(csvmInfo.LogicalOpShrUn, 1);
|
creator.AddId(csvmInfo.LogicalOpShrUn, 1);
|
||||||
creator.AddId(csvmInfo.LogicalOpShl, 2);
|
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.LocalsGet, 30);
|
||||||
creator.AddId(csvmInfo.LocalsSet, 31);
|
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;
|
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) {
|
static void GetReadAndExecMethods(TypeDef handler, out MethodDef readMethod, out MethodDef execMethod) {
|
||||||
readMethod = execMethod = null;
|
readMethod = execMethod = null;
|
||||||
foreach (var method in handler.Methods) {
|
foreach (var method in handler.Methods) {
|
||||||
|
@ -270,28 +281,5 @@ namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
||||||
|
|
||||||
return list;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -581,6 +581,23 @@ namespace de4dot.mdecrypt {
|
||||||
return hModule;
|
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) {
|
static unsafe bool PatchCM(IntPtr addr, IntPtr origValue, IntPtr newValue) {
|
||||||
var baseAddr = GetModuleHandle(addr);
|
var baseAddr = GetModuleHandle(addr);
|
||||||
IntPtr patchAddr;
|
IntPtr patchAddr;
|
||||||
|
@ -590,6 +607,45 @@ namespace de4dot.mdecrypt {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*(IntPtr*)patchAddr = newValue;
|
*(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user