2013-11-08 18:05:17 +08:00
|
|
|
|
/*
|
2015-10-30 05:45:26 +08:00
|
|
|
|
Copyright (C) 2011-2015 de4dot@gmail.com
|
2013-11-08 18:05:17 +08:00
|
|
|
|
|
|
|
|
|
This file is part of de4dot.
|
|
|
|
|
|
|
|
|
|
de4dot is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
de4dot is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using dnlib.DotNet;
|
|
|
|
|
using dnlib.DotNet.Emit;
|
|
|
|
|
using de4dot.blocks;
|
|
|
|
|
|
|
|
|
|
namespace de4dot.code.deobfuscators.Agile_NET.vm.v2 {
|
|
|
|
|
class CompositeHandlerDetector {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
readonly List<MethodSigInfo> handlers;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
public CompositeHandlerDetector(IList<MethodSigInfo> handlers) {
|
|
|
|
|
this.handlers = new List<MethodSigInfo>(handlers);
|
|
|
|
|
|
|
|
|
|
this.handlers.Sort((a, b) => {
|
|
|
|
|
int r = b.BlockSigInfos.Count.CompareTo(a.BlockSigInfos.Count);
|
|
|
|
|
if (r != 0)
|
|
|
|
|
return r;
|
|
|
|
|
return b.BlockSigInfos[0].Hashes.Count.CompareTo(a.BlockSigInfos[0].Hashes.Count);
|
|
|
|
|
});
|
2013-11-08 18:05:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct MatchState {
|
|
|
|
|
public HandlerState OtherState;
|
|
|
|
|
public HandlerState CompositeState;
|
|
|
|
|
|
|
|
|
|
public MatchState(HandlerState OtherState, HandlerState CompositeState) {
|
|
|
|
|
this.OtherState = OtherState;
|
|
|
|
|
this.CompositeState = CompositeState;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct HandlerState {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
public readonly List<BlockSigInfo> BlockSigInfos;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
public readonly int BlockIndex;
|
2013-11-24 05:00:13 +08:00
|
|
|
|
public int HashIndex;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
|
2014-03-25 03:18:37 +08:00
|
|
|
|
public HandlerState(List<BlockSigInfo> blockSigInfos, int blockIndex, int hashIndex) {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
this.BlockSigInfos = blockSigInfos;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
this.BlockIndex = blockIndex;
|
2014-03-25 03:18:37 +08:00
|
|
|
|
this.HashIndex = hashIndex;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public HandlerState Clone() {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
return new HandlerState(BlockSigInfos, BlockIndex, HashIndex);
|
2013-11-08 18:05:17 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct FindHandlerState {
|
|
|
|
|
public HandlerState CompositeState;
|
|
|
|
|
public readonly Dictionary<int, bool> VisitedCompositeBlocks;
|
|
|
|
|
public bool Done;
|
|
|
|
|
|
|
|
|
|
public FindHandlerState(HandlerState compositeState) {
|
|
|
|
|
this.CompositeState = compositeState;
|
|
|
|
|
this.VisitedCompositeBlocks = new Dictionary<int, bool>();
|
|
|
|
|
this.Done = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FindHandlerState(HandlerState compositeState, Dictionary<int, bool> visitedCompositeBlocks, bool done) {
|
|
|
|
|
this.CompositeState = compositeState;
|
|
|
|
|
this.VisitedCompositeBlocks = new Dictionary<int, bool>(visitedCompositeBlocks);
|
|
|
|
|
this.Done = done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public FindHandlerState Clone() {
|
|
|
|
|
return new FindHandlerState(CompositeState.Clone(), VisitedCompositeBlocks, Done);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool FindHandlers(CompositeOpCodeHandler composite) {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
composite.TypeCodes.Clear();
|
|
|
|
|
var compositeExecState = new FindHandlerState(new HandlerState(composite.BlockSigInfos, 0, 0));
|
2013-11-08 18:05:17 +08:00
|
|
|
|
while (!compositeExecState.Done) {
|
|
|
|
|
var handler = FindHandlerMethod(ref compositeExecState);
|
|
|
|
|
if (handler == null)
|
|
|
|
|
return false;
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
composite.TypeCodes.Add(handler.TypeCode);
|
2013-11-08 18:05:17 +08:00
|
|
|
|
}
|
2013-11-24 05:00:13 +08:00
|
|
|
|
return composite.TypeCodes.Count != 0;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
MethodSigInfo FindHandlerMethod(ref FindHandlerState findExecState) {
|
2013-11-08 18:05:17 +08:00
|
|
|
|
foreach (var handler in handlers) {
|
|
|
|
|
FindHandlerState findExecStateNew = findExecState.Clone();
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (!Matches(handler.BlockSigInfos, ref findExecStateNew))
|
2013-11-08 18:05:17 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
findExecState = findExecStateNew;
|
|
|
|
|
return handler;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stack<MatchState> stack = new Stack<MatchState>();
|
2013-11-24 05:00:13 +08:00
|
|
|
|
bool Matches(List<BlockSigInfo> handler, ref FindHandlerState findState) {
|
2013-11-08 18:05:17 +08:00
|
|
|
|
HandlerState? nextState = null;
|
|
|
|
|
stack.Clear();
|
|
|
|
|
stack.Push(new MatchState(new HandlerState(handler, 0, 0), findState.CompositeState));
|
|
|
|
|
while (stack.Count > 0) {
|
|
|
|
|
var matchState = stack.Pop();
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (matchState.CompositeState.HashIndex == 0) {
|
2013-11-08 18:05:17 +08:00
|
|
|
|
if (findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
|
|
|
|
|
continue;
|
|
|
|
|
findState.VisitedCompositeBlocks[matchState.CompositeState.BlockIndex] = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (!findState.VisitedCompositeBlocks.ContainsKey(matchState.CompositeState.BlockIndex))
|
|
|
|
|
throw new ApplicationException("Block hasn't been visited");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Compare(ref matchState.OtherState, ref matchState.CompositeState))
|
|
|
|
|
return false;
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
var hblock = matchState.OtherState.BlockSigInfos[matchState.OtherState.BlockIndex];
|
|
|
|
|
var hinstrs = hblock.Hashes;
|
|
|
|
|
int hi = matchState.OtherState.HashIndex;
|
|
|
|
|
var cblock = matchState.CompositeState.BlockSigInfos[matchState.CompositeState.BlockIndex];
|
|
|
|
|
var cinstrs = cblock.Hashes;
|
|
|
|
|
int ci = matchState.CompositeState.HashIndex;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
if (hi < hinstrs.Count)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (ci < cinstrs.Count) {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (hblock.Targets.Count != 0)
|
2013-11-08 18:05:17 +08:00
|
|
|
|
return false;
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (hblock.EndsInRet) {
|
2013-11-08 18:05:17 +08:00
|
|
|
|
if (nextState != null)
|
|
|
|
|
return false;
|
|
|
|
|
nextState = matchState.CompositeState;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (cblock.Targets.Count != hblock.Targets.Count)
|
|
|
|
|
return false;
|
|
|
|
|
if (cblock.HasFallThrough != hblock.HasFallThrough)
|
2013-11-08 18:05:17 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
for (int i = 0; i < cblock.Targets.Count; i++) {
|
|
|
|
|
var hs = new HandlerState(handler, hblock.Targets[i], 0);
|
|
|
|
|
var cs = new HandlerState(findState.CompositeState.BlockSigInfos, cblock.Targets[i], 0);
|
2013-11-08 18:05:17 +08:00
|
|
|
|
stack.Push(new MatchState(hs, cs));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-25 03:18:37 +08:00
|
|
|
|
if (nextState == null && findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
|
|
|
|
|
nextState = GetNextHandlerState(ref findState);
|
2013-11-08 18:05:17 +08:00
|
|
|
|
if (nextState == null) {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (findState.VisitedCompositeBlocks.Count != findState.CompositeState.BlockSigInfos.Count)
|
|
|
|
|
return false;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
findState.Done = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (findState.CompositeState.BlockIndex == nextState.Value.BlockIndex &&
|
2013-11-24 05:00:13 +08:00
|
|
|
|
findState.CompositeState.HashIndex == nextState.Value.HashIndex)
|
2013-11-08 18:05:17 +08:00
|
|
|
|
return false;
|
|
|
|
|
findState.CompositeState = nextState.Value;
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (findState.CompositeState.HashIndex == 0)
|
|
|
|
|
findState.VisitedCompositeBlocks.Remove(findState.CompositeState.BlockIndex);
|
2013-11-08 18:05:17 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-25 03:18:37 +08:00
|
|
|
|
static HandlerState? GetNextHandlerState(ref FindHandlerState findState) {
|
|
|
|
|
for (int i = 0; i < findState.CompositeState.BlockSigInfos.Count; i++) {
|
|
|
|
|
if (findState.VisitedCompositeBlocks.ContainsKey(i))
|
|
|
|
|
continue;
|
|
|
|
|
return new HandlerState(findState.CompositeState.BlockSigInfos, i, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-08 18:05:17 +08:00
|
|
|
|
static bool Compare(ref HandlerState handler, ref HandlerState composite) {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
var hhashes = handler.BlockSigInfos[handler.BlockIndex].Hashes;
|
|
|
|
|
int hi = handler.HashIndex;
|
|
|
|
|
var chashes = composite.BlockSigInfos[composite.BlockIndex].Hashes;
|
|
|
|
|
int ci = composite.HashIndex;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
|
|
|
|
|
while (true) {
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (hi >= hhashes.Count && ci >= chashes.Count)
|
2013-11-08 18:05:17 +08:00
|
|
|
|
break;
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (hi >= hhashes.Count) {
|
|
|
|
|
if (handler.BlockSigInfos[handler.BlockIndex].EndsInRet)
|
|
|
|
|
break;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (hi >= hhashes.Count || ci >= chashes.Count)
|
2013-11-08 18:05:17 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
var hhash = hhashes[hi++];
|
|
|
|
|
var chash = chashes[ci++];
|
2013-11-08 18:05:17 +08:00
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
if (chash != hhash)
|
2013-11-08 18:05:17 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-24 05:00:13 +08:00
|
|
|
|
handler.HashIndex = hi;
|
|
|
|
|
composite.HashIndex = ci;
|
2013-11-08 18:05:17 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|