MethodBodyReader (MethodBase method) { this.method = method; this.body = method.GetMethodBody (); if (this.body == null) throw new ArgumentException ("Method has no body"); var bytes = body.GetILAsByteArray (); if (bytes == null) throw new ArgumentException ("Can not get the body of the method"); if (!(method is ConstructorInfo)) method_arguments = method.GetGenericArguments (); if (method.DeclaringType != null) type_arguments = method.DeclaringType.GetGenericArguments (); if (!method.IsStatic) this_parameter = new ThisParameter(method.DeclaringType); this.parameters = method.GetParameters (); this.locals = body.LocalVariables; this.module = method.Module; this.il = new ByteBuffer (bytes); this.instructions = new List<Instruction> ((bytes.Length + 1) / 2); }
public NaiveMethodNameExtractor(Delegate @delegate) { delegateMethod = @delegate.Method; body = delegateMethod.GetMethodBody(); Debug.Assert(body != null); module = delegateMethod.Module; stream = new MemoryStream(body.GetILAsByteArray()); Read(); }
/// <summary> /// Disassemble the bytecode of the specified method or constructor /// </summary> /// <param name="MethodBase">The method to disassemble</param> /// <param name="Resolver">A resolver class used while disassembling the code. /// Every token resolution and local variable resolution will be made with this resolver</param> /// <returns>The list of intruction contained in the method</returns> static public List <Instruction> ReadMethod(System.Reflection.MethodBase MethodBase, Resolver Resolver) { System.Reflection.MethodBody methodBody = MethodBase.GetMethodBody(); if (methodBody == null) { return(new List <Instruction>()); } return(ReadMethod(methodBody.GetILAsByteArray(), Resolver)); }
private MethodBodyReader(MethodBase method) { _method = method; _body = method.GetMethodBody(); if (_body == null) throw new ArgumentException("Method has no body"); var iLAsByteArray = _body.GetILAsByteArray(); if (iLAsByteArray == null) throw new ArgumentException("Can not get the body of the method"); if (!(method is ConstructorInfo)) _methodArguments = method.GetGenericArguments(); if (method.DeclaringType != null) _typeArguments = method.DeclaringType.GetGenericArguments(); _parameters = method.GetParameters(); _locals = _body.LocalVariables; _module = method.Module; _il = new ByteBuffer(iLAsByteArray); }
private MethodBodyReader(MethodBase method, MethodBody mb) { this.method = method; body = mb; if (body == null) throw new ArgumentException(); var bytes = body.GetILAsByteArray(); if (bytes == null) throw new ArgumentException(); if (!(method is ConstructorInfo)) method_arguments = method.GetGenericArguments(); if (method.DeclaringType != null) generic_type_arguments = method.DeclaringType.GetGenericArguments(); parameters = method.GetParameters(); locals = body.LocalVariables; module = method.Module; il = new ByteBuffer(bytes); }
private void _CopyMethodToDefinition() { MethodBase method = OriginalMethod; Module moduleFrom = method.Module; System.Reflection.MethodBody bodyFrom = method.GetMethodBody(); byte[] data = bodyFrom?.GetILAsByteArray(); if (data == null) { throw new NotSupportedException("Body-less method"); } MethodDefinition def = Definition; ModuleDefinition moduleTo = def.Module; Mono.Cecil.Cil.MethodBody bodyTo = def.Body; ILProcessor processor = bodyTo.GetILProcessor(); Type[] typeArguments = null; if (method.DeclaringType.IsGenericType) { typeArguments = method.DeclaringType.GetGenericArguments(); } Type[] methodArguments = null; if (method.IsGenericMethod) { methodArguments = method.GetGenericArguments(); } foreach (LocalVariableInfo info in bodyFrom.LocalVariables) { TypeReference type = moduleTo.ImportReference(info.LocalType); if (info.IsPinned) { type = new PinnedType(type); } bodyTo.Variables.Add(new VariableDefinition(type)); } using (BinaryReader reader = new BinaryReader(new MemoryStream(data))) { while (reader.BaseStream.Position < reader.BaseStream.Length) { int offset = (int)reader.BaseStream.Position; Instruction instr = Instruction.Create(OpCodes.Nop); byte op = reader.ReadByte(); instr.OpCode = op != 0xfe ? _CecilOpCodes1X[op] : _CecilOpCodes2X[reader.ReadByte()]; instr.Offset = offset; ReadOperand(reader, instr); bodyTo.Instructions.Add(instr); } } foreach (Instruction instr in bodyTo.Instructions) { switch (instr.OpCode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: instr.Operand = GetInstruction((int)instr.Operand); break; case OperandType.InlineSwitch: int[] offsets = (int[])instr.Operand; Instruction[] targets = new Instruction[offsets.Length]; for (int i = 0; i < offsets.Length; i++) { targets[i] = GetInstruction(offsets[i]); } instr.Operand = targets; break; } } foreach (ExceptionHandlingClause clause in bodyFrom.ExceptionHandlingClauses) { ExceptionHandler handler = new ExceptionHandler((ExceptionHandlerType)clause.Flags); bodyTo.ExceptionHandlers.Add(handler); handler.TryStart = GetInstruction(clause.TryOffset); handler.TryEnd = GetInstruction(clause.TryOffset + clause.TryLength); handler.FilterStart = handler.HandlerType != ExceptionHandlerType.Filter ? null : GetInstruction(clause.FilterOffset); handler.HandlerStart = GetInstruction(clause.HandlerOffset); handler.HandlerEnd = GetInstruction(clause.HandlerOffset + clause.HandlerLength); handler.CatchType = handler.HandlerType != ExceptionHandlerType.Catch ? null : clause.CatchType == null ? null : moduleTo.ImportReference(clause.CatchType); } void ReadOperand(BinaryReader reader, Instruction instr) { int index, offs, length; switch (instr.OpCode.OperandType) { case OperandType.InlineNone: instr.Operand = null; break; case OperandType.InlineSwitch: length = reader.ReadInt32(); offs = (int)reader.BaseStream.Position + (4 * length); int[] targets = new int[length]; for (int i = 0; i < length; i++) { targets[i] = reader.ReadInt32() + offs; } instr.Operand = targets; break; case OperandType.ShortInlineBrTarget: offs = reader.ReadSByte(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.InlineBrTarget: offs = reader.ReadInt32(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.ShortInlineI: instr.Operand = instr.OpCode == OpCodes.Ldc_I4_S ? reader.ReadSByte() : (object)reader.ReadByte(); break; case OperandType.InlineI: instr.Operand = reader.ReadInt32(); break; case OperandType.ShortInlineR: instr.Operand = reader.ReadSingle(); break; case OperandType.InlineR: instr.Operand = reader.ReadDouble(); break; case OperandType.InlineI8: instr.Operand = reader.ReadInt64(); break; case OperandType.InlineSig: throw new NotSupportedException("Parsing CallSites at runtime currently not supported"); case OperandType.InlineString: instr.Operand = moduleFrom.ResolveString(reader.ReadInt32()); break; case OperandType.InlineTok: switch (moduleFrom.ResolveMember(reader.ReadInt32(), typeArguments, methodArguments)) { case Type i: instr.Operand = moduleTo.ImportReference(i); break; case FieldInfo i: instr.Operand = moduleTo.ImportReference(i); break; case MethodBase i: instr.Operand = moduleTo.ImportReference(i); break; } break; case OperandType.InlineType: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveType(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.InlineMethod: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveMethod(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.InlineField: instr.Operand = moduleTo.ImportReference(moduleFrom.ResolveField(reader.ReadInt32(), typeArguments, methodArguments)); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: index = instr.OpCode.OperandType == OperandType.ShortInlineVar ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = bodyTo.Variables[index]; break; case OperandType.InlineArg: case OperandType.ShortInlineArg: index = instr.OpCode.OperandType == OperandType.ShortInlineArg ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = def.Parameters[index]; break; case OperandType.InlinePhi: // No opcode seems to use this default: throw new NotSupportedException($"Unsupported opcode ${instr.OpCode.Name}"); } } Instruction GetInstruction(int offset) { int last = bodyTo.Instructions.Count - 1; if (offset < 0 || offset > bodyTo.Instructions[last].Offset) { return(null); } int min = 0; int max = last; while (min <= max) { int mid = min + ((max - min) / 2); Instruction instr = bodyTo.Instructions[mid]; if (offset == instr.Offset) { return(instr); } if (offset < instr.Offset) { max = mid - 1; } else { min = mid + 1; } } return(null); } }
public static void WriteILCode(MethodBody mb, BinaryWriter writer) { int codesize = mb.GetILAsByteArray().Length; writer.Write(mb.GetILAsByteArray()); // 对齐 4 bytes int ig = codesize & 3; if (ig == 0) return; if (mb.ExceptionHandlingClauses.Count == 0) return;//无SEH; ig = 4 - ig; for(int i=0; i<ig;i++) { writer.Write((byte)0); } }
public ControlFlowGraph(NetMethodBody body, Module module, Type[] genericTypeArguments, Type[] genericMethodArguments) { // Convert the byte code into instruction objects ushort ip = 0; byte[] il = body.GetILAsByteArray(); List <IInstruction> instructions = new List <IInstruction>(); while (ip < il.Length) { instructions.Add(OpCodeTable.GetInstruction(il, ref ip, module, genericTypeArguments, genericMethodArguments)); } // Iterate the instructions building a list of call graph nodes SortedList <ushort, CallGraphNode> nodes = new SortedList <ushort, CallGraphNode>(); CallGraphNode node = new CallGraphNode(0); nodes.Add(0, node); int index = 0; IInstruction instruction = instructions[index]; do { Console.Write(instruction); // Create the nodes that this instruction branches to switch (instruction.OpCode.FlowControl) { case FlowControl.Branch: { if ((instruction.OpCode != OpCodes.Leave) && (instruction.OpCode != OpCodes.Leave_S)) { // Direct branch to a new instruction that is not a leave instruction from a try-catch block. // Create a call graph node for the target of the branch. MakeNode((ushort)instruction.Argument, nodes); Console.Write(" <-- Branch {0:x4}", instruction.Argument); } break; } case FlowControl.Cond_Branch: { if (instruction.OpCode.Value == OpCodes.Switch.Value) { // Conditional branch to n-blocks foreach (ushort switchTargetIp in (ushort[])instruction.Argument) { MakeNode(switchTargetIp, nodes); } } else { // Conditional branch to two blocks MakeNode((ushort)instruction.Argument, nodes); Console.WriteLine("Making " + instruction.Argument); } // Set the next instruction of a branch to also be a target MakeNode(instructions[index + 1].IP, nodes); Console.Write(" <-- If Node {0:x4}", instruction.Argument); break; } case FlowControl.Return: // Set the next instruction of a branch to also be a target Console.Write(" <-- Exit Node"); break; case FlowControl.Throw: // End of graph Console.Write(" <-- Throw Node"); break; case FlowControl.Break: case FlowControl.Call: case FlowControl.Meta: case FlowControl.Next: #pragma warning disable 612,618 case FlowControl.Phi: #pragma warning restore 612,618 // Add the continuation link //node.NodeType = NodeType.FallThrough; //MakeNode(ip, node, nodes); break; } Console.WriteLine(); // Get the next instruction index++; if (index < instructions.Count) { instruction = instructions[index]; // Find the node to add the next instruction to CallGraphNode nextNode; if (nodes.TryGetValue(instruction.IP, out nextNode)) { /*if (node.NodeType == NodeType.FallThrough) * { * Console.Write("added fall through link "); * node.OutEdges.Add(nextNode); * nextNode.InEdges.Add(node); * }*/ node = nextNode; Console.Write("New Node --> "); } } } while (index < instructions.Count); Console.WriteLine(); // Iterate the instructions a second time adding them to the correct nodes //CallGraphNode node; node = nodes[0]; for (index = 0; index < instructions.Count; index++) { instruction = instructions[index]; if (index > 0) { CallGraphNode nextNode; if (nodes.TryGetValue(instruction.IP, out nextNode)) { if (node.OutEdges.Count == 0) { Console.WriteLine("ff"); node.NodeType = NodeType.FallThrough; LinkNode(node, nextNode); } Console.Write("--" + node.OutEdges.Count + "--"); node = nextNode; Console.Write("new node "); } } Console.WriteLine(instruction); node.Instructions.Add(instruction); // Create the nodes that this instruction branches to switch (instruction.OpCode.FlowControl) { case FlowControl.Branch: { if ((instruction.OpCode != OpCodes.Leave) && (instruction.OpCode != OpCodes.Leave_S)) { // Direct branch to a new instruction that is not a leave instruction from a try-catch block. // Create a call graph node for the target of the branch. node.NodeType = NodeType.OneBranch; LinkNode(node, nodes[(ushort)instruction.Argument]); Console.Write(" <-- Branch {0:x4}", instruction.Argument); } break; } case FlowControl.Cond_Branch: { if (instruction.OpCode.Value == OpCodes.Switch.Value) { // Conditional branch to n-blocks node.NodeType = NodeType.MultiBranch; foreach (ushort switchTargetIp in (ushort[])instruction.Argument) { LinkNode(node, nodes[switchTargetIp]); } } else { // Conditional branch to two blocks node.NodeType = NodeType.TwoBranch; LinkNode(node, nodes[(ushort)instruction.Argument]); Console.Write("Linking " + instruction.Argument); } // Set the next instruction of a branch to also be a target LinkNode(node, nodes[instructions[index + 1].IP]); Console.Write(" <-- If Node {0:x4}", instruction.Argument); break; } case FlowControl.Return: // Set the next instruction of a branch to also be a target node.NodeType = NodeType.Exit; Console.Write(" <-- Exit Node"); break; case FlowControl.Throw: // End of graph node.NodeType = NodeType.Throw; Console.Write(" <-- Throw Node"); break; } } // Copy the nodes to a simple list _nodes.AddRange(nodes.Values); Console.WriteLine(); Console.WriteLine(_nodes.Count); foreach (CallGraphNode n in _nodes) { Console.WriteLine(n.StartIP + " " + n.NodeType + " " + n.OutEdges.Count); } CheckGraph(); // Add the exception information - build a sorted tree of clauses SortedList <int, TryHandler> clauses = new SortedList <int, TryHandler>(); foreach (ExceptionHandlingClause clause in body.ExceptionHandlingClauses) { Add(new TryHandler(clause), clauses); } foreach (TryHandler clause in clauses.Values) { TraverseExceptionTree(clause); } // Find the root node -- This fails when there are multiple try statements on the first instruction for (int i = 0; i < _nodes.Count; i++) { if (_nodes[i].StartIP == 0) { _rootNode = _nodes[i]; break; } } if (_rootNode == null) { throw new ApplicationException("Unable to find a root node"); } CheckGraph(); // Remove redundancies and add in-edge information Optimize(); CheckGraph(); // Visit the graph in depth first order and label the nodes _depthFirstSearchLast = new CallGraphNode[_nodes.Count]; int last = _nodes.Count - 1; DepthFirstTraverse(_rootNode, ref last); // Find the immediate dominators of each node FindImmediateDominators(); // Check the graph for reducibility FindDerivedSequence(); // Work out the graphs back edges DetermineBackEdges(); ResetTraversal(); StructureCases(); StructureLoops(); StructureIfs(); ResetTraversal(); }
public static Action <MethodDef> ApplyMixin(this MethodBase mixin, PatchConfiguration patch) => original => { CilBody originalBody = original.Body; MethodBody mixinBody = mixin.GetMethodBody(); List <Instruction> originalIL = new List <Instruction>(originalBody.Instructions); List <Local> originalLocals = new List <Local>(originalBody.Variables); originalBody.Variables.Clear(); foreach (LocalVariableInfo local in mixinBody.LocalVariables.OrderBy(lvi => lvi.LocalIndex)) { originalBody.Variables.Add(original.Module.ToDNLib(local)); } List <Instruction> mixinIL = new CilParser(mixin.Module, originalBody.Variables, mixinBody.GetILAsByteArray()).Parse(); mixinIL.SimplifyMacros(originalBody.Variables, original.Parameters); IList <Instruction> newIL = originalBody.Instructions; newIL.Clear(); int ilStart = 0; if (mixin.IsConstructor) { foreach (Instruction inst in mixin.IsDefined(typeof(RewriteBaseAttribute)) ? mixinIL : originalIL) { ilStart++; newIL.Add(inst); if (inst.OpCode.FlowControl == FlowControl.Call) { break; } } RemoveCall(originalIL); RemoveCall(mixinIL); } MethodDef baseCopy = new MethodDefUser(original.DeclaringType.FindUnusedMethodName(original.Name + "<Base>$"), original.MethodSig, original.ImplAttributes, original.Attributes & CopyMask | CopyAttr); bool useBase = false; foreach (Instruction inst in mixinIL) { switch (inst.Operand) { case FieldInfo field: inst.Operand = patch.ResolveOrImport(original.Module, field); break; case MethodBase method: if (method.IsDefined(typeof(BaseDependencyAttribute))) { useBase = true; inst.Operand = baseCopy; break; } inst.Operand = patch.ResolveOrImport(original.Module, method); break; case Type type: inst.Operand = patch.ResolveOrImport(original.Module, type); break; case byte[] blob: throw new NotImplementedException("how do you import this?"); case MemberInfo member: throw new NotImplementedException("how do you import this?"); } newIL.Add(inst); } if (useBase) { baseCopy.Body = new CilBody(originalBody.InitLocals, originalIL, new List <ExceptionHandler>(originalBody.ExceptionHandlers), originalBody.Variables); original.DeclaringType.Methods.Add(baseCopy); } originalBody.ExceptionHandlers.Clear(); foreach (ExceptionHandlingClause ehc in mixinBody.ExceptionHandlingClauses) { originalBody.ExceptionHandlers.Add(ehc.ToDNLib(original.Module, newIL)); } originalBody.OptimizeMacros(); void RemoveCall(List <Instruction> il) { for (int index = 0; index < il.Count; index++) { if (il[index].OpCode.FlowControl != FlowControl.Call) { continue; } il.RemoveRange(0, index + 1); break; } } };
public static Action <MethodDef> ApplyInject(this MethodBase inject, PatchConfiguration patch) => stub => { CilBody stubBody = stub.Body; MethodBody injectBody = inject.GetMethodBody(); List <Instruction> originalIL = new List <Instruction>(stubBody.Instructions); List <Local> originalLocals = new List <Local>(stubBody.Variables); stubBody.Variables.Clear(); foreach (LocalVariableInfo local in injectBody.LocalVariables.OrderBy(lvi => lvi.LocalIndex)) { stubBody.Variables.Add(stub.Module.ToDNLib(local)); } List <Instruction> mixinIL = new CilParser(inject.Module, stubBody.Variables, injectBody.GetILAsByteArray()).Parse(); mixinIL.SimplifyMacros(stubBody.Variables, stub.Parameters); IList <Instruction> newIL = stubBody.Instructions; newIL.Clear(); foreach (Instruction inst in mixinIL) { switch (inst.Operand) { case FieldInfo field: inst.Operand = patch.ResolveOrImport(stub.Module, field); break; case MethodBase method: if (method.IsDefined(typeof(BaseDependencyAttribute))) { throw new InvalidOperationException("attempt to inject a body with a base dependency call"); } inst.Operand = patch.ResolveOrImport(stub.Module, method); break; case Type type: inst.Operand = patch.ResolveOrImport(stub.Module, type); break; case byte[] blob: throw new NotImplementedException("how do you import this?"); case MemberInfo member: throw new NotImplementedException("how do you import this?"); } newIL.Add(inst); } stubBody.ExceptionHandlers.Clear(); foreach (ExceptionHandlingClause ehc in injectBody.ExceptionHandlingClauses) { stubBody.ExceptionHandlers.Add(ehc.ToDNLib(stub.Module, newIL)); } stubBody.OptimizeMacros(); };
private void Write(BinaryWriter bw, Module module, MethodBody mb) { var locals = mb.LocalVariables; bw.Write(locals.Count); for (int i=0;i< locals.Count;i++) { bw.Write(locals[i].LocalType.FullName); bw.Write(locals[i].IsPinned); } var il = mb.GetILAsByteArray(); for(int i = 0; i < il.Length;) { EArgumentType argType = EArgumentType.None; var opcode = (EOpCode)il[i]; bw.Write(il[i]); i++; if(opcode == EOpCode.Extended) { bw.Write(il[i]); argType = ((EExtendedOpCode)il[i]).ArgFor(); i++; } else argType = opcode.ArgFor(); switch (argType) { case EArgumentType.Field: var fi = module.ResolveField(BitConverter.ToInt32(il, i)); i += 4; bw.Write(Names.Field(fi)); break; case EArgumentType.Float32: bw.Write(BitConverter.ToSingle(il, i)); i += 4; break; case EArgumentType.Float64: bw.Write(BitConverter.ToDouble(il, i)); i += 8; break; case EArgumentType.Token: case EArgumentType.Int32: bw.Write(BitConverter.ToInt32(il, i)); i += 4; break; case EArgumentType.Int64: bw.Write(BitConverter.ToInt64(il, i)); i += 8; break; case EArgumentType.Int8: bw.Write((sbyte)il[i]); i++; break; case EArgumentType.ListOfInt: uint count = BitConverter.ToUInt32(il, i); bw.Write(count); i += 4; while(count > 0) { bw.Write(BitConverter.ToInt32(il, i)); i += 4; } break; case EArgumentType.Method: var mi = module.ResolveMethod(BitConverter.ToInt32(il, i)); i += 4; bw.Write(Names.Method(mi)); break; case EArgumentType.String: var str = module.ResolveString(BitConverter.ToInt32(il, i)); i += 4; bw.Write(str); break; case EArgumentType.Type: var t = module.ResolveType(BitConverter.ToInt32(il, i)); i += 4; bw.Write(t.FullName); break; case EArgumentType.Uint16: bw.Write(BitConverter.ToUInt16(il, i)); i += 2; break; case EArgumentType.Uint32: bw.Write(BitConverter.ToUInt32(il, i)); i += 4; break; case EArgumentType.Uint8: bw.Write(il[i]); i++; break; } } bw.Write((byte)EOpCode.Terminator); /* var handlers = mb.ExceptionHandlingClauses; m_bw.Write(handlers.Count); foreach(var h in handlers) { m_bw.Write(h.TryOffset); m_bw.Write(h.TryLength); m_bw.Write(h.FilterOffset); m_bw.Write(h.HandlerOffset); m_bw.Write(h.HandlerLength); m_bw.Write((uint)h.Flags); //m_bw.Write(h.) }*/ }
private void _CopyMethodToDefinition() { MethodBase method = OriginalMethod; Module moduleFrom = method.Module; System.Reflection.MethodBody bodyFrom = method.GetMethodBody(); byte[] data = bodyFrom?.GetILAsByteArray(); if (data == null) { throw new NotSupportedException("Body-less method"); } MethodDefinition def = Definition; ModuleDefinition moduleTo = def.Module; Mono.Cecil.Cil.MethodBody bodyTo = def.Body; ILProcessor processor = bodyTo.GetILProcessor(); Type[] typeArguments = null; if (method.DeclaringType.IsGenericType) { typeArguments = method.DeclaringType.GetGenericArguments(); } Type[] methodArguments = null; if (method.IsGenericMethod) { methodArguments = method.GetGenericArguments(); } foreach (LocalVariableInfo info in bodyFrom.LocalVariables) { TypeReference type = moduleTo.ImportReference(info.LocalType); if (info.IsPinned) { type = new PinnedType(type); } bodyTo.Variables.Add(new VariableDefinition(type)); } using (BinaryReader reader = new BinaryReader(new MemoryStream(data))) { for (Instruction instr = null, prev = null; reader.BaseStream.Position < reader.BaseStream.Length; prev = instr) { int offset = (int)reader.BaseStream.Position; instr = Instruction.Create(OpCodes.Nop); byte op = reader.ReadByte(); instr.OpCode = op != 0xfe ? _CecilOpCodes1X[op] : _CecilOpCodes2X[reader.ReadByte()]; instr.Offset = offset; if (prev != null) { prev.Next = instr; } instr.Previous = prev; ReadOperand(reader, instr); bodyTo.Instructions.Add(instr); } } foreach (Instruction instr in bodyTo.Instructions) { switch (instr.OpCode.OperandType) { case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: instr.Operand = GetInstruction((int)instr.Operand); break; case OperandType.InlineSwitch: int[] offsets = (int[])instr.Operand; Instruction[] targets = new Instruction[offsets.Length]; for (int i = 0; i < offsets.Length; i++) { targets[i] = GetInstruction(offsets[i]); } instr.Operand = targets; break; } } foreach (ExceptionHandlingClause clause in bodyFrom.ExceptionHandlingClauses) { ExceptionHandler handler = new ExceptionHandler((ExceptionHandlerType)clause.Flags); bodyTo.ExceptionHandlers.Add(handler); handler.TryStart = GetInstruction(clause.TryOffset); handler.TryEnd = GetInstruction(clause.TryOffset + clause.TryLength); handler.FilterStart = handler.HandlerType != ExceptionHandlerType.Filter ? null : GetInstruction(clause.FilterOffset); handler.HandlerStart = GetInstruction(clause.HandlerOffset); handler.HandlerEnd = GetInstruction(clause.HandlerOffset + clause.HandlerLength); handler.CatchType = handler.HandlerType != ExceptionHandlerType.Catch ? null : clause.CatchType == null ? null : moduleTo.ImportReference(clause.CatchType); } void ReadOperand(BinaryReader reader, Instruction instr) { int index, offs, length; switch (instr.OpCode.OperandType) { case OperandType.InlineNone: instr.Operand = null; break; case OperandType.InlineSwitch: length = reader.ReadInt32(); offs = (int)reader.BaseStream.Position + (4 * length); int[] targets = new int[length]; for (int i = 0; i < length; i++) { targets[i] = reader.ReadInt32() + offs; } instr.Operand = targets; break; case OperandType.ShortInlineBrTarget: offs = reader.ReadSByte(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.InlineBrTarget: offs = reader.ReadInt32(); instr.Operand = (int)reader.BaseStream.Position + offs; break; case OperandType.ShortInlineI: instr.Operand = instr.OpCode == OpCodes.Ldc_I4_S ? reader.ReadSByte() : (object)reader.ReadByte(); break; case OperandType.InlineI: instr.Operand = reader.ReadInt32(); break; case OperandType.ShortInlineR: instr.Operand = reader.ReadSingle(); break; case OperandType.InlineR: instr.Operand = reader.ReadDouble(); break; case OperandType.InlineI8: instr.Operand = reader.ReadInt64(); break; case OperandType.InlineSig: instr.Operand = moduleTo.ImportCallSite(moduleFrom, moduleFrom.ResolveSignature(reader.ReadInt32())); break; case OperandType.InlineString: instr.Operand = moduleFrom.ResolveString(reader.ReadInt32()); break; case OperandType.InlineTok: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Any); break; case OperandType.InlineType: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Type); break; case OperandType.InlineMethod: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Method); break; case OperandType.InlineField: instr.Operand = ResolveTokenAs(reader.ReadInt32(), TokenResolutionMode.Field); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: index = instr.OpCode.OperandType == OperandType.ShortInlineVar ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = bodyTo.Variables[index]; break; case OperandType.InlineArg: case OperandType.ShortInlineArg: index = instr.OpCode.OperandType == OperandType.ShortInlineArg ? reader.ReadByte() : reader.ReadInt16(); instr.Operand = def.Parameters[index]; break; case OperandType.InlinePhi: // No opcode seems to use this default: throw new NotSupportedException($"Unsupported opcode ${instr.OpCode.Name}"); } } MemberReference ResolveTokenAs(int token, TokenResolutionMode resolveMode) { try { switch (resolveMode) { case TokenResolutionMode.Type: return(moduleTo.ImportReference(moduleFrom.ResolveType(token, typeArguments, methodArguments))); case TokenResolutionMode.Method: return(moduleTo.ImportReference(moduleFrom.ResolveMethod(token, typeArguments, methodArguments))); case TokenResolutionMode.Field: return(moduleTo.ImportReference(moduleFrom.ResolveField(token, typeArguments, methodArguments))); case TokenResolutionMode.Any: switch (moduleFrom.ResolveMember(token, typeArguments, methodArguments)) { case Type i: return(moduleTo.ImportReference(i)); case MethodBase i: return(moduleTo.ImportReference(i)); case FieldInfo i: return(moduleTo.ImportReference(i)); case var resolved: throw new NotSupportedException($"Invalid resolved member type {resolved.GetType()}"); } default: throw new NotSupportedException($"Invalid TokenResolutionMode {resolveMode}"); } } catch (MissingMemberException) { // we could not resolve the method normally, so lets read the import table // but we can only do that if the module was loaded from disk // this can still throw if the assembly is a dynamic one, but if that's broken, you have bigger issues string filePath = moduleFrom.Assembly.Location; if (!File.Exists(filePath)) { // in this case, the fallback cannot be followed, and so throwing the original error gives the user information throw; } // TODO: make this cached somehow so its not read and re-opened a bunch using (AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(filePath, new ReaderParameters { ReadingMode = ReadingMode.Deferred })) { ModuleDefinition module = assembly.Modules.First(m => m.Name == moduleFrom.Name); // this should only fail if the token itself is somehow wrong MemberReference reference = (MemberReference)module.LookupToken(token); // the explicit casts here are to throw if they are incorrect // normally the references would need to be imported, but moduleTo isn't written to anywhere switch (resolveMode) { case TokenResolutionMode.Type: return((TypeReference)reference); case TokenResolutionMode.Method: return((MethodReference)reference); case TokenResolutionMode.Field: return((FieldReference)reference); case TokenResolutionMode.Any: return(reference); default: throw new NotSupportedException($"Invalid TokenResolutionMode {resolveMode}"); } } } } Instruction GetInstruction(int offset) { int last = bodyTo.Instructions.Count - 1; if (offset < 0 || offset > bodyTo.Instructions[last].Offset) { return(null); } int min = 0; int max = last; while (min <= max) { int mid = min + ((max - min) / 2); Instruction instr = bodyTo.Instructions[mid]; if (offset == instr.Offset) { return(instr); } if (offset < instr.Offset) { max = mid - 1; } else { min = mid + 1; } } return(null); } }
public ILReader(MethodBase InputMethod, FieldInfo[] FieldsInModule, MethodBase[] MethodsInModule, Assembly currentAssm) { workingAssm = currentAssm; MethodOpcodes = new ArrayList(); InputMeth = InputMethod; ExceptionHandlers = new ArrayList(); if (InputMethod == null) { Console.WriteLine("Error, input method is not specified, can not continue"); return; } methodBody = InputMethod.GetMethodBody(); curModule = InputMethod.DeclaringType.Module; pos = 0; pos1 = 0; IL = methodBody.GetILAsByteArray(); IList<ExceptionHandlingClause> ehClauses = methodBody.ExceptionHandlingClauses; foreach( ExceptionHandlingClause ehclause in ehClauses ) { ExceptionHandlers.Add(new ExceptionInstruction(ehclause.TryOffset,ExceptionHandler.Try,null)); switch (ehclause.Flags) { //case 0: case ExceptionHandlingClauseOptions.Clause: ExceptionHandlers.Add(new ExceptionInstruction(ehclause.HandlerOffset,ExceptionHandler.Catch,ehclause.CatchType)); ExceptionHandlers.Add(new ExceptionInstruction(ehclause.HandlerOffset+ehclause.HandlerLength,ExceptionHandler.EndException,null)); break; //case 1: case ExceptionHandlingClauseOptions.Filter: ExceptionHandlers.Add(new ExceptionInstruction(ehclause.FilterOffset,ExceptionHandler.Filter,null)); ExceptionHandlers.Add(new ExceptionInstruction(ehclause.HandlerOffset,ExceptionHandler.EndFilter,null)); ExceptionHandlers.Add(new ExceptionInstruction(ehclause.HandlerOffset+ehclause.HandlerLength,ExceptionHandler.EndException,null)); break; //case 2: case ExceptionHandlingClauseOptions.Finally: ExceptionHandlers.Add(new ExceptionInstruction(ehclause.HandlerOffset,ExceptionHandler.Finally,null)); ExceptionHandlers.Add(new ExceptionInstruction(ehclause.HandlerOffset+ehclause.HandlerLength,ExceptionHandler.EndException,null)); break; //case 4: case ExceptionHandlingClauseOptions.Fault: ExceptionHandlers.Add(new ExceptionInstruction(ehclause.HandlerOffset,ExceptionHandler.Fault,null)); ExceptionHandlers.Add(new ExceptionInstruction(ehclause.HandlerOffset+ehclause.HandlerLength,ExceptionHandler.EndException,null)); break; } } // populate opcode Opcode Op = GetOpcode(); while (Op.Name != "") // This cycles through all the Opcodes { if (Op.Name != "stfld") MethodOpcodes.Add(Op); Op = GetOpcode(); } // sort the stfld opcodes and output // this will make the opcode invalid for run. // but out purpose is simply compare the assemblies. StfldList.Sort(new StringCompare()); foreach (object i in StfldList) { Opcode temp = new Opcode("stfld", i); MakeLabel(temp, false); MethodOpcodes.Add(temp); } }
MethodBodyReader(MethodBase method) { this.method = method; this.body = method.GetMethodBody(); if (this.body == null) throw new ArgumentNullException(); var bytes = body.GetILAsByteArray(); if (bytes == null) throw new ArgumentNullException(); if (!(method is ConstructorInfo)) method_arguments = method.GetGenericArguments(); if (method.DeclaringType != null) type_arguments = method.DeclaringType.GetGenericArguments(); this.parameters = method.GetParameters(); this.locals = body.LocalVariables; this.module = method.Module; this.il = new ByteBuffer(bytes); }
MethodBodyReader (MethodBase method) { //wicky.patch.start: check DynamicMethod byte[] bytes; if (DynamicMethodHelper.IsDynamicOrRTDynamicMethod(method)) { DynamicMethod dynamicMethod = DynamicMethodHelper.GetDynamicMethod(method); this.method = dynamicMethod; bytes = DynamicMethodHelper.GetILAsByteArray(dynamicMethod); if (bytes == null) bytes = new byte[0]; if (dynamicMethod.DeclaringType != null) type_arguments = dynamicMethod.DeclaringType.GetGenericArguments(); this.parameters = dynamicMethod.GetParameters(); this.module = dynamicMethod.Module; //this.locals = ?? this.il = new ByteBuffer(bytes); this.tokenResolver = new DynamicScopeTokenResolver(dynamicMethod); } else { this.method = method; this.body = method.GetMethodBody(); if (this.body == null) bytes = new byte[0]; else bytes = body.GetILAsByteArray(); if (bytes == null) bytes = new byte[0]; bytes = body.GetILAsByteArray(); if (!(method is ConstructorInfo)) method_arguments = method.GetGenericArguments(); if (method.DeclaringType != null) type_arguments = method.DeclaringType.GetGenericArguments(); this.parameters = method.GetParameters(); this.locals = body.LocalVariables; this.module = method.Module; this.il = new ByteBuffer(bytes); this.tokenResolver = new ModuleScopeTokenResolver(method); } /* this.method = method; this.body = method.GetMethodBody (); if (this.body == null) throw new ArgumentException ("Method has no body"); var bytes = body.GetILAsByteArray (); if (bytes == null) throw new ArgumentException ("Can not get the body of the method"); if (!(method is ConstructorInfo)) method_arguments = method.GetGenericArguments (); if (method.DeclaringType != null) type_arguments = method.DeclaringType.GetGenericArguments (); this.parameters = method.GetParameters (); this.locals = body.LocalVariables; this.module = method.Module; this.il = new ByteBuffer (bytes); */ //wicky.patch.end }