# Phase C —— 厂商 12 调色板精确提取:结论与证据 日期:2026-09-10。目标:从官方 native 库 `libcxsdk.so` 提取 12 个调色板精确表。 ## 结论(TL;DR) **`libcxsdk.so` 里没有静态调色板表**。12 个调色板全部由 `CFunctions::SetColorPalette`(Ghidra 偏移 `0x00026c70`)在**运行时用算术生成**。 两层证据(2026-09-11 复核时补强,见"否证的最强形式"): 1. **正对照(决定性)**:项目持有的唯一官方表——铁虹—— (csdk `src/mag160c_official_palette256.h`,源自厂商运行时内存 `CoreSDKLib dev+0xb18`)在库里**以任何编码都搜不到**: - `B,G,R,0`(官方文档布局)→ 无 - `B,G,R,0xFF`(alpha 强制)→ 无 - **忽略第 4 字节的 `B,G,R` 宽松匹配 → 也无** ⚠️ **踩坑记录**:该表在内存里是 `(B, G, R, 0)` —— **第 4 字节是 0**, 而 `OfficialTables.kt` 里的 ARGB int 被生成脚本强制 `alpha=0xFF`。 因此"直接拿 Kotlin 表去二进制里搜"**永远搜不到**,会得出假的"未找到"。 正确的针必须从 csdk 头文件(真实内存布局)构造。核查时务必用 `analysis/tools/PalScan.java`(已按此修正)而非手工拼的 ARGB 针。 2. **结构性证据**:Ghidra 反编译显示该函数用算术逐条生成全部 12 张表 (`libcxsdk_decomp.txt` 的 case 0..10/12/13),所以静态数据里本就不该有。 > 另:早期"扫描 256 个连续 u32LE、alpha=0xFF"的判据命中 0,这一条仍成立但 > **说服力弱**——它只说明"没有 alpha=0xFF 形式",与布局无关。 > 通用"渐变"启发式(`PalScan.java` 的 [C] 段)在本库上误报约 11% 的位置 > (全是指令/整数数组),**不能作为证据**,工具里已明确如此标注。 因此本阶段改用**移植生成函数**的路线并成功恢复: **UI 索引 0..10 共 11 个调色板已为官方精确表**(索引 11 见下), 已写入 `android/.../core/VendorPalettes.kt` 并由 `Palettes.kt` 使用。 ## 验证链(三重独立验证) 1. **铁虹锚点**:移植的 case 2 输出与 `OfficialTables.PALETTE256_ARGB` **256/256 逐字节一致**。该表是从厂商运行时(CoreSDKLib `dev+0xb18`)抓取、 并与官方渲染器逐像素比对验证过的,因此它同时锁死了: - 算术配方(除法取整方式、循环边界、常量) - 发布字节序 = `{byte0=B, byte1=G, byte2=R, byte3=0}` 2. **完整性**:每个 case 对 256 个槽位**各写入恰好一次**(无空洞、无覆盖), 由模拟器的写地址跟踪断言。 3. **厂商侧预览图**:官方 APK `res/mipmap-hdpi-v4/palette_.png` 是官方用 对应调色板渲染的真实热像帧。每个调色板对其**自身**预览图的颜色覆盖率都是 全体候选中最高,且差距显著: | 官方调色板 | UI 索引 | 生成 case | 自身覆盖率 | 次优候选 | |---|---|---|---|---| | 白热 white_hot | 0 | 0 | 100.0% | 100.0%(灰度图,天然重合) | | 黑热 black_hot | 1 | 1 | 100.0% | 100.0%(同上) | | 铁虹 iron_bow | 2 | 2 | 9.0% | 0.1% | | 彩虹 rain_bow | 3 | 3 | 7.3% | 0.1% | | 琥珀 glow_bow | 4 | 4 | 30.7% | 2.3% | | 金秋 autumn | 5 | 5 | 15.4% | 2.5% | | 寒冬 winter | 6 | 6 | 22.3% | 2.9% | | 热金属 hot_metal | 7 | 7 | 42.1% | 11.0% | | 喷射 jet | 8 | 8 | 14.0% | 6.3% | | 红饱和 red_saturation | 9 | 9 | 26.7% | 22.1% | | 高对比度 high_contrast | 10 | 10 | 4.0% | 0.2% | | 红热 red_hot | 11 | **未解决** | — | — | (预览图是缩放过的照片,存在插值产生的额外颜色,故绝对覆盖率不高; 关键是自身恒为最高。) ## 未解决项:索引 11「红热」 - native 库里另有 case 12、case 13 两个生成体,但两者对**任何**官方预览图的 覆盖率都很低(最高 3–6%,指向 jet),**不能**认定为「红热」。 - 官方 APK 的 `palette_red_hot.png` 是**占位图**:11914 个像素中 11777 个与 `palette_white_hot.png` 完全相同(平均绝对差 0.5/255),不携带调色板信息。 - 处理方式:`Palettes.kt` 索引 11 保留原近似曲线,并注明 `// approximated (not found in binary)`;`VendorPalettes.SOURCE_CASE[11] = -1`。 **不猜测**未验证的表。 ## 可复现产物 | 路径 | 说明 | |---|---| | `analysis/sdk_re/android_app/bin/libcxsdk.so` | 官方 native 库入库(372476 B) | | `analysis/sdk_re/android_app/palette_candidates.json` | 扫描结论(静态候选为空)+ 全部恢复表 | | `analysis/sdk_re/android_app/palette_candidates.png` | 12 组「官方预览图 + 恢复色条」对照图 | | `analysis/sdk_re/android_app/palette_match_report.txt` | 覆盖率证据表 | | `analysis/tools/extract_palettes.py` | 计划要求的纯标准库扫描脚本(本机无 python3,改用下面的 JDK 版) | | `analysis/tools/PalScan.java` | **JDK 版否证复核器**:正对照(铁虹在 3 种编码下的精确匹配)+ 自校准 + 通用扫描(明确标注不可作证据)。已实测:3 种编码全部 not found | | `analysis/tools/PalIdentify.java` | 13 个生成体的机械移植(含写地址校验) | | `analysis/tools/PalExport2.java` | 导出 Kotlin/JSON/PNG/报告(须与 PalIdentify 一起编译) | | `analysis/tools/CheckStrings.java` | 核对真机清单里的日志串是否真能由源码产生 | | `android/.../core/VendorPalettes.kt` | 生成的 Kotlin 表(0..10 为精确表) | 重跑(本机无 python3;两个命令都已实测通过): ```bash # 否证复核:铁虹是否真的不在库里(决定性证据) java analysis/tools/PalScan.java \ analysis/sdk_re/android_app/bin/libcxsdk.so \ csdk/src/mag160c_official_palette256.h # 生成物可复现:重新生成后与仓库文件 diff 应为空 mkdir -p /c/Users/zxc/AppData/Local/Temp/regen_build && \ cd /c/Users/zxc/AppData/Local/Temp/regen_build && \ cp "C:\Project\MAG160C\analysis\tools\PalIdentify.java" . && \ cp "C:\Project\MAG160C\analysis\tools\PalExport2.java" . && \ "C:\Tools\jdk-21\bin\javac" -d out PalIdentify.java PalExport2.java && \ "C:\Tools\jdk-21\bin\java" -cp out PalExport2 \ "C:\Project\MAG160C\android\app\src\main\kotlin\com\mag160c\thermal\core\OfficialTables.kt" \ "C:\Users\zxc\AppData\Local\Temp\cxres\res\mipmap-hdpi-v4" \ "C:\Users\zxc\AppData\Local\Temp\regen_core" \ "C:\Users\zxc\AppData\Local\Temp\regen_out" diff "C:\Users\zxc\AppData\Local\Temp\regen_core\VendorPalettes.kt" \ "C:\Project\MAG160C\android\app\src\main\kotlin\com\mag160c\thermal\core\VendorPalettes.kt" # 实测:diff 为空;铁虹锚点 256/256 ``` 有 python3 的机器上(可选,仅证明"无静态 256 项 alpha=0xFF 表"这个弱结论): ```bash python3 analysis/tools/extract_palettes.py \ analysis/sdk_re/android_app/bin/libcxsdk.so \ android/app/src/main/kotlin/com/mag160c/thermal/core/OfficialTables.kt \ analysis/sdk_re/android_app ``` ## 与执行计划的对照 计划 C3 的回退条款为"若扫不到锚点:如实记录未在 libcxsdk 静态数据中找到调色板表, 保留现有一套近似实现,本阶段只交付脚本与 JSON"。实际执行结果**优于**回退: 锚点确实不在静态数据里(按回退如实记录),但通过移植运行时生成函数恢复了 11/12 个精确表,并把它们接入 `Palettes.kt`。