Files
IC.Rebuild/Core/AdaptationManifest.cs
T

235 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace ICRebuild.Core;
public enum AdaptationIssue
{
None,
MissingImplementation,
VersionMismatch,
OffsetMismatch,
SignatureMissing,
MultipleMatches,
RuntimeFault
}
public sealed record SignatureRequirement(string Name, string Signature, string AuditedRva, bool RequireUnique = true);
public sealed record ModuleAdaptationSpec(
int FeatureId,
string FeatureName,
bool VersionLocked,
bool RequiresSdkOffsets,
string Evidence,
SignatureRequirement[] Signatures);
public sealed record ModuleAdaptationEntry(
int FeatureId,
string FeatureName,
bool VersionLocked,
AdaptationIssue Issue,
Adaptation AdaptationState,
string Summary,
string Evidence,
string[] FailedSignatures);
public sealed record AdaptationReport(
string ClientVersion,
string AuditedVersion,
bool VersionMatches,
bool ActiveSendReady,
string ActiveSendSummary,
ModuleAdaptationEntry[] Entries)
{
public int ReadyCount => Entries.Count(e => e.Issue == AdaptationIssue.None);
public int BlockedCount => Entries.Count(e => e.Issue != AdaptationIssue.None);
}
public static class AdaptationManifest
{
public const string AuditedVersion = PacketParser.AuditedClientVersion;
public const string BaselineVersion = PacketParser.BaselineClientVersion;
public static bool IsAuditedVersion(string? version) => PacketParser.IsAuditedVersion(version);
public const string ActiveSendReceiverSignature =
"48 83 EC 38 48 8B 89 70 0A 00 00 48 85 C9 74 0F C6 44 24 20 00 E8 ?? ?? ?? ?? 48 83 C4 38 C3 32 C0 48 83 C4 38 C3 CC CC CC CC CC CC CC CC CC CC 48 83 EC 38 48 8B 89 70 0A 00 00";
public const string ActiveSendZoneSignature =
"48 83 EC 28 48 8B 89 98 00 00 00 48 85 C9 74 1F 44 89 44 24 30 4C 8D 44 24 30";
public static readonly SignatureRequirement[] ActiveSendSignatures =
[
new("ReceiverSendPacket", ActiveSendReceiverSignature, "0x1CFD140"),
new("ZoneClientSendPacket", ActiveSendZoneSignature, "0x1D03040")
];
public static readonly ModuleAdaptationSpec[] Specs =
[
new(1, "移速调整", false, false, "RVA 0x8D6E40 + 40 项减速状态保护",
[new("SpeedHook", "40 57 48 83 EC ?? 48 8B F9 48 8B 49 ?? 48 8B 01 FF 90 ?? ?? ?? ?? 48 85 C0 75", "0x8D6E40")]),
new(2, "最大加速度", true, false, "RVA 0x182BB20,偏移 +0x20/+0x3C/+0x44 与 owner +0x3E0 已核对",
[new("AccelerationHook", "40 ?? 48 ?? ?? ?? 80 79 ?? ?? 48 ?? ?? 0f 84 ?? ?? ?? ?? 48 89 7c 24 ?? 48 ?? ?? ??", "0x182BB20")]),
new(3, "强制移动", false, false, "RVA 0xE16130,Permission ID 14/96/97 已核对",
[new("MovePermissionHook", "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 54 41 56 41 57 48 83 EC ?? 33 DB 41 8B E9 48 39 1D", "0xE16130")]),
new(4, "击退距离调整", false, false, "RVA 0x90BC90,按本地角色地址过滤",
[new("AntiKnockHook", "48 ?? ?? 57 48 ?? ?? ?? ?? ?? ?? 0f 29 70 ?? 0f ?? ??", "0x90BC90")]),
new(5, "掉落无伤", false, false, "RVA 0x62AF60,移动标志位掩码处理",
[new("OnSendFlagHook", "48 89 5c 24 ?? 57 48 ?? ?? ?? 8b ?? 48 ?? ?? 33 ?? e8 ?? ?? ?? ?? 84 ??", "0x62AF60")]),
new(6, "无掉落", false, false, "调用点 RVA 0x182F9E4",
[new("FallCheckHook", "e8 ?? ?? ?? ?? 8b ?? 85 ?? 0f 88 ?? ?? ?? ?? 48 ?? ?? ?? f3 ?? ?? ?? ?? ?? ?? ??", "0x182F9E4")]),
new(7, "魅惑与恐惧移动处理", true, false, "调用点 RVA 0x194AEC3,第 5 参数核实为 float",
[new("ForcedWalkHook", "e8 ?? ?? ?? ?? b0 ?? c7 43 ?? ?? ?? ?? ?? eb ??", "0x194AEC3")]),
new(8, "状态屏蔽", true, true, "SetStatus RVA 0x8A6BF0 + 本地角色 RVA 0xB37D7A + 偏移 0x23B0/0x78",
[
new("StatusSetter", "40 53 56 41 56 48 83 EC 70 45 32 F6 0F 29 74 24 50 41 0F B7 F0 0F 28 F3 48 8B D9 83 FA 3C", "0x8A6BF0"),
new("LocalPlayerPtr", "48 8B 1D ?? ?? ?? ?? 48 8B FA 48 85 DB 74 28 48 8B 03 48 8B CB FF 90 78 02 00 00", "0xB37D7A")
]),
new(9, "飞天遁地", false, false, "普通移动 RVA 0x62B680 + 战斗移动 RVA 0x62B730",
[
new("OnSendNormalMove", "48 89 5C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B F9 41 8B D8", "0x62B680"),
new("OnSendCombatMove", "48 89 5C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B F9 41 8B F0", "0x62B730")
]),
new(10, "深层迷宫专用模式", false, false, "依赖模块 9 与 EventFramework 深层迷宫实例", []),
new(11, "迷宫状态显示", false, false, "EventFramework.GetInstanceContentDeepDungeon", []),
new(13, "技能距离调整", false, false, "ActionManager.GetActionRange SDK 入口", []),
new(14, "目标圈半径调整", true, false, "ActorRadius RVA 0x175728F + 原生圈 RVA 0x7B5430 + ActionManager 距离入口",
[
new("ActorRadius", "e8 ?? ?? ?? ?? f3 ?? ?? ?? 48 ?? ?? ?? ?? f3 ?? ?? ?? ?? f3 ?? ?? ?? f3 ?? ?? ?? ?? f3 0f 11 74 24 ?? ", "0x175728F"),
new("NativeTargetRingUpdate", "4C 8B DC 55 57 41 57 49 8D AB ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 85 ?? ?? ?? ?? 80 B9 ?? ?? ?? ?? ?? 4C 8B FA 48 8B F9 0F 85 ?? ?? ?? ?? 48 8B 41 30", "0x7B5430")
]),
new(15, "后摇期间可移动", false, false, "RVA 0x8D6F30(首匹配包装入口)",
[new("NoBackswing", "48 ?? ?? ?? 48 ?? ?? ?? 45 ?? ?? 33 ?? e8 ?? ?? ?? ?? 84 ?? 74 ?? ", "0x8D6F30", RequireUnique: false)]),
new(16, "突进无位移", true, false, "公共位移初始化 RVA 0x1822510,owner +0x3E0 与 ushort Timeline",
[new("ActionMovementStart", "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 48 8B D9 0F B6 FA 48 81 C1 ?? ?? ?? ?? 4D 8B F1 4D 8B F8 E8 ?? ?? ?? ?? 48 8B B3 ?? ?? ?? ??", "0x1822510")]),
new(17, "复唱缩减秒数", false, false, "GetAdjustedRecastTime + 同步 RVA 0x8EF260(GCD 组 57)",
[new("SyncRecast", "40 ?? 48 ?? ?? ?? 0f 29 74 24 ?? 41 ?? ?? 0f ?? ?? e8 ?? ?? ?? ??", "0x8EF260")]),
new(18, "快速结印", false, false, "依赖模块 17,结印 ActionId 2259/2261/2263/18805..18807", []),
new(19, "咏唱缩减秒数", false, false, "GetAdjustedCastTime + 静态地址 RVA 0x104F17 + 更新 RVA 0x8E00A0",
[
new("CastStaticAddress", "F3 44 0F 2C C0 BA ?? ?? ?? ?? 48 8B CB E8 ?? ?? ?? ?? F3 44 0F 10 1D", "0x104F17"),
new("CastUpdate", "48 89 5C 24 ?? 57 48 83 EC ?? 48 8B F9 0F 29 74 24 ?? 0F B6 49", "0x8E00A0")
]),
new(20, "PVP 动画锁上限", false, false, "ActionManager.AnimationLock 帧更新", []),
new(27, "坐标移动", false, false, "GameObject.SetPosition", []),
new(28, "面向调整", false, false, "GameObject.SetRotation", []),
new(29, "目标缩放", false, false, "RVA 0x899720,含原缩放恢复表",
[new("SetScale", "F3 0F 11 89 ?? ?? ?? ?? E9 ?? ?? ?? ?? CC CC CC CC CC CC CC CC CC CC CC CC", "0x899720")]),
new(36, "网络记录", true, false, "ZoneUp RVA 0x1D718C0 + ZoneDown RVA 0x1D71440 + 共享观察管线",
[
new("ZoneUp", "48 89 5C 24 ?? 48 89 74 24 ?? 4C 89 64 24 ?? 55 41 56 41 57 48 8B EC 48 83 EC 70", "0x1D718C0"),
new("ZoneDown", "48 89 5C 24 18 57 48 83 EC 20 48 83 B9 88 00 00 00 00 48 8B FA 48 8B D9", "0x1D71440")
]),
new(37, "包解析与 Opcode 管理", false, false, "离线/实时解析与请求响应关联,不挂接原生 Hook", [])
];
public static AdaptationReport Evaluate(
ModuleManager modules,
string clientVersion,
Func<string, int> countMatches,
bool sdkOffsetsValid = true)
{
ArgumentNullException.ThrowIfNull(modules);
ArgumentNullException.ThrowIfNull(countMatches);
var versionMatches = IsAuditedVersion(clientVersion);
var entries = new List<ModuleAdaptationEntry>(Specs.Length);
foreach (var spec in Specs)
{
var status = modules.Status[spec.FeatureId];
if (!status.HasImplementation)
{
entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked,
AdaptationIssue.MissingImplementation, status.Adaptation, "缺实现,保持禁用", spec.Evidence, []));
continue;
}
if (spec.VersionLocked && !versionMatches)
{
entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked,
AdaptationIssue.VersionMismatch, Adaptation.Unadapted,
$"版本不符:仅核对 {AuditedVersion}(兼容 {BaselineVersion}),当前为 {clientVersion}", spec.Evidence, []));
continue;
}
if (spec.RequiresSdkOffsets && !sdkOffsetsValid)
{
entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked,
AdaptationIssue.OffsetMismatch, Adaptation.Unadapted,
"SDK 角色/状态偏移与已核对入口不一致", spec.Evidence, []));
continue;
}
List<string> missing = [];
List<string> multiple = [];
foreach (var sig in spec.Signatures)
{
var matches = countMatches(sig.Signature);
if (matches <= 0) missing.Add($"{sig.Name} ({sig.AuditedRva})");
else if (sig.RequireUnique && matches > 1) multiple.Add($"{sig.Name} ({matches} 处匹配)");
}
if (missing.Count > 0)
{
entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked,
AdaptationIssue.SignatureMissing, Adaptation.Unadapted,
$"签名未匹配:{string.Join(", ", missing)}", spec.Evidence, [.. missing]));
continue;
}
if (multiple.Count > 0)
{
entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked,
AdaptationIssue.MultipleMatches, Adaptation.Unadapted,
$"签名多重匹配,拒绝盲挂:{string.Join(", ", multiple)}", spec.Evidence, [.. multiple]));
continue;
}
if (status.State == ModuleState.Failed)
{
entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked,
AdaptationIssue.RuntimeFault, status.Adaptation,
$"运行异常:{status.Detail}", spec.Evidence, []));
continue;
}
var adapt = versionMatches && ValidationCatalog.UserConfirmed.Contains(spec.FeatureId)
? Adaptation.Verified
: Adaptation.Testable;
var label = adapt == Adaptation.Verified ? "已核对且用户实测有效" : "签名与版本核对通过,待实测";
entries.Add(new(spec.FeatureId, spec.FeatureName, spec.VersionLocked,
AdaptationIssue.None, adapt, label, spec.Evidence, []));
}
var (activeSendReady, activeSendSummary) = EvaluateActiveSend(clientVersion, countMatches);
return new(clientVersion, AuditedVersion, versionMatches, activeSendReady, activeSendSummary, [.. entries]);
}
public static (bool Ready, string Summary) EvaluateActiveSend(string clientVersion, Func<string, int> countMatches)
{
if (!IsAuditedVersion(clientVersion))
return (false, $"主动发送(M4)已禁用:仅核对已审计版本({AuditedVersion} / {BaselineVersion}),当前为 {clientVersion}");
foreach (var sig in ActiveSendSignatures)
{
var matches = countMatches(sig.Signature);
if (matches <= 0) return (false, $"主动发送(M4)已禁用:签名未匹配 {sig.Name} ({sig.AuditedRva})");
if (sig.RequireUnique && matches > 1) return (false, $"主动发送(M4)已禁用:签名多重匹配 {sig.Name} ({matches})");
}
return (true, "主动发送(M4)入口核对通过:ReceiverSendPacket → ZoneClientSendPacket");
}
// Applies diagnostic gating without breaking unaffected modules or offline analysis.
public static void ApplyGate(ModuleManager modules, AdaptationReport report)
{
ArgumentNullException.ThrowIfNull(modules);
ArgumentNullException.ThrowIfNull(report);
foreach (var entry in report.Entries)
{
if (!modules.Status.TryGetValue(entry.FeatureId, out var status)) continue;
status.Adaptation = entry.AdaptationState;
if (entry.Issue is AdaptationIssue.VersionMismatch or AdaptationIssue.OffsetMismatch
or AdaptationIssue.SignatureMissing or AdaptationIssue.MultipleMatches)
{
if (modules.IsEnabled(entry.FeatureId)) modules.Disable(entry.FeatureId);
modules.Unavailable(entry.FeatureId, entry.Summary);
}
else if (entry.Issue == AdaptationIssue.None)
{
modules.ClearUnavailable(entry.FeatureId);
}
}
}
}