放置江湖

000

放置江湖是深圳小猴跳跳出品的一款文字类武侠Mud游戏。我在TapTap上下载的。玩了之后一下子就触动了我一段久远的记忆。这个游戏非常像我高中时候在文曲星上玩得叫gmud的游戏。记得当时花了非常多的时间在这个游戏上(其实是因为上课太无聊)。当时的文曲星用的是2032的纽扣电池,一节电池要5块钱。我在这个游戏上用光了几十节电池。那时候为了能干掉武学修为达到返璞归真级别的张三丰,我开始修改游戏。从修改游戏数据到修改游戏图片到直接修改游戏代码。最后我练就了可以人肉6502指令集的汇编和反汇编技术。我会把大段代码抄在纸上分析,然后改完以后再写回到Rom里。现在想想真是疯狂啊。

言归正传。我玩了几天后发现网上的攻略都没有具体数值。于是想把这个游戏拆开看看。

001

放置江湖目前只能通过TapTap下载. 在TapTap里设置禁用自动删除安装包后, 游戏安装包可以在下面这个位置找到。

Android/data/com.taptap/files/Download/taptaptmp/

下载安装包后解压缩。首先看到的是这个文件

lib/armeabi/libcocos2dlua.so

看来游戏应该是基于cocos2dx的。随后在assets目录下发现了很多lua脚本以及图片资源。图片没有加密,直接都可以看到,但这不是我想要的。随便打开一个Lua脚本。看到如下内容

不认识这个文件。网上搜索ABCTJM也没有发现任何线索。看一下每个字节出现的频率

这个文件不是压缩了就是加密了。加密的可能性更大一些。鉴于lib下的那个文件的文件名是libcocos2dlua.so,这些扩展名是lua的文件应该是处理过的脚本文件。现在目标是弄明白这个文件是怎样压缩和加密的。不用废话了,直接开始反汇编吧。

objdump -CT libcocos2dlua.so > fzjh.sym

objdump -Cd libcocos2dlua.so > fzjh.asm

从cocos2d::cocos2dVersion()看到如下反汇编:

007364f8 <:cocos2dversion>:

7364f8:4801ldrr0,[pc,#4]; (736500 <:cocos2dversion>)

7364fa:4478addr0,pc

7364fc:4770bxlr

736500地址的值是47F533。将这个值加上7364fe等于BB5A31

这里就是版本号了。可以看到版本号是cocos2dx 3.9。来到cocos2dx的github上把3.9下载下来开始对照代码读汇编,效率果然高。

https://github.com/cocos2d/cocos2d-x

通过在符号表中搜索"key", "decrypt"等关键字,很快就找到了一些线索。

cocos2d::LuaStack::executeScriptFile() 会调用 cocos2d::LuaStack::luaLoadBuffer() 然后调用了 xxtea_encrypt()进行解密。貌似对lua加密是cocos2dx内置的功能。

int LuaStack::executeScriptFile(const char* filename)

{

CCAssert(filename, "CCLuaStack::executeScriptFile() - invalid filename");

std::string buf(filename);

//

// remove .lua or .luac

//

size_t pos = buf.rfind(BYTECODE_FILE_EXT);

if (pos != std::string::npos)

{

buf = buf.substr(0, pos);

}

else

{

pos = buf.rfind(NOT_BYTECODE_FILE_EXT);

if (pos == buf.length() - NOT_BYTECODE_FILE_EXT.length())

{

buf = buf.substr(0, pos);

}

}

FileUtils *utils = FileUtils::getInstance();

//

// 1. check .lua suffix

// 2. check .luac suffix

//

std::string tmpfilename = buf + NOT_BYTECODE_FILE_EXT;

if (utils->isFileExist(tmpfilename))

{

buf = tmpfilename;

}

else

{

tmpfilename = buf + BYTECODE_FILE_EXT;

if (utils->isFileExist(tmpfilename))

{

buf = tmpfilename;

}

}

std::string fullPath = utils->fullPathForFilename(buf);

Data data = utils->getDataFromFile(fullPath);

int rn = 0;

if (!data.isNull())

{

if (luaLoadBuffer(_state, (const char*)data.getBytes(), (int)data.getSize(), fullPath.c_str()) == 0)

{

rn = executeFunction(0);

}

}

return rn;

}

int LuaStack::luaLoadBuffer(lua_State *L, const char *chunk, int chunkSize, const char *chunkName)

{

int r = 0;

if (_xxteaEnabled && strncmp(chunk, _xxteaSign, _xxteaSignLen) == 0)

{

// decrypt XXTEA

xxtea_long len = 0;

unsigned char* result = xxtea_decrypt((unsigned char*)chunk + _xxteaSignLen,

(xxtea_long)chunkSize - _xxteaSignLen,

(unsigned char*)_xxteaKey,

(xxtea_long)_xxteaKeyLen,

&len);

r = luaL_loadbuffer(L, (char*)result, len, chunkName);

free(result);

}

else

{

r = luaL_loadbuffer(L, chunk, chunkSize, chunkName);

}

return r;

}

仔细读了一下源代码,发现密钥 xxteaKey必须要通过调用setXXTEAKeyAndSign()方法来设置。但是奇怪的是全局搜了都没有找到有调用过这个函数的地方。寻找密钥的过程在这里遇到了第一个困难。

002

回来继续看反汇编代码。因为objdump对arm的代码识别不怎么好,所以里面有很多错误的symbol。这个需要注意识别。比如说cocos2d::TextureAtlas::increaseTotalQuadsWith(int)+0xf54 就完全不知所云。而在源代码里面这里写的是strncmp()。进去看了一下,这个地方有点像plt table,但又不是plt。最糟糕的是那里应该是ARM指令而不是Thumb指令,objdump完全搞错了,所以没有办法深究了。

00471f7c <:luastack::lualoadbuffer const>:

471f7c:b5f0push{r4,r5,r6,r7,lr}

471f7e:1c1e addsr6,r3,#0

471f80:7f03 ldrbr3,[r0,#28]

471f82:b087subsp,#28

471f84:1c05 addsr5,r0,#0

471f86:1c0f addsr7,r1,#0

471f88:1c14 addsr4,r2,#0

471f8a:2b00cmpr3,#0

471f8c:d013 beq.n471fb6 <:luastack::lualoadbuffer const>

471f8e:6ac3 ldrr3,[r0,#44]; 0x2c

471f90:6aa9 ldrr1,[r5,#40]; 0x28

471f92:1c10 addsr0,r2,#0

471f94:1c1a addsr2,r3,#0

471f96:9303strr3,[sp,#12]

471f98:f298 fd46bl70aa28 <:textureatlas::increasetotalquadswith>

471f9c:2800cmpr0,#0

471f9e:d10a bne.n471fb6 <:luastack::lualoadbuffer const>

471fa0:9b03 ldrr3,[sp,#12]

471fa2:9005strr0,[sp,#20]

471fa4:6a2a ldrr2,[r5,#32]

471fa6:18e0 addsr0,r4,r3

471fa8:ac05addr4,sp,#20

471faa:1af1 subsr1,r6,r3

471fac:6a6b ldrr3,[r5,#36]; 0x24

471fae:9400strr4,[sp,#0]

471fb0:f08c fb50bl4fe654

471fb4:e00c b.n471fd0 <:luastack::lualoadbuffer const>

471fb6:2300movsr3,#0

471fb8:1c20 addsr0,r4,#0

471fba:1c31 addsr1,r6,#0

471fbc:9305strr3,[sp,#20]

471fbe:f7e5 fdebbl457b98 <:isencrypted char>

471fc2:2800cmpr0,#0

471fc4:d010 beq.n471fe8 <:luastack::lualoadbuffer const>

471fc6:1c20 addsr0,r4,#0

471fc8:1c31 addsr1,r6,#0

471fca:aa05addr2,sp,#20

471fcc:f7e5 fe92bl457cf4 <:decrypt char>

471fd0:1c05 addsr5,r0,#0

471fd2:9a05 ldrr2,[sp,#20]

471fd4:1c38 addsr0,r7,#0

471fd6:1c29 addsr1,r5,#0

471fd8:9b0c ldrr3,[sp,#48]; 0x30

471fda:f298 fb03bl70a5e4 <:textureatlas::increasetotalquadswith>

471fde:1c04 addsr4,r0,#0

471fe0:1c28 addsr0,r5,#0

471fe2:f297 fe2bbl709c3c <:textureatlas::increasetotalquadswith>

471fe6:e006 b.n471ff6 <:luastack::lualoadbuffer const>

471fe8:1c21 addsr1,r4,#0

471fea:1c38 addsr0,r7,#0

471fec:1c32 addsr2,r6,#0

471fee:9b0c ldrr3,[sp,#48]; 0x30

471ff0:f298 faf8bl70a5e4 <:textureatlas::increasetotalquadswith>

471ff4:1c04 addsr4,r0,#0

471ff6:1c20 addsr0,r4,#0

471ff8:b007addsp,#28

471ffa:bdf0pop{r4,r5,r6,r7,pc}

认真看了一遍才发现,这个竟然和cocos2dx的源代码不一样。看来小猴跳跳的人是修改了cocos2dx的源代码。他们没有使用原先解密方法,取而代之的是调用了一个JM::decrypt()的方法。确认传入的三个参数分别为密文,密文长度和明文长度,明文是通过返回值传出的。所以密钥应该是在这个函数内部取得。

00457cf4 <:decrypt char>:

457cf4:b5f0push{r4,r5,r6,r7,lr}

457cf6:4e18 ldrr6,[pc,#96]; (457d58 <:decrypt char unsigned int>)

457cf8:b0a7subsp,#156; 0x9c

457cfa:1c05 addsr5,r0,#0

457cfc:447eaddr6,pc

457cfe:6836ldrr6,[r6,#0]

457d00:1c0c addsr4,r1,#0

457d02:6833ldrr3,[r6,#0]

457d04:1c17 addsr7,r2,#0

457d06:9325strr3,[sp,#148]; 0x94

457d08:f7ff ff46bl457b98 <:isencrypted char>

457d0c:9603strr6,[sp,#12]

457d0e:2800cmpr0,#0

457d10:d00f beq.n457d32 <:decrypt char>

457d12:ae05addr6,sp,#20

457d14:1c21 addsr1,r4,#0

457d16:1c32 addsr2,r6,#0

457d18:ab04addr3,sp,#16

457d1a:1c28 addsr0,r5,#0

457d1c:f7ff fe9cbl457a58 <:gdk char>

457d20:9904ldrr1,[sp,#16]

457d22:9700strr7,[sp,#0]

457d24:1c32 addsr2,r6,#0

457d26:1868addsr0,r5,r1

457d28:2380movsr3,#128; 0x80

457d2a:1a61 subsr1,r4,r1

457d2c:f0a6 fc92bl4fe654

457d30:e009 b.n457d46 <:decrypt char>

457d32:1c20 addsr0,r4,#0

457d34:f2b1 ff4ebl709bd4 <:textureatlas::increasetotalquadswith>

457d38:1c06 addsr6,r0,#0

457d3a:1c29 addsr1,r5,#0

457d3c:1c22 addsr2,r4,#0

457d3e:f2b1 ff51bl709be4 <:textureatlas::increasetotalquadswith>

457d42:1c30 addsr0,r6,#0

457d44:603cstrr4,[r7,#0]

457d46:9b03 ldrr3,[sp,#12]

457d48:9a25 ldrr2,[sp,#148]; 0x94

457d4a:681b ldrr3,[r3,#0]

457d4c:429acmpr2,r3

457d4e:d001 beq.n457d54 <:decrypt char>

457d50:f2b1 ff7cbl709c4c <:textureatlas::increasetotalquadswith>

457d54:b027addsp,#156; 0x9c

457d56:bdf0pop{r4,r5,r6,r7,pc}

457d58:5264strhr4,[r4,r1]

457d5a:0086lslsr6,r0,#2

最终还是调用了xxtea_decrypt这个函数来解密的。这个函数的第三个参数就是密钥。

457d12:ae05addr6,sp,#20

457d24:1c32 addsr2,r6,#0

457d28:2380movsr3,#128; 0x80

通过以上这几行可知密钥被存在了局部变量sp+20的位置上。他的长度是128字节。显然这个密钥是通过JM::gdk的第三个参数传出的。让我们看一下JM::gdk这个函数做了什么?

00457a58 <:gdk char>:

457a58:b5f0push{r4,r5,r6,r7,lr}

457a5a:4d2f ldrr5,[pc,#188]; (457b18 <:gdk char unsigned int>)

457a5c:1c14 addsr4,r2,#0

457a5e:447daddr5,pc

457a60:682d ldrr5,[r5,#0]

457a62:b093subsp,#76; 0x4c

457a64:1e01 subsr1,r0,#0

457a66:682a ldrr2,[r5,#0]

457a68:9211strr2,[sp,#68]; 0x44

457a6a:d04c beq.n457b06 <:gdk char>

457a6c:780a ldrbr2,[r1,#0]

457a6e:2a41cmpr2,#65; 0x41

457a70:d126 bne.n457ac0 <:gdk char>

457a72:784a ldrbr2,[r1,#1]

457a74:2000movsr0,#0

457a76:2a42cmpr2,#66; 0x42

457a78:d145 bne.n457b06 <:gdk char>

457a7a:788a ldrbr2,[r1,#2]

457a7c:2a43cmpr2,#67; 0x43

457a7e:d142 bne.n457b06 <:gdk char>

457a80:78ca ldrbr2,[r1,#3]

457a82:2a54cmpr2,#84; 0x54

457a84:d13f bne.n457b06 <:gdk char>

457a86:790a ldrbr2,[r1,#4]

457a88:2a4acmpr2,#74; 0x4a

457a8a:d13c bne.n457b06 <:gdk char>

457a8c:794a ldrbr2,[r1,#5]

457a8e:2a4dcmpr2,#77; 0x4d

457a90:d139 bne.n457b06 <:gdk char>

457a92:2001movsr0,#1

457a94:2c00cmpr4,#0

457a96:d036 beq.n457b06 <:gdk char>

457a98:2206movsr2,#6

457a9a:4e20 ldrr6,[pc,#128]; (457b1c <:gdk char unsigned int>)

457a9c:af01addr7,sp,#4

457a9e:601astrr2,[r3,#0]

457aa0:447eaddr6,pc

457aa2:1c31 addsr1,r6,#0

457aa4:2240movsr2,#64; 0x40

457aa6:1c38 addsr0,r7,#0

457aa8:f2b2 f89cbl709be4 <:textureatlas::increasetotalquadswith>

457aac:1c31 addsr1,r6,#0

457aae:1c20 addsr0,r4,#0

457ab0:3140addsr1,#64; 0x40

457ab2:2240movsr2,#64; 0x40

457ab4:f2b2 f896bl709be4 <:textureatlas::increasetotalquadswith>

457ab8:1c20 addsr0,r4,#0

457aba:1c39 addsr1,r7,#0

457abc:3040addsr0,#64; 0x40

457abe:e01e b.n457afe <:gdk char>

457ac0:2000movsr0,#0

457ac2:2a54cmpr2,#84; 0x54

457ac4:d11f bne.n457b06 <:gdk char>

457ac6:784a ldrbr2,[r1,#1]

457ac8:2a4acmpr2,#74; 0x4a

457aca:d11c bne.n457b06 <:gdk char>

457acc:788a ldrbr2,[r1,#2]

457ace:2a4dcmpr2,#77; 0x4d

457ad0:d119 bne.n457b06 <:gdk char>

457ad2:2001movsr0,#1

457ad4:2c00cmpr4,#0

457ad6:d016 beq.n457b06 <:gdk char>

457ad8:2203movsr2,#3

457ada:4f11 ldrr7,[pc,#68]; (457b20 <:gdk char unsigned int>)

457adc:ae01addr6,sp,#4

457ade:601astrr2,[r3,#0]

457ae0:447faddr7,pc

457ae2:1c39 addsr1,r7,#0

457ae4:2240movsr2,#64; 0x40

457ae6:1c30 addsr0,r6,#0

457ae8:f2b2 f87cbl709be4 <:textureatlas::increasetotalquadswith>

457aec:1c39 addsr1,r7,#0

457aee:1c20 addsr0,r4,#0

457af0:3140addsr1,#64; 0x40

457af2:2240movsr2,#64; 0x40

457af4:f2b2 f876bl709be4 <:textureatlas::increasetotalquadswith>

457af8:1c20 addsr0,r4,#0

457afa:1c31 addsr1,r6,#0

457afc:3040addsr0,#64; 0x40

457afe:2240movsr2,#64; 0x40

457b00:f2b2 f870bl709be4 <:textureatlas::increasetotalquadswith>

457b04:2001movsr0,#1

457b06:9a11 ldrr2,[sp,#68]; 0x44

457b08:682b ldrr3,[r5,#0]

457b0a:429acmpr2,r3

457b0c:d001 beq.n457b12 <:gdk char>

457b0e:f2b2 f89dbl709c4c <:textureatlas::increasetotalquadswith>

457b12:b013addsp,#76; 0x4c

457b14:bdf0pop{r4,r5,r6,r7,pc}

这个函数最开始一部分代码检查了密文的前六个字符是不是“ABCTJM”,这正好是那个加密过的lua文件的前六个字节。So Excited! 胜利就在眼前。457ad6这条指令判断了返回指针是否为空。然后代码从数据区加载了一个指针到r7。经过计算这个指针的值是BB64AC

457ada:4f11       ldrr7,[pc,#68]

457ae0:447faddr7,pc

察看一下这个地址的内容,发现这个指针指向的这堆数据很可疑

放置江湖html5源码,codearchive/reverse/放置江湖 at master · crazyyao0/codearchive · GitHub...相关推荐

  1. 3款动态网页时间时钟HTML5源码

    介绍: 3款动态网页时间时钟HTML5源码 网盘下载地址: http://kekewangLuo.cc/H5VLrhVBiis0 图片:

  2. 实现太阳系行星公转动画实例(CSS+HTML5 源码)

    实现太阳系行星公转动画实例(CSS+HTML5 源码) 效果图 源代码(CSS+HTML5) 效果图 源代码(CSS+HTML5) <html> <head> <styl ...

  3. 分享79个ASP江湖论坛源码,总有一款适合您

    分享79个ASP江湖论坛源码,总有一款适合您 79个ASP江湖论坛源码下载链接:https://pan.baidu.com/s/1CcDFNCbVqZGX9m2cZzhlsg?pwd=bov2  提取 ...

  4. 分享77个PHP江湖论坛源码,总有一款适合您

    分享77个PHP江湖论坛源码,总有一款适合您 77个PHP江湖论坛源码下载链接:https://pan.baidu.com/s/1dLuixhvCs4Pp27BU6pJq6Q?pwd=1d2o 提取码 ...

  5. 一个简单漂亮的网址导航HTML5源码

    正文: 一个简单漂亮的网址导航HTML5源码页面自适应,手机电脑都自动适应大小. 纯HTML代码,然后一个CSS一个JS文件,根据设备自适应,更多信息自行研究,修改index.html内容. 字节网盘 ...

  6. 分享73个ASP江湖论坛源码,总有一款适合您

    分享73个ASP江湖论坛源码,总有一款适合您 73个ASP江湖论坛源码下载链接:https://pan.baidu.com/s/1cvtPY2s9kwM_L9sVRxI_xw?pwd=k08d  提取 ...

  7. 分享66个ASP江湖论坛源码,总有一款适合您

    分享66个ASP江湖论坛源码,总有一款适合您 66个ASP江湖论坛源码下载链接:https://pan.baidu.com/s/1QuQTTtYlDPu8vT_a2PNsyg?pwd=wg6r  提取 ...

  8. 我的CSDN笔记总索引(阅读量降序,代码自动遍历生成HTML5源码)

    Python代码用"命令容器"方法os.system(),调用Linux命令行工具crul获取CSDN博文页面源码,Python内置re正则解析出博文笔记信息,按阅读量降序模块输出 ...

  9. 分享53个ASP江湖论坛源码,总有一款适合您

    分享53个ASP江湖论坛源码,总有一款适合您 53个ASP江湖论坛源码下载链接:https://pan.baidu.com/s/1FZ3LLkL2eeSCqXUuLfbPQQ?pwd=5x9x  提取 ...

  10. 分享72个ASP江湖论坛源码,总有一款适合您

    分享72个ASP江湖论坛源码,总有一款适合您 72个ASP江湖论坛源码下载链接:https://pan.baidu.com/s/1mnIn_CiMunHiFgmovsIADw?pwd=de5e  提取 ...

最新文章

  1. 跟我学交换机配置(三)
  2. Linux下的XAMPP基本配置技巧(设置虚拟主机、添加FTP账户等)
  3. linux用户开放crontab权限,linux – / etc / crontab权限
  4. C#设计模式之20-状态模式
  5. 进程/线程间的同步方式
  6. 看不起胖子?自如员工爆料身高、体重决定能否晋升,官方回应侧面实锤?
  7. UI设计干货模板|引导网格系统
  8. 一般处理程序在VS2012中打开问题
  9. 骑士CMS模版注入+文件包含getshell漏洞复现
  10. Air720UGUH 极简封装 LTE Cat.1 bis 模块[合宙通信]
  11. 百度招聘实习生:网页搜索部_语法研究实习工程师(七种语
  12. Python函数式编程(fn)
  13. Go 每日一库之 negroni
  14. ebc是什么意思_ebc是什么意思?金蝶软件可靠吗?
  15. 解决西门子PLC模拟量输入值不稳定的问题
  16. 成为跨领域的「解决方案架构师」需要什么素养?
  17. UVa-10082-WERTYU
  18. android 蒙层动画,Android酷炫加载进度动画
  19. c语言程序设计数组实验报告,c语言程序设计实验报告(数组).doc
  20. 鸿蒙系统主题曲,新红楼梦的主题曲和片尾曲

热门文章

  1. python隐藏窗口_python怎么隐藏界面?
  2. 想学PLC编程,先弄清5种PLC专用语言
  3. 计算机软件需求说明编制指南gb/t 9385-2008,GBT 9385-2008 计算机软件需求说明编制指南.pdf...
  4. Dreamweaver CS4自学实例视频教程(高清)
  5. 屏幕录像专家 V6.0+注册机
  6. 计算机网络网线制作工具有,网线制作工具 网线水晶头制作过程详解(视频+图文教程)...
  7. 计算机网络网线制作与测试结果,《计算机网络》网线制作实验报告.doc
  8. 【色彩管理】HSI色彩模式详解
  9. 为什么说精益管理模式是适合中国企业的管理方法(zt)
  10. 向 Linux kernel 社区提交patch补丁步骤总结(已验证成功)