Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion PostNamazu/Actions/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down
6 changes: 4 additions & 2 deletions PostNamazu/Actions/Preset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ public override void GetOffsets()
var GetUiModulePtr = SigScanner.ScanText("E8 * * * * 80 7B 1D 01", "GetUiModulePtr");
UIModulePtr = Memory.CallInjected64<IntPtr>(GetUiModulePtr, PostNamazu.FrameworkPtr);

var mapIDOffset = SigScanner.Read<UInt16>(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<UInt16>(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()
Expand Down
4 changes: 2 additions & 2 deletions PostNamazu/Common/Localization/CoreLocalizations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
156 changes: 112 additions & 44 deletions PostNamazu/Common/SigScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,46 +378,140 @@ public T ScanText<T>(string pattern, Func<IntPtr, T> visitor, string name = null
}

/// <summary>
/// 从内存中扫描指定的内存签名,返回唯一匹配的地址,否则报错。<br /><br />
///
/// ? 或 ?? 表示普通通配符,如:<br />
/// <c> 48 89 5C 24 ?? ... </c><br /><br />
///
/// * 或 ** 表示相对寻址通配符,如果使用,则仅能有连续四个,如:<br />
/// <c> 48 8D 0D * * * * 4C 8B 85 ... </c> <br />
/// <c> E8 * * * * 48 83 C4 ? E9 ? ? ? ? ... </c> <br />
/// 相对寻址计算方式为 * * * * 后的地址 + 这四字节对应的 int 偏移量。<br /><br />
/// 使用签名字符串扫描内存,并返回唯一匹配的位置指针,格式详见 <see cref="SigPatternInfo(string)"/> 。<br/><br/>
/// 如果需要手动指定相对偏移或指令长度,请使用重载版本 <see cref="ScanText(SigPatternInfo, string)"/>。<br/><br/>
/// </summary>
/// <param name="pattern">
/// 签名字符串,格式详见 <see cref="SigPatternInfo"/>。
/// </param>
/// <param name="name">
/// (可选)该签名的名称,用于调试或报错信息中显示。
/// </param>
/// <returns>匹配到的内存地址指针(如启用相对寻址,则为计算后的地址)。</returns>
public IntPtr ScanText(string pattern, string name = null)
=> ScanText(new SigPatternInfo(pattern), name);

/// <summary>
/// 使用已构造的签名模式对象扫描内存,并返回唯一匹配的位置指针。<br/><br/>
/// 通常应使用 <see cref="ScanText(string, string)"/> 简化调用流程。<br/><br/>
/// 本重载用于处理更复杂的情况,详见 <see cref="SigPatternInfo(string, int, int?)"/>。
/// </summary>
/// <param name="sig">
/// 签名模式对象,包含解析后的字节序列,以及相对寻址参数(如启用)。
/// </param>
/// <param name="name">
/// (可选)该签名的名称,用于调试或报错信息中显示。
/// </param>
/// <returns>匹配到的内存地址指针(如启用相对寻址,则为计算后的地址)。</returns>
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;
/// <summary> 内存签名的字节序列对应的整数值。通配符 ? 和 * 分别以 -1 和 -2 表示。 </summary>
public readonly List<int> Bytes;
/// <summary> 是否为相对寻址。 </summary>
public bool IsRelAddressing;
/// <summary> 相对寻址的 disp32(即 * 的起始处)相对于内存签名起始处的偏移。</summary>
public int Disp32Offset;
/// <summary> 相对寻址的下一条指令(即 * 后的指令)相对于内存签名起始处的偏移。</summary>
public int NextCmdOffset;

/// <summary>
/// 构造一个签名模式信息对象,将十六进制字符串解析为字节列表,并判断是否使用相对寻址。<br /><br />
///
/// ? 或 ?? 表示普通通配符,如:<br />
/// <c> · 48 89 5C 24 ?? ... </c> <br /><br />
///
/// * 或 ** 表示相对寻址通配符,如果使用,则至少有连续四个,如:<br />
/// <c> · 48 8D 0D * * * * 4C 8B 85 ... </c> <br />
/// <c> · E8 * * * * 48 83 C4 ? E9 ? ? ? ? ... </c> <br />
/// <c> · 48 83 3D * * * * * 74 ? ... </c>(第五个星号为指令末尾的立即数的占位符)<br /><br />
/// 相对寻址计算方式为 * 后的地址 + 前四个 * 对应的 int 偏移量。<br /><br />
///
/// 如果需要手动指定偏移量和相对寻址指令长度,请使用 <see cref="SigPatternInfo(string, int, int?)"/> 构造函数。
/// </summary>
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;
}
}

/// <summary>
/// 构造一个签名模式信息对象,并强制指定相对寻址的偏移与指令结束位置。<br /><br />
/// 用于处理复杂、非标准格式、或距离相对寻址指令较远的内存签名。<br /><br />
/// 此构造函数不会再自动判断是否使用相对寻址,而是直接按指定值处理。<br /><br />
/// 参数 <paramref name="nextCmdOffset"/> 若未指定,则默认指令以相对寻址的地址结尾。<br /><br />
/// 通常推荐使用 <see cref="SigPatternInfo(string)"/> 由星号自动识别相对寻址。
/// </summary>
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<IntPtr> FindPattern(List<int> pattern)
{
var results = Find(pattern);
Expand Down Expand Up @@ -451,33 +545,6 @@ bool ByteMatch(byte[] bytes, int start, List<int> pattern) {
return true;
}

(List<int>, 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);
}

/// <summary>
/// Scan for a .data address using a .text function.
/// This is intended to be used with IDA sigs.
Expand All @@ -486,6 +553,7 @@ bool ByteMatch(byte[] bytes, int start, List<int> pattern) {
/// <param name="signature">The signature of the function using the data.</param>
/// <param name="offset">The offset from function start of the instruction using the data.</param>
/// <returns>An IntPtr to the static memory location.</returns>
[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);
Expand Down
22 changes: 10 additions & 12 deletions PostNamazu/PostNamazu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ internal void SetState(StateEnum value)
{
_state = value;
#if DEBUG
PluginUI?.Log($"插件状态变更:{value}");
PluginUi?.Log($"插件状态变更:{value}");
#endif
}

Expand Down Expand Up @@ -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);
Expand All @@ -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
}

Expand Down Expand Up @@ -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();
Expand Down
Loading