00003 不思议迷宫.0001:解密Lua脚本

《不思议迷宫》是我想要重点研究的游戏之一。之所以说是重点,是因为我最近一直在玩它,并且花的时间还比较多。虽然严格来说,它并不怎么样。主要的原因是,我自己手贱,在这个游戏上花钱了。这对我这个吊死来说简直不可思议。既然花钱了那就继续玩吧。玩了几天就发现特累,每次副本都得n个小时,而且收获感觉也不怎么样。这个游戏号称能让人“肝到爆”,也就体现在这个副本时间上了。游戏有其不错的地方,但也有不少槽点,甚至是常识性错误。当我感觉到累和不爽之后,就开始研究它,看能不能改改。结果才发现,这居然是个网络游戏、网络游戏、网络游戏。玩家数据这就没办法直接改了,那就继续研究看看吧,也许能够找到什么bug来间接改呢。我的这个愿望落空了,但是我还是想把一些过程和经验给分享出来。另外,我会试图修正游戏中的那些槽点,然后将修正后的文件共享给大家。修正槽点将会消耗较长的时间,中途可能会出现各种意外,游戏停服、游戏大版本更新并加强了程序保护、我的技术储备不够改不了、游戏我腻得透透的不玩也就算了甚至连看一眼都恶心、我失去耐心不改了。总之,对修正槽点大家不要抱太大的期望就是了。

弄出“不思议迷宫.ipa”,解压,到“Payload\slime.app\”目录,我一眼就看到了“res”和“src”这两个目录。我知道cocos2d捣鼓出来的游戏默认会把资源放到res目录中。src从名字看就是源码之类的,进入一看,果然是。

源码是luac文件,也就是说,游戏是cocos2dx-lua开发的。随便打开一个luac文件,一看,意料之中的情况——不是明文:

像乱码又不是乱码——被某种形式地加密了。老方法,下载安卓版游戏,解压,找到libcocos2dlua.so,祭出ida反编译。

cocos2dx-lua在加载lua脚本时,要么使用默认的cocos2dx_lua_loader函数(包括用户扩展版),要么自己创建一个。

先试试查找cocos2dx_lua_loader函数,居然就找到了……来得太容易了,都不怎么真实。游戏公司大概是觉得这个网络游戏玩家是没办法直接修改玩家数据的,也就不怎么在意了吧。直接就找到了固然是幸福的,但万一没找到呢,该怎么办?

好在默认的cocos2dx_lua_loader函数会引用文件名后缀“.lua”和“.luac”。正常情况下,前者表示普通的lua文件,后者表示lua字节码文件(LuaJIT生成)。万一通过函数名称找不到,那就可以试着跟踪字符串“.lua”和“.luac”的引用。引用可能会非常多,这个时候就需要耐心了,或者根据具体情况,看看能不能从其他的字符串入手。

得到的cocos2dx_lua_loader伪码很长,但我们还是一眼就定位了一个非常可疑的函数调用,就在局部变量之后的第二行,想不发现都难:

signed int__fastcall cocos2dx_lua_loader(int a1)

{

……

一大堆局部变量

……

v1 = a1;

buildEncryptMap();

if ( !(byte_9B4E5C & 1) &&j_j___cxa_guard_acquire(&byte_9B4E5C))

{

sub_63E9BC((int)&dword_9B4E58,(int)".luac", (int)&v57);

j_j___cxa_atexit(sub_7856B8,&dword_9B4E58, &unk_9A3000);

j_j___cxa_guard_release(&byte_9B4E5C);

}

if ( !(byte_9B4E64 & 1) &&j_j___cxa_guard_acquire(&byte_9B4E64) )

{

sub_63E9BC((int)&dword_9B4E60,(int)".lua", (int)&v56);

j_j___cxa_atexit(sub_7856B8,&dword_9B4E60, &unk_9A3000);

j_j___cxa_guard_release(&byte_9B4E64);

}

v2 = j_j_luaL_checklstring(v1, 1, 0);

……

真的,幸福来得太容易了,太不真实了。

跟进buildEncryptMap看看:

void *buildEncryptMap()

{

void *result; // r0@1

unsigned int v1; // r1@1

result = (void *)0xFFFFB65C;

v1 = 0;

if ( !charMapInited )

{

do

{

charMapList[charMaps[v1 + 1]] = charMaps[v1];

v1 += 2;

}

while ( v1 < 0x90 );

result = &charMapInited;

charMapInited = 1;

}

return result;

}

这还需要多解释吗?我们只需要弄清楚charMaps就可以了。

跟进,查看charMaps的定义,一点保护的手段都没有:

.data:009A3018   EXPORT charMaps

.data:009A3018 ; _BYTE charMaps[144]

.data:009A3018 charMaps    DCB 0x61, 0x67, 0x62, 0x78, 0x63, 0x77,0x64, 0x76, 0x65

.data:009A3018   ; DATA XREF: .got:charMaps_ptro

.data:009A3018   DCB 0x66, 0x66, 0x75, 0x67, 0x74, 0x68, 0x7A, 0x69, 0x73

.data:009A3018   DCB 0x6A, 0x68,0x6B, 0x65, 0x6C, 0x69,0x6D, 0x79, 0x6E

.data:009A3018   DCB 0x72, 0x6F, 0x64,0x70, 0x63, 0x71, 0x71, 0x72, 0x62

.data:009A3018   DCB 0x73, 0x6A, 0x74,0x70, 0x75, 0x6B, 0x76, 0x61, 0x77

.data:009A3018   DCB 0x6C, 0x78,0x6D, 0x79, 0x6F, 0x7A, 0x6E, 0x41, 0x4F

.data:009A3018   DCB 0x42, 0x4D, 0x43, 0x45, 0x44, 0x4E, 0x45, 0x50, 0x46

.data:009A3018   DCB 0x44, 0x47, 0x51, 0x48, 0x4B, 0x49, 0x43, 0x4A, 0x4C

.data:009A3018   DCB 0x4B, 0x53, 0x4C,0x55, 0x4D, 0x4A, 0x4E,0x42, 0x4F

.data:009A3018   DCB 0x52, 0x50, 0x54, 0x51, 0x41, 0x52, 0x49, 0x53, 0x47

.data:009A3018   DCB 0x54, 0x46, 0x55, 0x5A,0x56, 0x58, 0x57, 0x57, 0x58

.data:009A3018   DCB 0x56, 0x59, 0x48, 0x5A,0x59, 0x30, 0x33, 0x31, 0x39

.data:009A3018   DCB 0x32, 0x35, 0x33, 0x32, 0x34, 0x34, 0x35, 0x30, 0x36

.data:009A3018   DCB 0x37, 0x37, 0x31, 0x38, 0x36, 0x39, 0x38, 0x7B, 0x28

.data:009A3018   DCB 0x7D, 0x29, 0x28, 0x3A,0x29, 0x7B, 0x2E, 0x7D, 0x3A

.data:009A3018   DCB 0x20, 0x20, 0x5F,0x5F, 0x2C, 0x2C, 0xA, 0xA, 0x2E

接下来干什么?打开VC建工程、编写自己的buildEncryptMap,然后解密。——等等,src目录下的luac文件是utf8编码的,并且没有BOM头,还是换成VC#好了。

privatestaticbyte[]charMaps = new byte[144]

{

0x61, 0x67, 0x62, 0x78, 0x63, 0x77, 0x64, 0x76, 0x65

,0x66, 0x66, 0x75, 0x67, 0x74, 0x68, 0x7A, 0x69, 0x73

,0x6A, 0x68,0x6B, 0x65, 0x6C, 0x69,0x6D, 0x79, 0x6E

,0x72, 0x6F, 0x64,0x70, 0x63, 0x71, 0x71, 0x72, 0x62

,0x73, 0x6A, 0x74,0x70, 0x75, 0x6B, 0x76, 0x61, 0x77

,0x6C, 0x78,0x6D, 0x79, 0x6F, 0x7A, 0x6E, 0x41, 0x4F

,0x42, 0x4D, 0x43, 0x45, 0x44, 0x4E, 0x45, 0x50, 0x46

,0x44, 0x47, 0x51, 0x48, 0x4B, 0x49, 0x43, 0x4A, 0x4C

,0x4B, 0x53, 0x4C,0x55, 0x4D, 0x4A, 0x4E,0x42, 0x4F

,0x52, 0x50, 0x54, 0x51, 0x41, 0x52, 0x49, 0x53, 0x47

,0x54, 0x46, 0x55, 0x5A,0x56, 0x58, 0x57, 0x57, 0x58

,0x56, 0x59, 0x48, 0x5A,0x59, 0x30, 0x33, 0x31, 0x39

,0x32, 0x35, 0x33, 0x32, 0x34, 0x34, 0x35, 0x30, 0x36

,0x37,0x37, 0x31, 0x38, 0x36, 0x39, 0x38, 0x7B, 0x28

,0x7D, 0x29, 0x28, 0x3A,0x29, 0x7B, 0x2E, 0x7D, 0x3A

,0x20, 0x20, 0x5F,0x5F, 0x2C, 0x2C, 0xA, 0xA, 0x2E

};

privatestaticboolcharMapInited = false;

privatestaticbyte[]encodedToPlain = new byte[256];

privatestaticbyte[]plainToEncoded = new byte[256];

privatestaticvoidbuildEncryptMap()

{

if(!charMapInited)

{

int v1 = 0;

do

{

encodedToPlain[charMaps[v1 + 1]] = charMaps[v1];

plainToEncoded[charMaps[v1]] = charMaps[v1 + 1];

v1 += 2;

}

while (v1 < 0x90);

charMapInited = true;

}

}

privatestaticcharToPlain(char v)

{

buildEncryptMap();

if(v >= 256) return v;

if(encodedToPlain[v] == 0) return v;

return(char)encodedToPlain[v];

}

privatestaticcharToEncoded(char v)

{

buildEncryptMap();

if(v >= 256) return v;

if(plainToEncoded[v] == 0) return v;

return(char)plainToEncoded[v];

}

privatestaticstringToPlain(string v)

{

char[]r = new char[v.Length];

for(inti = 0; i < v.Length;++i )r[i]= ToPlain(v[i]);

returnnewstring(r);

}

privatestaticstringToEncoded(string v)

{

char[]r = new char[v.Length];

for(inti = 0; i < v.Length; ++i) r[i] = ToEncoded(v[i]);

returnnewstring(r);

}

然后,利用上面的几个函数批量转换整个src目录。打开解密后的Config.luac看看内容。用“记事本”打开,得,没有换行;用“写字板”打开,我去,中文乱码;VS,唉,转换时没有写入BOM头,VS不认识,当二进制显示了。Ultra Edit吧。

-- Config

-- create by zouyb

-- 服务器配置

-- SERVER_IP = "127.0.0.1";

-- SERVER_PORT = "8001";

CC_IP   =  CC_IP or "gumballslogin.leiting.com"

CC_PORT =  CC_PORTor "8050"

-- 默认区组id

DEFAULT_AAA_ID = 1;

-- dislist下载链接

DISLIST_URL_ARR = {

"http://update.leiting.com/gumballs/leiting/ios/dislist/dislist_ios.json",

"http://10.2.49.75:8080/slime/leiting/ios/dislist/dislist.json",

"",

"",

"",

}

-- dislist测试标签

DISLIST_TEST_TAG = "0.5.161125.05"

-- 公告下载链接

OUT_BOARD_URL ="http://update.leiting.com/gumballs/leiting/ios/dislist/out_board.json"

-- WEB公告下载链接

WEB_BOARD_URL ="http://update.leiting.com/gumballs/leiting/ios/web_board"

-- 文件缺失上报地址

MISSING_FILE_URL ="http://update.leiting.com/gumballs/missing_report/missing.php"

-- 更新失败上报地址

DOWNLOAD_ERROR_REPORT_URL ="http://update.leiting.com/gumballs/download_report/error.php"

-- 快捷登录

--EXPRESS_LOGIN = 1

-- 调试模式

DEBUG_MODE = 0

-- 是否允许print

ENABLE_PRINT = 0

-- release日志输出开关

RELEASE_LOG_ENABLED = 0

-- 支持版本号(由version.py自动生成)

SUPPORT_VERSION = "0.5.161120.05"

-- 需求引擎版本号

REQUIRE_ENGINE_VERSION = "2"

-- 是否测试怪物模型

TEST_MONSTER_MODEL = 0;

-- 是否略过炼金引导

SKIP_WORKSHOP_GUIDE = 0;

-- 是否略过新手关卡引导

SKIP_DUNGEON_GUIDE = 0;

-- 功能全开

ALL_FEATURE_OPEN = 0;

-- 显示AUTOPATCH的LOG

-- SHOW_AUTO_PATCH_LOG = 0;

-- 允许切换语言版本

ALLOW_TO_SWITCH_LANG = 0;

-- 获取不到系统语言后/默认语言

DEFAULT_LANGUAGE = "en";

-- 强制更新完整包

FORCE_UPDATE_FULL_PKG = 0;

-- 运营平台

PUBLISH_PLATFORM = "lt"

src目录下的的luac文件有4000多个。我们需要关心的是game目录下的那些,不过也还是有3940多个。看起来很多,其实按照目录去理解,也就那么几个了。

l        base:一些基本工具,一般无需过问

l        cmd:和服务器的通信回调之类的

l        csv:这个不用说了吧,表格型数据都在这儿了

l        formula:各种计算

l        loc:语言包

l        logic:逻辑控制

l        operation:向服务器发送消息

l        scene:几种场景,基本用不上,想象成界面的容器就对了

l        sdk:这个不用管

l        ui:一些具体的界面

game目录下还有3个文件:

l        dislist.jsonc:一个json文件,一些起来了没用的发布信息?

l        PreloadList.luac:看说明:配置在客户端启动后,需要预先加载的内容。这样在后续就可以避免大量的IO读取。需要注意的是,预先加载时应该在比较闲空的页面(目前是准备开始游戏界面和登录界面)

l        StartGame.luac:看名字就知道了。

本章先介绍到这里。下一章我们介绍如何修改luac文件,来达到过过眼瘾的目的。比如,签到获得10万钻石。

00003 不思议迷宫.0001:解密Lua脚本相关推荐

  1. 00003 不思议迷宫.0008:分析了半天我们能干什么?

    00003 不思议迷宫.0008:分析了半天我们能干什么? 玩家数据不能直接修改,间接的似乎也不行,那我们还能干什么? 能干的有很多. 比如,我先问问,大家是如何在炼金坊捡钱的?除开玩模拟器使用按键精 ...

  2. 00003 不思议迷宫.0009.6:一键翻开石板捡取物品

    00003 不思议迷宫.0009.6:一键翻开石板捡取物品 先上主要代码: local function onMyButton_AutoPickUpAllItems(sender, eventType ...

  3. 00003 不思议迷宫.0003:玩家数据真的就不能改了吗?

     00003 不思议迷宫.0003:玩家数据真的就不能改了吗? 玩家数据保存在服务器的数据库里,这使得我们没办法直接修改它.那间接的呢? 在以前,iOS上有一些内购插件,据说可以破解App内购.其 ...

  4. 00003 不思议迷宫.0009.2.1:自动换装:简单规划

     00003 不思议迷宫.0009.2.1:自动换装:简单规划 我今天白天在思考问题之余,又玩了会游戏,下了个竞技场副本,才第一次注意到竞技场中的观众也是可以杀的.当然,是没办法直接攻击观众的,必 ...

  5. 00003 不思议迷宫.0009.9:命运之链

    00003 不思议迷宫.0009.9:命运之链 我不知道别人的怎么样,反正在我的手机们上,仅在该功能刚出来时找到过其他玩家.然后,官方说部分玩家该功能不能用,修复了.可惜的是,自从这个"修复 ...

  6. 00003 不思议迷宫.0009.7:一键采矿(钻石、金蛋等)

    00003 不思议迷宫.0009.7:一键采矿(钻石.金蛋等) 矿有很多种,今天要说的是其中的钻石矿这种,也是就神龙许愿"我想要钻石"后进到夹层中,地上显示的那些需要点击99次(初 ...

  7. 00003 不思议迷宫.0006:客户端的操作如何反应到服务器?

     00003 不思议迷宫.0006:客户端的操作如何反应到服务器? 玩家点击手机屏幕,根据点到内容的不同而执行不同的操作,比如切换画面或者场景.播放动画或声音.发送数据等等.我现在所关心的是点到物 ...

  8. 00003 不思议迷宫.0009.10:Bug之二:免称号锻造、升级装备,合成卷轴

    00003 不思议迷宫.0009.10:Bug之二:免称号锻造.升级装备,合成卷轴 今天玩德古拉城堡,想击杀100层Boss完成"首领礼包".平时我都是用双大地,但一直听说啥主流套 ...

  9. 00003 不思议迷宫.0009.2.2:自动换装:界面模拟

     00003 不思议迷宫.0009.2.2:自动换装:界面模拟 这两天一直在研究游戏的csb解析显示.重用luac之类的问题,中间遇到各种问题,各种痛苦.唉,还是知识储备不足啊,耽搁了不少时间.其 ...

  10. 00003 不思议迷宫.0009.2.4:自动换装:在事件中实现自动换装

     00003 不思议迷宫.0009.2.4:自动换装:在事件中实现自动换装 具体的换装动作如何实现呢?老办法:学原版.在前一章中,我们已经接触过一个叫做"UIEquipsOperatio ...

最新文章

  1. 特别篇 :从 0 开始创作云原生应用 (殷达)
  2. 根据皮肤亮度来区分salmon和sea bass,这个比较好
  3. python分位数回归模型_如何理解分位数回归风险价值 (VaR) 模型?
  4. 无法激活安全认证服务
  5. 初学必读:61条面向对象设计的经验原则
  6. 如何修改服务器Tomcat的首页为项目
  7. go去掉最后一个字符_Go:字符串操作
  8. C/C++线程与多线程工作笔记0005---c/c++中的wchar_t类型
  9. ZooKeeper监控
  10. 网络负载平衡(Network Load Balancing)的工作原理
  11. 【 Codeforces Round #547 (Div. 3) F2】Same Sum Blocks (Hard)【思维贪心】
  12. python表白代码大全简单-程序员python表白代码
  13. 用python开发文本翻译小软件
  14. WinForm BackgroundWorker笔记
  15. android 字体设置为中等粗细
  16. MTK AF如何开启log 录制mobile log 如何full scan(无指令无图片版本)
  17. 【echarts应用】---pie饼图篇
  18. 优教信使同步辅学总是显示服务器,优教信使同步学习卡在教学中的应用论文
  19. 校外培训机构被叫停,中止营业,这属于营业中断险的保障范围吗?
  20. Halo——zcash新的零知识证明机制,无需Trusted Setup

热门文章

  1. python空格隔开输入
  2. 类型多样的数码配件免抠元素素材,速来收藏
  3. Elasticsearch 如何自定义扩展词库?
  4. 腾讯对战平台显示版本服务器连接超时,腾讯对战平台怎么了_腾讯对战平台出现问题怎么解决...
  5. java获取网络时间_java使用ntp同步获取网络时间
  6. fmodex.dll已加载,但找不到入口点怎么解决?
  7. 1分钟让你的App 适配 锤子OneStep
  8. Xmy的Python----Numpy库
  9. Echarts实现以秒为单位的动态三条折线图显示
  10. 千万级中文公开免费聊天语料数据分享