fix: variable-offset theory falsified (fixed layout @0x3C/0x34/0x30 confirmed); single-frame verbatim rejected outside stream context 鈥?gating is stream-level

This commit is contained in:
tonycao 2026-09-11 08:47:42 +08:00
parent a4a3ed916f
commit b644bdae79
2 changed files with 122 additions and 4 deletions

View File

@ -677,15 +677,20 @@ AECH 质询须源自 192.168.123.113(真机固件过滤,§3.7)。
- **AECH 握手成功 ≠ 会话数据通道打通**——认领(47B/AERE 全过)后,自构造的
type=4 帧(DMX/RDM)仍被静默丢弃;而 verbatim 重放 SL 的历史会话帧立即全通
(遥测/RDM 应答恢复)→ Butler 在帧级校验某种我们尚未破解的会话一致性
- **RDM 请求帧的消息起始位置可变**(UN_MUTE@0x3A vs UNIQUE_BRANCH@0x3C,
前+len16 字段位置随之浮动 2B)——固定偏移构造的 RDM 帧必被拒;变长规则未破解
(实用绕过: 直接重放 SL 原帧)
- **~~RDM 请求帧消息起始位置可变~~(09-11 更正:解析错误,实为固定)**:
深夜复核证实所有 RDM 请求帧布局恒定——SubSC/msgLen@0x3C、len16(msgLen+1)@0x34、
flag@0x30(00 独立/01 副本,配对 srcUID 末字节 ff/fe,UN_MUTE 同样成对)、
counter@0x1A、qseq@0x22、TN@0x4A。此前"0x3A vs 0x3C 变长"系手工解析错位
- **★单帧 verbatim 在流外仍被拒**(slbisect 突变实验:SL 原版 GET→NFS 帧单独
发送 → 零应答;同一帧在完整流重放中 → 正常应答)→ **门控在会话流上下文**
(疑似流级防重放指纹/状态机,具体算法未破解)——实用方案即完整流重放
- 1947 端口"密钥报文"实为 **40B ASCII 许可令牌**(`BlZRQphA…`,恒定值,双目标
21 帧 @200ms 每 ~34s 一轮);EUCE 实为全程每 6s 的许可信标
- 真机认领门控行为(当晚早段观察): 灯具 MUTE 态跨会话持久(SL 遗留的 mute
挡住后续 branch 查询);SymphoLight 关闭无释放帧,DMX 流直接消失
**遗留**:RDM 帧变长结构规则(破解后可用纯自构造帧完成发现,摆脱对 SL 原帧的依赖)。
**遗留**:会话流上下文门控的具体算法(破解后可用纯自构造帧完成发现,摆脱对
SL 原帧重放的依赖——当前 slfull 重放方案已可复现全部功能,不影响使用)。
**历史过程记录(假设-证伪链,供复盘)**:完整冷启动前奏(45s)/绑定帧×4/EUCE 6s 节奏/
新鲜时间戳宣告/1947 密钥/会话保持 2h 模型——均单因素排除;最终由 verbatim 重放

View File

@ -594,6 +594,119 @@ pub fn run(target: &str, bind_ip: &str, secs: u64) {
return;
}
// slbisect: SL 原帧逐字段突变 — 定位 Butler 拒收我们 RDM 帧的确切字段
// 突变序列: verbatim(对照) → counter → TN → qseq → 全部 → 纯我们构造
if std::env::var("HOSTDEMO_MODE").unwrap_or_default() == "slbisect" {
// 认领
let o2: Vec<u8> = bind_ip.split('.').map(|x| x.parse().unwrap()).collect();
sock.send_to(&load_template("announce144"), &dst).unwrap();
std::thread::sleep(Duration::from_millis(300));
let nonce = rng.next();
let bc = rng.next();
let mut ch = load_template("claim_h112");
ch[0x1A..0x1E].copy_from_slice(&[o2[3], o2[2], o2[1], o2[0]]);
ch[0x88..0x8C].copy_from_slice(&nonce.to_le_bytes());
ch[0x8C..0x90].copy_from_slice(&bc.to_le_bytes());
sock.send_to(&ch, &dst).unwrap();
std::thread::sleep(Duration::from_millis(500));
println!("[B] 认领完成 B12=0x{:08x}", bc);
// verbatim DMX 背景流 + 突变 branch 查询
let path = std::env::var("REPLAY_FILE")
.unwrap_or_else(|_| "C:/Users/tonycao/AppData/Local/Temp/opencode/replay_frames.txt".into());
let data = std::fs::read_to_string(&path).expect("replay file");
let mut dmxf: Vec<Vec<u8>> = Vec::new();
for line in data.lines() {
let p: Vec<&str> = line.split('|').collect();
if p.len() < 4 { continue; }
let hex = p[3];
if hex.len() != 1084 * 2 { continue; }
let byte = |o: usize| u8::from_str_radix(&hex[o * 2..o * 2 + 2], 16).unwrap();
if byte(0x18) == 1 && byte(0x20) == 1 && byte(0x21) == 1 && byte(0x3c) != 1 {
let mut fb = Vec::new();
for i in (0..hex.len()).step_by(2) { fb.push(u8::from_str_radix(&hex[i..i + 2], 16).unwrap()); }
dmxf.push(fb);
}
}
let sl_branch = std::fs::read_to_string("C:/Users/tonycao/AppData/Local/Temp/opencode/sl_branch_exact.hex")
.unwrap_or_else(|_| String::new());
let mut slb: Vec<u8> = Vec::new();
{
let h = sl_branch.trim();
for i in (0..h.len()).step_by(2) { slb.push(u8::from_str_radix(&h[i..i + 2], 16).unwrap()); }
}
// NFS1K2D GET DEVICE_INFO 探针 (被 MUTE 的设备也须应答 GET — 应答可观测)
let sl_get = std::fs::read_to_string("C:/Users/tonycao/AppData/Local/Temp/opencode/sl_get_exact.hex")
.unwrap_or_default();
let mut slg: Vec<u8> = Vec::new();
{
let h = sl_get.trim();
for i in (0..h.len()).step_by(2) { slg.push(u8::from_str_radix(&h[i..i + 2], 16).unwrap()); }
}
let known: [[u8; 6]; 3] = [
[0x01, 0x07, 0x34, 0x67, 0x01, 0x25],
[0x01, 0x07, 0x34, 0x88, 0x09, 0x00],
[0x08, 0x99, 0x50, 0x00, 0x26, 0xc9],
];
println!("[B] 开始突变序列 (GET→NFS; 每步 1s DMX 背景 + 发送 + 500ms 侦听)");
let mut di = 0usize;
let mutations = ["verbatim对照", "counter=ours", "TN=ours", "qseq=ours", "全突变"];
for round in 0..2 {
for (mi, mname) in mutations.iter().enumerate() {
let seg = Instant::now();
while seg.elapsed() < Duration::from_millis(1000) {
let f = &dmxf[di % dmxf.len()];
di += 1;
let _ = sock.send_to(f, &dst);
if di % 30 == 0 { let _ = sock.send_to(&load_template("heartbeat"), &dst); }
std::thread::sleep(Duration::from_millis(33));
while sock.recv_from(&mut buf).is_ok() {}
}
let mut f = slg.clone();
let ctr = (di as u32).wrapping_add(9000);
match mi {
1 => { f[0x1A..0x1E].copy_from_slice(&ctr.to_le_bytes()); }
2 => { f[0x4A] = 0x77; }
3 => { f[0x22] = 0x55; f[0x23] = 0x00; }
4 => {
f[0x1A..0x1E].copy_from_slice(&ctr.to_le_bytes());
f[0x4A] = 0x78;
f[0x22] = 0x56; f[0x23] = 0x00;
}
_ => {}
}
let _ = sock.send_to(&f, &dst);
let mut f2 = f.clone();
f2[0x30] = 0x01;
f2[0x49] = f2[0x49].wrapping_sub(1);
let _ = sock.send_to(&f2, &dst);
let mut info = false;
let mut any = 0usize;
let w = Instant::now();
// ★边发 DMX 边侦听 (Butler 仅在 DMX 流持续时吐应答, 停流即饿死)
while w.elapsed() < Duration::from_millis(500) {
let f = &dmxf[di % dmxf.len()];
di += 1;
let _ = sock.send_to(f, &dst);
if di % 30 == 0 { let _ = sock.send_to(&load_template("heartbeat"), &dst); }
while let Ok((n, src)) = sock.recv_from(&mut buf) {
if src.ip().to_string() != target { continue; }
let b = &buf[..n];
any += 1;
if let Some((false, d)) = rdm_region(b) {
if d.len() >= 0x18 + 19 && d[0] == 0xCC && d[0x15..0x17] == [0x00, 0x60] {
info = true;
}
}
}
std::thread::sleep(Duration::from_millis(33));
}
println!(" [B] r{} {:<14} → 收帧 {} DEVICE_INFO={}", round, mname, any, info);
}
}
let _ = known;
return;
}
let mut b12 = rng.next();
let mut claim_ok = false;