求助大神

我也是新手,之前拼过一次而已

楼下大佬出整理工具了

2 个赞

楼上的key是android版,网页版的资源key是*web-desktop_dmm*+文件签名后的后4个bytes(也是每三位按序异或一次)
文件名看上去还是走的cocos2d的内部处理模式,不过就是加了salt然后md5了一下,如果相关的东西还是走的cocos2d的资源管理,那么应该能用我写的这套东西处理,不过要改点东西配合它的魔改。有空再验证,非占坑,欢迎其他大佬来搞

他的atlas在json里例如\assets\assets\5a229a3a1dcb7631b81335e558793161\import\01\01b9e20c2.json
内容如

[1,["5ejbp0nDpJvZGKD6jsCzVj","11xr5HVD1JjKeHmNQIxzB3@6c48a"],["node","root","data","_skeletonData"],[["cc.Prefab",["_name"],2],["cc.Node",["_name","_components","_prefab","_lscale"],2,9,4,5],["cc.UITransform",["node","__prefab","_contentSize"],3,1,4,5],["cc.CompPrefabInfo",["fileId"],2],["sp.Skeleton",["_preCacheMode","defaultSkin","defaultAnimation","node","__prefab","_skeletonData"],0,1,4,6],["cc.PrefabInfo",["fileId","root","asset"],2,1,1],["sp.SkeletonData",["_name","_native","_atlasText","textureNames","textures"],-1,3]],[[3,0,2],[0,0,2],[1,0,1,2,3,2],[2,0,1,2,1],[4,0,1,2,3,4,5,4],[5,0,1,2,2],[6,0,1,2,3,4,5]],[[[[1,"1400168"],[2,"1400168",[[3,-2,[0,"6dRm6qnPNH1JRC4X1NVkUd"],[5,699.4560546875,873.743896484375]],[4,0,"default","idle",-3,[0,"b939LJ3FNEFY9FbqA5GR6p"],0]],[5,"3dLqephGhIfoxCwmLSO4dd",-1,0],[1,0.15,0.15,1]]],0,[0,1,1,0,0,1,0,0,1,0,2,1,3],[0],[3],[0]],[[[6,"1400168",".bin","\n1400168.png\nsize: 2048,1024\nformat: RGBA8888\nfilter: Linear,Linear\nrepeat: none\nA_NLU_31\n  rotate: true\n  xy: 817, 448\n  size: 34, 51\n  orig: 34, 51\n  offset: 0, 0\n  index: -1\nA_NLU_32\n  rotate: true\n  xy: 796, 4\n  size: 35, 59\n  orig: 35, 59\n  offset: 0, 0\n  index: -1\nA_NLU_33\n  rotate: true\n  xy: 817, 484\n  size: 32, 78\n  orig: 32, 78\n  offset: 0, 0\n  index: -1\nA_NLU_34\n  rotate: false\n  xy: 1314, 349\n  size: 30, 102\n  orig: 30, 102\n  offset: 0, 0\n  index: -1\nA_NLU_35\n  rotate: false\n  xy: 983, 260\n  size: 112, 75\n  orig: 112, 75\n  offset: 0, 0\n  index: -1\nA_NLU_36\n  rotate: false\n  xy: 1214, 262\n  size: 71, 73\n  orig: 71, 73\n  offset: 0, 0\n  index: -1\nA_NLU_37\n  rotate: true\n  xy: 207, 5\n  size: 227, 139\n  orig: 227, 139\n  offset: 0, 0\n  index: -1\nA_NLU_39\n  rotate: false\n  xy: 2, 234\n  size: 307, 788\n  orig: 309, 789\n  offset: 0, 0\n  index: -1\nA_NLU_40\n  rotate: true\n  xy: 311, 448\n  size: 574, 504\n  orig: 574, 504\n  offset: 0, 0\n  index: -1\nA_NLU_41\n  rotate: false\n  xy: 1679, 149\n  size: 300, 388\n  orig: 300, 389\n  offset: 0, 0\n  index: -1\nA_NLU_42\n  rotate: true\n  xy: 817, 518\n  size: 504, 488\n  orig: 509, 488\n  offset: 0, 0\n  index: -1\nA_NLU_43\n  rotate: true\n  xy: 490, 16\n  size: 220, 113\n  orig: 223, 113\n  offset: 0, 0\n  index: -1\nA_NLU_46\n  rotate: true\n  xy: 782, 253\n  size: 193, 113\n  orig: 203, 119\n  offset: 0, 4\n  index: -1\nA_NLU_48\n  rotate: true\n  xy: 1387, 112\n  size: 157, 290\n  orig: 157, 290\n  offset: 0, 0\n  index: -1\nA_NLU_51\n  rotate: true\n  xy: 1015, 3\n  size: 65, 89\n  orig: 65, 89\n  offset: 0, 0\n  index: -1\nA_NLU_52\n  rotate: false\n  xy: 1861, 62\n  size: 67, 85\n  orig: 67, 85\n  offset: 0, 0\n  index: -1\nA_NLU_53\n  rotate: true\n  xy: 920, 3\n  size: 65, 93\n  orig: 65, 93\n  offset: 0, 0\n  index: -1\nA_NLU_54\n  rotate: false\n  xy: 1097, 261\n  size: 115, 74\n  orig: 115, 74\n  offset: 0, 0\n  index: -1\nA_NLU_55\n  rotate: true\n  xy: 1328, 18\n  size: 50, 82\n  orig: 50, 82\n  offset: 0, 0\n  index: -1\nA_NLU_56\n  rotate: false\n  xy: 1187, 7\n  size: 40, 61\n  orig: 40, 61\n  offset: 0, 0\n  index: -1\nA_NLU_57\n  rotate: false\n  xy: 898, 70\n  size: 487, 182\n  orig: 487, 184\n  offset: 0, 2\n  index: -1\nA_NLU_59\n  rotate: false\n  xy: 1307, 539\n  size: 380, 483\n  orig: 391, 485\n  offset: 10, 0\n  index: -1\nNLU_0\n  rotate: false\n  xy: 348, 3\n  size: 50, 7\n  orig: 50, 7\n  offset: 0, 0\n  index: -1\nNLU_1\n  rotate: false\n  xy: 1314, 477\n  size: 41, 29\n  orig: 41, 29\n  offset: 0, 0\n  index: -1\nNLU_10\n  rotate: true\n  xy: 897, 254\n  size: 262, 84\n  orig: 262, 84\n  offset: 0, 0\n  index: -1\nNLU_11\n  rotate: true\n  xy: 722, 2\n  size: 37, 72\n  orig: 37, 72\n  offset: 0, 0\n  index: -1\nNLU_12\n  rotate: false\n  xy: 605, 17\n  size: 115, 219\n  orig: 115, 219\n  offset: 0, 0\n  index: -1\nNLU_13\n  rotate: false\n  xy: 311, 236\n  size: 127, 210\n  orig: 127, 210\n  offset: 0, 0\n  index: -1\nNLU_14\n  rotate: false\n  xy: 1371, 271\n  size: 117, 266\n  orig: 117, 266\n  offset: 0, 0\n  index: -1\nNLU_15\n  rotate: false\n  xy: 722, 41\n  size: 79, 201\n  orig: 79, 201\n  offset: 0, 0\n  index: -1\nNLU_16\n  rotate: false\n  xy: 348, 12\n  size: 140, 222\n  orig: 140, 222\n  offset: 0, 0\n  index: -1\nNLU_17\n  rotate: false\n  xy: 440, 238\n  size: 199, 208\n  orig: 199, 208\n  offset: 0, 0\n  index: -1\nNLU_18\n  rotate: true\n  xy: 1229, 16\n  size: 52, 28\n  orig: 58, 30\n  offset: 0, 2\n  index: -1\nNLU_18_1\n  rotate: false\n  xy: 857, 6\n  size: 61, 55\n  orig: 61, 55\n  offset: 0, 0\n  index: -1\nNLU_19\n  rotate: false\n  xy: 400, 3\n  size: 23, 7\n  orig: 27, 9\n  offset: 1, 2\n  index: -1\nNLU_2\n  rotate: true\n  xy: 1679, 115\n  size: 32, 24\n  orig: 33, 26\n  offset: 0, 1\n  index: -1\nNLU_20\n  rotate: false\n  xy: 1314, 508\n  size: 49, 29\n  orig: 49, 29\n  offset: 0, 0\n  index: -1\nNLU_21\n  rotate: true\n  xy: 490, 2\n  size: 12, 9\n  orig: 12, 9\n  offset: 0, 0\n  index: -1\nNLU_22\n  rotate: false\n  xy: 870, 452\n  size: 25, 30\n  orig: 25, 31\n  offset: 0, 1\n  index: -1\nNLU_23\n  rotate: true\n  xy: 1259, 16\n  size: 52, 26\n  orig: 52, 27\n  offset: 0, 1\n  index: -1\nNLU_24\n  rotate: false\n  xy: 1314, 453\n  size: 41, 22\n  orig: 41, 22\n  offset: 0, 0\n  index: -1\nNLU_25\n  rotate: false\n  xy: 803, 45\n  size: 22, 16\n  orig: 22, 17\n  offset: 0, 1\n  index: -1\nNLU_26\n  rotate: true\n  xy: 1346, 423\n  size: 28, 22\n  orig: 28, 22\n  offset: 0, 0\n  index: -1\nNLU_27\n  rotate: false\n  xy: 2, 5\n  size: 203, 227\n  orig: 220, 227\n  offset: 0, 0\n  index: -1\nNLU_27_1\n  rotate: false\n  xy: 1287, 17\n  size: 39, 51\n  orig: 39, 51\n  offset: 0, 0\n  index: -1\nNLU_28\n  rotate: false\n  xy: 641, 244\n  size: 139, 202\n  orig: 139, 202\n  offset: 0, 0\n  index: -1\nNLU_3\n  rotate: true\n  xy: 1705, 116\n  size: 31, 24\n  orig: 32, 25\n  offset: 0, 1\n  index: -1\nNLU_4\n  rotate: true\n  xy: 1346, 394\n  size: 27, 22\n  orig: 28, 22\n  offset: 0, 0\n  index: -1\nNLU_5\n  rotate: false\n  xy: 1772, 37\n  size: 87, 110\n  orig: 87, 110\n  offset: 0, 0\n  index: -1\nNLU_6\n  rotate: true\n  xy: 1106, 3\n  size: 65, 79\n  orig: 65, 79\n  offset: 0, 0\n  index: -1\nNLU_7\n  rotate: true\n  xy: 1287, 266\n  size: 69, 82\n  orig: 69, 82\n  offset: 0, 0\n  index: -1\nNLU_8\n  rotate: true\n  xy: 803, 63\n  size: 188, 93\n  orig: 188, 93\n  offset: 0, 0\n  index: -1\nNLU_9\n  rotate: true\n  xy: 983, 337\n  size: 179, 329\n  orig: 179, 329\n  offset: 0, 0\n  index: -1\nm1\n  rotate: false\n  xy: 1412, 8\n  size: 118, 102\n  orig: 118, 102\n  offset: 0, 0\n  index: -1\nm2\n  rotate: false\n  xy: 1532, 16\n  size: 118, 94\n  orig: 118, 94\n  offset: 0, 0\n  index: -1\nm3\n  rotate: false\n  xy: 1652, 16\n  size: 118, 94\n  orig: 118, 94\n  offset: 0, 0\n  index: -1\n",["1400168.png"],[0]],-1],0,0,[0],[-1],[1]]]]

使用这个代码

BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
BASE64_VALUES = [0] * 128
for idx, char in enumerate(BASE64_CHARS):
    BASE64_VALUES[ord(char)] = idx

HEX_CHARS = list('0123456789abcdef')
_t = ['', '', '', '']
UUID_TEMPLATE = _t + _t + ['-'] + _t + ['-'] + _t + ['-'] + _t + ['-'] + _t + _t + _t
INDICES = [i for i, x in enumerate(UUID_TEMPLATE) if x != '-']


def decode_uuid(base64_str):
    if len(base64_str) != 22:
        return base64_str
    result = UUID_TEMPLATE.copy()

    result[0] = base64_str[0]
    result[1] = base64_str[1]

    j = 2
    for i in range(2, 22, 2):
        lhs = BASE64_VALUES[ord(base64_str[i])]
        rhs = BASE64_VALUES[ord(base64_str[i + 1])]

        result[INDICES[j]] = HEX_CHARS[lhs >> 2]
        j += 1
        result[INDICES[j]] = HEX_CHARS[((lhs & 3) << 2) | (rhs >> 4)]
        j += 1
        result[INDICES[j]] = HEX_CHARS[rhs & 0xF]
        j += 1

    return ''.join(result)

input_str = "5ejbp0nDpJvZGKD6jsCzVj"
decoded = decode_uuid(input_str)
print(decoded)

还原5ejbp0nDpJvZGKD6jsCzVj的uuid得到5e8dba74-9c3a-49bd-918a-0fa8ec0b3563
在\assets\assets\5a229a3a1dcb7631b81335e558793161\native\5e下存在5e8dba74-9c3a-49bd-918a-0fa8ec0b3563.bin打开发现符合spine的skel文件内容,至于图片json文件里给的是png图片名而这游戏的图片资源都是astc怀疑有地方会根据png名字匹配astc文件,具体可以解密\assets\assets\main下的index.jsc审计代码试试或者纯干撸so二进制文件逆向找到png和astc的关系
贴一个可能有用的链接https://github.com/cocos/cocos-engine/blob/v2.4.3-bufang/cocos2d/core/utils/decode-uuid.js
在分析so文件找到了jsc的xxtea解密密钥为dfSGHYk0tLJKqzrl



他采用了远程包加载
而且js脚本使用了高度混淆
如果你只想还原R18的这里有段代码

System.register("chunks:///_virtual/SpineStandNames.ts",["./_rollupPluginModLoBabelHelpers.js","cc"],(function(e){"use strict";var t,n;return{setters:[function(e){t=e.defineProperty},function(e){n=e.cclegacy}],execute:function(){n._RF.push({},"8ef03lj7CZLp4XAhEqm4bGm","SpineStandNames",void 0);class s{}e("SpineStandNames",s),t(s,"FileNameList",["12091","1002","1003","1004","1005","1006","1007","1008","1009","20008","1011","1012","1013","1015","1016","1017","1018","1019","1021","1023","1024","1025","1027","1030","20001","1033","1034","1035","1036","1037","1038","1039","1040","1047","30009","1058","1059","1062","1063","1064","1065","1066","1067","1068","1069","1070","1071","1072","1073","1074","1075","1084","1085","100001","100002","100003","100004","10001","10002","10003","10004","10005","10006","10007","10008","10009","10010","10011","10012","10013","10014","10015","10016","10017","10018","10019","20002","20003","20004","20005","20006","20007","20009","20010","20011","20012","20013","20014","20015","20016","20017","20018","30001","30002","30003","30004","30005","30006","30007","30008","30010","30011","30012","30013","30014","30015","30016","30017","30018","40001","40002","40003","40004","40005","40006","40007","40008","40009","40010","40011","40012","40013","40014","40015","40016","40017","40018","40019","50001","50002","50003","50004","50005","50006","50007","50008","50009","50010","60001","60002","60003","60004","60005","60006","60007","60008","60009","1100040","1100041","1100042","1100050","1100051","1100052","1100060","1100061","1100062","1100070","1100071","1100072","1100080","1100081","1100082","1100090","1100091","1100092","1100100","1100101","1100102","1100110","1100111","1100112","1100120","1100121","1100122","1100130","1100131","1100132","1100140","1100141","1100142","1100150","1100151","1100152","1100153","1100159","1100160","1100161","1100162","1100170","1100171","1100172","1100180","1100181","1100182","1100190","1100191","1100192","1200040","1200041","1200042","1200050","1200051","1200052","1200060","1200061","1200062","1200070","1200071","1200072","1200080","1200081","1200082","1200090","1200091","1200092","1200100","1200101","1200102","1200110","1200111","1200112","1200120","1200121","1200122","1200130","1200131","1200132","1200140","1200141","1200142","1200150","1200151","1200152","1200160","1200161","1200162","1200170","1200171","1200172","1200180","1200181","1200182","1300040","1300041","1300042","1300050","1300051","1300052","1300060","1300061","1300062","1300070","1300071","1300072","1300080","1300081","1300082","1300090","1300091","1300092","1300100","1300101","1300102","1300110","1300111","1300112","1300120","1300121","1300122","1300130","1300131","1300132","1300140","1300141","1300142","1300150","1300151","1300152","1300160","1300161","1300162","1300170","1300171","1300172","1300180","1300181","1300182","1400040","1400041","1400042","1400050","1400051","1400052","1400060","1400061","1400062","1400070","1400071","1400072","1400080","1400081","1400082","1400090","1400091","1400092","1400100","1400101","1400102","1400110","1400111","1400112","1400120","1400121","1400122","1400130","1400131","1400132","1400140","1400141","1400142","1400150","1400151","1400152","1400160","1400161","1400162","1400170","1400171","1400172","1400180","1400181","1400182","1400190","1400191","1400192","1500020","1500021","1500022","1500030","1500031","1500032","1500040","1500041","1500042","1500050","1500051","1500052","1500060","1500061","1500062","1500070","1500071","1500072","1500080","1500081","1500082","1500090","1500091","1500092","1500100","1500101","1500102","1600010","1600011","1600012","1600020","1600021","1600022","1600030","1600031","1600032","1600040","1600041","1600042","1600050","1600051","1600052","1600060","1600061","1600062","1600070","1600071","1600072","1600080","1600081","1600082","1600090","1600091","1600092","100018","100028","100038","1100058","1100098","1100138","1100188","1100198","200018","200020","200038","1200058","1200118","1200128","1200178","300018","300028","300038","1300098","1300108","1300148","400018","400028","400038","1400088","1400168","1500010","1500048","1600028","1600048"]),n._RF.pop()}}}));

例如搜索1200102.png可以在0400f9e9c.json找到,通过uuid还原得到
skel是54f4ecf3-8f03-4b43-b394-92b3fbb796ff
再根据atlas信息得到图片长宽信息匹配到
62746128-79c77-cb8fa-94ff6-e240c7190
遇到长宽一样的我也没辙现在
例如1600048他的特征就是额。。。反正靠人力筛选png还原了

感谢各位大神思路跟分享资源

当然上面已经提到了怎么获取对应的skel文件,那么我们就可以使用spine打开,因为图片资源丢失画面都是missing的橙色填充,可以通过截图某个具有特征的插槽区域例如身体,利用opencv在指定长宽的文件中识别类似图像来尝试找到对应图像

把第二项11xr5HVD1JjKeHmNQIxzB3@6c48a 解uuid后去掉@以及后面的东西,再去加上扩展名和salt md5,然后相应位置插-号,就能得到图片文件名

dmm网页版的salt是428a2929a5e5f34dfe5d3aefea81caa6

if __name__ == '__main__':
    downloader = loadConfigAndCreate("https://b2v2-jp-prd-cdn.playrr.me/game2.0/jpdmm/web-desktopr/src/settings.eb45c.json")
    downloader.downloadAllManifest()
    # mjname = '2ced132d1ae1e5eaf349843e2c94029a'
    mjname = '5a229a3a1dcb7631b81335e558793161'
    # downloader.downloadAllFromManifest() # stand应该主要是上面这两个,全下有一部分下不下来
    mj = downloader.getMJfromName(mjname)
    downloader.downloadAllFromMJ(mj)
    mj.setRealPaths() # 少数没有用pack的可以直接和资源清单中的path对应,用了pack清单的有相应的asset但找不到和有path的空asset对应的地方,只能去通过解析import或pack清单的json获取信息。
    # print(mj.assetList) # 查看内部情况
    # print(mj.packinfoDict)

# config.py常量 (dmm网页版)
Asign = 'd29f2acf4a3d1ee0a806b694c4'
Akey = b'*web-desktop_dmm*'
SALT = b'428a2929a5e5f34dfe5d3aefea81caa6'
Unencrypted_extensions = {
    "js": True,
    "jsc": True,
    "mp3": True,
    "ogg": True,
    "wav": True,
    "m4a": True,
    "mp4": True,
    "avi": True,
    "mov": True,
    "mpg": True,
    "mpeg": True,
    "rm": True,
    "rmvb": True,
    "font": True,
    "eot": True,
    "ttf": True,
    "woff": True,
    "ttc": True,
    "svg": True
}


cocosasset_config =  {
            'downloader_weburl': '',
            'downloader_assetroot': 'https://b2v2-jp-prd-cdn.playrr.me/game2.0/jpdmm/web-desktopr/assets',  # 用于下载manifest的地址前缀
            'downloader_savepath': 'nabiAsset', # 保存位置
            'downloader_threadnum': 10,
            'asset_baseurl': 'https://b2v2-jp-prd-cdn.playrr.me/game2.0/jpdmm/web-desktopr/assets', # 用于manifestJson拼接的地址前缀
        }

你的意思是类似使用11xr5HVD1JjKeHmNQIxzB3解出11c6be47-543d-498c-a787-98d408c73077然后加上后缀例如.webm就是11c6be47-543d-498c-a787-98d408c73077.webm然后计算11c6be47-543d-498c-a787-98d408c73077.webm428a2929a5e5f34dfe5d3aefea81caa6的md5加上-?

不是很懂用你GitHub的代码下载了资源
例如0bSJZGSHdGgae12nB/ZN2A@6c48a
就是解出0bSJZGSHdGgae12nB/ZN2A → 0b489646-4877-4681-a7b5-da707f64dd80
使用0b489646-4877-4681-a7b5-da707f64dd80.png428a2929a5e5f34dfe5d3aefea81caa6
0b489646-4877-4681-a7b5-da707f64dd80.webm428a2929a5e5f34dfe5d3aefea81caa6
的md5都没有找到文件

请教一个问题,SALT是怎么获取的

抱歉我漏说了,还要加上资源清单中的version版本,此外网页版中格式都是webp

getHashedFilename('0b489646-4877-4681-a7b5-da707f64dd80.d8e45.webp')

得到23b1637a-d6790-56c88-13faf-57ab92aaa就能找到文件了
这一项是mj.assetList[36]

从那个application的js里找

ok看到了,不过不清楚为什么有些文件是丢失的365平台有部分丢失但是这个在线的丢的最多,而且有些图片打了码365的没有,话说你是怎么反混淆他的js代码获取盐值的

webcrack处理一下能稍微清晰点。可能有点马后炮,但其实不需要去混淆,这个值在混淆的代码中也只是从一个完整的字符串变成了用+号拼接的而已。m_convert也没混淆可以通过常量判断是个md5函数,直接在上面打断点也行。这个文件量不大也可以随便丢个ai去分析,不过要千万小心ai犯错。

感谢,纯爱航线是“a09e04e892e708a0a121741b03a99c11”

纯爱航线_舰B娘_Spine整理工具.zip (2.9 MB)
不知道导出的Spine全不全

4 个赞

感谢大佬的整理工具,舒服了,纯享spine
D9D1931275627F8CB397A57D53273F8C

还是得感谢dewrfe53535大佬,原来就一直卡在图片匹配上,以前写代码按尺寸匹配,同尺寸的能有上百个,然后这个项目就扔那没管了