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.
///