Add a cast deobfuscator
This commit is contained in:
parent
05ec2794eb
commit
fb9e217dac
|
@ -117,6 +117,7 @@
|
|||
<Compile Include="deobfuscators\CryptoObfuscator\StringDecrypter.cs" />
|
||||
<Compile Include="deobfuscators\CryptoObfuscator\TamperDetection.cs" />
|
||||
<Compile Include="deobfuscators\DeepSea\ArrayBlockDeobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\DeepSea\CastDeobfuscator.cs" />
|
||||
<Compile Include="deobfuscators\DeepSea\DsConstantsReader.cs" />
|
||||
<Compile Include="deobfuscators\DeepSea\FieldsRestorer.cs" />
|
||||
<Compile Include="deobfuscators\DeobfuscatorBase.cs" />
|
||||
|
|
213
de4dot.code/deobfuscators/DeepSea/CastDeobfuscator.cs
Normal file
213
de4dot.code/deobfuscators/DeepSea/CastDeobfuscator.cs
Normal file
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
Copyright (C) 2011-2012 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 de4dot.blocks;
|
||||
using de4dot.blocks.cflow;
|
||||
using Mono.Cecil;
|
||||
using Mono.Cecil.Cil;
|
||||
|
||||
namespace de4dot.code.deobfuscators.DeepSea {
|
||||
class CastDeobfuscator : IBlocksDeobfuscator {
|
||||
Blocks blocks;
|
||||
Dictionary<VariableDefinition, LocalInfo> localInfos = new Dictionary<VariableDefinition, LocalInfo>();
|
||||
|
||||
class LocalInfo {
|
||||
public readonly VariableDefinition local;
|
||||
TypeReference type;
|
||||
bool isValid;
|
||||
|
||||
public TypeReference CastType {
|
||||
get { return type; }
|
||||
set {
|
||||
if (!isValid)
|
||||
return;
|
||||
|
||||
if (value == null) {
|
||||
invalid();
|
||||
return;
|
||||
}
|
||||
|
||||
if (type != null && !MemberReferenceHelper.compareTypes(type, value)) {
|
||||
invalid();
|
||||
return;
|
||||
}
|
||||
|
||||
type = value;
|
||||
}
|
||||
}
|
||||
|
||||
public LocalInfo(VariableDefinition local) {
|
||||
this.local = local;
|
||||
this.isValid = true;
|
||||
}
|
||||
|
||||
public void invalid() {
|
||||
isValid = false;
|
||||
type = null;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
if (type == null)
|
||||
return string.Format("{0} - INVALID", local);
|
||||
return string.Format("{0} - {1:X8} {2}", local, type.MetadataToken.ToInt32(), type.FullName);
|
||||
}
|
||||
}
|
||||
|
||||
public bool ExecuteOnNoChange {
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public void deobfuscateBegin(Blocks blocks) {
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
public bool deobfuscate(List<Block> allBlocks) {
|
||||
if (!init(allBlocks))
|
||||
return false;
|
||||
|
||||
bool changed = false;
|
||||
|
||||
var indexesToRemove = new List<int>();
|
||||
foreach (var block in allBlocks) {
|
||||
indexesToRemove.Clear();
|
||||
var instrs = block.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var instr = instrs[i];
|
||||
if (instr.OpCode.Code == Code.Ldloca || instr.OpCode.Code == Code.Ldloca_S) {
|
||||
var local = instr.Operand as VariableDefinition;
|
||||
if (local == null)
|
||||
continue;
|
||||
localInfos[local].invalid();
|
||||
}
|
||||
else if (instr.isLdloc()) {
|
||||
var local = DotNetUtils.getLocalVar(blocks.Locals, instr.Instruction);
|
||||
if (local == null)
|
||||
continue;
|
||||
var localInfo = localInfos[local];
|
||||
var cast = instrs[i + 1];
|
||||
if (localInfo.CastType == null)
|
||||
continue;
|
||||
if (!isCast(cast))
|
||||
throw new ApplicationException("Not a cast instr");
|
||||
|
||||
indexesToRemove.Add(i + 1);
|
||||
}
|
||||
}
|
||||
if (indexesToRemove.Count > 0) {
|
||||
block.remove(indexesToRemove);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var info in localInfos.Values) {
|
||||
if (info.CastType == null)
|
||||
continue;
|
||||
info.local.VariableType = info.CastType;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
foreach (var block in allBlocks) {
|
||||
var instrs = block.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var instr = instrs[i];
|
||||
int castIndex = i + 1;
|
||||
if (instr.OpCode.Code == Code.Dup) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
castIndex = i;
|
||||
instr = instrs[i - 1];
|
||||
}
|
||||
|
||||
if (instr.isLdarg())
|
||||
addCast(block, castIndex, i + 1, DotNetUtils.getArgType(blocks.Method, instr.Instruction));
|
||||
else if (instr.OpCode.Code == Code.Ldfld || instr.OpCode.Code == Code.Ldsfld) {
|
||||
var field = instr.Operand as FieldReference;
|
||||
if (field == null)
|
||||
continue;
|
||||
addCast(block, castIndex, i + 1, field.FieldType);
|
||||
}
|
||||
else if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt) {
|
||||
var calledMethod = instr.Operand as MethodReference;
|
||||
if (calledMethod == null || !DotNetUtils.hasReturnValue(calledMethod))
|
||||
continue;
|
||||
addCast(block, castIndex, i + 1, calledMethod.MethodReturnType.ReturnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool addCast(Block block, int castIndex, int index, TypeReference type) {
|
||||
if (type == null)
|
||||
return false;
|
||||
if (castIndex >= block.Instructions.Count || index >= block.Instructions.Count)
|
||||
return false;
|
||||
var stloc = block.Instructions[index];
|
||||
if (!stloc.isStloc())
|
||||
return false;
|
||||
var local = DotNetUtils.getLocalVar(blocks.Locals, stloc.Instruction);
|
||||
if (local == null)
|
||||
return false;
|
||||
var localInfo = localInfos[local];
|
||||
if (localInfo.CastType == null)
|
||||
return false;
|
||||
|
||||
if (!MemberReferenceHelper.compareTypes(localInfo.CastType, type))
|
||||
block.insert(castIndex, new Instruction(OpCodes.Castclass, localInfo.CastType));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init(List<Block> allBlocks) {
|
||||
localInfos.Clear();
|
||||
foreach (var local in blocks.Locals)
|
||||
localInfos[local] = new LocalInfo(local);
|
||||
if (localInfos.Count == 0)
|
||||
return false;
|
||||
|
||||
foreach (var block in allBlocks) {
|
||||
var instrs = block.Instructions;
|
||||
for (int i = 0; i < instrs.Count - 1; i++) {
|
||||
var ldloc = instrs[i];
|
||||
if (!ldloc.isLdloc())
|
||||
continue;
|
||||
var local = DotNetUtils.getLocalVar(blocks.Locals, ldloc.Instruction);
|
||||
if (local == null)
|
||||
continue;
|
||||
var localInfo = localInfos[local];
|
||||
localInfo.CastType = getCastType(instrs[i + 1]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool isCast(Instr instr) {
|
||||
return instr.OpCode.Code == Code.Castclass || instr.OpCode.Code == Code.Isinst;
|
||||
}
|
||||
|
||||
static TypeReference getCastType(Instr instr) {
|
||||
if (!isCast(instr))
|
||||
return null;
|
||||
return instr.Operand as TypeReference;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -108,17 +108,23 @@ namespace de4dot.code.deobfuscators.DeepSea {
|
|||
|
||||
public override IEnumerable<IBlocksDeobfuscator> BlocksDeobfuscators {
|
||||
get {
|
||||
var list = new List<IBlocksDeobfuscator>();
|
||||
if (CanInlineMethods) {
|
||||
if (arrayBlockDeobfuscator.Detected)
|
||||
list.Add(arrayBlockDeobfuscator);
|
||||
|
||||
list.Add(new DsMethodCallInliner(new CachedCflowDeobfuscator(list)));
|
||||
}
|
||||
var list = new List<IBlocksDeobfuscator>(getBlocksDeobfuscators());
|
||||
if (CanInlineMethods)
|
||||
list.Add(new DsMethodCallInliner(new CachedCflowDeobfuscator(getBlocksDeobfuscators())));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
List<IBlocksDeobfuscator> getBlocksDeobfuscators() {
|
||||
var list = new List<IBlocksDeobfuscator>();
|
||||
if (CanInlineMethods) {
|
||||
if (arrayBlockDeobfuscator.Detected)
|
||||
list.Add(arrayBlockDeobfuscator);
|
||||
list.Add(new CastDeobfuscator());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public Deobfuscator(Options options)
|
||||
: base(options) {
|
||||
this.options = options;
|
||||
|
|
Loading…
Reference in New Issue
Block a user