-
-
[原创]从0到1的某Cocos2dlua手游解包笔记
-
发表于: 2023-3-31 17:26 6997
-
本文研究的apk基于2023/03/31的国际服版本。lua文件和图像文件都进行了加密。
简单看一下,java层基本没上加密。文件加密估计放在native层。打开ida分析libcocos2dlua.so文件,根据https://bbs.kanxue.com/thread-268574.htm#msg_header_h1_6的指导,定位到cocos2d::Image::initWithImageData(),直接就看到cocos2d::FileUtils::decryptUF(),分析后应该是所有加密文件都由这个函数解密。解密函数就是简单的异或固定的密钥。从ida拉出函数并稍加改写就得到了可用的解密器
(由于是直接复制ida的函数,不大好看)
参数1是要解密的文件,参数2是输出的文件名,处理多个文件可以再写个批处理。解密后至少有3类,png图片,用于生成spine的.pvr.ccz,lua脚本(LuaJit)。
想要获取动态立绘,可以用spite软件加载。以应用数据下upgrade\res\common\knight_spine\40008001对应的角色动态立绘为例。首先,同目录下的.png文件替换成用解密器解出来的.pvr.ccz再用texturePackerGUI解出来的同名png。打开spine点左上角的"spine"再选导入数据选40008001.atlas,再点开左上角再选纹理解包器,选同目录对应的.skel解到某个目录。之后右侧的图片选中刚刚解包纹理的目录,不出意外的话就可以看到合成出来cg图片了。
右侧的动画可以切换动作,左上角“设置”可以切换为“动画”来预览效果。
附:spine是旧版本的v3.8.99,正版的免费试用版不支持旧版,请自行寻找旧的破解版或考虑自行破解
解包出来的luajit可以自行反编译。
#include<iostream>
#include <cinttypes>
#include <fstream>
#define _BYTE unsigned char
#define _DWORD unsigned int
unsigned char key[]
=
{
19
,
91
,
12
,
13
,
102
,
22
,
34
,
43
,
17
,
25
,
88
,
64
,
36
,
16
,
14
,
66
,
49
,
87
,
56
,
44
,
53
,
28
,
11
,
5
,
116
,
37
,
58
,
105
,
20
,
15
,
77
,
7
,
29
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
19
,
91
,
12
,
13
,
102
,
22
,
34
,
43
,
17
,
25
,
88
,
64
,
36
,
16
,
14
,
66
,
49
,
87
,
56
,
44
,
53
,
28
,
11
,
5
,
116
,
37
,
58
,
105
,
20
,
15
,
77
,
7
,
29
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
};
unsigned
int
decryptFile(_BYTE
*
a1,
int
a2, _DWORD
*
a3, _DWORD
*
a4, _BYTE
*
a5)
{
__int64 v5;
/
/
x8
__int64 v6;
/
/
x5
__int64 v7;
/
/
x3
int
v8;
/
/
w9
int
v9;
/
/
w11
int
v10;
/
/
w7
__int64 v11;
/
/
x2
int
v12;
/
/
w5
int
v13;
/
/
w1
int
v15;
/
/
w5
_BYTE
*
v16;
/
/
x8
int
v17;
/
/
w12
int
v18;
/
/
w11
int
v19;
/
/
w3
char v20;
/
/
w6
unsigned
int
v21;
/
/
w8
unsigned
int
v22;
/
/
w2
int
v23;
/
/
w7
unsigned
int
v24;
/
/
w7
int
v25;
/
/
w3
_BYTE
*
v26;
/
/
x0
int
v27;
/
/
w8
int
v28;
/
/
w2
if
(a2 <
=
3
)
return
0xFFFFFFFFLL
;
if
(
*
a1 !
=
0x55
|| a1[
1
] !
=
0x46
)
return
0xFFFFFFFELL
;
if
(a1[
2
]
=
=
0x4F
)
{
v5
=
4LL
;
*
a4
=
(unsigned __int8)a1[
3
];
v8
=
1
;
v6
=
5LL
;
v7
=
6LL
;
v9
=
4
;
}
else
{
v5
=
2LL
;
v6
=
3LL
;
v7
=
4LL
;
v8
=
0
;
v9
=
2
;
}
*
a3
=
(unsigned __int8)a1[v5];
v10
=
(unsigned __int8)a1[v6];
if
(v10
=
=
1
)
{
v13
=
a2
-
3
-
v9;
if
(v13 <
=
0
)
{
LABEL_13:
*
a5
=
v13;
return
0LL
;
}
v15
=
v9
+
3
;
v16
=
a1;
v17
=
v13
+
v9
+
3
;
v18
=
(unsigned __int8)a1[(unsigned
int
)v7]
-
v9
-
3
;
do
{
v19
=
v18
+
v15;
v20
=
a1[v15
+
+
];
*
v16
+
+
=
key[v19
%
33
] ^ v20;
}
while
(v15 !
=
v17);
*
a5
=
v13;
return
0LL
;
}
else
{
if
(v10 !
=
2
)
{
v11
=
0LL
;
if
(v8)
v12
=
7
;
else
v12
=
5
;
v13
=
a2
-
v12;
if
(v13 >
0
)
{
do
{
a1[v11]
=
a1[(unsigned
int
)(v12
+
v11)];
+
+
v11;
}
while
(v13 > (
int
)v11);
}
goto LABEL_13;
}
v21
=
(unsigned __int8)a1[v7];
v22
=
v9
+
3
;
v13
=
a2
-
(v9
+
3
);
*
a1
=
a1[v13] ^ key[v21
%
0x21
+
48
];
a1[
1
]
=
a1[v13
+
1
] ^ key[(v21
+
1
)
%
0x21
+
48
];
a1[
2
]
=
a1[v13
+
2
] ^ key[(v21
+
2
)
%
0x21
+
48
];
a1[
3
]
=
a1[v13
+
3
] ^ key[(v21
+
3
)
%
0x21
+
48
];
a1[
4
]
=
a1[v13
+
4
] ^ key[(v21
+
4
)
%
0x21
+
48
];
if
(v9 !
=
2
)
{
a1[
6
]
=
a1[v13
+
6
] ^ key[(v21
+
6
)
%
0x21
+
48
];
a1[
5
]
=
a1[v13
+
5
] ^ key[(v21
+
5
)
%
0x21
+
48
];
}
if
((
int
)(v13
-
v22) >
95
)
v23
=
95
;
else
v23
=
v13
-
v22;
v24
=
v23
+
v22;
if
(v22 >
=
v24)
goto LABEL_13;
v25
=
v21
+
v22;
v26
=
&a1[v22];
v27
=
v21
+
v24;
do
{
v28
=
v25
%
33
;
+
+
v25;
*
v26
+
+
^
=
key[v28
+
48
];
}
while
(v25 !
=
v27);
*
a5
=
v13;
return
0LL
;
}
}
unsigned char mydata[
1000000
]
=
{
0
};
unsigned char outdata[
1000000
]
=
{
0
};
int
main(
int
argc, char
*
argv[]) {
if
(argc !
=
3
) {
std::cerr <<
"Usage: "
<< argv[
0
] <<
" input_file output_file\n"
;
return
1
;
}
std::ifstream infile(argv[
1
], std::ios::binary);
if
(!infile) {
std::cerr <<
"Error opening input file.\n"
;
return
1
;
}
std::ofstream outfile(argv[
2
], std::ios::binary);
if
(!outfile) {
std::cerr <<
"Error opening output file.\n"
;
return
1
;
}
if
(infile && outfile) {
infile.seekg(
0
, std::ios::end);
std::streamsize size
=
infile.tellg();
infile.seekg(
0
, std::ios::beg);
char
*
buffer
=
new char[size];
if
(infile.read(
buffer
, size)) {
decryptFile((unsigned char
*
)
buffer
, size, (_DWORD
*
)&outdata[
100000
], (_DWORD
*
)&outdata[
200000
], outdata);
outfile.write(
buffer
, size);
}
delete[]
buffer
;
}
infile.close();
outfile.close();
return
0
;
}
#include<iostream>
#include <cinttypes>
#include <fstream>
#define _BYTE unsigned char
#define _DWORD unsigned int
unsigned char key[]
=
{
19
,
91
,
12
,
13
,
102
,
22
,
34
,
43
,
17
,
25
,
88
,
64
,
36
,
16
,
14
,
66
,
49
,
87
,
56
,
44
,
53
,
28
,
11
,
5
,
116
,
37
,
58
,
105
,
20
,
15
,
77
,
7
,
29
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
19
,
91
,
12
,
13
,
102
,
22
,
34
,
43
,
17
,
25
,
88
,
64
,
36
,
16
,
14
,
66
,
49
,
87
,
56
,
44
,
53
,
28
,
11
,
5
,
116
,
37
,
58
,
105
,
20
,
15
,
77
,
7
,
29
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
};
unsigned
int
decryptFile(_BYTE
*
a1,
int
a2, _DWORD
*
a3, _DWORD
*
a4, _BYTE
*
a5)
{
__int64 v5;
/
/
x8
__int64 v6;
/
/
x5
__int64 v7;
/
/
x3
int
v8;
/
/
w9
int
v9;
/
/
w11
int
v10;
/
/
w7
__int64 v11;
/
/
x2
int
v12;
/
/
w5
int
v13;
/
/
w1
int
v15;
/
/
w5
_BYTE
*
v16;
/
/
x8
int
v17;
/
/
w12
int
v18;
/
/
w11
int
v19;
/
/
w3
char v20;
/
/
w6
unsigned
int
v21;
/
/
w8
unsigned
int
v22;
/
/
w2
int
v23;
/
/
w7
unsigned
int
v24;
/
/
w7
int
v25;
/
/
w3
_BYTE
*
v26;
/
/
x0
int
v27;
/
/
w8
int
v28;
/
/
w2
if
(a2 <
=
3
)
return
0xFFFFFFFFLL
;
if
(
*
a1 !
=
0x55
|| a1[
1
] !
=
0x46
)
return
0xFFFFFFFELL
;
if
(a1[
2
]
=
=
0x4F
)
{
v5
=
4LL
;
*
a4
=
(unsigned __int8)a1[
3
];
v8
=
1
;
v6
=
5LL
;
v7
=
6LL
;
v9
=
4
;
}
else
{
v5
=
2LL
;
v6
=
3LL
;
v7
=
4LL
;
v8
=
0
;
v9
=
2
;
}
*
a3
=
(unsigned __int8)a1[v5];
v10
=
(unsigned __int8)a1[v6];
if
(v10
=
=
1
)
{
v13
=
a2
-
3
-
v9;
if
(v13 <
=
0
)
{
LABEL_13:
*
a5
=
v13;
return
0LL
;
}
v15
=
v9
+
3
;
v16
=
a1;
v17
=
v13
+
v9
+
3
;
v18
=
(unsigned __int8)a1[(unsigned
int
)v7]
-
v9
-
3
;
do
{
v19
=
v18
+
v15;
v20
=
a1[v15
+
+
];
*
v16
+
+
=
key[v19
%
33
] ^ v20;
}
while
(v15 !
=
v17);
*
a5
=
v13;
return
0LL
;