protected override CallResult createCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex) { int methodId; if (!methodTokenToId.TryGetValue(method.MDToken.ToInt32(), out methodId)) return null; return new MyCallResult(block, callInstrIndex, methodId, gim); }
protected override bool Deobfuscate(Block block) { bool modified = false; constantsReader = null; var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { bool ch = Deobfuscate1(block, i); if (ch) { modified = true; continue; } ch = Deobfuscate2(block, i); if (ch) { modified = true; continue; } ch = Deobfuscate3(block, i); if (ch) { modified = true; continue; } } return modified; }
protected override CallResult createCallResult(MethodReference method, Block block, int callInstrIndex) { int methodId; if (!methodTokenToId.TryGetValue(method.MetadataToken.ToInt32(), out methodId)) return null; return new MyCallResult(block, callInstrIndex, methodId); }
public void AddInitializeArrayCode(Block block, int start, int numToRemove, ITypeDefOrRef elementType, byte[] data) { int index = start; block.Replace(index++, numToRemove, Instruction.CreateLdcI4(data.Length / elementType.ToTypeSig().ElementType.GetPrimitiveSize())); block.Insert(index++, OpCodes.Newarr.ToInstruction(elementType)); block.Insert(index++, OpCodes.Dup.ToInstruction()); block.Insert(index++, OpCodes.Ldtoken.ToInstruction((IField)Create(data))); block.Insert(index++, OpCodes.Call.ToInstruction((IMethod)InitializeArrayMethod)); }
public void addInitializeArrayCode(Block block, int start, int numToRemove, TypeReference elementType, byte[] data) { int index = start; block.replace(index++, numToRemove, DotNetUtils.createLdci4(data.Length / elementType.PrimitiveSize)); block.insert(index++, Instruction.Create(OpCodes.Newarr, elementType)); block.insert(index++, Instruction.Create(OpCodes.Dup)); block.insert(index++, Instruction.Create(OpCodes.Ldtoken, create(data))); block.insert(index++, Instruction.Create(OpCodes.Call, InitializeArrayMethod)); }
protected override bool deobfuscate(Block block) { bool changed = false; instructionEmulator.init(blocks); var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { var instr = instrs[i]; switch (instr.OpCode.Code) { case Code.Ldarg: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: case Code.Ldarg_S: changed |= fixLoadInstruction(block, i, instructionEmulator.getArg(DotNetUtils.getParameter(args, instr.Instruction))); break; case Code.Ldloc: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: case Code.Ldloc_S: changed |= fixLoadInstruction(block, i, instructionEmulator.getLocal(DotNetUtils.getLocalVar(blocks.Locals, instr.Instruction))); break; case Code.Ldarga: case Code.Ldarga_S: instructionEmulator.makeArgUnknown((ParameterDefinition)instr.Operand); break; case Code.Ldloca: case Code.Ldloca_S: instructionEmulator.makeLocalUnknown((VariableDefinition)instr.Operand); break; } try { instructionEmulator.emulate(instr.Instruction); } catch (NullReferenceException) { // Here if eg. invalid metadata token in a call instruction (operand is null) break; } } return changed; }
protected override bool Deobfuscate(Block block) { bool modified = false; instructionEmulator.Initialize(blocks, allBlocks[0] == block); var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { var instr = instrs[i]; switch (instr.OpCode.Code) { case Code.Ldarg: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: case Code.Ldarg_S: modified |= FixLoadInstruction(block, i, instructionEmulator.GetArg(instr.Instruction.GetParameter(args))); break; case Code.Ldloc: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: case Code.Ldloc_S: modified |= FixLoadInstruction(block, i, instructionEmulator.GetLocal(instr.Instruction.GetLocal(blocks.Locals))); break; case Code.Ldarga: case Code.Ldarga_S: instructionEmulator.MakeArgUnknown((Parameter)instr.Operand); break; case Code.Ldloca: case Code.Ldloca_S: instructionEmulator.MakeLocalUnknown((Local)instr.Operand); break; } try { instructionEmulator.Emulate(instr.Instruction); } catch (NullReferenceException) { // Here if eg. invalid metadata token in a call instruction (operand is null) break; } } return modified; }
static int findCallMethod(Block block, int index, bool keepLooking, Func<IMethod, bool> func) { var instrs = block.Instructions; for (int i = index; i < instrs.Count; i++) { var instr = instrs[i]; if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt) continue; var calledMethod = instr.Operand as IMethod; if (calledMethod != null && func(calledMethod)) return i; if (!keepLooking) return -1; } return -1; }
void add(Dictionary<Block, List<RemoveInfo>> removeInfos, Block block, int index, DelegateInfo di) { List<RemoveInfo> list; if (!removeInfos.TryGetValue(block, out list)) removeInfos[block] = list = new List<RemoveInfo>(); list.Add(new RemoveInfo { Index = index, DelegateInfo = di, }); }
public MyCallResult(Block block, int callEndIndex, IMethod method, MethodSpec gim) : base(block, callEndIndex) { this.IMethod = method; this.gim = gim; }
protected override CallResult createCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex) { if (stringDecrypters.find(method) == null) return null; return new MyCallResult(block, callInstrIndex, method, gim); }
void removeDeadBlock(Block block) { var parent = block.Parent; if (parent != null) // null if already dead parent.removeDeadBlock(block); }
static Block GetNopBlockTarget(Dictionary<Block, bool> nopBlocks, Block source, Block nopBlock) { if (nopBlock == null || !nopBlocks.ContainsKey(nopBlock) || source == nopBlock.FallThrough) return null; if (nopBlock.Parent.BaseBlocks[0] == nopBlock) return null; var target = nopBlock.FallThrough; if (nopBlock.Parent != target.Parent) return null; return target; }
bool GetArg(IMethod method, Block block, ref object arg, ref int instrIndex) { while (true) { if (instrIndex < 0) { // We're here if there were no cflow deobfuscation, or if there are two or // more blocks branching to the decrypter method, or the two blocks can't be // merged because one is outside the exception handler (eg. buggy obfuscator). Logger.w("Could not find all arguments to method {0} ({1:X8})", Utils.RemoveNewlines(method), method.MDToken.ToInt32()); errors++; return false; } var instr = block.Instructions[instrIndex--]; switch (instr.OpCode.Code) { case Code.Ldc_I4: case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: case Code.Ldstr: arg = instr.Operand; break; case Code.Ldc_I4_S: arg = (int)(sbyte)instr.Operand; break; case Code.Ldc_I4_0: arg = 0; break; case Code.Ldc_I4_1: arg = 1; break; case Code.Ldc_I4_2: arg = 2; break; case Code.Ldc_I4_3: arg = 3; break; case Code.Ldc_I4_4: arg = 4; break; case Code.Ldc_I4_5: arg = 5; break; case Code.Ldc_I4_6: arg = 6; break; case Code.Ldc_I4_7: arg = 7; break; case Code.Ldc_I4_8: arg = 8; break; case Code.Ldc_I4_M1:arg = -1; break; case Code.Ldnull: arg = null; break; case Code.Nop: continue; case Code.Ldloc: case Code.Ldloc_S: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: GetLocalVariableValue(instr.Instruction.GetLocal(theMethod.Body.Variables), out arg); break; case Code.Ldfld: case Code.Ldsfld: arg = instr.Operand; break; default: int pushes, pops; instr.Instruction.CalculateStackUsage(false, out pushes, out pops); if (!useUnknownArgs || pushes != 1) { Logger.w("Could not find all arguments to method {0} ({1:X8}), instr: {2}", Utils.RemoveNewlines(method), method.MDToken.ToInt32(), instr); errors++; return false; } for (int i = 0; i < pops; i++) { if (!GetArg(method, block, ref arg, ref instrIndex)) return false; } arg = null; break; } break; } return true; }
// Returns null if method is not a method we should inline protected abstract CallResult CreateCallResult(IMethod method, MethodSpec gim, Block block, int callInstrIndex);
public MyCallResult(Block block, int callEndIndex, MethodReference method) : base(block, callEndIndex) { this.methodKey = new MethodReferenceAndDeclaringTypeKey(method); }
protected override CallResult createCallResult(MethodReference method, Block block, int callInstrIndex) { if (!stringDecrypters.ContainsKey(new MethodReferenceAndDeclaringTypeKey(method))) return null; return new MyCallResult(block, callInstrIndex, method); }
public MyCallResult(Block block, int callEndIndex, int methodId) : base(block, callEndIndex) { this.methodId = methodId; }
bool remove(Blocks blocks, Block block) { var instrs = block.Instructions; const int numInstrsToRemove = 11; if (instrs.Count < numInstrsToRemove) return false; int startIndex = instrs.Count - numInstrsToRemove; int index = startIndex; if (instrs[index++].OpCode.Code != Code.Ldtoken) return false; if (!checkCall(instrs[index++], "System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)")) return false; if (!checkCall(instrs[index++], "System.Reflection.Assembly System.Type::get_Assembly()")) return false; if (!checkCall(instrs[index++], "System.Reflection.AssemblyName System.Reflection.Assembly::GetName()")) return false; if (!checkCall(instrs[index++], "System.Byte[] System.Reflection.AssemblyName::GetPublicKeyToken()")) return false; if (!checkCall(instrs[index++], "System.String System.Convert::ToBase64String(System.Byte[])")) return false; if (instrs[index++].OpCode.Code != Code.Ldstr) return false; if (!checkCall(instrs[index++], "System.String", "(System.String,System.String)")) return false; if (instrs[index++].OpCode.Code != Code.Ldstr) return false; if (!checkCall(instrs[index++], "System.Boolean System.String::op_Inequality(System.String,System.String)")) return false; if (!instrs[index++].isBrfalse()) return false; var badBlock = block.FallThrough; var goodblock = block.Targets[0]; if (badBlock == null) return false; if (badBlock == goodblock) { // All of the bad block was removed by the cflow deobfuscator. It was just a useless // calculation (div by zero). block.replaceLastInstrsWithBranch(numInstrsToRemove, goodblock); } else if (badBlock.Sources.Count == 1) { instrs = badBlock.Instructions; if (instrs.Count != 12) return false; index = 0; if (!instrs[index++].isLdcI4()) return false; if (!instrs[index].isStloc()) return false; var local = Instr.getLocalVar(blocks.Locals, instrs[index++]); if (local == null) return false; if (!checkLdloc(blocks.Locals, instrs[index++], local)) return false; if (!checkLdloc(blocks.Locals, instrs[index++], local)) return false; if (instrs[index++].OpCode.Code != Code.Sub) return false; if (instrs[index++].OpCode.Code != Code.Conv_U1) return false; if (!checkStloc(blocks.Locals, instrs[index++], local)) return false; if (!checkLdloc(blocks.Locals, instrs[index++], local)) return false; if (!checkLdloc(blocks.Locals, instrs[index++], local)) return false; if (instrs[index++].OpCode.Code != Code.Div) return false; if (instrs[index++].OpCode.Code != Code.Conv_U1) return false; if (!checkStloc(blocks.Locals, instrs[index++], local)) return false; block.replaceLastInstrsWithBranch(numInstrsToRemove, goodblock); badBlock.Parent.removeDeadBlock(badBlock); } else return false; return true; }
BlockInfo findBadBlock(Block last) { /* * ldstr "........." * newobj System.Security.SecurityException(string) * throw */ var instrs = last.Instructions; if (instrs.Count != 3) return null; Instr instr; int start = 0; int end = 0; instr = instrs[end++]; if (instr.OpCode != OpCodes.Ldstr) return null; instr = instrs[end++]; if (instr.OpCode != OpCodes.Newobj) return null; var method = instr.Operand as IMethod; if (method == null || method.ToString() != "System.Void System.Security.SecurityException::.ctor(System.String)") return null; instr = instrs[end++]; if (instr.OpCode != OpCodes.Throw) return null; end--; return new BlockInfo { Block = last, Start = start, End = end, }; }
void FindBlocks(List<Block> instrToBlock, List<Block> allBlocks) { Block block = null; for (var i = 0; i < instructions.Count; i++) { List<int> branchSources; if (branches.TryGetValue(i, out branchSources) || block == null) { block = new Block(); allBlocks.Add(block); } block.Add(new Instr(this.instructions[i])); instrToBlock.Add(block); } }
BlockInstr findProxyCall(DelegateInfo di, Block block, int index, Dictionary<Block, bool> visited, int stack) { if (visited.ContainsKey(block)) return null; if (index <= 0) visited[block] = true; var instrs = block.Instructions; for (int i = index + 1; i < instrs.Count; i++) { if (stack <= 0) return null; var instr = instrs[i]; DotNetUtils.updateStack(instr.Instruction, ref stack, false); if (stack < 0) return null; if (instr.OpCode != OpCodes.Call && instr.OpCode != OpCodes.Callvirt) continue; var method = DotNetUtils.getMethod(module, instr.Operand as MethodReference); if (method == null) continue; if (stack != (DotNetUtils.hasReturnValue(method) ? 1 : 0)) continue; if (method.DeclaringType != di.field.DeclaringType) continue; return new BlockInstr { Block = block, Index = i, }; } if (stack <= 0) return null; foreach (var target in block.getTargets()) { var info = findProxyCall(di, target, -1, visited, stack); if (info != null) return info; } return null; }
public CallResult(Block block, int callEndIndex) { this.block = block; this.callEndIndex = callEndIndex; }
bool FixLoadInstruction(Block block, int index, Value value) { if (value.IsInt32()) { var intValue = (Int32Value)value; if (!intValue.AllBitsValid()) return false; block.Instructions[index] = new Instr(Instruction.CreateLdcI4(intValue.Value)); return true; } else if (value.IsInt64()) { var intValue = (Int64Value)value; if (!intValue.AllBitsValid()) return false; block.Instructions[index] = new Instr(OpCodes.Ldc_I8.ToInstruction(intValue.Value)); return true; } return false; }
void FindCallResults(Block block) { for (int i = 0; i < block.Instructions.Count; i++) { var instr = block.Instructions[i]; if (instr.OpCode != OpCodes.Call) continue; var method = instr.Operand as IMethod; if (method == null) continue; IMethod elementMethod = method; var gim = method as MethodSpec; if (gim != null) elementMethod = gim.Method; var callResult = CreateCallResult(elementMethod, gim, block, i); if (callResult == null) continue; if (FindArgs(callResult)) callResults.Add(callResult); } }
protected override bool Deobfuscate(Block block) { bool modified = false; instructionEmulator.Initialize(Blocks, AllBlocks[0] == block); var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { var instr = instrs[i]; switch (instr.OpCode.Code) { case Code.Ldarg: case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: case Code.Ldarg_S: modified |= FixLoadInstruction(block, i, instructionEmulator.GetArg(instr.Instruction.GetParameter(args))); break; case Code.Ldloc: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: case Code.Ldloc_S: modified |= FixLoadInstruction(block, i, instructionEmulator.GetLocal(instr.Instruction.GetLocal(Blocks.Locals))); break; case Code.Ldarga: case Code.Ldarga_S: instructionEmulator.MakeArgUnknown((Parameter)instr.Operand); break; case Code.Ldloca: case Code.Ldloca_S: instructionEmulator.MakeLocalUnknown((Local)instr.Operand); break; case Code.Add: case Code.Add_Ovf: case Code.Add_Ovf_Un: case Code.And: case Code.Ceq: case Code.Cgt: case Code.Cgt_Un: case Code.Clt: case Code.Clt_Un: case Code.Conv_I: case Code.Conv_I1: case Code.Conv_I2: case Code.Conv_I4: case Code.Conv_I8: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I_Un: case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I1_Un: case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I2_Un: case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I4_Un: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U_Un: case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U1_Un: case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U2_Un: case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U4_Un: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: case Code.Conv_R_Un: case Code.Conv_R4: case Code.Conv_R8: case Code.Conv_U: case Code.Conv_U1: case Code.Conv_U2: case Code.Conv_U4: case Code.Conv_U8: case Code.Div: case Code.Div_Un: case Code.Dup: case Code.Mul: case Code.Mul_Ovf: case Code.Mul_Ovf_Un: case Code.Neg: case Code.Not: case Code.Or: case Code.Rem: case Code.Rem_Un: case Code.Shl: case Code.Shr: case Code.Shr_Un: case Code.Sub: case Code.Sub_Ovf: case Code.Sub_Ovf_Un: case Code.Xor: if (DisableNewCode) break; if (i + 1 < instrs.Count && instrs[i + 1].OpCode.Code == Code.Pop) break; if (!VerifyValidArgs(instr.Instruction)) break; instructionEmulator.Emulate(instr.Instruction); var tos = instructionEmulator.Peek(); Instruction newInstr = null; if (tos.IsInt32()) { var val = (Int32Value)tos; if (val.AllBitsValid()) newInstr = Instruction.CreateLdcI4(val.Value); } else if (tos.IsInt64()) { var val = (Int64Value)tos; if (val.AllBitsValid()) newInstr = OpCodes.Ldc_I8.ToInstruction(val.Value); } else if (tos.IsReal8()) { var val = (Real8Value)tos; if (val.IsValid) newInstr = GetLoadRealInstruction(val.Value); } if (newInstr != null) { block.Insert(i + 1, Instruction.Create(OpCodes.Pop)); block.Insert(i + 2, newInstr); i += 2; modified = true; } continue; } try { instructionEmulator.Emulate(instr.Instruction); } catch (NullReferenceException) { // Here if eg. invalid metadata token in a call instruction (operand is null) break; } } return modified; }
bool GetValue(Block block, int index, out object obj) { while (true) { if (index <= 0) { obj = null; return false; } var instr = block.Instructions[--index]; if (instr.OpCode == OpCodes.Nop) continue; switch (instr.OpCode.Code) { case Code.Ldc_I4: case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: case Code.Ldstr: obj = instr.Operand; return true; case Code.Ldc_I4_S: obj = (int)(sbyte)instr.Operand; return true; case Code.Ldc_I4_0: obj = 0; return true; case Code.Ldc_I4_1: obj = 1; return true; case Code.Ldc_I4_2: obj = 2; return true; case Code.Ldc_I4_3: obj = 3; return true; case Code.Ldc_I4_4: obj = 4; return true; case Code.Ldc_I4_5: obj = 5; return true; case Code.Ldc_I4_6: obj = 6; return true; case Code.Ldc_I4_7: obj = 7; return true; case Code.Ldc_I4_8: obj = 8; return true; case Code.Ldc_I4_M1:obj = -1; return true; case Code.Ldnull: obj = null; return true; default: obj = null; return false; } } }
bool fixLoadInstruction(Block block, int index, Value value) { if (value.isInt32()) { var intValue = (Int32Value)value; if (!intValue.allBitsValid()) return false; block.Instructions[index] = new Instr(DotNetUtils.createLdci4(intValue.value)); return true; } else if (value.isInt64()) { var intValue = (Int64Value)value; if (!intValue.allBitsValid()) return false; block.Instructions[index] = new Instr(Instruction.Create(OpCodes.Ldc_I8, intValue.value)); return true; } return false; }
public LocalVariableInfo(Block block, int index) { this.block = block; this.index = index; }
bool findFirstBlocks(Block block, TamperBlocks tamperBlocks, IList<Block> allBlocks, IList<Local> locals) { if (!block.LastInstr.isBrfalse()) return false; /* * ldc.i4.0 * stloc X * call GetExecutingAssembly() * stloc Y * ldloc Y * callvirt Location * ldc.i4.1 * ldloca X * call StrongNameSignatureVerificationEx * pop / brfalse bad_code * ldloc X * brfalse bad_code * ldloc Y * callvirt FullName() * ldstr "......" * callvirt EndsWith(string) * brfalse bad_code / brtrue good_code */ var instrs = block.Instructions; int end = instrs.Count - 1; Instr instr; IMethod method; tamperBlocks.type = Type.V1; int index = 0; int start = findCallMethod(block, index, true, (calledMethod) => calledMethod.ToString() == "System.Reflection.Assembly System.Reflection.Assembly::GetExecutingAssembly()"); if (start < 0) return false; index = start + 1; instr = instrs[--start]; if (!instr.isStloc()) return false; var loc0 = Instr.getLocalVar(locals, instr); instr = instrs[--start]; if (!instr.isLdcI4()) return false; index = findCallMethod(block, index, false, (calledMethod) => calledMethod.ToString() == "System.String System.Reflection.Assembly::get_Location()"); if (index < 0) return false; index++; index = findCallMethod(block, index, false, (calledMethod) => { tamperBlocks.pinvokeMethod = DotNetUtils.getMethod(module, calledMethod); return DotNetUtils.isPinvokeMethod(tamperBlocks.pinvokeMethod, "mscorwks", "StrongNameSignatureVerificationEx"); }); if (index < 0) return false; index++; if (!instrs[index].isBrfalse()) { if (instrs[index].OpCode.Code != Code.Pop) return false; instr = instrs[index + 1]; if (!instr.isLdloc() || Instr.getLocalVar(locals, instr) != loc0) return false; if (!instrs[index + 2].isBrfalse()) return false; tamperBlocks.type = Type.V1; tamperBlocks.first = new BlockInfo { Block = block, Start = start, End = end, }; } else { tamperBlocks.type = Type.V2; tamperBlocks.first = new BlockInfo { Block = block, Start = start, End = end, }; block = block.FallThrough; if (block == null) return false; instrs = block.Instructions; index = 0; instr = instrs[index]; if (!instr.isLdloc() || Instr.getLocalVar(locals, instr) != loc0) return false; if (!instrs[index + 1].isBrfalse()) return false; } block = block.FallThrough; instrs = block.Instructions; start = end = 0; instr = instrs[end++]; if (!instr.isLdloc()) return false; instr = instrs[end++]; if (instr.OpCode != OpCodes.Callvirt) return false; method = instr.Operand as IMethod; if (method == null || method.ToString() != "System.String System.Reflection.Assembly::get_FullName()") return false; instr = instrs[end++]; if (instr.OpCode != OpCodes.Ldstr) return false; instr = instrs[end++]; if (instr.OpCode != OpCodes.Callvirt) return false; method = instr.Operand as IMethod; if (method == null || method.ToString() != "System.Boolean System.String::EndsWith(System.String)") return false; instr = instrs[end++]; if (!instr.isBrfalse() && !instr.isBrtrue()) return false; end--; tamperBlocks.second = new BlockInfo { Block = block, Start = start, End = end, }; return true; }