首页
社区
课程
招聘
《刀塔传奇》游戏C++部分解密算法
发表于: 2014-6-1 20:26 15202

《刀塔传奇》游戏C++部分解密算法

2014-6-1 20:26
15202
这个星期在逆向移动平台上非常火热的一款游戏,叫做《刀塔传奇》

它是用 cocos2d-x 游戏引擎开发的,游戏逻辑是用 lua 脚本写的,但是很可惜,资源文件里的lua脚本都经过了加密,于是我就逆向了它的c++代码。

它的解密算法一共分为2个部分:

1.  将 /data/ 文件夹下的 <filename>.abc 文件 通过异或算法解密成 .zip 压缩文件.

2. 再用 zlib 库将 zip 压缩文件解压成 lua 代码.

这里我给出最重要的第一部分的逆向结果。

安卓 arm 版本逆向结果:

 loc_23AB9A                              ; CODE XREF: cocos2d::CCFileUtils::getEncryptedFileData(char const*,ulong *)+E6j
.text:0023AB9A 04 95                                   STR     R5, [SP,#0xE8+var_D8] ; R5 = 0x17
.text:0023AB9C 00 24                                   MOVS    R4, #0          ; R4 = 0
.text:0023AB9E ED 17                                   ASRS    R5, R5, #0x1F   ; R5 = r5 >> 31 /// 0
.text:0023ABA0 05 95                                   STR     R5, [SP,#0xE8+var_D4] ; VAR_d4 = r5
.text:0023ABA2 00 20                                   MOVS    R0, #0
.text:0023ABA4 00 21                                   MOVS    R1, #0
.text:0023ABA6 25 1C                                   MOVS    R5, R4
.text:0023ABA8 03 97                                   STR     R7, [SP,#0xE8+var_DC] ; var_DC = this
.text:0023ABAA 22 E0                                   B       loc_23ABF2      ; R2 = data_size
.text:0023ABAC                         ; ---------------------------------------------------------------------------
.text:0023ABAC
.text:0023ABAC                         loc_23ABAC                              ; CODE XREF: cocos2d::CCFileUtils::getEncryptedFileData(char const*,ulong *)+B4j
.text:0023ABAC 44 48                                   LDR     R0, =(aGetfiledatafro - loc_23ABB6)
.text:0023ABAE 45 49                                   LDR     R1, =(aCocos2dXAssert - loc_23ABC0)
.text:0023ABB0 45 4A                                   LDR     R2, =(aSFunctionSLine - loc_23ABC2)
.text:0023ABB2 78 44                                   ADD     R0, PC          ; "getFileDataFromZipData"
.text:0023ABB4 60 30                                   ADDS    R0, #0x60
.text:0023ABB6
.text:0023ABB6                         loc_23ABB6                              ; DATA XREF: .text:off_23ACC0o
.text:0023ABB6 45 4B                                   LDR     R3, =(aUsersBuilde_74 - loc_23ABC6)
.text:0023ABB8 00 90                                   STR     R0, [SP,#0xE8+var_E8]
.text:0023ABBA 45 48                                   LDR     R0, =0x312
.text:0023ABBC 79 44                                   ADD     R1, PC          ; "cocos2d-x assert"
.text:0023ABBE 7A 44                                   ADD     R2, PC          ; "%s function:%s line:%d"
.text:0023ABC0
.text:0023ABC0                         loc_23ABC0                              ; DATA XREF: .text:off_23ACC4o
.text:0023ABC0 01 90                                   STR     R0, [SP,#0xE8+var_E4]
.text:0023ABC2
.text:0023ABC2                         loc_23ABC2                              ; DATA XREF: .text:off_23ACC8o
.text:0023ABC2 7B 44                                   ADD     R3, PC          ; "/Users/builder/Perforce/dgame/d-game/Cl"...
.text:0023ABC4 06 20                                   MOVS    R0, #6
.text:0023ABC6
.text:0023ABC6                         loc_23ABC6                              ; DATA XREF: .text:off_23ACCCo
.text:0023ABC6 0A F7 2C ED                             BLX     __android_log_print
.text:0023ABCA E6 E7                                   B       loc_23AB9A      ; R5 = 0x17
.text:0023ABCC                         ; ---------------------------------------------------------------------------
.text:0023ABCC
.text:0023ABCC                         loc_23ABCC                              ; CODE XREF: cocos2d::CCFileUtils::getEncryptedFileData(char const*,ulong *)+11Ej
.text:0023ABCC 00 23                                   MOVS    R3, #0
.text:0023ABCE D3 F1 D8 EF                             BLX     __aeabi_uldivmod ; A = (R1 << 32) + R0;
.text:0023ABCE                                                                 ; B = (R3 << 32) + R2;
.text:0023ABCE                                                                 ; R1 = (A/B) >> 32;
.text:0023ABCE                                                                 ; R0 = (A/B) & 0xFFFFFFFF;
.text:0023ABCE                                                                 ; R3 = (A%B) >> 32;
.text:0023ABCE                                                                 ; R2 = (A%B) & 0xFFFFFFFF
.text:0023ABD2 08 9E                                   LDR     R6, [SP,#0xE8+var_C8] ; R6 = pFileNameBuffer
.text:0023ABD4 07 9F                                   LDR     R7, [SP,#0xE8+var_CC] ; R7 = pFileDataBuffer
.text:0023ABD6 11 1C                                   MOVS    R1, R2          ; R1 = R0 % R2
.text:0023ABD8 32 5D                                   LDRB    R2, [R6,R4]     ; R2 = *( (char*)pFileNameBuffer + R4)
.text:0023ABDA 7B 5D                                   LDRB    R3, [R7,R5]     ; R3 = *( (char*)pFileDataBuffer + R5)
.text:0023ABDC 06 9E                                   LDR     R6, [SP,#0xE8+var_D0] ; R6 = pOutputBuffer
.text:0023ABDE 60 1C                                   ADDS    R0, R4, #1      ; R0 = R4 + 1
.text:0023ABE0 53 40                                   EORS    R3, R2          ; R3 = R3 ^ R2
.text:0023ABE2 73 54                                   STRB    R3, [R6,R1]     ; *( (char*)pOutputBuffer + R1) = R3
.text:0023ABE4 09 99                                   LDR     R1, [SP,#0xE8+var_C4] ; R1 = strlen(pFileNameBuffer)
.text:0023ABE6 D2 F1 72 EE                             BLX     __aeabi_idivmod ; R1 = R0 % R1
.text:0023ABEA 01 35                                   ADDS    R5, #1          ; ++R5
.text:0023ABEC 0C 1C                                   MOVS    R4, R1          ; R4 = R1
.text:0023ABEE 0A 98                                   LDR     R0, [SP,#0xE8+var_C0]
.text:0023ABF0 0B 99                                   LDR     R1, [SP,#0xE8+var_BC]
.text:0023ABF2
.text:0023ABF2                         loc_23ABF2                              ; CODE XREF: cocos2d::CCFileUtils::getEncryptedFileData(char const*,ulong *)+C6j
.text:0023ABF2 0F 9A                                   LDR     R2, [SP,#0xE8+var_AC] ; R2 = data_size
.text:0023ABF4 04 9E                                   LDR     R6, [SP,#0xE8+var_D8] ; var_D8 = 0x17
.text:0023ABF6 05 9F                                   LDR     R7, [SP,#0xE8+var_D4] ; R7 = 0
.text:0023ABF8 36 18                                   ADDS    R6, R6, R0      ; R6 += R0
.text:0023ABFA 4F 41                                   ADCS    R7, R1          ; R7 += R1
.text:0023ABFC 0A 96                                   STR     R6, [SP,#0xE8+var_C0]
.text:0023ABFE 0B 97                                   STR     R7, [SP,#0xE8+var_BC]
.text:0023AC00 95 42                                   CMP     R5, R2          ; if( R5 < R2 ) ///for looper
.text:0023AC02 E3 D3                                   BCC     loc_23ABCC
.text:0023AC04 07 9C                                   LDR     R4, [SP,#0xE8+var_CC]
.text:0023AC06 03 9F                                   LDR     R7, [SP,#0xE8+var_DC]
.text:0023AC08 00 2C                                   CMP     R4, #0
.text:0023AC0A 02 D0                                   BEQ     loc_23AC12
.text:0023AC0C 20 1C                                   MOVS    R0, R4          ; void *
.text:0023AC0E C5 F1 44 ED                             BLX     _ZdaPv          ; operator delete[](void *)


然后我根据这个逆向结果,写了一个c++的解密算法:
static void decode(const std::vector<unsigned char>& data, const std::size_t data_size,
				   const std::vector<unsigned char>& name, const std::size_t name_size,
				   std::vector<unsigned char>& out)
{
	const int primes[] = {0x17, 0x19, 0x35, 0x37, 0x4d};

	int prime(0);
	for(auto i : primes) {
		if(data_size % i) {
			prime = i;
			break;
		}
	}

	std::cout << "prime : " << prime << std::endl;
	std::cout << "data_size : " << data_size << std::endl;

	int name_index(0);
	for(int i = 0; i < int(data_size); ++i)
	{
		unsigned int index = prime * i;

		unsigned char r2 = data[i];
		unsigned char r3 = name[name_index];

		unsigned long long A = (0LL << 32) + index;
		unsigned long long B = (0LL << 32) + data_size;

		unsigned long long mod = A % B;

		unsigned int pos = unsigned int(mod & 0xFFFFFFFF);

		out[pos] = r2 ^ r3;

		name_index = (name_index + 1) % name_size;
	}
}


不过,非常可惜的是,我写的解密算法并不能正确的将加密过的资源文件解密成.zip格式的压缩文件。 因为 zip 格式的前4个字节是 0x50, 0x4b, 0x03, 0x04

但是巧合的是,我的解密算法却能保证第一个字节是 0x50, 也就是说,我的解密算法还差最后一个小细节有问题,这个小细节我找了很久都没有找到,能否请各位高手花一点时间提点一下小弟~

谢谢大家~

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (13)
雪    币: 3725
活跃值: (629)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
2
哇,我这是在沙发位置吗?
不错的分析,以前也逆向过一个游戏血量校验的算法.
2014-6-1 20:41
0
雪    币: 239
活跃值: (133)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
3
这个能如何利用
2014-6-1 21:15
0
雪    币: 3110
活跃值: (143)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
加密最恶心了
2014-6-1 23:15
0
雪    币: 50
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
const int primes[] = {0x2717, 0x2719, 0x2735, 0x2737, 0x274d, 0x2753, 0x2755};
2014-6-13 16:13
0
雪    币: 862
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
会就不恶心,加密解密
2014-7-8 12:17
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我想知道zip的密码,有谁跟到了吗?
2014-7-12 03:14
0
雪    币: 30
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
你好?你过了1个半月了,最后解密成功没?能否给我一份解密后与解密前的文件给我,谢谢!yhx5000@126.com
2014-7-15 19:56
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
lua经过luac 5.1的编译,数据区经过了加密.
2014-7-20 19:45
0
雪    币: 9
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
都是强淫啊。。。
2014-7-24 21:49
0
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
提供批解为luac文件的工具代码,VS2013工程,先编译zlib,然后编译工程,zlib是静态链接的,所以不需要dll.
exe文件只要放进data文件夹运行即可,它会遍历子目录的.
至于luac的加密,静待能人解出.

下载地址:DecodeABC.zip
2014-8-4 20:15
0
雪    币: 1933
活跃值: (113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
你牛逼 ,相信 你一定会成功的 ,加油 !!
2014-8-5 09:42
0
雪    币: 36
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
我倒是找到办法反编译出了lua源码,不过毕竟是商业游戏,大家自己研究即可,公布出来有点不妥感觉
2014-8-10 17:08
0
雪    币: 2
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
能否给个方法或者算法供研究和学习的 286505491@qq.com
2015-3-29 12:49
0
游客
登录 | 注册 方可回帖
返回
//