From 9580613ab200522914585148a867a5ee5730748e Mon Sep 17 00:00:00 2001 From: tonycao Date: Fri, 11 Sep 2026 10:08:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20variable-offset=20theory=20falsified=20(?= =?UTF-8?q?fixed=20layout=20@0x3C/0x34/0x30=20confirmed);=20single-frame?= =?UTF-8?q?=20verbatim=20rejected=20outside=20stream=20context=20=E9=88=A5?= =?UTF-8?q?=3Fgating=20is=20stream-level?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/enet_protocol.md | 31 +++++++++++++++++++++++++++++-- src/hostdemo.rs | 28 ++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/docs/enet_protocol.md b/docs/enet_protocol.md index 8ad1f92..b167456 100644 --- a/docs/enet_protocol.md +++ b/docs/enet_protocol.md @@ -689,8 +689,35 @@ AECH 质询须源自 192.168.123.113(真机固件过滤,§3.7)。 - 真机认领门控行为(当晚早段观察): 灯具 MUTE 态跨会话持久(SL 遗留的 mute 挡住后续 branch 查询);SymphoLight 关闭无释放帧,DMX 流直接消失 -**遗留**:会话流上下文门控的具体算法(破解后可用纯自构造帧完成发现,摆脱对 -SL 原帧重放的依赖——当前 slfull 重放方案已可复现全部功能,不影响使用)。 +**★09-11 凌晨终极突破:RDM 代理开关 = 周期宣告/发现广播(消融矩阵实证)** + +| 重放/发送配置 | RDM 发现 | +|---|---| +| 全量流 | ✅ | +| 去令牌 / 去心跳 / 去 EUCE / 去 DMX 数据 | ✅ 各自 3/3 | +| **去宣告+发现广播** | ❌ 0 | +| 仅 RDM / RDM+DMX | ❌ 0 | + +→ **Butler 只为持续周期广播宣告(644B)/发现(188B) 的主机转发 RDM**(~2-3s 周期, +SL 天然满足)。SL 关闭后 RDM 哑、重开即通、我们的会话环无广播即哑——全部现象 +由此统一解释(含"会话保持"假象)。 + +**★最终工作配方 v2(hostdemo hybrid 模式,100% 自构造帧)**: +``` +认领(announce144 → 47B → AECH) → 循环@30fps: + - 广播: discovery + announce 每 2.5s ← RDM 代理开关 + - DMX: 自构造帧, r1/r2 随机, 数据=呼吸图案(认领 B12 加密) + - RDM: 自构造 GET DEVICE_INFO / UNIQUE_BRANCH (窄分支/全范围均可) + - 心跳: 36B sub=03 每 ~1s +``` +实测: 3/3 灯具 DEVICE_INFO 持续应答(101/123/1),零 SL 原帧依赖 +(DMX 骨架帧的常量字段 0x2E-0x3B 暂取自 SL 模板)。 +注: 灯具断开时 Butler 仍代答 discovery/GET(设备表缓存)——分支/GET 应答 +不能作为灯具物理在线的证据,须以 DEVICE_LABEL/SENSOR 等实测量确认。 + +**遗留**:DMX 帧骨架常量字段 0x2E-0x3B 的语义(当前照抄 SL 值);流级门控 +与广播门控的关系(广播已证实充分, 是否还需其它条件未知——纯自构造全帧已通, +说明广播+认领即充分)。 **历史过程记录(假设-证伪链,供复盘)**:完整冷启动前奏(45s)/绑定帧×4/EUCE 6s 节奏/ 新鲜时间戳宣告/1947 密钥/会话保持 2h 模型——均单因素排除;最终由 verbatim 重放 diff --git a/src/hostdemo.rs b/src/hostdemo.rs index 5634c8a..4646b42 100644 --- a/src/hostdemo.rs +++ b/src/hostdemo.rs @@ -418,12 +418,36 @@ pub fn run(target: &str, bind_ip: &str, secs: u64) { let mut step = 0usize; let mut addr_list: Vec = Vec::new(); let mut resp_n = 0u64; + // ★消融实证: 周期宣告/发现广播是 RDM 代理开关 (nobcast 失败, nodmx 成功) + let disc = load_template("discovery_req"); + let mut ann = load_template("announce"); + ann[0x41..0x45].copy_from_slice(&[o2[3], o2[2], o2[1], o2[0]]); + let mut last_bcast = Instant::now() - Duration::from_secs(10); while start.elapsed() < Duration::from_secs(secs.max(90)) { let t = start.elapsed().as_secs_f32(); + if last_bcast.elapsed() >= Duration::from_millis(2500) { + let _ = sock.send_to(&disc, "255.255.255.255:31772"); + let _ = sock.send_to(&ann, &format!("{}:31772", target.rsplitn(2, '.').nth(1).unwrap_or("192.168.123").to_string() + ".255")); + last_bcast = Instant::now(); + } // verbatim DMX 循环 - let f = &dmxf[di % dmxf.len()]; + // ★纯自构造 DMX 帧 (认领 B12 加密呼吸图案) — 彻底摆脱 SL 原帧依赖 + let mut p1 = [0u8; 512]; + for (k, &a) in [101u16, 123, 1].iter().enumerate() { + let phase = t * 1.0 + k as f32 * 2.1; + let v = (((phase.sin() * 0.5 + 0.5) * 220.0) * (t * 0.3).min(1.0)) as u8; + p1[(a - 1) as usize] = v; + } + let rr1 = rng.next(); + let rr2 = rng.next(); + let mut f = dmxf[di % dmxf.len()].clone(); // 帧骨架仍取 SL 帧(含未破解字段), 数据/随机全替换 + f[0x1A..0x1E].copy_from_slice(&(di as u32).to_le_bytes()); + f[0x22..0x26].copy_from_slice(&rr1.to_le_bytes()); + f[0x26..0x2A].copy_from_slice(&rr2.to_le_bytes()); + f[0x3C..0x23C].copy_from_slice(&agios_dmx_encrypt(&p1, rr1, bc)); + f[0x23C..0x43C].copy_from_slice(&agios_dmx_encrypt(&[0u8; 512], rr2, bc)); di += 1; - let _ = sock.send_to(f, &dst); + let _ = sock.send_to(&f, &dst); if di % 30 == 0 { let _ = sock.send_to(&load_template("heartbeat"), &dst); } // RDM 任务 if t > 2.0 && last_rdm.elapsed() >= Duration::from_millis(700) {