de4dot-cex/de4dot.code/deobfuscators/Babel_NET/BabelMethodCallInliner.cs

245 lines
6.5 KiB
C#
Raw Normal View History

2012-06-12 16:37:51 +08:00
/*
2014-03-12 05:15:43 +08:00
Copyright (C) 2011-2014 de4dot@gmail.com
2012-06-12 16:37:51 +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.Collections.Generic;
using dnlib.DotNet;
using dnlib.DotNet.Emit;
2012-06-12 16:37:51 +08:00
using de4dot.blocks;
using de4dot.blocks.cflow;
namespace de4dot.code.deobfuscators.Babel_NET {
class BabelMethodCallInliner : MethodCallInlinerBase, IBranchHandler {
InstructionEmulator emulator;
BranchEmulator branchEmulator;
int emulateIndex;
IList<Instruction> instructions;
public BabelMethodCallInliner() {
emulator = new InstructionEmulator();
branchEmulator = new BranchEmulator(emulator, this);
}
2013-01-19 20:03:57 +08:00
public static List<MethodDef> Find(ModuleDefMD module, IEnumerable<MethodDef> notInlinedMethods) {
var notInlinedMethodsDict = new Dictionary<MethodDef, bool>();
2012-06-12 16:37:51 +08:00
foreach (var method in notInlinedMethods)
notInlinedMethodsDict[method] = true;
var inlinedMethods = new List<MethodDef>();
2012-06-12 16:37:51 +08:00
foreach (var type in module.GetTypes()) {
foreach (var method in type.Methods) {
2013-01-19 20:03:57 +08:00
if (!notInlinedMethodsDict.ContainsKey(method) && CanInline(method))
2012-06-12 16:37:51 +08:00
inlinedMethods.Add(method);
}
}
return inlinedMethods;
}
2013-01-19 20:03:57 +08:00
void IBranchHandler.HandleNormal(int stackArgs, bool isTaken) {
2012-06-12 16:37:51 +08:00
if (!isTaken)
emulateIndex++;
else
emulateIndex = instructions.IndexOf((Instruction)instructions[emulateIndex].Operand);
}
2013-01-19 20:03:57 +08:00
bool IBranchHandler.HandleSwitch(Int32Value switchIndex) {
if (!switchIndex.AllBitsValid())
2012-06-12 16:37:51 +08:00
return false;
var instr = instructions[emulateIndex];
var targets = (Instruction[])instr.Operand;
if (switchIndex.Value >= 0 && switchIndex.Value < targets.Length)
emulateIndex = instructions.IndexOf(targets[switchIndex.Value]);
2012-06-12 16:37:51 +08:00
else
emulateIndex++;
return true;
}
2013-01-19 20:03:57 +08:00
protected override bool DeobfuscateInternal() {
2013-04-30 18:15:07 +08:00
bool modified = false;
2012-06-12 16:37:51 +08:00
var instructions = block.Instructions;
for (int i = 0; i < instructions.Count; i++) {
var instr = instructions[i].Instruction;
if (instr.OpCode.Code == Code.Call)
2013-04-30 18:15:07 +08:00
modified |= InlineMethod(instr, i);
2012-06-12 16:37:51 +08:00
}
instructions = null;
2013-04-30 18:15:07 +08:00
return modified;
2012-06-12 16:37:51 +08:00
}
2013-01-19 20:03:57 +08:00
static bool CanInline(MethodDef method) {
if (!DotNetUtils.IsMethod(method, "System.Int32", "(System.Int32)"))
2012-06-12 16:37:51 +08:00
return false;
if (!method.IsAssembly)
return false;
2012-11-08 14:06:46 +08:00
if (method.MethodSig.GetGenParamCount() > 0)
2012-06-12 16:37:51 +08:00
return false;
return method.IsStatic;
}
2013-01-19 20:03:57 +08:00
bool CanInline2(MethodDef method) {
return CanInline(method) && method != blocks.Method;
2012-06-12 16:37:51 +08:00
}
2013-01-19 20:03:57 +08:00
bool InlineMethod(Instruction callInstr, int instrIndex) {
var methodToInline = callInstr.Operand as MethodDef;
2012-06-12 16:37:51 +08:00
if (methodToInline == null)
return false;
2013-01-19 20:03:57 +08:00
if (!CanInline2(methodToInline))
2012-06-12 16:37:51 +08:00
return false;
var body = methodToInline.Body;
if (body == null)
return false;
if (instrIndex == 0)
return false;
var ldci4 = block.Instructions[instrIndex - 1];
2013-01-19 20:03:57 +08:00
if (!ldci4.IsLdcI4())
2012-06-12 16:37:51 +08:00
return false;
int newValue;
2013-01-19 20:03:57 +08:00
if (!GetNewValue(methodToInline, ldci4.GetLdcI4Value(), out newValue))
2012-06-12 16:37:51 +08:00
return false;
2012-12-16 07:03:56 +08:00
block.Instructions[instrIndex - 1] = new Instr(OpCodes.Nop.ToInstruction());
2012-11-01 23:42:02 +08:00
block.Instructions[instrIndex] = new Instr(Instruction.CreateLdcI4(newValue));
2012-06-12 16:37:51 +08:00
return true;
}
2013-01-19 20:03:57 +08:00
bool GetNewValue(MethodDef method, int arg, out int newValue) {
2012-06-12 16:37:51 +08:00
newValue = 0;
2013-01-19 20:03:57 +08:00
emulator.Initialize(method);
emulator.SetArg(method.Parameters[0], new Int32Value(arg));
2012-06-12 16:37:51 +08:00
Instruction instr;
emulateIndex = 0;
instructions = method.Body.Instructions;
int counter = 0;
while (true) {
if (counter++ >= 50)
return false;
if (emulateIndex < 0 || emulateIndex >= instructions.Count)
return false;
instr = instructions[emulateIndex];
switch (instr.OpCode.Code) {
case Code.Ldarg:
case Code.Ldarg_S:
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
case Code.Stloc:
case Code.Stloc_S:
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
case Code.Ldloc:
case Code.Ldloc_S:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
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:
case Code.Add:
case Code.Sub:
case Code.Xor:
case Code.Or:
case Code.Nop:
case Code.Dup:
case Code.Mul:
case Code.Rem:
case Code.Div:
2013-01-19 20:03:57 +08:00
emulator.Emulate(instr);
2012-06-12 16:37:51 +08:00
emulateIndex++;
break;
case Code.Br:
case Code.Br_S:
case Code.Beq:
case Code.Beq_S:
case Code.Bge:
case Code.Bge_S:
case Code.Bge_Un:
case Code.Bge_Un_S:
case Code.Bgt:
case Code.Bgt_S:
case Code.Bgt_Un:
case Code.Bgt_Un_S:
case Code.Ble:
case Code.Ble_S:
case Code.Ble_Un:
case Code.Ble_Un_S:
case Code.Blt:
case Code.Blt_S:
case Code.Blt_Un:
case Code.Blt_Un_S:
case Code.Bne_Un:
case Code.Bne_Un_S:
case Code.Brfalse:
case Code.Brfalse_S:
case Code.Brtrue:
case Code.Brtrue_S:
case Code.Switch:
2013-01-19 20:03:57 +08:00
if (!branchEmulator.Emulate(instr))
2012-06-12 16:37:51 +08:00
return false;
break;
case Code.Ret:
2013-01-19 20:03:57 +08:00
var retValue = emulator.Pop();
if (!retValue.IsInt32())
2012-06-12 16:37:51 +08:00
return false;
var retValue2 = (Int32Value)retValue;
2013-01-19 20:03:57 +08:00
if (!retValue2.AllBitsValid())
2012-06-12 16:37:51 +08:00
return false;
newValue = retValue2.Value;
2012-06-12 16:37:51 +08:00
return true;
default:
if (instr.OpCode.OpCodeType != OpCodeType.Prefix)
return false;
emulateIndex++;
break;
}
}
}
2013-01-19 20:03:57 +08:00
protected override bool IsCompatibleType(int paramIndex, IType origType, IType newType) {
2012-11-15 04:44:57 +08:00
if (new SigComparer(SigComparerOptions.IgnoreModifiers).Equals(origType, newType))
2012-06-12 16:37:51 +08:00
return true;
2013-01-19 20:03:57 +08:00
if (IsValueType(newType) || IsValueType(origType))
2012-06-12 16:37:51 +08:00
return false;
return newType.FullName == "System.Object";
}
}
}