从黑盒到可交互画面:极域 V6.0 连续投屏与远程操控协议逆向

目录

从黑盒到可交互画面:极域 V6.0 连续投屏与远程操控协议逆向

本文记录 2026.07.31 研究预览版中连续屏幕观看与远程操控链路的逆向过程。结论来自 IDA Pro 静态分析、官方教师端/学生端真实流量对照、逐字节重放和运行日志验证。本文只讨论隔离实验环境中的协议研究,不应被用于未经授权的监控或控制。

摘要

极域 V6.0 的“观看学生屏幕”和“远程控制学生”不是一个简单的 UDP 命令,也不是把截图循环发送回来。完整链路至少跨越三类通道:

  1. 教师端先经 5512/UDP 的 MESS feature=8 通知学生端启动桌面发送功能;
  2. 教师端连接学生端 4806/TCP,发送 SHCO 选择 UMSP channel 10,再从 TKPC 中重组 HHRF/HJRF 桌面记录;
  3. 进入控制模式时,教师端再用 COMD 事务承载 MCMD,让学生端在指定 UDP 端口启动模拟输入接收器;鼠标和键盘事件通过固定 28 字节输入包发送。

截至当前版本,连续观看、H.264/JPEG 解封装、色度修正、SPUC 光标解析以及远程鼠标移动/点击已经在测试环境验证。键盘只验证到教师端捕获和 kind=16 发包,学生端是否最终完成 SendInput 仍不稳定,因此仍是实验性功能。

能力当前证据
4806/TCP 建连与 SHCO 选路已验证
TKPC 分片重组已验证
HHRF/H.264、HJRF/JPEG 解析已验证
U/V 色度平面修正已验证
SPUC 远端光标解析已验证
MCMD mode=2 建立控制已验证
28 字节鼠标包移动与点击已验证
kind=16 键盘包捕获与发包已验证,学生端执行未稳定验证

一、先建立正确的系统模型

最初最容易犯的错误,是把“投屏”理解成缩略图协议 LANT/TNAL 的高频版本。抓包很快就能否定这个假设:点击官方教师端的“监看”后,学生端除了继续保活,还会开放或使用 4806/TCP;真正的连续画面主要出现在这条 TCP 流中。

远程控制同样不是直接向 4705/UDP 塞一个 WM_MOUSEMOVE。官方流程会先复用已经建立的桌面观看会话,然后通过通用命令事务启动一个独立的模拟输入通道。

mermaid
sequenceDiagram
    participant T as 第三方教师端
    participant S as 极域学生端

    T->>S: TCP connect probe :4806(只探测)
    T->>S: MESS feature=8 / start(5512/UDP)
    T->>S: TCP connect :4806
    T->>S: SHCO / channel 10
    S-->>T: TKPC / channel 10 / 桌面分片
    S-->>T: HHRF(H.264) 或 HJRF(JPEG)
    T->>S: COMD transaction → MCMD mode=2
    Note over S: BeginSimulate,监听指定 UDP 端口
    T->>S: 28-byte mouse input
    S-->>T: SPUC cursor record
    T->>S: 28-byte kind=16 keyboard input(实验性)

这个模型解释了几个看似无关的现象:

  • 只发送 feature 8,不连接 TCP,不会得到可显示的连续画面;
  • 直接发输入包时,学生端没有对应 UDP 接收器,数据只会被操作系统丢弃;
  • 从 view 切换到 control 时重启 H.264 解码器,容易永久黑屏,因为新解码器没有收到此前的 SPS/PPS/IDR;
  • 本地鼠标与学生端鼠标短暂错位并非只有坐标算法问题,还包含编码、网络、显示和 SPUC 回传延迟。

二、在 IDA 中如何找到入口

2.1 不要只搜索可见字符串

这类老式 C/C++ 网络库常把 FourCC 写成 32 位立即数。文件里的字节顺序是人眼可读的 SHCO,反汇编中却可能出现:

text
wire bytes: 53 48 43 4F  -> "SHCO"
IDA imm32 : 0x4F434853

wire bytes: 54 4B 50 43  -> "TKPC"
IDA imm32 : 0x43504B54

原因是 x86 使用小端序。仅在 Strings 窗口里搜索 SHCO 很可能什么也找不到,应该同时搜索对应的立即数,然后查看交叉引用。

本次逆向中最有效的一组锚点是:

线索作用
0x4F434853定位 UMSP channel 选择包 SHCO
0x43504B54定位 UMSP 数据包 TKPC
0x46524848定位 HHRF H.264 桌面记录
0x46524A48定位 HJRF JPEG 桌面记录
MCMD定位监看/控制模式切换结构
SPUC定位光标状态记录
0x2321347C定位模拟输入包分发器
常量 4806、channel 10从通用传输库缩小到桌面通道

2.2 从网络 API 反推对象边界

打开 LibBaseTrans.dll 后,先建立导入函数关系:connect、send、recv、WSARecv、线程创建、临界区和缓冲区复制。不要急着给每个函数命名,先回答三个问题:

  1. 哪个对象持有 socket?
  2. 哪个循环读取 12 字节头并按长度字段切包?
  3. 哪个分支在 payload 起始位置读取 channel id?

从 0x43504B54 的交叉引用向上回溯,可以看到一个典型的“版本 + magic + payload length”检查;继续向下跟踪,payload 的首个 u32 被当作 channel。channel 10 随后进入桌面数据处理对象,而其他 channel 被分派给不同业务。

在 IDA 中可以先做以下重命名,之后伪代码会清晰很多:

text
sub_xxx_connect     -> umsp_connect
sub_xxx_read_loop   -> umsp_recv_loop
sub_xxx_dispatch    -> dispatch_umsp_channel
sub_xxx_channel10   -> handle_desktop_fragment
sub_xxx_record      -> handle_desktop_record

名字不必一开始就完全正确。关键是让“传输层、分片层、记录层、编解码层”不再混在同一张调用图里。

2.3 从 feature 分发器找到 617 字节参数块

在学生端的 MESS 处理路径中,feature id 8 会进入远程观看分支。这个分支不是只读一个布尔值,而是复制一个较大的参数对象。把官方教师端报文和伪代码中的复制长度对照后,可以确定:

  • 内层 feature payload 总长为 617 字节;
  • 前 12 字节是 length / feature / flags;
  • 中间 604 字节是远程观看参数;
  • 最后还有 1 字节尾部填充。

不要把参数块里的端口直接当成学生端 4806/TCP。其中两个端口属于教师会话/桌面监控端点;学生端的 TCP 服务端口是另一层连接目标。这两个概念混用,会构造出长度正确但状态错误的请求。

2.4 从 MCMD 跟到模拟输入

MCMD 位于通用 COMD 事务内部。沿 MCMD 分支继续跟踪,可以看到 mode 分派以及模拟输入初始化路径。当前观察到的行为是:

  • mode=0:Share,双方可操作;
  • mode=2:Control Student,启动模拟输入并额外进入学生端本地输入锁定路径;
  • mode=1:本项目用于停止当前模拟输入会话。

再从输入接收线程向下跟踪,固定 magic 0x2321347C 是很强的定位点。分发器读取紧随其后的 kind,然后按鼠标或键盘结构解释剩余 20 字节。

逆向时必须继续跟到系统调用边界。看到 UDP recvfrom 并不表示控制已经生效,真正需要确认的是后续是否构造 INPUT、是否调用 SendInput、调用发生在哪个 Windows Session/desktop,以及本地 Hook 是否会再次拦截注入事件。


三、用抓包给反汇编“定类型”

IDA 告诉我们代码可能怎样解释内存,抓包则告诉我们线上实际发送了什么。两者必须互相约束。

建议只在隔离测试网中采集,并把一次操作拆成单变量实验:

  1. 只打开“观看屏幕”,不移动鼠标;
  2. 只切换到“远程控制”,不输入;
  3. 只移动一次鼠标;
  4. 只按一次左键;
  5. 只按一个普通字母键;
  6. 分别停止控制和停止观看。

Wireshark 初始过滤器:

text
udp.port == 4705 || udp.port == 5512 || tcp.port == 4806

找到对应 TCP stream 后,再单独查看:

text
tcp.stream eq <n>

抓包分析时不要依赖 TCP segment 边界。一次 recv 可能拿到半个 UMSP 包,也可能一次拿到多个包。正确做法是维护流缓冲区,只有当缓冲区至少包含 12 字节头,并且达到 12 + payload_len 后才取出一包。

3.1 差分比对比猜字段更快

对 MCMD 和输入包尤其适合做差分:固定所有条件,只改变一个操作。例如把鼠标从画面左上移动到右下,比较两包中变化的 4 字节字段;连续点击左键,观察 0x0201 与 0x0202 的成对出现;滚轮则会让 data 字段变化。

字段命名按证据逐步升级:

text
unknown_08
  -> changes_with_x
  -> normalized_x
  -> normalized_x_u16_range_in_u32

不要因为某次值恰好等于屏幕像素,就立即命名为 pixel_x。本协议鼠标坐标实际使用 0..65535 归一化范围,窗口尺寸和远端编码尺寸只是映射输入。


四、观看请求:MESS feature 8

当前实现构造的 feature payload 如下。所有多字节整数均为小端;IP 地址保持网络序原始字节。

4.1 feature 8 内层结构

偏移大小当前解释观察值
0x0004payload length617
0x0044feature id8
0x0084start flags0x80000000
0x00C604remote-view params见下表
0x2681tail padding0

604 字节参数块中,已经通过官方流量和代码路径确认或稳定观察到的字段:

参数内偏移大小含义当前值
+0x004RemoteWithVoice0
+0x044教师 IPnetwork order
+0x082教师会话端口当前频道端口
+0x0A4教师 IP(第二端点)network order
+0x0E2桌面监控端口当前频道端口
+0x244NetworkType1
+0x284ShowMonitorControlMessage1
+0x2C4MaxSendSpeed20480
+0x304RepairMode1
+0x344MaxPacketSize1440
+0x384FrameLimit25
+0x3C4CaptureQuality75
+0x404TcpCommMode1
+0x444学生 IPnetwork order
+0x4812未完全命名的三元组5, 12, 16

最后一组三元组虽然已经稳定复现,但在没有进一步交叉引用证据前不应强行解释其业务名称。保留“已知偏移 + 已知值 + 未知语义”比写一个听起来合理的名字更有研究价值。

停止观看使用另一种短结构:

text
u32 length  = 13
u32 feature = 0
u32 flags   = 0
u8  tail    = 0

4.2 正确启动时序

当前稳定时序是:

text
TCP connect probe 4806(立即关闭,不发 SHCO)
    -> MESS feature 8 start
    -> 单次连接 4806/TCP
    -> 立即发送 SHCO channel 10
    -> 从第一条 H.264 记录开始喂给同一个解码器

探测步骤只检查 TCP 是否监听,不启动编码器,也不发送 SHCO。正式启动后不能在失败时高频重试:学生端编码器和内部线程存在状态,重复 feature 请求或并发 TCP 会话可能导致学生端异常退出。当前实现限制每个 IP 同时只有一个观看会话,并在失败后冷却 60 秒。


五、UMSP:SHCO、TKPC 与 channel 10

5.1 SHCO 选择包

连接 4806/TCP 后,教师端发送 20 字节选择包:

偏移类型值
0x00u32version 0x00010000
0x04u320x4F434853,线上为 SHCO
0x08u32body length 8
0x0Cu32selector/op,观察值 1
0x10u32desktop channel 10

这里的 channel 10 是业务复用编号,不是 TCP/UDP 端口。

5.2 TKPC 数据包

学生端返回的 UMSP 包使用 12 字节公共头:

偏移类型说明
0x00u32version,预期 0x00010000
0x04u320x43504B54,线上为 TKPC
0x08u32payload length
0x0Cu32channel id,桌面为 10
0x10byteschannel payload

代码或符号中可能把它写作 TCPK,但线上字节是 TKPC。逆向协议时应始终区分“源码/反编译变量名”和“wire bytes”,否则 Wireshark 搜索与代码常量会互相对不上。


六、桌面分片重组

channel 10 的 payload 不是直接的 H.264 NAL,而是先经过一层 12 字节桌面分片:

text
+0x00  u32 frame_seq
+0x04  u32 fragment_offset
+0x08  u32 record_total_size
+0x0C  bytes fragment_data

重组器按 frame_seq 保存状态,以 record_total_size 分配缓冲区,然后把每个 fragment 写入指定 offset。实现时至少要处理:

  • TCP 读取边界与 UMSP 包边界不一致;
  • 同一分片重复到达;
  • 分片乱序;
  • 新 frame_seq 到来时旧帧仍未完成;
  • offset 或 length 越界;
  • 恶意或损坏的 total size 导致大内存分配。

当前实现给每帧维护一份 seen 位图,只把第一次出现的字节计入 received,避免重复分片使计数提前达到 total。最多同时保留四个未完成帧,并将桌面记录大小限制在 0x241800。

一个重要踩坑是:并非所有完整记录都大于 64 字节。SPUC 光标记录只有 16 字节。如果在分片层直接用“total < 64”判定非法,就会把光标状态误报为坏帧。正确做法是先完成通用重组,再在记录层按 magic 和长度分流。


七、HHRF/HJRF 桌面记录

视频类记录包含一个 64 字节头:

偏移大小说明
0x004magic:HHRF / HJRF / HMRF
0x044declared record size
0x084timestamp
0x0C16encoded rect:left/top/right/bottom
0x1C16visible rect:left/top/right/bottom
0x2C4frame type
0x3016尚未完全命名的字段
0x40variable编码 payload

magic 对应关系:

text
0x46524848 -> wire "HHRF" -> H.264 Annex-B
0x46524A48 -> wire "HJRF" -> JPEG
0x46524D48 -> wire "HMRF" -> legacy/兼容记录

日志中的一个真实样本为:

text
H264 frame=1 seq=11 record=623 declared=623
encoded=(0,0,1728,928) visible=(0,0,1718,918)

这说明编码尺寸和实际可见尺寸并不总相同。直接按 encoded rect 展示会在边缘出现填充区域,所以解码后还需要按 visible rect 裁剪。

7.1 为什么请求真实 H.264 时容易“黑屏”

H.264 是有状态码流。解码器通常需要先看到 SPS、PPS 和 IDR,才能解释后续 P/B 帧。下面几种做法都会造成只有数据、没有画面:

  • TCP 建连太晚,错过码流初始化;
  • 先用一个播放器观看,切换 control 时杀掉播放器再启动另一个;
  • 把多次观看留下的半段 .h264 直接拼在一起;
  • 将 UMSP/桌面记录头误写进 H.264 payload;
  • 按 TCP recv 块直接喂解码器,破坏了上层记录边界。

当前实现从第一帧开始固定使用 bundled FFmpeg,view -> control 只改变窗口交互状态,不重启解码进程。可选裸流也按会话时间戳独立保存,避免把上一次的不完整码流接到新会话前面。

7.2 为什么画面颜色会错

拿到画面后,最明显的问题曾是整体色相不对:本应为蓝色的区域显示成另一种颜色。几何内容正确、亮度基本正确而色相系统性错误,通常不是 RGB/BGR 顺序问题,而是 YUV 色度平面顺序问题。

对同一帧分别尝试常见转换后,可以确认极域这条 H.264 链路的 U/V 平面需要交换。FFmpeg 过滤器为:

text
shuffleplanes=0:2:1:3

然后再按可见尺寸裁剪:

text
shuffleplanes=0:2:1:3,crop=<visible_w>:<visible_h>:0:0

这里选择在显示管线修正,而不改写保存的 H.264 裸流。这样原始证据仍可用于后续协议分析,同时实时窗口显示正确颜色。


八、SPUC:远端光标不是画面的一部分

光标状态使用独立的 16 字节记录:

偏移类型说明
0x004 bytesSPUC
0x04u32record size,预期 16
0x08u32timestamp
0x0Cu32packed position

位置打包方式:

text
x = packed_position & 0xFFFF
y = packed_position >> 16

实际控制窗口中有三个“鼠标位置”:

  1. 本机系统指针;
  2. 刚刚发送给学生端的预测位置;
  3. 学生端通过 SPUC 回传的确认位置。

如果三者同时显示,用户会看到两个指针互相追赶。因此投屏区域隐藏本机系统指针;发送鼠标事件后的短时间内显示本地预测位置,约 180 ms 后切回 SPUC 确认位置。这个策略不能消除网络和编码延迟,但能减少操作感上的跳变。

画面显示可能经过缩放,坐标必须基于实际图像区域,而不是整个窗口或屏幕:

text
normalized_x = round(local_x * 65535 / (display_width  - 1))
normalized_y = round(local_y * 65535 / (display_height - 1))

预测光标绘制回源画面时,再从 0..65535 映射到 encoded width/height。忽略这两次映射,会在窗口缩放后产生越来越明显的位置偏差。


九、远控建立:COMD 事务中的 MCMD

MCMD 不能作为裸 UDP 报文发送,它是通用 COMD transaction 的 payload。COMD 外层负责版本、事务 GUID、超时、发送者和 payload 长度;学生端先进入事务分发器,再把 MCMD 交给监看/控制模块。

当前 MCMD 内层固定为 53 字节:

偏移大小说明
0x004inner length 53
0x044feature/category 8
0x084flags 0
0x0C4magic MCMD
0x104mode:0 / 1 / 2
0x144学生 IP,网络序字节
0x182学生端输入监听 UDP 端口
0x1A27保留/零填充

项目默认从 49152..65535 随机选择一个高位端口。使用固定端口虽然方便抓包,但学生端异常退出后旧线程或状态可能仍占用它;随机端口更适合反复调试。

MCMD 发出后不能立即发送第一条输入。学生端需要创建接收线程并完成 BeginSimulate 初始化。当前实现保守等待约 350 ms;这不是协议字段,而是从实际时序中得到的工程性保护。

为了避免学生端进入“有控制状态、没有画面会话”的不完整状态,control 只在 4806/TCP 已经连接后发送 MCMD。停止时发送 mode=1 并关闭本地 UDP sender。


十、28 字节模拟输入包

所有输入事件使用相同外壳:

text
+0x00  u32 magic = 0x2321347C
+0x04  u32 kind
+0x08  u8  payload[20]
total = 28 bytes

线上 magic 的小端字节是:

text
7C 34 21 23

固定总长非常重要。多一个字节或少一个字节都可能让学生端接收线程丢包,或者让后续字段错位。

10.1 鼠标:kind=1

鼠标 payload 是五个 u32:

payload 偏移字段说明
+0x00messageWindows 鼠标消息
+0x04x0..65535 归一化坐标
+0x08y0..65535 归一化坐标
+0x0Cdata滚轮等附加数据
+0x10swapped键位交换/保留状态

已验证的 message:

动作值
move0x0200
left down / up0x0201 / 0x0202
right down / up0x0204 / 0x0205
middle down / up0x0207 / 0x0208
wheel0x020A

鼠标移动和点击在当前学生端环境已经观察到实际执行结果,因此证据链不仅停留在“教师端 sendto 成功”。

10.2 键盘:kind=16,仍是实验性

当前根据反汇编字段访问和教师端行为构造的 20 字节 payload:

payload 偏移类型说明
+0x00u16scan code
+0x02u16virtual key
+0x04u32flags
+0x0812 byteszero/reserved

当前 flags:

text
bit 0    = extended key
bit 7    = key up

普通按下为 flags=0,释放为 flags=0x80;扩展键按下/释放再或上 0x01。

Tk 的键盘事件会受输入法和焦点影响,尤其在中文输入法状态下,部分按键不会按预期到达 Tk。因此控制窗口额外使用 WH_KEYBOARD_LL 获取 Windows 提供的 VK、扫描码、扩展键标志以及 key down/up,并拦截 Alt、Windows 键,防止这些键先作用于教师机本地桌面。

但是,“Hook 日志出现”和“学生端收到有效键盘输入”之间仍有多层边界。当前只能确认:

text
本地物理按键
  -> WH_KEYBOARD_LL 捕获成功
  -> kind=16 的 28 字节包构造成功
  -> UDP sendto 成功
  -x-> 学生端解析/SendInput/目标应用收到字符:尚未稳定证明

可能影响学生端最终执行的因素包括:学生端所在 Windows Session、当前 input desktop、UAC 安全桌面、接收线程权限、学生端本地 Hook、扫描码/VK 组合、扩展键标志以及注入事件过滤。没有接收端 ACK 时,教师端日志不能跨越这些边界作结论。


十一、如何判断“真的成功”,而不是日志看起来成功

逆向远控最危险的误区是把 sendto() 返回成功当成远端执行成功。建议把证据拆成六级:

等级证据鼠标键盘
A教师端 UI/Hook 捕获事件已验证已验证
B教师端构造并发送正确长度报文已验证已验证
C抓包看到报文到达学生端已验证需持续复核
D学生端接收器进入对应 kind 分支已验证尚缺稳定动态证据
E学生端系统注入 API 成功已验证实际效果未稳定验证
F目标桌面/应用收到输入已验证未稳定验证

如果要继续研究键盘,下一步不应继续盲改教师端字段,而应在授权测试机上对学生端接收分支做动态观测:

  1. 在 recvfrom 返回后记录 28 字节缓冲区;
  2. 确认 magic、kind 和 payload 分支;
  3. 在 SendInput 前检查构造出的 INPUT;
  4. 记录 SendInput 返回值和 GetLastError;
  5. 确认线程所属 Session 与当前 input desktop;
  6. 最后再观察目标窗口是否收到键盘消息。

只有走完这条链,才能判断问题究竟是协议字段错误,还是 Windows 输入隔离与 Hook 策略导致。


十二、几个真正耗时的坑

12.1 把 4806 与 feature 参数端口混为一谈

feature 参数里的教师端点不等于学生端 TCP 监听端口。包长和 IP 都正确时,这种错误特别难发现,因为学生端可能进入部分状态,却不产生正确桌面流。

12.2 按 recv 边界解析 TCP

本地网络里一次 recv 经常“刚好”是一包,导致错误解析器看似可用。一旦包被拆分或合并,就出现随机 magic、超大 length 和画面断流。TCP 必须按字节流处理。

12.3 把 16 字节 SPUC 当坏视频帧

早期解析器假设桌面记录至少 64 字节,日志中不断出现 total=16 的“非法帧”。保留这批原始数据并查看 magic 后,才发现它是独立光标记录。

12.4 在码流中途更换播放器

view 能显示、control 一切换就卡在“等待画面”,根因不是 MCMD,而是切换时重启了解码器。H.264 参数集已经在流开头发过,新解码器只能等待下一次可恢复点。

12.5 把颜色问题误判为 RGB/BGR

如果交换 R/B 后肤色和亮度仍不合理,应检查 YUV 平面。当前链路需要交换 U/V,而不是在最终 RGB 图像上交换红蓝通道。

12.6 本地指针、预测指针和远端指针混在一起

鼠标“不同步”不一定是包没生效。若本机系统指针可见,同时又绘制预测位置和 SPUC 位置,视觉上必然出现错位。隐藏本地指针并定义明确的预测回退窗口后,问题才可测量。

12.7 用错误的 COMD 边界调 MCMD

MCMD 是通用事务的 payload,不是 COMD 应用命令里的任意 cmdId。外层长度、GUID、事务字段或 payload offset 错一处,学生端通用分发器就可能走入完全不同的命令分支。调试时若出现与鼠标无关的窗口或系统提示,应先停止发送,重新核对事务边界,而不是继续猜键码。


十三、实现中的防崩溃与可观测性设计

协议能跑通不等于实现足够稳。当前版本加入了以下约束:

  • view_probe 只做 TCP connect 探测,不发送 feature 8 或 SHCO;
  • 每个学生 IP 同时只允许一个 RemoteViewSession;
  • 正式观看只进行一次 TCP 连接,不循环轰炸学生端;
  • 连接/接收失败后发送停止 feature,并进入 60 秒冷却;
  • UMSP payload 和桌面 record 都有长度上限与越界检查;
  • 未完成分片数量受限,重复字节不重复计数;
  • H.264 原始流按会话独立保存;
  • control 必须等待 TCP 会话 connected event;
  • MCMD 后等待接收线程初始化,再发送首个输入包;
  • 远控可用 TEACHER_ENABLE_REMOTE_CONTROL=0 紧急禁用;
  • 日志区分“捕获”“发包”“远端 SPUC 反馈”,避免把不同证据混成一句成功。

建议保留的关键日志字段:

text
[RemoteView] feature start / stop
[RemoteView] TCP connected, SHCO channel
[RemoteView] frame_seq / offset / total
[RemoteView] record magic / declared size / rect / frame type
[RemoteControl] MCMD mode / UDP endpoint
[RemoteControl] input count / kind / exact 28-byte hex
[RemoteControl] SPUC x / y / timestamp

日志必须限频。鼠标 move 可能达到每秒上百次,全量 INFO 不仅难读,还会反过来增加延迟;当前实现只详细记录前几包、关键按键和周期性样本。


十四、当前结论与下一步

连续投屏链路已经形成闭环:

text
IDA 定位 feature 8 和 UMSP
  -> 抓包确认 SHCO/TKPC/channel 10
  -> 重组桌面分片
  -> 识别 HHRF/HJRF/SPUC
  -> FFmpeg 解码、U/V 修正、visible rect 裁剪
  -> Pillow/Tk 内嵌交互窗口

远程鼠标也形成了从 MCMD 建立接收器到 28 字节输入包、学生端实际动作、SPUC 位置反馈的闭环。

键盘尚未闭环。当前研究最重要的结论不是“再换一个键码试试”,而是已经明确缺失的证据位于学生端接收分支到 Windows 输入桌面之间。下一阶段应优先补动态观测和返回值证据,再决定是否修改 kind=16 字段。

逆向协议真正有价值的部分,不是记住几个 magic 和 offset,而是把每个结论绑定到可重复的证据:反汇编交叉引用说明代码如何读,抓包说明线上如何写,日志说明我们的实现走到了哪一层,远端可见行为才说明功能最终生效。

这也是本项目在 README 中坚持区分“已验证”“可用”“部分验证”和“实验性”的原因。


附录 A:协议层级速查

text
MESS feature 8 (5512/UDP)
└── 617-byte remote-view payload

4806/TCP
└── UMSP
    ├── SHCO: select channel 10
    └── TKPC
        └── channel 10
            └── desktop fragment: seq + offset + total
                ├── HHRF: H.264 Annex-B
                ├── HJRF: JPEG
                ├── HMRF: legacy record
                └── SPUC: cursor position

COMD transaction (4705/UDP)
└── MCMD mode 0/1/2 + student input UDP port
    └── 28-byte input packet
        ├── kind=1: mouse
        └── kind=16: keyboard (experimental)

附录 B:运行命令

text
view_probe <ip>       # 只探测 4806/TCP
view <ip>             # 启动连续观看
control <ip>          # 在观看会话上启用远控
control_stop <ip>     # 停止输入模拟
view_stop <ip>        # 停止桌面流

请先执行 view_probe,并只在自己拥有管理权限或已获得明确授权的设备上测试。

云散皆星河

行至水穷处,坐看云起时

评论 0

发表评论
评论需要审核后才会显示

还没有评论,来说点什么吧。