diff --git a/Dalamud/Game/SigScanner.cs b/Dalamud/Game/SigScanner.cs index 197131c14..4d3a78830 100644 --- a/Dalamud/Game/SigScanner.cs +++ b/Dalamud/Game/SigScanner.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using Dalamud.IoC; using Dalamud.IoC.Internal; +using Iced.Intel; using Newtonsoft.Json; using Serilog; @@ -173,26 +174,36 @@ public class SigScanner : IDisposable, IServiceType /// Scan for a .data address using a .text function. /// This is intended to be used with IDA sigs. /// Place your cursor on the line calling a static address, and create and IDA sig. + /// The signature and offset should not break through instruction boundaries. /// /// The signature of the function using the data. /// The offset from function start of the instruction using the data. /// An IntPtr to the static memory location. - public IntPtr GetStaticAddressFromSig(string signature, int offset = 0) + public unsafe IntPtr GetStaticAddressFromSig(string signature, int offset = 0) { - var instrAddr = this.ScanText(signature); - instrAddr = IntPtr.Add(instrAddr, offset); - var bAddr = (long)this.Module.BaseAddress; - long num; + var instructionAddress = (byte*)this.ScanText(signature); + instructionAddress += offset; - do + try { - instrAddr = IntPtr.Add(instrAddr, 1); - num = Marshal.ReadInt32(instrAddr) + (long)instrAddr + 4 - bAddr; + var reader = new UnsafeCodeReader(instructionAddress, signature.Length + 8); + var decoder = Decoder.Create(64, reader, (ulong)instructionAddress, DecoderOptions.AMD); + while (reader.CanReadByte) + { + var instruction = decoder.Decode(); + if (instruction.IsInvalid) continue; + if (instruction.Op0Kind is OpKind.Memory || instruction.Op1Kind is OpKind.Memory) + { + return (IntPtr)instruction.MemoryDisplacement64; + } + } + } + catch + { + // ignored } - while (!(num >= this.DataSectionOffset && num <= this.DataSectionOffset + this.DataSectionSize) - && !(num >= this.RDataSectionOffset && num <= this.RDataSectionOffset + this.RDataSectionSize)); - return IntPtr.Add(instrAddr, Marshal.ReadInt32(instrAddr) + 4); + throw new KeyNotFoundException($"Can't find any referenced address in the given signature {signature}."); } /// @@ -384,6 +395,26 @@ public class SigScanner : IDisposable, IServiceType } } + private unsafe class UnsafeCodeReader : CodeReader + { + private readonly int length; + private readonly byte* address; + private int pos; + public UnsafeCodeReader(byte* address, int length) + { + this.length = length; + this.address = address; + } + + public bool CanReadByte => this.pos < this.length; + + public override int ReadByte() + { + if (this.pos >= this.length) return -1; + return *(this.address + this.pos++); + } + } + /// /// Helper for ScanText to get the correct address for IDA sigs that mark the first JMP or CALL location. ///