104 lines
6.0 KiB
Markdown
104 lines
6.0 KiB
Markdown
# MAG160C 官方 MAG-Cx 完整逆向结论(2026-09-10,jadx + Ghidra 全量解包)
|
||
|
||
> 产物来源:
|
||
> - Java 层:`analysis/sdk_re/android_app/jadx_magcx/`(jadx 1.5.1 反编译官方普通版 MAG-Cx.apk 全量源码)
|
||
> - Native 层:`analysis/sdk_re/android_app/libcxsdk_decomp.txt`
|
||
> (Ghidra 11.3.2 headless 全量反编译 lib/armeabi/libcxsdk.so,1290 函数)
|
||
> - libcoresdk(arm64) 反编译已在 `analysis/sdk_re/android_app/`(专业版/网络路径)
|
||
> - 本文结论全部来自以上反编译源码,与真机日志交叉验证(vivo V2509A, Android 16)。
|
||
|
||
## 1. USB 协议权威版(以官方 Java UsbCommunication.java 为准)
|
||
|
||
### 1.1 端点与超时
|
||
| 端点 | 方向 | 用途 | 超时 |
|
||
|---|---|---|---|
|
||
| 0x03 | OUT | 命令(4B 小端 magic;FFC/激光/帧率带参数) | 800ms |
|
||
| 0x82 | IN | 命令响应/ack(读 ≤64B) | 800ms |
|
||
| 0x81 | IN | 图像流(28B 头 + 38400B + 28B 尾) | 800ms |
|
||
| 0x84 | IN | 标定文件下载(16KB 块) | 800ms/块 |
|
||
| 0x05 | OUT | 向相机发送标定(SendCaliFile 上传方向,本项目暂不用) | 800ms |
|
||
|
||
**全部 800ms**(官方 `TIMEOUT` 常量)。响应缓冲 64B。
|
||
|
||
### 1.2 命令集(P2DCmd,全部 4 字节小端)
|
||
| 值 | 官方名 | 说明 |
|
||
|---|---|---|
|
||
| 0x6BB6B66B | GetParameter1 | → 0x5BB5B55B BasePara1(60B) |
|
||
| 0x6BB6B66C | GetParameter2 | → 0x5BB5B55C BasePara2(60B) |
|
||
| 0x6BB6B66D | SetParameter1 | 带 ack(64B 读) |
|
||
| 0x6BB6B66E | SetParameter2 | 带 ack |
|
||
| 0x6BB6B66F | GetCaliInfo | → 0x5BB5B55E {i32 size, i32 reserved, i64 date} |
|
||
| 0x6BB6B670 | GetCaliFile | ack 0x5BB5B55D,随后相机在 0x84 推标定文件 |
|
||
| 0x6BB6B671 | SendCaliFile | 上传方向(配 0x05 OUT) |
|
||
| 0x6BB6B672 | SetShutterState | FFC!8B {magic LE, u32 on LE} |
|
||
| 0x6BB6B673 | StartTransferImg | 开始推流,带 ack |
|
||
| 0x6BB6B674 | StopTransferImg | 停流,带 ack |
|
||
| 0x6BB6B675 | GetLifeTime | → 0x5BB5B561 {magic, i32 开机毫秒} |
|
||
| 0x6BB6B676 | SetLaserState | 8B(激光,非省电!) |
|
||
| 0x6BB6B677 | PowerSave | 8B |
|
||
| 0x6BB6B678 | GetFPAState | → 0x5BB5B562 |
|
||
| 0x6BB6B679 | SetFrameRate | 12B {magic, i32 interFrame, i32 interLine} |
|
||
|
||
D2P 响应魔数:5B=SendParameter1、5C=SendParameter2、5D=SendCaliFile、
|
||
5E=SendCaliInfo、61=SendLifeTime(均在 0x5BB5B5xx 空间)。
|
||
|
||
**注意**:0x6BB6B66B 是回文数(字节对称),因此历史上"66b 有响应、其余全无"
|
||
正是字节序反了的特征——非回文命令全部变成无效字节。`MagProtocolTest` 已锁死。
|
||
|
||
### 1.3 BasePara1(0x5BB5B55B payload,14×i32 = 56B)
|
||
int[0] serialNumber;int[1] hwVersion(低24位)|devType(高8位);
|
||
int[2] swVersion;int[4] fpaWidth;int[5] fpaHeight;int[6] fps;
|
||
int[8] fpaGain;int[9] fpaFlip;int[10] interFrame;int[11] interLine。
|
||
devType:0=c1, 1=c3, 2=c3p, **3=core160(MAG160C)**, 5=c1pro, 6=c1prolite。
|
||
|
||
### 1.4 官方连接序列(connect() + startTransfer())
|
||
```
|
||
1. write GetParameter1 → read 64B → BasePara1(失败则整个 connect 放弃)
|
||
2. write GetParameter2 → read → BasePara2
|
||
3. write GetCaliInfo → read → {size, reserved, date}
|
||
4. 缓存判定:{caliDir}/{productType}.{serial}.{date} 存在且长度==size
|
||
├─ 命中:直接 startTransfer()
|
||
└─ 未命中:启动 ThreadCaliRecv(0x84 连续读,16KB/块,无数据 5s 放弃)
|
||
→ sleep 50ms → write GetCaliFile(670)(waitForCmdAck 读 ack)
|
||
→ 收满 size 字节存盘 → startTransfer(caliPath)
|
||
5. startTransfer:
|
||
a. native startProcess(w, h, serial, devType, shutterClose/OpenSpeed,
|
||
ffcTriggerFrame, ffcTriggerTemperature, paletteIndex, baseLineAcc,
|
||
caliPath) ← libcxsdk Controller::StartProcess → LoadCalibrationTable
|
||
(caliPath),加载失败即 startProcess 失败并删除缓存文件
|
||
b. native setEX / getExtParameter+setExtParameter(dwFlip) / setAutoEnlarge
|
||
(全部 native,不占 USB)
|
||
c. 启动 ThreadImgRecv + ThreadImgProcess → sleep 5ms
|
||
→ write StartTransferImg(673)(waitForCmdAck 读 ack)
|
||
```
|
||
|
||
### 1.5 图像流帧结构(与 FrameStream/管线一致)
|
||
28B 头:0x1BB1B11B, frameIndex, dataLen(=w*h*2), type(0/1), period, 保留×3。
|
||
38400B u16LE 像素。
|
||
28B 尾:0x1BB1B11C, frameIndex, fpaTemp, intDrop(=type), reserved[2]。
|
||
官方 ThreadImgRecv:搜头→凑满 frameBytes→校验尾→drop∈{0,1} 才交给处理线程;
|
||
fpaTemp 在尾 +8(devType0/5/6/3),camTemp=fpaTemp-500。
|
||
|
||
### 1.6 FFC 触发(官方逻辑)
|
||
- 双击/消息(MSG_TRIGGER_FFC)→ SetShutterState(672);
|
||
- 每 16 帧查 GetLifeTime(675):devType1/2 按 6.5s/13s/19.5s/26s 档位触发 FFC;
|
||
**devType0/5/6/3(含 core160)该路径不自动 FFC**(仅温度稳定标志)。
|
||
- 本项目管线内部 FFC 调度(onFfc→672)为等效实现,且 672 相机随时接受。
|
||
|
||
## 2. 本项目复刻状态(IrSession.kt = 官方 UsbCommunication 等价物)
|
||
- 连接序列 1-5 已逐行复刻(含 0x84 拉取、缓存 files/cali/{product}.{serial}.{date});
|
||
- 命令打包小端(与官方 intToByteArray 一致)——**历史上 cmd4/cmd8 用
|
||
ByteBuffer.putInt 默认大端导致非回文命令全部反转**(16 轮黑屏的根因,
|
||
MagProtocolTest 锁死);
|
||
- usfs 坑:bulk 读超时后端点被标 halted,后续传输全部瞬间失败,须每次失败后
|
||
CLEAR_HALT(IrSession.diagnoseEndpoint);
|
||
- 会话互斥(同一时刻仅一个 IrSession 持有相机)+ DETACHED 释放 + 去抖。
|
||
|
||
## 3. 工具与环境(2026-09-10 本机)
|
||
- jadx 1.5.1:C:\Tools\jadx-1.5.1(反编译产物 C:\Tools\jadx-out,已拷贝入库
|
||
analysis/sdk_re/android_app/jadx_magcx/)
|
||
- Ghidra 11.3.2:C:\Tools\ghidra_11.3.2_PUBLIC;工程 C:\Tools\ghidra_proj\MagCX;
|
||
全量反编译脚本 C:\Tools\ghidra_scripts_user\DumpAllDecomp.java
|
||
- 重跑命令(PowerShell/cmd):
|
||
`set JAVA_HOME=C:\Tools\jdk-21&& C:\Tools\ghidra_11.3.2_PUBLIC\support\analyzeHeadless.bat C:\Tools\ghidra_proj MagCX -process libcxsdk.so -scriptPath C:\Tools\ghidra_scripts_user -postScript DumpAllDecomp.java <输出文件>`
|