Files
IC.Rebuild/diagnostics/2026-10-11-network-full-capture.md

56 lines
4.7 KiB
Markdown
Raw Permalink 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.
# 0.1.8 完整游戏载荷采集
基线:国际服 2026.09.15.0000.0000,本机 ffxiv_dx11.exe;实现限定此完整版本。前期线索见 network-length-research.md。本次原生检查只读磁盘文件,不调用原生函数;现场验收尚未完成。
## 上行证据
上行签名唯一匹配 RVA 0x1D718C0,ABI 为 byte(connection, data, arg, byte flag)。data 是发送对象,Opcode 在 +0,消息长度为 +8 的 uint64,业务载荷在 +0x20。
- 0x1D7198C:从 [rsi+8] 取长度,源指针 rsi+0x20,长度减 0x10,调用 0x1DA6CB0。
- 0x1D71A84:另一分支执行相同的复制区间。
- 0x1DA6CB0:按 r8 长度分派复制;0x1DA6DD0 的 16—32 字节分支从 rdx、rdx+r8-0x10 读取并写入 rcx、rcx+r8-0x10,确认其复制含义。
- 0x1CFD1D0 的发送对象创建例:Opcode 在对象 +0,uint64 长度 0x18 在 +8,经 ZoneClient.SendPacket(0x1D03040)进入上述函数。复制的业务长度为 8。
采集发生在发送原函数之前,只表示进入发送路径,不代表发送成功或服务端接收。
## 下行证据与有效期
调用链:NetworkModule 0x1D02040 → ZoneClient.ReceivePacket 0x1D03020 → ZoneReceive 0x1D71440。后者 ABI 为 byte(connection, holder),返回值非零表示接收成功。
- 0x1D71464—0x1D71468:将消息对象写入 holder+0x10。
- 0x1D714D7—0x1D714E0:从 holder+0x10 取对象,再从对象+0x38 取 IPC 缓冲区。
- 对象+0x30 为 uint64 消息长度。接收构造路径 0x1D68875—0x1D6889E 从外层消息长度减去 0x10,按此大小复制到对象+0x38,并将相同大小写入对象+0x30。它包含 0x10 字节 IPC 头。
- 0x20EF800 读取缓冲区+2 的 Opcode,其各分支从缓冲区+0x10 取得业务载荷。
- NetworkModule 0x1D021AD 从对象+0x20 取得目标标识;保留位范围按原函数标准化,不能把对象+0x24 的其他值擅自标为 Source。
- 0x1D02203—0x1D02220 将 IPC 缓冲区交给 Application 接收回调;0x482440 转发到 PacketDispatcher 0x18D9500。
- 0x1D02366—0x1D02370 在分派后释放消息,下一次接收前清空 holder+0x10。Hook 在接收原函数成功返回后立即复制,尚未返回给上述调用者,不保存原生指针供后台使用。
下行签名的栈保存偏移 0x18 必须保留。将其通配后同时匹配 0x1D20BF0(另一接收入口)和 0x1D71440。最终完整签名在当前文件仅匹配一次:
```text
48 89 5C 24 18 57 48 83 EC 20 48 83 B9 88 00 00 00 00 48 8B FA 48 8B D9
```
下行不再挂接 PacketDispatcher,不重复记录同一包,也不从 IPC 指针之前猜读外层头部。
## 读取与失败行为
- 使用 Dalamud.SafeMemory.ReadBytes(当前进程 ReadProcessMemory)复制;没有使用旧结构大小推断原始指针长度。
- 先验证指针、头部读取和 uint64 长度,长度减 0x10 前检查下限及上限,单载荷最多 65536 字节。
- 完整读取才标记 PayloadComplete=true;确实零字节的合法载荷可以完整,不等于失败。
- 已有 Opcode 的异常长度、截断或复制失败保留仅元数据及 CaptureIssue;头部/对象失败不能可靠获得 Opcode,记录异常计数及最近原因,不伪造包。
- 暂停或方向过滤可避免读取对象,Opcode 过滤在读取载荷之前执行。
- 两个原函数都保持一次调用及原参数/返回值;发送在采集后调用,接收先调用再读取成功结果。采集托管异常不会替代游戏原函数结果。
- 记录通过复制成为托管数组;缓冲区按 2048 条和 8 MiB 载荷双重限制,淘汰最旧记录。后台保存只使用这些副本。
- 只覆盖当前版本 Zone 通道。聊天、登录和录像回放通道未挂接。上行 Source/Target、下行 Source 没有足够依据,保持 null。
## 结果与测试
Release 构建通过,0 警告、0 错误;57 项离线测试通过。新增模拟有界内存场景覆盖精确复制区间、对象引用链、目标标准化、恶意 uint64 长度、截断/部分读取、空载荷、64 KiB 上限、无效指针、过滤、错误原因导入导出和缓冲字节预算。
一次新增导出测试使用系统临时目录时受到沙箱文件移动限制;已改为与既有测试一致的测试输出目录,完整构建和测试重跑通过。此修正没有放宽插件文件路径或权限策略。
现场验证:重新加载 0.1.8,开启 36、37,方向全部、Opcode -1;正常移动、使用技能 20—30 秒。观察完整上下行计数是否增长、异常是否出现,再 `/icr export capture-018.jsonl` 并关闭 36。以导出样本核验真实载荷和已有解析,之后再扩展 37。
本版完成采集代码接入与离线边界验证,不把 36 标为游戏内已验证,也不据此宣称 37 的历史解析全部正确。