using System.Reflection; using System.Collections; using System.Reflection.PortableExecutable; using Iced.Intel; internal static class NativeInspect { static object Prop(object o, string n) => o.GetType().GetProperty(n)!.GetValue(o)!; static string Label(object m) => m == null ? "" : Prop(Prop(m,"DeclaringType"),"Name") + "::" + Prop(m,"Name"); public static void Run(Type main, object metadata, string binary, string typeName, string methodName) { var methods = ((IEnumerable)metadata.GetType().GetField("methodDefs")!.GetValue(metadata)!).Cast() .Select(m => (Method:m, Address:(ulong)Prop(m,"MethodPointer"))).Where(m=>m.Address!=0).OrderBy(m=>m.Address).ToArray(); // An address target (decimal or 0x hex) disassembles that instruction window directly. var raw = typeName.Replace("0x", "").Trim(); if (raw.Length > 4 && (ulong.TryParse(raw, out var fixedAddress) || ulong.TryParse(raw, System.Globalization.NumberStyles.HexNumber, null, out fixedAddress))) { DisassembleOne(main, metadata, binary, fixedAddress, methods); return; } var bytes=File.ReadAllBytes(binary); using var pe=new PEReader(new MemoryStream(bytes)); ulong imageBase=pe.PEHeaders.PEHeader!.ImageBase; int Raw(ulong address) { var rva=address-imageBase; var s=pe.PEHeaders.SectionHeaders.First(s=>rva>=(ulong)s.VirtualAddress && rva<(ulong)(s.VirtualAddress+s.SizeOfRawData)); return (int)(rva-(ulong)s.VirtualAddress)+s.PointerToRawData; } object Nearest(ulong address) => methods.LastOrDefault(m=>m.Address<=address).Method; foreach(var item in methods.Where(m=>Prop(Prop(m.Method,"DeclaringType"),"Name").ToString()==typeName && (methodName=="" || Prop(m.Method,"Name").ToString()==methodName))) { Console.WriteLine($"\nMETHOD {Label(item.Method)} 0x{item.Address:X}"); Emit(main, pe, imageBase, bytes, Raw, Nearest, methods, item.Address); } } static void DisassembleOne(Type main, object metadata, string binary, ulong address, (object Method, ulong Address)[] methods) { var bytes=File.ReadAllBytes(binary); using var pe=new PEReader(new MemoryStream(bytes)); ulong imageBase=pe.PEHeaders.PEHeader!.ImageBase; int Raw(ulong address) { var rva=address-imageBase; var s=pe.PEHeaders.SectionHeaders.First(s=>rva>=(ulong)s.VirtualAddress && rva<(ulong)(s.VirtualAddress+s.SizeOfRawData)); return (int)(rva-(ulong)s.VirtualAddress)+s.PointerToRawData; } object Nearest(ulong address) => methods.LastOrDefault(m=>m.Address<=address).Method; Console.WriteLine($"\nMETHOD {Label(Nearest(address))}+0x{address - (Nearest(address)!=null ? (ulong)Prop(Nearest(address),"MethodPointer") : 0):X} 0x{address:X}"); Emit(main, pe, imageBase, bytes, Raw, Nearest, methods, address); } static void Emit(Type main, PEReader pe, ulong imageBase, byte[] bytes, Func Raw, Func Nearest, (object Method, ulong Address)[] methods, ulong start) { var item = (Method: Nearest(start), Address: start); foreach(var section in pe.PEHeaders.SectionHeaders.Where(s=>(s.SectionCharacteristics & SectionCharacteristics.MemExecute)!=0)) for(int i=section.PointerToRawData;i m.Address > item.Address).Address; for(int i=0;i<1500 && (next == 0 || decoder.IP < next);i++) { decoder.Decode(out var instruction); output.Value=""; formatter.Format(instruction,output); string note=""; if(instruction.FlowControl==FlowControl.Call && instruction.Op0Kind==OpKind.NearBranch64) { var called=Nearest(instruction.NearBranchTarget); if(called!=null && (ulong)Prop(called,"MethodPointer")==instruction.NearBranchTarget) note=" ; "+Label(called); } if(instruction.IsIPRelativeMemoryOperand) { try { var literal=main.GetMethod("GetLiteralByAddress")!.Invoke(null,new object[]{instruction.IPRelativeMemoryAddress}); if(literal!=null) note+=" ; literal: "+literal; } catch {} } Console.WriteLine($"{instruction.IP:X}: {output.Value}{note}"); } } sealed class LineOutput:FormatterOutput { public string Value=""; public override void Write(string text,FormatterTextKind kind)=>Value+=text; } }