2011-12-21 04:47:45 +08:00
|
|
|
|
/*
|
2012-01-10 06:02:47 +08:00
|
|
|
|
Copyright (C) 2011-2012 de4dot@gmail.com
|
2011-12-21 04:47:45 +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 Mono.Cecil;
|
|
|
|
|
using Mono.Cecil.Cil;
|
|
|
|
|
using de4dot.blocks;
|
|
|
|
|
|
|
|
|
|
namespace de4dot.code.deobfuscators {
|
|
|
|
|
static class InlinedMethodsFinder {
|
|
|
|
|
public static List<MethodDefinition> find(ModuleDefinition module) {
|
|
|
|
|
// Not all garbage methods are inlined, possibly because we remove some code that calls
|
|
|
|
|
// the garbage method before the methods inliner has a chance to inline it. Try to find
|
|
|
|
|
// all garbage methods and other code will figure out if there are any calls left.
|
|
|
|
|
|
|
|
|
|
var inlinedMethods = new List<MethodDefinition>();
|
|
|
|
|
foreach (var type in module.GetTypes()) {
|
|
|
|
|
foreach (var method in type.Methods) {
|
|
|
|
|
if (!method.IsStatic)
|
|
|
|
|
continue;
|
2011-12-28 20:28:17 +08:00
|
|
|
|
if (!method.IsAssembly && !method.IsCompilerControlled && !method.IsPrivate)
|
2011-12-21 04:47:45 +08:00
|
|
|
|
continue;
|
|
|
|
|
if (method.GenericParameters.Count > 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (method.Name == ".cctor")
|
|
|
|
|
continue;
|
|
|
|
|
if (method.Body == null)
|
|
|
|
|
continue;
|
|
|
|
|
var instrs = method.Body.Instructions;
|
|
|
|
|
if (instrs.Count < 2)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
switch (instrs[0].OpCode.Code) {
|
|
|
|
|
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.Ldc_I8:
|
|
|
|
|
case Code.Ldc_R4:
|
|
|
|
|
case Code.Ldc_R8:
|
|
|
|
|
case Code.Ldftn:
|
|
|
|
|
case Code.Ldnull:
|
|
|
|
|
case Code.Ldstr:
|
|
|
|
|
case Code.Ldtoken:
|
|
|
|
|
case Code.Ldsfld:
|
|
|
|
|
case Code.Ldsflda:
|
|
|
|
|
if (instrs[1].OpCode.Code != Code.Ret)
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case Code.Ldarg:
|
|
|
|
|
case Code.Ldarg_S:
|
|
|
|
|
case Code.Ldarg_0:
|
|
|
|
|
case Code.Ldarg_1:
|
|
|
|
|
case Code.Ldarg_2:
|
|
|
|
|
case Code.Ldarg_3:
|
2011-12-28 20:28:17 +08:00
|
|
|
|
case Code.Ldarga:
|
|
|
|
|
case Code.Ldarga_S:
|
2011-12-21 04:47:45 +08:00
|
|
|
|
case Code.Call:
|
2011-12-28 20:28:17 +08:00
|
|
|
|
case Code.Newobj:
|
2011-12-21 04:47:45 +08:00
|
|
|
|
if (!isCallMethod(method))
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inlinedMethods.Add(method);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return inlinedMethods;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isCallMethod(MethodDefinition method) {
|
|
|
|
|
int loadIndex = 0;
|
|
|
|
|
int methodArgsCount = DotNetUtils.getArgsCount(method);
|
|
|
|
|
var instrs = method.Body.Instructions;
|
|
|
|
|
int i = 0;
|
|
|
|
|
for (; i < instrs.Count && i < methodArgsCount; i++) {
|
|
|
|
|
var instr = instrs[i];
|
|
|
|
|
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:
|
2011-12-28 20:28:17 +08:00
|
|
|
|
case Code.Ldarga:
|
|
|
|
|
case Code.Ldarga_S:
|
2011-12-21 04:47:45 +08:00
|
|
|
|
if (DotNetUtils.getArgIndex(method, instr) != loadIndex)
|
|
|
|
|
return false;
|
|
|
|
|
loadIndex++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (loadIndex != methodArgsCount)
|
|
|
|
|
return false;
|
|
|
|
|
if (i + 1 >= instrs.Count)
|
|
|
|
|
return false;
|
|
|
|
|
|
2011-12-28 20:28:17 +08:00
|
|
|
|
switch (instrs[i].OpCode.Code) {
|
|
|
|
|
case Code.Call:
|
|
|
|
|
case Code.Callvirt:
|
|
|
|
|
case Code.Newobj:
|
|
|
|
|
case Code.Ldfld:
|
|
|
|
|
case Code.Ldflda:
|
|
|
|
|
case Code.Ldftn:
|
|
|
|
|
case Code.Ldvirtftn:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2011-12-21 04:47:45 +08:00
|
|
|
|
return false;
|
2011-12-28 20:28:17 +08:00
|
|
|
|
}
|
2011-12-21 04:47:45 +08:00
|
|
|
|
if (instrs[i + 1].OpCode.Code != Code.Ret)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|