Files
2026-10-16 23:33:13 -07:00

70 lines
5.0 KiB
C#

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 ? "<native>" : 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<object>()
.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<ulong,int> Raw, Func<ulong,object> 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<section.PointerToRawData+section.SizeOfRawData-5;i++)
if(bytes[i]==0xE8 && (ulong)((long)imageBase+section.VirtualAddress+i-section.PointerToRawData+5+BitConverter.ToInt32(bytes,i+1))==item.Address)
{ ulong addr=imageBase+(ulong)(section.VirtualAddress+i-section.PointerToRawData); Console.WriteLine($"CALLER 0x{addr:X} {Label(Nearest(addr))}"); }
var decoder=Decoder.Create(64,new ByteArrayCodeReader(bytes,Raw(item.Address),Math.Min(10000,bytes.Length-Raw(item.Address)))); decoder.IP=item.Address;
var formatter=new IntelFormatter(); var output=new LineOutput();
var next = methods.FirstOrDefault(m => 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; }
}