Move methods to base class

This commit is contained in:
de4dot 2012-01-21 19:55:37 +01:00
parent 6c7bcbed79
commit 6a5ddba022
2 changed files with 133 additions and 125 deletions

View File

@ -49,18 +49,18 @@ namespace de4dot.blocks.cflow {
}
bool inlineMethod(Instruction callInstr, int instrIndex) {
var method = callInstr.Operand as MethodDefinition;
if (method == null)
var methodToInline = callInstr.Operand as MethodDefinition;
if (methodToInline == null)
return false;
if (MemberReferenceHelper.compareMethodReferenceAndDeclaringType(method, blocks.Method))
if (MemberReferenceHelper.compareMethodReferenceAndDeclaringType(methodToInline, blocks.Method))
return false;
if (!canInline(method))
if (!canInline(methodToInline))
return false;
var body = method.Body;
var body = methodToInline.Body;
if (body == null)
return false;
if (!MemberReferenceHelper.compareTypes(method.DeclaringType, blocks.Method.DeclaringType))
if (!MemberReferenceHelper.compareTypes(methodToInline.DeclaringType, blocks.Method.DeclaringType))
return false;
int index = 0;
@ -78,8 +78,9 @@ namespace de4dot.blocks.cflow {
case Code.Ldarga:
case Code.Ldarga_S:
case Code.Call:
case Code.Callvirt:
case Code.Newobj:
return inlineOtherMethod(instrIndex, method, instr, index);
return inlineOtherMethod(instrIndex, methodToInline, instr, index);
case Code.Ldc_I4:
case Code.Ldc_I4_0:
@ -102,130 +103,14 @@ namespace de4dot.blocks.cflow {
case Code.Ldtoken:
case Code.Ldsfld:
case Code.Ldsflda:
return inlineLoadMethod(instrIndex, method, instr, index);
return inlineLoadMethod(instrIndex, methodToInline, instr, index);
default:
return false;
}
}
bool inlineLoadMethod(int patchIndex, MethodDefinition method, Instruction loadInstr, int instrIndex) {
var instr = DotNetUtils.getInstruction(method.Body.Instructions, ref instrIndex);
if (instr == null || instr.OpCode.Code != Code.Ret)
return false;
int methodArgsCount = DotNetUtils.getArgsCount(method);
for (int i = 0; i < methodArgsCount; i++)
block.insert(patchIndex++, Instruction.Create(OpCodes.Pop));
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(loadInstr));
return true;
}
bool inlineOtherMethod(int patchIndex, MethodDefinition method, Instruction instr, int instrIndex) {
int loadIndex = 0;
int methodArgsCount = DotNetUtils.getArgsCount(method);
bool foundLdarga = false;
while (instr != null && loadIndex < methodArgsCount) {
bool isLdarg = true;
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:
break;
case Code.Ldarga:
case Code.Ldarga_S:
foundLdarga = true;
break;
default:
isLdarg = false;
break;
}
if (!isLdarg)
break;
if (DotNetUtils.getArgIndex(method, instr) != loadIndex)
return false;
loadIndex++;
instr = DotNetUtils.getInstruction(method.Body.Instructions, ref instrIndex);
}
if (instr == null || loadIndex != methodArgsCount)
return false;
if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt) {
if (foundLdarga)
return false;
var callInstr = instr;
var calledMethod = callInstr.Operand as MethodReference;
if (calledMethod == null)
return false;
if (!isCompatibleType(calledMethod.MethodReturnType.ReturnType, method.MethodReturnType.ReturnType))
return false;
var methodArgs = DotNetUtils.getArgs(method);
var calledMethodArgs = DotNetUtils.getArgs(calledMethod);
if (methodArgs.Count != calledMethodArgs.Count)
return false;
for (int i = 0; i < methodArgs.Count; i++) {
if (!isCompatibleType(calledMethodArgs[i], methodArgs[i]))
return false;
}
instr = DotNetUtils.getInstruction(method.Body.Instructions, ref instrIndex);
if (instr == null || instr.OpCode.Code != Code.Ret)
return false;
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(callInstr));
return true;
}
else if (instr.OpCode.Code == Code.Newobj) {
if (foundLdarga)
return false;
var newobjInstr = instr;
var ctor = newobjInstr.Operand as MethodReference;
if (ctor == null)
return false;
if (!isCompatibleType(ctor.DeclaringType, method.MethodReturnType.ReturnType))
return false;
var methodArgs = DotNetUtils.getArgs(method);
var calledMethodArgs = DotNetUtils.getArgs(ctor);
if (methodArgs.Count + 1 != calledMethodArgs.Count)
return false;
for (int i = 0; i < methodArgs.Count; i++) {
if (!isCompatibleType(calledMethodArgs[i + 1], methodArgs[i]))
return false;
}
instr = DotNetUtils.getInstruction(method.Body.Instructions, ref instrIndex);
if (instr == null || instr.OpCode.Code != Code.Ret)
return false;
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(newobjInstr));
return true;
}
else if (instr.OpCode.Code == Code.Ldfld || instr.OpCode.Code == Code.Ldflda ||
instr.OpCode.Code == Code.Ldftn || instr.OpCode.Code == Code.Ldvirtftn) {
var ldInstr = instr;
instr = DotNetUtils.getInstruction(method.Body.Instructions, ref instrIndex);
if (instr == null || instr.OpCode.Code != Code.Ret)
return false;
if (methodArgsCount != 1)
return false;
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(ldInstr));
return true;
}
return false;
}
static bool isCompatibleType(TypeReference origType, TypeReference newType) {
protected override bool isCompatibleType(TypeReference origType, TypeReference newType) {
if (MemberReferenceHelper.compareTypes(origType, newType))
return true;
if (newType.IsValueType || origType.IsValueType)

View File

@ -17,6 +17,9 @@
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace de4dot.blocks.cflow {
public abstract class MethodCallInlinerBase : IMethodCallInliner {
// We can't catch all infinite loops, so inline methods at most this many times
@ -40,5 +43,125 @@ namespace de4dot.blocks.cflow {
}
protected abstract bool deobfuscateInternal();
protected bool inlineLoadMethod(int patchIndex, MethodDefinition methodToInline, Instruction loadInstr, int instrIndex) {
var instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex);
if (instr == null || instr.OpCode.Code != Code.Ret)
return false;
int methodArgsCount = DotNetUtils.getArgsCount(methodToInline);
for (int i = 0; i < methodArgsCount; i++)
block.insert(patchIndex++, Instruction.Create(OpCodes.Pop));
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(loadInstr));
return true;
}
protected bool inlineOtherMethod(int patchIndex, MethodDefinition methodToInline, Instruction instr, int instrIndex, int popLastArgs = 0) {
int loadIndex = 0;
int methodArgsCount = DotNetUtils.getArgsCount(methodToInline);
bool foundLdarga = false;
while (instr != null && loadIndex < methodArgsCount) {
bool isLdarg = true;
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:
break;
case Code.Ldarga:
case Code.Ldarga_S:
foundLdarga = true;
break;
default:
isLdarg = false;
break;
}
if (!isLdarg)
break;
if (DotNetUtils.getArgIndex(methodToInline, instr) != loadIndex)
return false;
loadIndex++;
instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex);
}
if (instr == null || loadIndex != methodArgsCount - popLastArgs)
return false;
if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt) {
if (foundLdarga)
return false;
var callInstr = instr;
var calledMethod = callInstr.Operand as MethodReference;
if (calledMethod == null)
return false;
if (!isCompatibleType(calledMethod.MethodReturnType.ReturnType, methodToInline.MethodReturnType.ReturnType))
return false;
var methodArgs = DotNetUtils.getArgs(methodToInline);
var calledMethodArgs = DotNetUtils.getArgs(calledMethod);
if (methodArgs.Count - popLastArgs != calledMethodArgs.Count)
return false;
for (int i = 0; i < calledMethodArgs.Count; i++) {
if (!isCompatibleType(calledMethodArgs[i], methodArgs[i]))
return false;
}
instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex);
if (instr == null || instr.OpCode.Code != Code.Ret)
return false;
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(callInstr));
return true;
}
else if (instr.OpCode.Code == Code.Newobj) {
if (foundLdarga)
return false;
var newobjInstr = instr;
var ctor = newobjInstr.Operand as MethodReference;
if (ctor == null)
return false;
if (!isCompatibleType(ctor.DeclaringType, methodToInline.MethodReturnType.ReturnType))
return false;
var methodArgs = DotNetUtils.getArgs(methodToInline);
var calledMethodArgs = DotNetUtils.getArgs(ctor);
if (methodArgs.Count + 1 - popLastArgs != calledMethodArgs.Count)
return false;
for (int i = 1; i < calledMethodArgs.Count; i++) {
if (!isCompatibleType(calledMethodArgs[i], methodArgs[i - 1]))
return false;
}
instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex);
if (instr == null || instr.OpCode.Code != Code.Ret)
return false;
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(newobjInstr));
return true;
}
else if (instr.OpCode.Code == Code.Ldfld || instr.OpCode.Code == Code.Ldflda ||
instr.OpCode.Code == Code.Ldftn || instr.OpCode.Code == Code.Ldvirtftn) {
var ldInstr = instr;
instr = DotNetUtils.getInstruction(methodToInline.Body.Instructions, ref instrIndex);
if (instr == null || instr.OpCode.Code != Code.Ret)
return false;
if (methodArgsCount != 1)
return false;
block.Instructions[patchIndex] = new Instr(DotNetUtils.clone(ldInstr));
return true;
}
return false;
}
protected virtual bool isCompatibleType(TypeReference origType, TypeReference newType) {
return MemberReferenceHelper.compareTypes(origType, newType);
}
}
}