internal bool getLdcValue(Instr instr, out int value) { if (Code.Ldc_I4_0 <= instr.OpCode.Code && instr.OpCode.Code <= Code.Ldc_I4_8) { value = instr.OpCode.Code - Code.Ldc_I4_0; } else if (instr.OpCode.Code == Code.Ldc_I4) { value = (int)instr.Operand; } else if (instr.OpCode.Code == Code.Ldc_I4_S) { value = (sbyte)instr.Operand; } else if (instr.OpCode.Code == Code.Ldc_I4_M1) { value = -1; } else { value = 0; return(false); } return(true); }
// Returns the variable or null if it's not a ldloc/stloc instruction public static VariableDefinition getLocalVar(IList<VariableDefinition> locals, Instr instr) { switch (instr.OpCode.Code) { case Code.Ldloc: case Code.Ldloc_S: case Code.Stloc: case Code.Stloc_S: return (VariableDefinition)instr.Operand; case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: return locals[instr.OpCode.Code - Code.Ldloc_0]; case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: return locals[instr.OpCode.Code - Code.Stloc_0]; default: return null; } }
static bool checkStloc(IList<VariableDefinition> locals, Instr instr, VariableDefinition local) { if (!instr.isStloc()) return false; if (Instr.getLocalVar(locals, instr) != local) return false; return true; }
static bool checkStloc(IList<Local> locals, Instr instr, Local local) { if (!instr.isStloc()) return false; if (Instr.getLocalVar(locals, instr) != local) return false; return true; }
public bool CanAppend(Block other) { if (other == null || other == this || GetOnlyTarget() != other) { return(false); } // If it's eg. a leave, then don't merge them since it clears the stack. return(LastInstr.IsBr() || Instr.IsFallThrough(LastInstr.OpCode)); }
static bool checkCall(Instr instr, string returnType, string parameters) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt) return false; var calledMethod = instr.Operand as IMethod; if (calledMethod == null) return false; return DotNetUtils.isMethod(calledMethod, returnType, parameters); }
static bool checkCall(Instr instr, string methodFullname) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt) return false; var calledMethod = instr.Operand as IMethod; if (calledMethod == null) return false; return calledMethod.ToString() == methodFullname; }
public void Deobfuscate(Blocks blocks) { foreach (var block in blocks.MethodBlocks.GetAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count - 1; i++) { var first = instrs[i]; var second = instrs[i + 1]; if (first.OpCode.Code == Code.Not && second.OpCode.Code == Code.Neg) { // It's increment instrs[i] = new Instr(OpCodes.Ldc_I4_1.ToInstruction()); instrs[i + 1] = new Instr(OpCodes.Add.ToInstruction()); } else if (first.OpCode.Code == Code.Neg && second.OpCode.Code == Code.Not) { // It's decrement instrs[i] = new Instr(OpCodes.Ldc_I4_1.ToInstruction()); instrs[i + 1] = new Instr(OpCodes.Sub.ToInstruction()); } } } }
// Fix all branches so they now point to a Block, and not an Instruction. The // block's Targets field is updated, not the Instruction's Operand field. // Also update Block.FallThrough with next Block if last instr falls through. void fixBranchTargets(List <Block> instrToBlock, List <Block> allBlocks) { for (var i = 0; i < allBlocks.Count; i++) { var block = allBlocks[i]; var lastInstr = block.LastInstr; switch (lastInstr.OpCode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: var targetInstr = lastInstr.Operand as Instruction; if (targetInstr != null) { block.Targets = new List <Block> { instrToBlock[instrToIndex[targetInstr]] } } ; break; case OperandType.InlineSwitch: var switchTargets = (Instruction[])lastInstr.Operand; var newSwitchTargets = new List <Block>(); block.Targets = newSwitchTargets; foreach (var target in switchTargets) { if (target != null) { newSwitchTargets.Add(instrToBlock[instrToIndex[target]]); } } break; } if (i + 1 < allBlocks.Count && Instr.isFallThrough(lastInstr.OpCode)) { block.FallThrough = allBlocks[i + 1]; } } }
// Returns the variable or null if it's not a ldloc/stloc instruction. It does not return // a local variable if it's a ldloca/ldloca.s instruction. public static VariableDefinition getLocalVar(IList<VariableDefinition> locals, Instr instr) { return DotNetUtils.getLocalVar(locals, instr.Instruction); }
// Returns the variable or null if it's not a ldloc/stloc instruction. It does not return // a local variable if it's a ldloca/ldloca.s instruction. public static VariableDefinition getLocalVar(IList <VariableDefinition> locals, Instr instr) { return(DotNetUtils.getLocalVar(locals, instr.Instruction)); }
public void deobfuscate(Blocks blocks) { foreach (var block in blocks.MethodBlocks.getAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { var instr = instrs[i]; if (instr.OpCode.Code != Code.Ldsfld) continue; var field = instr.Operand as FieldReference; if (field == null) continue; var info = stringInfos.find(field); if (info == null) continue; var decrypted = decrypt(info); instrs[i] = new Instr(Instruction.Create(OpCodes.Ldstr, decrypted)); Log.v("Decrypted string: {0}", Utils.toCsharpString(decrypted)); } } }
static bool CheckCall(Instr instr, IMethod expectedMethod) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt) return false; var calledMethod = instr.Operand as IMethod; if (calledMethod == null) return false; return MethodEqualityComparer.CompareDeclaringTypes.Equals(calledMethod, expectedMethod); }
public int OptimizeLocals() { if (locals.Count == 0) { return(0); } var usedLocals = new Dictionary <Local, List <LocalVariableInfo> >(); foreach (var block in methodBlocks.GetAllBlocks()) { for (int i = 0; i < block.Instructions.Count; i++) { var instr = block.Instructions[i]; Local local; switch (instr.OpCode.Code) { 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.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: local = Instr.GetLocalVar(locals, instr); break; case Code.Ldloca_S: case Code.Ldloca: local = (Local)instr.Operand; break; default: local = null; break; } if (local == null) { continue; } List <LocalVariableInfo> list; if (!usedLocals.TryGetValue(local, out list)) { usedLocals[local] = list = new List <LocalVariableInfo>(); } list.Add(new LocalVariableInfo(block, i)); if (usedLocals.Count == locals.Count) { return(0); } } } int newIndex = -1; var newLocals = new List <Local>(usedLocals.Count); var newLocalsDict = new Dictionary <Local, bool>(usedLocals.Count); foreach (var local in usedLocals.Keys) { newIndex++; newLocals.Add(local); newLocalsDict[local] = true; foreach (var info in usedLocals[local]) { info.block.Instructions[info.index] = new Instr(OptimizeLocalInstr(info.block.Instructions[info.index], local, (uint)newIndex)); } } // We can't remove all locals. Locals that reference another assembly will // cause the CLR to load that assembly before the method is executed if it // hasn't been loaded yet. This is a side effect the program may depend on. // At least one program has this dependency and will crash if we remove the // unused local. This took a while to figure out... var keptAssemblies = new Dictionary <string, bool>(StringComparer.Ordinal); foreach (var local in locals) { if (newLocalsDict.ContainsKey(local)) { continue; } var defAsm = local.Type.DefinitionAssembly; if (defAsm == null) { continue; // eg. fnptr } if (defAsm == method.DeclaringType.Module.Assembly) { continue; // this assembly is always loaded } if (defAsm.IsCorLib()) { continue; // mscorlib is always loaded } var asmName = defAsm.FullName; if (keptAssemblies.ContainsKey(asmName)) { continue; } keptAssemblies[asmName] = true; newLocals.Add(local); } int numRemoved = locals.Count - newLocals.Count; locals.Clear(); foreach (var local in newLocals) { locals.Add(local); } return(numRemoved); }
void layOutInstructions(out IList<Instruction> allInstructions, out IList<ExceptionHandler> allExceptionHandlers) { allInstructions = new List<Instruction>(); allExceptionHandlers = new List<ExceptionHandler>(); var blockInfos = new List<BlockInfo>(); for (int i = 0; i < blocks.Count; i++) { var block = blocks[i]; int startIndex = allInstructions.Count; for (int j = 0; j < block.Instructions.Count - 1; j++) allInstructions.Add(block.Instructions[j].Instruction); if (block.Targets != null) { var targets = new List<Instr>(); foreach (var target in block.Targets) targets.Add(target.FirstInstr); block.LastInstr.updateTargets(targets); } allInstructions.Add(block.LastInstr.Instruction); var next = i + 1 < blocks.Count ? blocks[i + 1] : null; // If eg. ble next, then change it to bgt XYZ and fall through to next. if (block.Targets != null && block.canFlipConditionalBranch() && block.Targets[0] == next) { block.flipConditionalBranch(); block.LastInstr.updateTargets(new List<Instr> { block.Targets[0].FirstInstr }); } else if (block.FallThrough != null && block.FallThrough != next) { var instr = new Instr(Instruction.Create(OpCodes.Br, block.FallThrough.FirstInstr.Instruction)); instr.updateTargets(new List<Instr> { block.FallThrough.FirstInstr }); allInstructions.Add(instr.Instruction); } int endIndex = allInstructions.Count - 1; blockInfos.Add(new BlockInfo(startIndex, endIndex)); } foreach (var ex in exceptions) { var tryStart = blockInfos[ex.tryStart].start; var tryEnd = blockInfos[ex.tryEnd].end; var filterStart = ex.filterStart == -1 ? -1 : blockInfos[ex.filterStart].start; var handlerStart = blockInfos[ex.handlerStart].start; var handlerEnd = blockInfos[ex.handlerEnd].end; var eh = new ExceptionHandler(ex.handlerType); eh.CatchType = ex.catchType; eh.TryStart = getInstruction(allInstructions, tryStart); eh.TryEnd = getInstruction(allInstructions, tryEnd + 1); eh.FilterStart = filterStart == -1 ? null : getInstruction(allInstructions, filterStart); eh.HandlerStart = getInstruction(allInstructions, handlerStart); eh.HandlerEnd = getInstruction(allInstructions, handlerEnd + 1); allExceptionHandlers.Add(eh); } }
bool Deobfuscate1(Block block, int i) { var instrs = block.Instructions; if (i >= instrs.Count - 2) return false; var ldloc = instrs[i]; if (!ldloc.IsLdloc()) return false; var local = ldloc.Instruction.GetLocal(Blocks.Locals); if (local == null) return false; ArrayBlockState.FieldInfo info; if (!localToInfo.TryGetValue(local, out info)) return false; var ldci4 = instrs[i + 1]; if (!ldci4.IsLdcI4()) return false; var ldelem = instrs[i + 2]; if (!IsLdelem(info, ldelem.OpCode.Code)) return false; block.Remove(i, 3 - 1); instrs[i] = new Instr(Instruction.CreateLdcI4((int)info.ReadArrayElement(ldci4.GetLdcI4Value()))); return true; }
public int optimizeLocals() { if (locals.Count == 0) { return(0); } var usedLocals = new Dictionary <VariableDefinition, List <LocalVariableInfo> >(); foreach (var block in methodBlocks.getAllBlocks()) { for (int i = 0; i < block.Instructions.Count; i++) { var instr = block.Instructions[i]; VariableDefinition local; switch (instr.OpCode.Code) { 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.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: local = Instr.getLocalVar(locals, instr); break; case Code.Ldloca_S: case Code.Ldloca: local = (VariableDefinition)instr.Operand; break; default: local = null; break; } if (local == null) { continue; } List <LocalVariableInfo> list; if (!usedLocals.TryGetValue(local, out list)) { usedLocals[local] = list = new List <LocalVariableInfo>(); } list.Add(new LocalVariableInfo(block, i)); if (usedLocals.Count == locals.Count) { return(0); } } } int newIndex = -1; var newLocals = new List <VariableDefinition>(usedLocals.Count); foreach (var local in usedLocals.Keys) { newIndex++; newLocals.Add(local); foreach (var info in usedLocals[local]) { info.block.Instructions[info.index] = new Instr(optimizeLocalInstr(info.block.Instructions[info.index], local, (uint)newIndex)); } } int numRemoved = locals.Count - newLocals.Count; locals.Clear(); foreach (var local in newLocals) { locals.Add(local); } return(numRemoved); }
public void Deobfuscate(Blocks blocks) { foreach (var block in blocks.MethodBlocks.GetAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { var instr = instrs[i]; if (instr.OpCode.Code == Code.Call || instr.OpCode.Code == Code.Callvirt) { if (blocks.Method.DeclaringType == decrypterType) continue; var calledMethod = instr.Operand as IMethod; if (calledMethod != null && calledMethod.DeclaringType == decrypterType) canRemoveType = false; } else if (instr.OpCode.Code == Code.Ldsfld) { if (instr.OpCode.Code != Code.Ldsfld) continue; var field = instr.Operand as IField; if (field == null) continue; var decrypted = fieldToDecryptedString.Find(field); if (decrypted == null) continue; instrs[i] = new Instr(OpCodes.Ldstr.ToInstruction(decrypted)); Logger.v("Decrypted string: {0}", Utils.ToCsharpString(decrypted)); } } } }
static Instruction optimizeLocalInstr(Instr instr, VariableDefinition local, uint newIndex) { switch (instr.OpCode.Code) { case Code.Ldloc: case Code.Ldloc_S: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: if (newIndex == 0) { return(Instruction.Create(OpCodes.Ldloc_0)); } if (newIndex == 1) { return(Instruction.Create(OpCodes.Ldloc_1)); } if (newIndex == 2) { return(Instruction.Create(OpCodes.Ldloc_2)); } if (newIndex == 3) { return(Instruction.Create(OpCodes.Ldloc_3)); } if (newIndex <= 0xFF) { return(Instruction.Create(OpCodes.Ldloc_S, local)); } return(Instruction.Create(OpCodes.Ldloc, local)); case Code.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: if (newIndex == 0) { return(Instruction.Create(OpCodes.Stloc_0)); } if (newIndex == 1) { return(Instruction.Create(OpCodes.Stloc_1)); } if (newIndex == 2) { return(Instruction.Create(OpCodes.Stloc_2)); } if (newIndex == 3) { return(Instruction.Create(OpCodes.Stloc_3)); } if (newIndex <= 0xFF) { return(Instruction.Create(OpCodes.Stloc_S, local)); } return(Instruction.Create(OpCodes.Stloc, local)); case Code.Ldloca_S: case Code.Ldloca: if (newIndex <= 0xFF) { return(Instruction.Create(OpCodes.Ldloca_S, local)); } return(Instruction.Create(OpCodes.Ldloca, local)); default: throw new ApplicationException("Invalid ld/st local instruction"); } }
public void deobfuscate(Blocks blocks) { foreach (var block in blocks.MethodBlocks.getAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { var call = instrs[i]; if (call.OpCode.Code != Code.Call) continue; var calledMethod = call.Operand as MethodDefinition; if (calledMethod == null) continue; MethodReference newMethod = null; if (calledMethod == getManifestResourceStream1Method) newMethod = Assembly_GetManifestResourceStream1; else if (calledMethod == getManifestResourceStream2Method) newMethod = Assembly_GetManifestResourceStream2; else if (calledMethod == getManifestResourceNamesMethod) newMethod = Assembly_GetManifestResourceNames; if (newMethod == null) continue; instrs[i] = new Instr(Instruction.Create(OpCodes.Callvirt, newMethod)); } } }
public void add(Instr instr) { instructions.Add(instr); }
public void Deobfuscate(Blocks blocks) { if (type == null) return; foreach (var block in blocks.MethodBlocks.GetAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count - 1; i++) { var instr = instrs[i]; if (instr.OpCode.Code != Code.Ldc_I4) continue; var call = instrs[i + 1]; if (call.OpCode.Code != Code.Call) continue; var method = call.Operand as IMethod; if (method == null) continue; if (!new SigComparer().Equals(type, method.DeclaringType)) continue; var methodDef = DotNetUtils.GetMethod(module, method); if (methodDef == null) continue; if (methodDef != typeMethod && methodDef != fieldMethod) continue; uint token = (uint)(int)instrs[i].Operand; instrs[i] = new Instr(OpCodes.Nop.ToInstruction()); instrs[i + 1] = new Instr(new Instruction(OpCodes.Ldtoken, module.ResolveToken(token) as ITokenOperand)); } } }
bool Deobfuscate2(Block block, int i) { var instrs = block.Instructions; if (i >= instrs.Count - 2) return false; var ldsfld = instrs[i]; if (ldsfld.OpCode.Code != Code.Ldsfld) return false; var info = arrayBlockState.GetFieldInfo(ldsfld.Operand as IField); if (info == null) return false; var ldci4 = instrs[i + 1]; if (!ldci4.IsLdcI4()) return false; var ldelem = instrs[i + 2]; if (!IsLdelem(info, ldelem.OpCode.Code)) return false; block.Remove(i, 3 - 1); instrs[i] = new Instr(Instruction.CreateLdcI4((int)info.ReadArrayElement(ldci4.GetLdcI4Value()))); return true; }
// Returns the variable or null if it's not a ldloc/stloc instruction. It does not return // a local variable if it's a ldloca/ldloca.s instruction. public static Local GetLocalVar(IList <Local> locals, Instr instr) { return(instr.Instruction.GetLocal(locals)); }
// Returns the variable or null if it's not a ldloc/stloc instruction. It does not return // a local variable if it's a ldloca/ldloca.s instruction. public static Local GetLocalVar(IList<Local> locals, Instr instr) { return instr.Instruction.GetLocal(locals); }
public void Deobfuscate(Blocks blocks) { if (decrypter == null) return; foreach (var block in blocks.MethodBlocks.GetAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { var instr = instrs[i]; if (instr.OpCode.Code != Code.Ldsfld) continue; var field = instr.Operand as IField; if (field == null) continue; var info = stringInfos.Find(field); if (info == null) continue; var decrypted = Decrypt(info); instrs[i] = new Instr(OpCodes.Ldstr.ToInstruction(decrypted)); Logger.v("Decrypted string: {0}", Utils.ToCsharpString(decrypted)); } } }
static Instruction optimizeLocalInstr(Instr instr, VariableDefinition local, uint newIndex) { switch (instr.OpCode.Code) { case Code.Ldloc: case Code.Ldloc_S: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: if (newIndex == 0) return Instruction.Create(OpCodes.Ldloc_0); if (newIndex == 1) return Instruction.Create(OpCodes.Ldloc_1); if (newIndex == 2) return Instruction.Create(OpCodes.Ldloc_2); if (newIndex == 3) return Instruction.Create(OpCodes.Ldloc_3); if (newIndex <= 0xFF) return Instruction.Create(OpCodes.Ldloc_S, local); return Instruction.Create(OpCodes.Ldloc, local); case Code.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: if (newIndex == 0) return Instruction.Create(OpCodes.Stloc_0); if (newIndex == 1) return Instruction.Create(OpCodes.Stloc_1); if (newIndex == 2) return Instruction.Create(OpCodes.Stloc_2); if (newIndex == 3) return Instruction.Create(OpCodes.Stloc_3); if (newIndex <= 0xFF) return Instruction.Create(OpCodes.Stloc_S, local); return Instruction.Create(OpCodes.Stloc, local); case Code.Ldloca_S: case Code.Ldloca: if (newIndex <= 0xFF) return Instruction.Create(OpCodes.Ldloca_S, local); return Instruction.Create(OpCodes.Ldloca, local); default: throw new ApplicationException("Invalid ld/st local instruction"); } }
public void Add(Instr instr) { instructions.Add(instr); }
static bool CheckLdloc(IList<Local> locals, Instr instr, Local local) { if (!instr.IsLdloc()) return false; if (Instr.GetLocalVar(locals, instr) != local) return false; return true; }
public void deobfuscate(Blocks blocks) { if (type == null) return; foreach (var block in blocks.MethodBlocks.getAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count - 1; i++) { var instr = instrs[i]; if (instr.OpCode.Code != Code.Ldc_I4) continue; var call = instrs[i + 1]; if (call.OpCode.Code != Code.Call) continue; var method = call.Operand as MethodReference; if (method == null) continue; if (!MemberReferenceHelper.compareTypes(type, method.DeclaringType)) continue; var methodDef = DotNetUtils.getMethod(module, method); if (methodDef == null) continue; if (methodDef != typeMethod && methodDef != fieldMethod) continue; int token = (int)instrs[i].Operand; instrs[i] = new Instr(Instruction.Create(OpCodes.Nop)); instrs[i + 1] = new Instr(new Instruction(OpCodes.Ldtoken, module.LookupToken(token) as MemberReference)); } } }
static bool checkCall(Instr instr, string methodFullName) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt) return false; var calledMethod = instr.Operand as MethodReference; if (calledMethod == null) return false; return calledMethod.FullName == methodFullName; }
void fixTypeofDecrypterInstructions(Blocks blocks) { var type = getDecrypterType(); if (type == null) return; foreach (var block in blocks.MethodBlocks.getAllBlocks()) { var instructions = block.Instructions; for (int i = 0; i < instructions.Count; i++) { var instr = instructions[i]; if (instr.OpCode.Code != Code.Ldtoken) continue; if (!MemberReferenceHelper.compareTypes(type, instr.Operand as TypeReference)) continue; instructions[i] = new Instr(Instruction.Create(OpCodes.Ldtoken, blocks.Method.DeclaringType)); } } }
static bool checkCall(Instr instr, MethodReference expectedMethod) { if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt) return false; var calledMethod = instr.Operand as MethodReference; if (calledMethod == null) return false; return MemberReferenceHelper.compareMethodReferenceAndDeclaringType(calledMethod, expectedMethod); }
void layOutInstructions(out IList <Instruction> allInstructions, out IList <ExceptionHandler> allExceptionHandlers) { allInstructions = new List <Instruction>(); allExceptionHandlers = new List <ExceptionHandler>(); var blockInfos = new List <BlockInfo>(); for (int i = 0; i < blocks.Count; i++) { var block = blocks[i]; int startIndex = allInstructions.Count; for (int j = 0; j < block.Instructions.Count - 1; j++) { allInstructions.Add(block.Instructions[j].Instruction); } if (block.Targets != null) { var targets = new List <Instr>(); foreach (var target in block.Targets) { targets.Add(target.FirstInstr); } block.LastInstr.updateTargets(targets); } allInstructions.Add(block.LastInstr.Instruction); var next = i + 1 < blocks.Count ? blocks[i + 1] : null; // If eg. ble next, then change it to bgt XYZ and fall through to next. if (block.Targets != null && block.canFlipConditionalBranch() && block.Targets[0] == next) { block.flipConditionalBranch(); block.LastInstr.updateTargets(new List <Instr> { block.Targets[0].FirstInstr }); } else if (block.FallThrough != null && block.FallThrough != next) { var instr = new Instr(OpCodes.Br.ToInstruction(block.FallThrough.FirstInstr.Instruction)); instr.updateTargets(new List <Instr> { block.FallThrough.FirstInstr }); allInstructions.Add(instr.Instruction); } int endIndex = allInstructions.Count - 1; blockInfos.Add(new BlockInfo(startIndex, endIndex)); } foreach (var ex in exceptions) { var tryStart = getBlockInfo(blockInfos, ex.tryStart).start; var tryEnd = getBlockInfo(blockInfos, ex.tryEnd).end; var filterStart = ex.filterStart == -1 ? -1 : getBlockInfo(blockInfos, ex.filterStart).start; var handlerStart = getBlockInfo(blockInfos, ex.handlerStart).start; var handlerEnd = getBlockInfo(blockInfos, ex.handlerEnd).end; var eh = new ExceptionHandler(ex.handlerType); eh.CatchType = ex.catchType; eh.TryStart = getInstruction(allInstructions, tryStart); eh.TryEnd = getInstruction(allInstructions, tryEnd + 1); eh.FilterStart = filterStart == -1 ? null : getInstruction(allInstructions, filterStart); eh.HandlerStart = getInstruction(allInstructions, handlerStart); eh.HandlerEnd = getInstruction(allInstructions, handlerEnd + 1); allExceptionHandlers.Add(eh); } }
void FixTypeofDecrypterInstructions(Blocks blocks) { var type = GetDecrypterType(); if (type == null) return; foreach (var block in blocks.MethodBlocks.GetAllBlocks()) { var instructions = block.Instructions; for (int i = 0; i < instructions.Count; i++) { var instr = instructions[i]; if (instr.OpCode.Code != Code.Ldtoken) continue; if (!new SigComparer().Equals(type, instr.Operand as ITypeDefOrRef)) continue; instructions[i] = new Instr(OpCodes.Ldtoken.ToInstruction(blocks.Method.DeclaringType)); } } }
static Instruction OptimizeLocalInstr(Instr instr, Local local, uint newIndex) { switch (instr.OpCode.Code) { case Code.Ldloc: case Code.Ldloc_S: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: if (newIndex == 0) { return(OpCodes.Ldloc_0.ToInstruction()); } if (newIndex == 1) { return(OpCodes.Ldloc_1.ToInstruction()); } if (newIndex == 2) { return(OpCodes.Ldloc_2.ToInstruction()); } if (newIndex == 3) { return(OpCodes.Ldloc_3.ToInstruction()); } if (newIndex <= 0xFF) { return(OpCodes.Ldloc_S.ToInstruction(local)); } return(OpCodes.Ldloc.ToInstruction(local)); case Code.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: if (newIndex == 0) { return(OpCodes.Stloc_0.ToInstruction()); } if (newIndex == 1) { return(OpCodes.Stloc_1.ToInstruction()); } if (newIndex == 2) { return(OpCodes.Stloc_2.ToInstruction()); } if (newIndex == 3) { return(OpCodes.Stloc_3.ToInstruction()); } if (newIndex <= 0xFF) { return(OpCodes.Stloc_S.ToInstruction(local)); } return(OpCodes.Stloc.ToInstruction(local)); case Code.Ldloca_S: case Code.Ldloca: if (newIndex <= 0xFF) { return(OpCodes.Ldloca_S.ToInstruction(local)); } return(OpCodes.Ldloca.ToInstruction(local)); default: throw new ApplicationException("Invalid ld/st local instruction"); } }
static bool IsCast(Instr instr) { return instr.OpCode.Code == Code.Castclass || instr.OpCode.Code == Code.Isinst; }
public void Deobfuscate(Blocks blocks) { if (oldToNewMethod.Count == 0) return; foreach (var block in blocks.MethodBlocks.GetAllBlocks()) { var instrs = block.Instructions; for (int i = 0; i < instrs.Count; i++) { var call = instrs[i]; if (call.OpCode.Code != Code.Call) continue; var calledMethod = call.Operand as MethodDef; if (calledMethod == null) continue; var newMethodInfo = oldToNewMethod.Find(calledMethod); if (newMethodInfo == null) continue; instrs[i] = new Instr(Instruction.Create(newMethodInfo.opCode, newMethodInfo.method)); } } }
static ITypeDefOrRef GetCastType(Instr instr) { if (!IsCast(instr)) return null; return instr.Operand as ITypeDefOrRef; }
static Instruction OptimizeLocalInstr(Instr instr, Local local, uint newIndex) { switch (instr.OpCode.Code) { case Code.Ldloc: case Code.Ldloc_S: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: if (newIndex == 0) return OpCodes.Ldloc_0.ToInstruction(); if (newIndex == 1) return OpCodes.Ldloc_1.ToInstruction(); if (newIndex == 2) return OpCodes.Ldloc_2.ToInstruction(); if (newIndex == 3) return OpCodes.Ldloc_3.ToInstruction(); if (newIndex <= 0xFF) return OpCodes.Ldloc_S.ToInstruction(local); return OpCodes.Ldloc.ToInstruction(local); case Code.Stloc: case Code.Stloc_S: case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: if (newIndex == 0) return OpCodes.Stloc_0.ToInstruction(); if (newIndex == 1) return OpCodes.Stloc_1.ToInstruction(); if (newIndex == 2) return OpCodes.Stloc_2.ToInstruction(); if (newIndex == 3) return OpCodes.Stloc_3.ToInstruction(); if (newIndex <= 0xFF) return OpCodes.Stloc_S.ToInstruction(local); return OpCodes.Stloc.ToInstruction(local); case Code.Ldloca_S: case Code.Ldloca: if (newIndex <= 0xFF) return OpCodes.Ldloca_S.ToInstruction(local); return OpCodes.Ldloca.ToInstruction(local); default: throw new ApplicationException("Invalid ld/st local instruction"); } }
VariableDefinition getLocalVar(Instr instr) { return Instr.getLocalVar(blocks.Locals, instr); }