diff --git a/PostNamazu/Actions/Command.cs b/PostNamazu/Actions/Command.cs index 4f533a3..64a17fe 100644 --- a/PostNamazu/Actions/Command.cs +++ b/PostNamazu/Actions/Command.cs @@ -25,7 +25,16 @@ private static class Localizations public override void GetOffsets() { base.GetOffsets(); - ProcessChatBoxPtr = SigScanner.ScanText("E8 * * * * FE 86 ? ? ? ? C7 86", nameof(ProcessChatBoxPtr)); + // 函数本体:40 53 56 57 48 83 EC ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 44 24 ?? 48 8B 02 49 8B F0 ... + try // 7.3 + { + ProcessChatBoxPtr = SigScanner.ScanText("FF 52 ? 4C 8B C7 48 8D 54 24 ? 48 8B C8 E8 * * * *", nameof(ProcessChatBoxPtr)); + } + catch // 7.2 + { + ProcessChatBoxPtr = SigScanner.ScanText("E8 * * * * FE 86 ? ? ? ? C7 86", nameof(ProcessChatBoxPtr)); + } + GetUiModulePtr = SigScanner.ScanText("E8 * * * * 80 7B 1D 01", nameof(GetUiModulePtr)); } diff --git a/PostNamazu/Actions/Preset.cs b/PostNamazu/Actions/Preset.cs index 8c31864..8ae4e5b 100644 --- a/PostNamazu/Actions/Preset.cs +++ b/PostNamazu/Actions/Preset.cs @@ -30,8 +30,10 @@ public override void GetOffsets() var GetUiModulePtr = SigScanner.ScanText("E8 * * * * 80 7B 1D 01", "GetUiModulePtr"); UIModulePtr = Memory.CallInjected64(GetUiModulePtr, PostNamazu.FrameworkPtr); - var mapIDOffset = SigScanner.Read(SigScanner.ScanText("44 89 81 ? ? ? ? 0F B7 84 24", "mapIDOffset") + 3); - MapIDPtr = SigScanner.ScanText("48 8D 0D * * * * 0F B6 55 ?? 24", nameof(MapIDPtr)) + mapIDOffset; + // FFXIVClientStructs/FFXIV/Client/Game/GameMain.cs + var mapIDOffset = 0x40B8; // to-do:自动获取 + // var mapIDOffset = SigScanner.Read(SigScanner.ScanText("44 89 81 ? ? ? ? 0F B7 84 24", "mapIDOffset") + 3); + MapIDPtr = SigScanner.ScanText("48 8D 0D * * * * 0F B6 55 ?? 24", "GameMainPtr") + mapIDOffset; } private void GetWayMarkSlotOffset() diff --git a/PostNamazu/Common/Localization/CoreLocalizations.cs b/PostNamazu/Common/Localization/CoreLocalizations.cs index 61619f8..099a18c 100644 --- a/PostNamazu/Common/Localization/CoreLocalizations.cs +++ b/PostNamazu/Common/Localization/CoreLocalizations.cs @@ -207,8 +207,8 @@ public static class CoreLocalizations private static readonly string exportWaymarksFail; // SigScanner相关 - [Localized("Relative addressing sigcode ({0}) must contain exactly 4 consecutive stars (* * * *) and no additional * elsewhere.", - "相对寻址签名码({0})必须恰好包含4个连续的星号(* * * *),且其他地方不能有额外的*。")] + [Localized("Relative addressing sigcode ({0}) must contain at least 4 consecutive stars (* * * * ...) and no additional * elsewhere.", + "相对寻址签名码({0})必须含至少四个连续星号通配符(* * * * ...),且无额外星号。")] private static readonly string relAddressingFormatError; [Localized("Scanned{0} and found {1} memory signatures, unable to determine a unique location.", diff --git a/PostNamazu/Common/SigScanner.cs b/PostNamazu/Common/SigScanner.cs index 0534523..9286515 100644 --- a/PostNamazu/Common/SigScanner.cs +++ b/PostNamazu/Common/SigScanner.cs @@ -378,46 +378,140 @@ public T ScanText(string pattern, Func visitor, string name = null } /// - /// 从内存中扫描指定的内存签名,返回唯一匹配的地址,否则报错。

- /// - /// ? 或 ?? 表示普通通配符,如:
- /// 48 89 5C 24 ?? ...

- /// - /// * 或 ** 表示相对寻址通配符,如果使用,则仅能有连续四个,如:
- /// 48 8D 0D * * * * 4C 8B 85 ...
- /// E8 * * * * 48 83 C4 ? E9 ? ? ? ? ...
- /// 相对寻址计算方式为 * * * * 后的地址 + 这四字节对应的 int 偏移量。

+ /// 使用签名字符串扫描内存,并返回唯一匹配的位置指针,格式详见

+ /// 如果需要手动指定相对偏移或指令长度,请使用重载版本

///
+ /// + /// 签名字符串,格式详见 。 + /// + /// + /// (可选)该签名的名称,用于调试或报错信息中显示。 + /// + /// 匹配到的内存地址指针(如启用相对寻址,则为计算后的地址)。 public IntPtr ScanText(string pattern, string name = null) + => ScanText(new SigPatternInfo(pattern), name); + + /// + /// 使用已构造的签名模式对象扫描内存,并返回唯一匹配的位置指针。

+ /// 通常应使用 简化调用流程。

+ /// 本重载用于处理更复杂的情况,详见 。 + ///
+ /// + /// 签名模式对象,包含解析后的字节序列,以及相对寻址参数(如启用)。 + /// + /// + /// (可选)该签名的名称,用于调试或报错信息中显示。 + /// + /// 匹配到的内存地址指针(如启用相对寻址,则为计算后的地址)。 + public IntPtr ScanText(SigPatternInfo sig, string name = null) { - (var bytes, var relAddressingOffset) = HexToBytes(pattern); - var results = FindPattern(bytes); + var results = FindPattern(sig.Bytes); if (results.Count > 1) { - throw new ArgumentException(L.Get("PostNamazu/resultMultiple", + throw new ArgumentException(L.Get("PostNamazu/resultMultiple", name == null ? "" : $" {name} ", results.Count )); } if (results.Count == 0) { - throw new ArgumentException(L.Get("PostNamazu/resultNone", + throw new ArgumentException(L.Get("PostNamazu/resultNone", name == null ? "" : $" {name} " )); } var patternPtr = results[0]; - if (relAddressingOffset.HasValue) // 指定相对寻址 + if (sig.IsRelAddressing) // 指定相对寻址 { - var starPtr = patternPtr + relAddressingOffset.Value; // 第一个 * 的地址 - patternPtr = starPtr + 4 + ReadInt32(starPtr); + var disp32Ptr = patternPtr + sig.Disp32Offset; // 第一个 * 的地址 + patternPtr = patternPtr + sig.NextCmdOffset + ReadInt32(disp32Ptr); } #if DEBUG - PostNamazu.Plugin.PluginUI.Log($"[Scanner] {name ?? ""} ({pattern}) @ {patternPtr} (jump={relAddressingOffset?.ToString() ?? "null"})"); + PostNamazu.Plugin.PluginUi.Log($"[Scanner] {name ?? ""} @ {patternPtr} ({sig})"); #endif return patternPtr; } + public struct SigPatternInfo + { + public readonly string Pattern; + /// 内存签名的字节序列对应的整数值。通配符 ? 和 * 分别以 -1 和 -2 表示。 + public readonly List Bytes; + /// 是否为相对寻址。 + public bool IsRelAddressing; + /// 相对寻址的 disp32(即 * 的起始处)相对于内存签名起始处的偏移。 + public int Disp32Offset; + /// 相对寻址的下一条指令(即 * 后的指令)相对于内存签名起始处的偏移。 + public int NextCmdOffset; + + /// + /// 构造一个签名模式信息对象,将十六进制字符串解析为字节列表,并判断是否使用相对寻址。

+ /// + /// ? 或 ?? 表示普通通配符,如:
+ /// · 48 89 5C 24 ?? ...

+ /// + /// * 或 ** 表示相对寻址通配符,如果使用,则至少有连续四个,如:
+ /// · 48 8D 0D * * * * 4C 8B 85 ...
+ /// · E8 * * * * 48 83 C4 ? E9 ? ? ? ? ...
+ /// · 48 83 3D * * * * * 74 ? ... (第五个星号为指令末尾的立即数的占位符)

+ /// 相对寻址计算方式为 * 后的地址 + 前四个 * 对应的 int 偏移量。

+ /// + /// 如果需要手动指定偏移量和相对寻址指令长度,请使用 构造函数。 + ///
+ public SigPatternInfo(string hexPattern) + { + Pattern = hexPattern; + Bytes = hexPattern.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(s => + { + return s switch + { + "*" or "**" => -2, + "?" or "??" => -1, + _ => byte.Parse(s, NumberStyles.AllowHexSpecifier), + }; + }).ToList(); + + // relative addressing + var firstStar = Bytes.IndexOf(-2); + if (firstStar >= 0) + { + var lastStar = Bytes.LastIndexOf(-2); + var starLength = lastStar - firstStar + 1; + if (starLength < 4 || Bytes.GetRange(firstStar, starLength).Any(b => b != -2)) + { + throw new FormatException(L.Get("PostNamazu/relAddressingFormatError", hexPattern)); + } + IsRelAddressing = true; + Disp32Offset = firstStar; + NextCmdOffset = lastStar + 1; + } + else + { + IsRelAddressing = false; + Disp32Offset = 0; + NextCmdOffset = 0; + } + } + + /// + /// 构造一个签名模式信息对象,并强制指定相对寻址的偏移与指令结束位置。

+ /// 用于处理复杂、非标准格式、或距离相对寻址指令较远的内存签名。

+ /// 此构造函数不会再自动判断是否使用相对寻址,而是直接按指定值处理。

+ /// 参数 若未指定,则默认指令以相对寻址的地址结尾。

+ /// 通常推荐使用 由星号自动识别相对寻址。 + ///
+ public SigPatternInfo(string hexPattern, int disp32Offset, int? nextCmdOffset = null) : this(hexPattern) + { + IsRelAddressing = true; + Disp32Offset = disp32Offset; + NextCmdOffset = nextCmdOffset ?? disp32Offset + 4; + } + + public override string ToString() => IsRelAddressing + ? $"{Pattern}, Disp32Offset={Disp32Offset}, NextCmdOffset={NextCmdOffset}" + : Pattern; + } + public List FindPattern(List pattern) { var results = Find(pattern); @@ -451,33 +545,6 @@ bool ByteMatch(byte[] bytes, int start, List pattern) { return true; } - (List, int?) HexToBytes(string hex) - { - var bytes = hex.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(s => - { - return s switch - { - "*" or "**" => -2, - "?" or "??" => -1, - _ => byte.Parse(s, NumberStyles.AllowHexSpecifier), - }; - }).ToList(); - - int? jump = null; // relative addressing - var idx = bytes.IndexOf(-2); - if (idx >= 0) - { - jump = idx; - if (jump > bytes.Count - 4 || - bytes.Skip(jump.Value).Take(4).Any(b => b != -2) || // these 4 digits must be * - bytes.Skip(jump.Value + 4).Any(b => b == -2)) // no more * after these 4 digits - { - throw new FormatException(L.Get("PostNamazu/relAddressingFormatError", hex)); - } - } - return (bytes, jump); - } - /// /// Scan for a .data address using a .text function. /// This is intended to be used with IDA sigs. @@ -486,6 +553,7 @@ bool ByteMatch(byte[] bytes, int start, List pattern) { /// 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. + [Obsolete("Use relative addressing sigcodes.")] public IntPtr GetStaticAddressFromSig(string signature, int offset = 0, string name = null) { var instrAddr = ScanText(signature, name); instrAddr = IntPtr.Add(instrAddr, offset); diff --git a/PostNamazu/PostNamazu.cs b/PostNamazu/PostNamazu.cs index daf8c33..b4ba120 100644 --- a/PostNamazu/PostNamazu.cs +++ b/PostNamazu/PostNamazu.cs @@ -67,7 +67,7 @@ internal void SetState(StateEnum value) { _state = value; #if DEBUG - PluginUI?.Log($"插件状态变更:{value}"); + PluginUi?.Log($"插件状态变更:{value}"); #endif } @@ -129,7 +129,7 @@ public void InitializeActions() { foreach (var t in Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(typeof(NamazuModule)) && !t.IsAbstract)) { #if DEBUG - PluginUI.Log($"Initalizing Module: {t.Name}"); + PluginUi.Log($"Initalizing Module: {t.Name}"); #endif var module = (NamazuModule)Activator.CreateInstance(t); Modules.Add(module); @@ -141,7 +141,7 @@ public void InitializeActions() { SetAction(command.Command, handlerDelegate); #if DEBUG - PluginUI.Log($"{action.Name}@{command.Command}"); + PluginUi.Log($"{action.Name}@{command.Command}"); #endif } @@ -267,19 +267,17 @@ internal bool GetOffsets() { PluginUi.Log(L.Get("PostNamazu/sigScanning")); SigScanner = new SigScanner(FFXIV); - try { - _entrancePtr = SigScanner.ScanText("4C 8B DC 56 41 57 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 84 24 ? ? ? ? 48 83 B9 ? ? ? ? ? 4C 8B FA"); //7.0 - _frameworkPtrPtr = IntPtr.Zero; - _isCN = null; - GetRegion(); - return true; + + try + { + _entrancePtr = SigScanner.ScanText("4C 8B DC 56 41 57 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 84 24 ? ? ? ? 48 83 B9 ? ? ? ? ? 4C 8B FA"); // 7.0-7.2 } - catch (ArgumentException) { - //PluginUI.Log(L.Get("PostNamazu/xivProcInjectFail")); + catch + { + _entrancePtr = IntPtr.Zero; // 7.3 临时修复,使用默认方式注入 } try { - _entrancePtr = SigScanner.ScanText("E9 * * * * 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 83 B9"); _frameworkPtrPtr = IntPtr.Zero; _isCN = null; GetRegion();