From 05b03c3d5f931a9a6959fde2ca7685ab9f5bb7d5 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 13 Jan 2023 16:09:32 +0100 Subject: [PATCH 1/2] Rework static address scanning. --- Dalamud/Game/SigScanner.cs | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Dalamud/Game/SigScanner.cs b/Dalamud/Game/SigScanner.cs index 197131c14..cc0a7b0a7 100644 --- a/Dalamud/Game/SigScanner.cs +++ b/Dalamud/Game/SigScanner.cs @@ -176,23 +176,30 @@ public class SigScanner : IDisposable, IServiceType /// /// 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) + /// An IntPtr to the static memory location or IntPtr.Zero if no valid offset could be found. + 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; + var baseAddress = (long)this.Module.BaseAddress; + var data = this.DataSectionOffset + baseAddress; + var dataEnd = data + this.DataSectionSize; + var rData = this.RDataSectionOffset + baseAddress; + var rDataEnd = rData + this.RDataSectionSize; - do + for (var end = instructionAddress + signature.Length + 4; instructionAddress < end; ++instructionAddress) { - instrAddr = IntPtr.Add(instrAddr, 1); - num = Marshal.ReadInt32(instrAddr) + (long)instrAddr + 4 - bAddr; + var byte1 = instructionAddress[0]; + var byte2 = instructionAddress[1]; + if (byte1 is >= 0x40 and <= 0x4F && byte2 is 0x89 or 0x8B or 0x8D) + { + var ret = *(int*)(instructionAddress + 3) + (long)instructionAddress + 7; + if ((ret >= data && ret <= dataEnd) || (ret >= rData && ret <= rDataEnd)) + return (IntPtr)ret; + } } - 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); + return IntPtr.Zero; } /// From 08c95711d34d0951b8f08b31ea790218869ec387 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 13 Jan 2023 18:05:42 +0100 Subject: [PATCH 2/2] Use Iced for static sig scanning. --- Dalamud/Game/SigScanner.cs | 52 ++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/Dalamud/Game/SigScanner.cs b/Dalamud/Game/SigScanner.cs index cc0a7b0a7..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,33 +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 or IntPtr.Zero if no valid offset could be found. + /// An IntPtr to the static memory location. public unsafe IntPtr GetStaticAddressFromSig(string signature, int offset = 0) { var instructionAddress = (byte*)this.ScanText(signature); instructionAddress += offset; - var baseAddress = (long)this.Module.BaseAddress; - var data = this.DataSectionOffset + baseAddress; - var dataEnd = data + this.DataSectionSize; - var rData = this.RDataSectionOffset + baseAddress; - var rDataEnd = rData + this.RDataSectionSize; - for (var end = instructionAddress + signature.Length + 4; instructionAddress < end; ++instructionAddress) + try { - var byte1 = instructionAddress[0]; - var byte2 = instructionAddress[1]; - if (byte1 is >= 0x40 and <= 0x4F && byte2 is 0x89 or 0x8B or 0x8D) + var reader = new UnsafeCodeReader(instructionAddress, signature.Length + 8); + var decoder = Decoder.Create(64, reader, (ulong)instructionAddress, DecoderOptions.AMD); + while (reader.CanReadByte) { - var ret = *(int*)(instructionAddress + 3) + (long)instructionAddress + 7; - if ((ret >= data && ret <= dataEnd) || (ret >= rData && ret <= rDataEnd)) - return (IntPtr)ret; + 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 + } - return IntPtr.Zero; + throw new KeyNotFoundException($"Can't find any referenced address in the given signature {signature}."); } /// @@ -391,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. ///