Move methods to base class
This commit is contained in:
parent
6c7bcbed79
commit
6a5ddba022
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user