From bb817b85e5fa681f710033b10b1bbe1bac65cfd4 Mon Sep 17 00:00:00 2001 From: tianmo Date: Fri, 16 Oct 2026 18:30:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=98=A0=E5=B0=84=E8=A1=A8=EF=BC=9A=E7=94=A8?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=99=A8=E8=87=AA=E5=B8=A6=E7=9A=84=20JSON?= =?UTF-8?q?=20=E5=AF=BC=E5=87=BA=E5=99=A8(sB)=E5=8F=8D=E6=9F=A5=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=90=AB=E4=B9=89=EF=BC=88=E6=9D=83=E5=A8=81=E5=AF=B9?= =?UTF-8?q?=E7=85=A7=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 依据:导出 JSON 时每个 key 后面紧跟被读的字段,所以 key 名就是字段语义。 - 可读载荷 spine398.jar(DecAll 产出)javap -c sB 能直接看到 key 紧跟 getfield; - 未解密载荷用 strings.tsv(class sB, method D) 的密文顺序核对,281 条顺序逐条一致(三段解密器各自成组)。 新增:Gp(骨骼) length/transform/skin;GU(插槽) color/dark/attachment/blend(注意是 B 不是 D); 各附件 GO/GE/Gx/Gr/Gs 与附件基类 Gn;约束 Gw/GX/GD。 修正:删掉被导出器证伪的 Gp.Class=length 与'静姿态 setup 组'推断(C:F 就是 length)。 同步:names.tsv 合并成 297 条,payload-named.zip 重新产出。 --- tools/deobf/anchors.tsv | 144 ++++++++++++++++++++++++++++++++++++---- tools/deobf/names.tsv | 78 +++++++++++++++++++--- 混淆名对照表.md | 77 +++++++++++++++++++++ 3 files changed, 274 insertions(+), 25 deletions(-) diff --git a/tools/deobf/anchors.tsv b/tools/deobf/anchors.tsv index 237d966..076c045 100644 --- a/tools/deobf/anchors.tsv +++ b/tools/deobf/anchors.tsv @@ -38,27 +38,25 @@ Gp Code F scaleX Gp SourceFile F scaleY Gp StackMapTable F shearX Gp LineNumberTable F shearY -# 静止姿态(rest pose)那一组:值与默认姿态吻合(0,0,0,1,1,0),且未改动时与上面那组相等 —— 推断,留注释待复核 -Gp D F setupX -Gp B F setupY -Gp L F setupRotation -Gp I F setupScaleX -Gp S F setupScaleY -Gp C F setupShear +# 【已作废·未定】静止姿态(rest pose)那一组(D/B/L/I/S/C 的 float)原本只是"值与默认姿态吻合"的推断, +# 2026-10-16 被 JSON 导出器证伪:导出器写 length 用的就是 Gp.C:F(见文件末尾"JSON 导出器"一节)。 +# C 只能是 length,故整组推断不成立;这些字段的语义**目前未定**,不写进表里(宁可显示混淆名也不写错名)。 +# Gp D F setupX +# Gp B F setupY +# Gp L F setupRotation +# Gp I F setupScaleX +# Gp S F setupScaleY # 引用类字段:skeleton 由 hd.D(set, bone.D)+GP.D(LGp;) 的用法确定;parent 由创建骨骼时 bone.D=parent 确定 Gp D LGP; skeleton Gp D LGp; parent Gp B Lcom/badlogic/gdx/graphics/Color; color # ---- 2026-10-16 setup pose 实测补充(用户拍照:root/bone/slot/region 四种对象)---- -# Gp(root/bone):面板 Length=0.0 与 float Class=0.0 同;Ljava/java 与 Code/SourceFile 相等 → 世界缩放 -Gp Class F length -Gp Ljava F worldScaleX -Gp java F worldScaleY -# GU(插槽 mega_dg4):面板 Slot 属性只有 Name/Color;Inspector 里 String D=mega_dg4、Gp D=所属骨骼、Gn D=附件 +# 【已作废·未定】原写 Gp.Class:F=length / Ljava,java=worldScale*:都是"数值相等"的弱证据, +# 其中 length 已被 JSON 导出器改成 Gp.C:F(导出器写 length 时读的就是 C)。 +# 剩下 Class/Ljava/java/init/String 这几个 float 导出器一个都没用,语义未定,不写进表。 +# GU(插槽):面板 Slot 属性只有 Name/Color;Inspector 里 String D=mega_dg4、Gp D=所属骨骼 GU D Ljava/lang/String; name GU D LGp; bone -GU D LGn; attachment -GU D Lcom/badlogic/gdx/graphics/Color; color # GO(region 附件 mega_dg4):面板只有 Image path/Color;Inspector 六个 float 与 # Region 附件的 旋转49.00014 / 缩放(1.997,1.335) / 宽高(157,154) 一一对应 GO S F rotation @@ -130,3 +128,121 @@ GP Z LfI slots Gn I ()Ljava/lang/String; type # 附件上指向自己所属占位附件的引用:GP.removeAttachment 的占位分支按它级联删除 Gn D LHi; placeholderRef + +# ============================================================================ +# 【权威来源】编辑器自带的 JSON 导出器(载荷类 sB,2026-10-16) +# ---------------------------------------------------------------------------- +# 为什么权威:导出 JSON 时**每个 key 后面紧跟被读的那个字段**,key 名就是字段语义。 +# 证据链(两处独立,顺序逐条一致): +# 1) 可读载荷 ~/Desktop/spine398/spine398.jar(DecAll 产出:ldc 密文已换明文、解密调用已换 nop) +# `javap -p -c -cp spine398.jar sB` → `ldc "rotation"` 紧跟 `getfield Gp.F:F`,全部可读; +# 2) 未解密载荷 (payload-public.zip) 的 strings.tsv(class sB, method D):同一(类,方法)内 +# 密文顺序 = 字节码顺序,281 条与可读副本里的 key 顺序逐条对得上(含三组解密器)。 +# 导出器方法:sB.D(GP,boolean,boolean,gy,StringBuilder)=骨架;sB.D(gy,String,Gn,boolean)=附件。 +# 字段名重复(D/B/L/I/S…)时**必须按描述符取**,表里已经带描述符。 +# ============================================================================ + +# ---- Gp = 骨骼(导出器写 "bones" 段时读的就是这些)---- +Gp C F length +# ^ length 是 C(之前写的 Class:F 是错的,已作废) +Gp D LiC; transform +# ^ iC = 继承模式枚举(normal/onlyTranslation/noScale…) +Gp String Z skinOverride +# ^ 导出器写 key="skin"(布尔:该骨骼是否覆盖当前 skin) + +# ---- GU = 插槽(导出器写 "slots" 段)---- +GU B Lcom/badlogic/gdx/graphics/Color; color +# ^ 写 key="color" 读的是 B(不是 D) +GU I Lcom/badlogic/gdx/graphics/Color; darkColor +# ^ 写 key="dark" +GU I Z hasDarkColor +# ^ 写 "dark" 之前先看这个布尔开关 +GU B LGn; attachment +# ^ 写 key="attachment" 读的是 B(不是 D) +GU D Liz; blend +# ^ iz = 混合模式枚举 + +# ---- Gn = 附件基类 ---- +Gn D Ljava/lang/String; name + +# ---- GO = 图片(region)附件 ---- +GO D Lcom/badlogic/gdx/graphics/Color; color +GO B Ljava/lang/String; path +# ^ 导出器写 key="path",值取自静态取值器 GO.B(GO) + +# ---- GE = 点(point)附件 ---- +GE B Lcom/badlogic/gdx/graphics/Color; color +GE D F x +GE B F y +GE L F rotation + +# ---- Gx = 网格(mesh / linkedmesh)附件 ---- +Gx B Lcom/badlogic/gdx/graphics/Color; color +Gx B Ljava/lang/String; path +Gx D Lga; uvs +Gx D Lhp; triangles +Gx B LHl; vertices +Gx L I hull +# ^ 导出器写 hull = Gx.L / 2 +Gx D Lgf; edges +Gx StackMapTable Z deform +Gx D F width +# ^ 只在导出器带 extra 标志时写 +Gx B F height +Gx D LGx; parentMesh +# ^ 写 "parent" 时先取它(父网格附件) +Gx D LGT; skin +# ^ 写 "skin" 时取父网格的 skin +Gx D LHi; parentPlaceholder +# ^ 父网格的占位附件(Hi) +Gx D Ljava/lang/String; parentName +# ^ 写 "parent"(非 linkedmesh 分支) + +# ---- Gr = 包围盒(boundingbox)附件 ---- +Gr I Lga; vertexCount +Gr B LHl; vertices +Gr B Lcom/badlogic/gdx/graphics/Color; color + +# ---- Gs = 裁剪(clipping)附件 ---- +Gs I Lga; vertexCount +Gs B LHl; vertices +Gs B Lcom/badlogic/gdx/graphics/Color; color +Gs B LGU; end +# ^ 裁剪结束的那个插槽 + +# ---- Gw = IK 约束 ---- +Gw D Ljava/lang/String; name +Gw D LGp; target +Gw D F mix +Gw L F softness +Gw F Z uniform +Gw S Z stretch +Gw Z Z compress + +# ---- GX = 变换(transform)约束 ---- +GX D Ljava/lang/String; name +GX B LGp; target +GX SourceFile F rotation +GX S Z local +GX C Z relative +GX L F x +GX I F y +GX StackMapTable F scaleX +GX init F scaleY +GX LineNumberTable F shearY +GX S F rotateMix +GX D F translateMix +GX Z F scaleMix +GX F F shearMix + +# ---- GD = 路径(path)约束 ---- +GD D Ljava/lang/String; name +GD D LGU; target +GD D Ljm; positionMode +GD D Ljo; spacingMode +GD D Ljn; rotateMode +GD Z F rotation +GD D F position +GD V F spacing +GD S F rotateMix +GD L F translateMix diff --git a/tools/deobf/names.tsv b/tools/deobf/names.tsv index 7db3608..2fdc4dc 100644 --- a/tools/deobf/names.tsv +++ b/tools/deobf/names.tsv @@ -1,9 +1,25 @@ # 合并后的名字映射表:确定(=)指纹 + 手动/实测锚点 # owner name desc newName +GD D F position +GD D LGU; target +GD D Ljava/lang/String; name +GD D Ljm; positionMode +GD D Ljn; rotateMode +GD D Ljo; spacingMode +GD L F translateMix +GD S F rotateMix +GD V F spacing +GD Z F rotation +GE B F y +GE B Lcom/badlogic/gdx/graphics/Color; color +GE D F x +GE L F rotation GO B F y +GO B Ljava/lang/String; path GO C F width GO D (FFFFF)V setTransform GO D F x +GO D Lcom/badlogic/gdx/graphics/Color; color GO I F scaleY GO L F scaleX GO S F rotation @@ -11,34 +27,74 @@ GO Z F height GP L (LGn;ZZ)V removeAttachment GP L LfI attachments GP Z LfI slots -GU D LGn; attachment +GU B LGn; attachment +GU B Lcom/badlogic/gdx/graphics/Color; color GU D LGp; bone -GU D Lcom/badlogic/gdx/graphics/Color; color +GU D Liz; blend GU D Ljava/lang/String; name +GU I Lcom/badlogic/gdx/graphics/Color; darkColor +GU I Z hasDarkColor +GX B LGp; target +GX C Z relative +GX D F translateMix +GX D Ljava/lang/String; name +GX F F shearMix +GX I F y +GX L F x +GX LineNumberTable F shearY +GX S F rotateMix +GX S Z local +GX SourceFile F rotation +GX StackMapTable F scaleX +GX Z F scaleMix +GX init F scaleY Gn D LHi; placeholderRef +Gn D Ljava/lang/String; name Gn I ()Ljava/lang/String; type Gn L ()V delete -Gp B F setupY Gp B Lcom/badlogic/gdx/graphics/Color; color -Gp C F setupShear -Gp Class F length +Gp C F length Gp Code F scaleX Gp D (Ljava/lang/String;Z)V setName -Gp D F setupX Gp D LGP; skeleton Gp D LGp; parent +Gp D LiC; transform Gp D Ljava/lang/String; name Gp F F rotation -Gp I F setupScaleX -Gp L F setupRotation Gp LineNumberTable F shearY -Gp Ljava F worldScaleX -Gp S F setupScaleY Gp SourceFile F scaleY Gp StackMapTable F shearX +Gp String Z skinOverride Gp V F y Gp Z F x -Gp java F worldScaleY +Gr B LHl; vertices +Gr B Lcom/badlogic/gdx/graphics/Color; color +Gr I Lga; vertexCount +Gs B LGU; end +Gs B LHl; vertices +Gs B Lcom/badlogic/gdx/graphics/Color; color +Gs I Lga; vertexCount +Gw D F mix +Gw D LGp; target +Gw D Ljava/lang/String; name +Gw F Z uniform +Gw L F softness +Gw S Z stretch +Gw Z Z compress +Gx B F height +Gx B LHl; vertices +Gx B Lcom/badlogic/gdx/graphics/Color; color +Gx B Ljava/lang/String; path +Gx D F width +Gx D LGT; skin +Gx D LGx; parentMesh +Gx D LHi; parentPlaceholder +Gx D Lga; uvs +Gx D Lgf; edges +Gx D Lhp; triangles +Gx D Ljava/lang/String; parentName +Gx L I hull +Gx StackMapTable Z deform KP B ()Ljava/lang/String; getSelected KP B (I)V setSelectedIndex KP B (Ljava/lang/String;)V setSelected diff --git a/混淆名对照表.md b/混淆名对照表.md index c984762..8add26f 100644 --- a/混淆名对照表.md +++ b/混淆名对照表.md @@ -383,3 +383,80 @@ macOS 文件系统大小写不敏感,解到目录里会互相覆盖 —— 所 - 20 个新建插槽的图片附件:`x/y/rotation` 从 `-99.49988 / -302.0 / 40.00014`、`scaleX/scaleY` 从 `1.997 / 1.532` → 全部重置为 `0/0/0` 与 `1/1`(宽度高度 157x154 保持不变)。 - 20 个 `Hi` 占位附件全部删除;骨架附件表 `43 → 23`(正好 23 个插槽各 1 个图片附件)。 - 删除占位附件**不会**连带删掉图片附件:日志里逐个核对了"删除后该插槽当前附件=GO"。 + +--- + +## 九、权威对照:编辑器自带的 JSON 导出器(2026-10-16) + +**思路**:编辑器导出 Spine JSON 时,写 key 的那段代码里,key 后面紧跟的就是它读的那个字段。 +所以"JSON key ↔ 混淆字段"的对照不用猜,直接读导出器即可。这一节就是那份对照,**已确认**。 + +**导出器是谁**:载荷类 `sB`(构造骨架 JSON 的执行者),两个关键方法 + +| 方法 | 干什么 | +| --- | --- | +| `sB.D(GP, boolean, boolean, gy, StringBuilder)` | 写骨架 JSON:`bones` / `slots` / `ik` / `transform` / `path` / `skins` / `events` / `animations` | +| `sB.D(gy, String, Gn, boolean)` | 写一个附件(region / point / mesh / boundingbox / clipping) | + +**怎么拿到明文**(两条独立证据,顺序逐条一致): + +1. `~/Desktop/spine398/spine398.jar` 是可读载荷(`DecAll` 产出:`ldc 密文` 已换成明文、解密调用已换成 `nop`)。 + `javap -p -c -cp spine398.jar sB` 就能看到 `ldc "rotation"` 紧跟 `getfield Gp.F:F`。 +2. 未解密的载荷走 `strings.tsv`(`class sB, method D`,281 条):同一 (类, 方法) 内**密文顺序 = 字节码顺序**, + 与可读副本里的 key 顺序**逐条对得上**(该类的三段解密器 `za$Zr.J` / `aeB$Cp.I` / `aaQ$Wm.x` 各自成组、组内按方法顺序)。 + +### 骨骼 `Gp` + +| 字段(带描述符) | JSON key | 备注 | +| --- | --- | --- | +| `D:Ljava/lang/String;` | name | | +| `D:LGp;` | parent | 父骨骼 | +| `C:F` | **length** | ⚠️ 之前写的 `Class:F=length` 作废 | +| `F:F` | rotation | | +| `Z:F` / `V:F` | x / y | | +| `Code:F` / `SourceFile:F` | scaleX / scaleY | | +| `StackMapTable:F` / `LineNumberTable:F` | shearX / shearY | | +| `D:LiC;` | transform | `iC` = 继承模式枚举 | +| `String:Z` | skin | 布尔:该骨骼是否覆盖当前 skin | +| `B:Lcom/badlogic/gdx/graphics/Color;` | color | | + +> 同时**作废**了原先"静姿态那一组 `D/B/L/I/S/C` = setupX…"的推断:`C:F` 被导出器证明是 `length`, +> 那一组整体不成立,现在这些 float 的语义**未定**(宁可显示混淆名,也不写错名)。 + +### 插槽 `GU` + +| 字段(带描述符) | JSON key | 备注 | +| --- | --- | --- | +| `D:Ljava/lang/String;` | name | | +| `D:LGp;` | bone | 所属骨骼 | +| `B:Lcom/badlogic/gdx/graphics/Color;` | **color** | ⚠️ 是 `B`,不是 `D`(之前写错了) | +| `I:Lcom/badlogic/gdx/graphics/Color;` | dark | 二色染色的暗色 | +| `I:Z` | —("dark" 的开关) | 写 `dark` 之前先看它 | +| `B:LGn;` | **attachment** | ⚠️ 是 `B`,不是 `D`(之前写错了) | +| `D:Liz;` | blend | `iz` = 混合模式枚举 | + +### 附件(基类 `Gn` + 各子类) + +| 类 | 字段(带描述符) | JSON key | +| --- | --- | --- | +| `Gn` | `D:Ljava/lang/String;` | name(附件名) | +| `GO`(图片) | `D:Color` / `D:F` / `B:F` / `L:F` / `I:F` / `S:F` / `C:F` / `Z:F` / `B:Ljava/lang/String;` | color / x / y / scaleX / scaleY / rotation / width / height / path | +| `GE`(点) | `B:Color` / `D:F` / `B:F` / `L:F` | color / x / y / rotation | +| `Gx`(网格) | `B:Color` / `B:Ljava/lang/String;` / `D:Lga;` / `D:Lhp;` / `B:LHl;` / `L:I` / `D:Lgf;` / `StackMapTable:Z` / `D:F` / `B:F` | color / path / uvs / triangles / vertices / hull(=L/2) / edges / deform / width / height | +| `Gx`(linkedmesh 分支) | `D:LGx;` / `D:LGT;` / `D:LHi;` / `D:Ljava/lang/String;` | parentMesh / skin / parentPlaceholder / parentName | +| `Gr`(包围盒) | `I:Lga;` / `B:LHl;` / `B:Color` | vertexCount / vertices / color | +| `Gs`(裁剪) | `I:Lga;` / `B:LHl;` / `B:Color` / `B:LGU;` | vertexCount / vertices / color / end(结束插槽) | + +### 约束(顺带一起确认) + +| 类 | 字段 → key | +| --- | --- | +| `Gw`(IK) | `D:String`=name、`D:LGp;`=target、`D:F`=mix、`L:F`=softness、`F:Z`=uniform、`S:Z`=stretch、`Z:Z`=compress | +| `GX`(变换) | name、target(`B:LGp;`)、rotation(`SourceFile:F`)、local(`S:Z`)、relative(`C:Z`)、x(`L:F`)、y(`I:F`)、scaleX(`StackMapTable:F`)、scaleY(`init:F`)、shearY(`LineNumberTable:F`)、rotateMix(`S:F`)、translateMix(`D:F`)、scaleMix(`Z:F`)、shearMix(`F:F`) | +| `GD`(路径) | name、target(`D:LGU;` 是**插槽**)、positionMode(`D:Ljm;`)、spacingMode(`D:Ljo;`)、rotateMode(`D:Ljn;`)、rotation(`Z:F`)、position(`D:F`)、spacing(`V:F`)、rotateMix(`S:F`)、translateMix(`L:F`) | + +### 落表位置 + +以上全部写进了 `tools/deobf/anchors.tsv`(末尾"【权威来源】JSON 导出器"一节),再合并进 +`tools/deobf/names.tsv`(297 条),面板 Inspector 会按"真名(混淆名)"显示。 +重命名载荷也已同步产出:`/tmp/spinework/payload-named.zip`(4176 个类,5247 处成员引用)。