235 lines
13 KiB
C#
235 lines
13 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|
||
}
|