diff --git a/Dalamud/Game/SigScanner.cs b/Dalamud/Game/SigScanner.cs index b19024098..b5fe0b5b3 100644 --- a/Dalamud/Game/SigScanner.cs +++ b/Dalamud/Game/SigScanner.cs @@ -15,12 +15,17 @@ using Serilog; namespace Dalamud.Game; +// TODO(v9): There are static functions here that we can't keep due to interfaces + /// /// A SigScanner facilitates searching for memory signatures in a given ProcessModule. /// [PluginInterface] [InterfaceVersion("1.0")] -public class SigScanner : IDisposable, IServiceType +#pragma warning disable SA1015 +[ResolveVia] +#pragma warning restore SA1015 +public class SigScanner : IDisposable, IServiceType, ISigScanner { private readonly FileInfo? cacheFile; @@ -65,69 +70,43 @@ public class SigScanner : IDisposable, IServiceType this.Load(); } - /// - /// Gets a value indicating whether or not the search on this module is performed on a copy. - /// + /// public bool IsCopy { get; } - /// - /// Gets a value indicating whether or not the ProcessModule is 32-bit. - /// + /// public bool Is32BitProcess { get; } - /// - /// Gets the base address of the search area. When copied, this will be the address of the copy. - /// + /// public IntPtr SearchBase => this.IsCopy ? this.moduleCopyPtr : this.Module.BaseAddress; - /// - /// Gets the base address of the .text section search area. - /// + /// public IntPtr TextSectionBase => new(this.SearchBase.ToInt64() + this.TextSectionOffset); - /// - /// Gets the offset of the .text section from the base of the module. - /// + /// public long TextSectionOffset { get; private set; } - /// - /// Gets the size of the text section. - /// + /// public int TextSectionSize { get; private set; } - /// - /// Gets the base address of the .data section search area. - /// + /// public IntPtr DataSectionBase => new(this.SearchBase.ToInt64() + this.DataSectionOffset); - /// - /// Gets the offset of the .data section from the base of the module. - /// + /// public long DataSectionOffset { get; private set; } - /// - /// Gets the size of the .data section. - /// + /// public int DataSectionSize { get; private set; } - /// - /// Gets the base address of the .rdata section search area. - /// + /// public IntPtr RDataSectionBase => new(this.SearchBase.ToInt64() + this.RDataSectionOffset); - /// - /// Gets the offset of the .rdata section from the base of the module. - /// + /// public long RDataSectionOffset { get; private set; } - /// - /// Gets the size of the .rdata section. - /// + /// public int RDataSectionSize { get; private set; } - /// - /// Gets the ProcessModule on which the search is performed. - /// + /// public ProcessModule Module { get; } private IntPtr TextSectionTop => this.TextSectionBase + this.TextSectionSize; @@ -229,11 +208,7 @@ public class SigScanner : IDisposable, IServiceType } } - /// - /// Scan for a byte signature in the .data section. - /// - /// The signature. - /// The real offset of the found signature. + /// public IntPtr ScanData(string signature) { var scanRet = Scan(this.DataSectionBase, this.DataSectionSize, signature); @@ -244,12 +219,7 @@ public class SigScanner : IDisposable, IServiceType return scanRet; } - /// - /// Try scanning for a byte signature in the .data section. - /// - /// The signature. - /// The real offset of the signature, if found. - /// true if the signature was found. + /// public bool TryScanData(string signature, out IntPtr result) { try @@ -264,11 +234,7 @@ public class SigScanner : IDisposable, IServiceType } } - /// - /// Scan for a byte signature in the whole module search area. - /// - /// The signature. - /// The real offset of the found signature. + /// public IntPtr ScanModule(string signature) { var scanRet = Scan(this.SearchBase, this.Module.ModuleMemorySize, signature); @@ -279,12 +245,7 @@ public class SigScanner : IDisposable, IServiceType return scanRet; } - /// - /// Try scanning for a byte signature in the whole module search area. - /// - /// The signature. - /// The real offset of the signature, if found. - /// true if the signature was found. + /// public bool TryScanModule(string signature, out IntPtr result) { try @@ -299,23 +260,14 @@ public class SigScanner : IDisposable, IServiceType } } - /// - /// Resolve a RVA address. - /// - /// The address of the next instruction. - /// The relative offset. - /// The calculated offset. + /// public IntPtr ResolveRelativeAddress(IntPtr nextInstAddr, int relOffset) { if (this.Is32BitProcess) throw new NotSupportedException("32 bit is not supported."); return nextInstAddr + relOffset; } - /// - /// Scan for a byte signature in the .text section. - /// - /// The signature. - /// The real offset of the found signature. + /// public IntPtr ScanText(string signature) { if (this.textCache != null) @@ -347,12 +299,7 @@ public class SigScanner : IDisposable, IServiceType return scanRet; } - /// - /// Try scanning for a byte signature in the .text section. - /// - /// The signature. - /// The real offset of the signature, if found. - /// true if the signature was found. + /// public bool TryScanText(string signature, out IntPtr result) { try diff --git a/Dalamud/Plugin/Services/ISigScanner.cs b/Dalamud/Plugin/Services/ISigScanner.cs new file mode 100644 index 000000000..c3bb7d6c1 --- /dev/null +++ b/Dalamud/Plugin/Services/ISigScanner.cs @@ -0,0 +1,150 @@ +using System; +using System.Diagnostics; + +namespace Dalamud.Game; + +/// +/// A SigScanner facilitates searching for memory signatures in a given ProcessModule. +/// +public interface ISigScanner +{ + /// + /// Gets a value indicating whether or not the search on this module is performed on a copy. + /// + public bool IsCopy { get; } + + /// + /// Gets a value indicating whether or not the ProcessModule is 32-bit. + /// + public bool Is32BitProcess { get; } + + /// + /// Gets the base address of the search area. When copied, this will be the address of the copy. + /// + public IntPtr SearchBase { get; } + + /// + /// Gets the base address of the .text section search area. + /// + public IntPtr TextSectionBase { get; } + + /// + /// Gets the offset of the .text section from the base of the module. + /// + public long TextSectionOffset { get; } + + /// + /// Gets the size of the text section. + /// + public int TextSectionSize { get; } + + /// + /// Gets the base address of the .data section search area. + /// + public IntPtr DataSectionBase { get; } + + /// + /// Gets the offset of the .data section from the base of the module. + /// + public long DataSectionOffset { get; } + + /// + /// Gets the size of the .data section. + /// + public int DataSectionSize { get; } + + /// + /// Gets the base address of the .rdata section search area. + /// + public IntPtr RDataSectionBase { get; } + + /// + /// Gets the offset of the .rdata section from the base of the module. + /// + public long RDataSectionOffset { get; } + + /// + /// Gets the size of the .rdata section. + /// + public int RDataSectionSize { get; } + + /// + /// Gets the ProcessModule on which the search is performed. + /// + public ProcessModule Module { get; } + + /// + /// 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 nint GetStaticAddressFromSig(string signature, int offset = 0); + + /// + /// Try scanning 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 of the function using the data. + /// An IntPtr to the static memory location, if found. + /// The offset from function start of the instruction using the data. + /// true if the signature was found. + public bool TryGetStaticAddressFromSig(string signature, out nint result, int offset = 0); + + /// + /// Scan for a byte signature in the .data section. + /// + /// The signature. + /// The real offset of the found signature. + public nint ScanData(string signature); + + /// + /// Try scanning for a byte signature in the .data section. + /// + /// The signature. + /// The real offset of the signature, if found. + /// true if the signature was found. + public bool TryScanData(string signature, out nint result); + + /// + /// Scan for a byte signature in the whole module search area. + /// + /// The signature. + /// The real offset of the found signature. + public nint ScanModule(string signature); + + /// + /// Try scanning for a byte signature in the whole module search area. + /// + /// The signature. + /// The real offset of the signature, if found. + /// true if the signature was found. + public bool TryScanModule(string signature, out nint result); + + /// + /// Resolve a RVA address. + /// + /// The address of the next instruction. + /// The relative offset. + /// The calculated offset. + public nint ResolveRelativeAddress(nint nextInstAddr, int relOffset); + + /// + /// Scan for a byte signature in the .text section. + /// + /// The signature. + /// The real offset of the found signature. + public nint ScanText(string signature); + + /// + /// Try scanning for a byte signature in the .text section. + /// + /// The signature. + /// The real offset of the signature, if found. + /// true if the signature was found. + public bool TryScanText(string signature, out nint result); +}