吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 14424|回复: 35
收起左侧

[Android 原创] 二进制比较:破解 LuaJIT 加密脚本的一种新思路。直接修改,无需反编译!

[复制链接]
SQLite 发表于 2020-6-14 00:47
本帖最后由 SQLite 于 2020-9-3 12:01 编辑

        有时候,一些游戏的Lua脚本会采用 LuaJIT 的方式来加密,但有些Lua脚本之间相互引用,导致了现有的反编译工具(如 ljd )无法100%地反编译出某些 LuaJIT 的源文件,进而出现一些“err: unwarper.py assert isinstance(else_warp_out, nodes.EndWarp), ”一类的错误。这也导致了我们反编译LuaJIT之后,虽然看到了 Lua 源文件的一些代码,却因为代码不全而无法重新编译,无法修改游戏逻辑。本文便着眼于该问题,提出了一种无需反编译、直接修改LuaJIT 脚本二进制代码的思路。实例如下:        某传奇类手机游戏有一个“挂机”按钮,点选后能够自动打怪。但在某些“挑战地图”中,该功能无法使用,需要氪金40元才可以。由于挂机功能比较复杂,推测其逻辑是在本地完成,遂对其进行一番剖析,实现了不氪金解锁挂机功能。之前从来没破解过手游,在此简要记录流程如下:
        1、解压游戏的 apk 安装包,发现 lib 文件夹下 有 LuaCocos2d.so , 推测其为基于 Cocos2d 引擎的游戏,用 lua脚本实现游戏逻辑;
        2、翻看游戏对应data目录中的文件,未找到  *.lua 脚本,发现了 ZIP 文件,推测所有Lua脚本打包为了ZIP;
        3、将 ZIP 复制到本地,双击打开提示“不是ZIP格式文件”,用文本编辑器打开,推测是采用了 cocos2d 的 xxtea 加密;
        4、借助 IDA Pro 找到了该 ZIP 的加密 sign 和 key , 使用网上现成的 “XXTEA解密工具” 进行解密;
        5、解密后的 ZIP 包解压后得到很多疑似脚本的文件,但用文本编辑器打开后是乱码,观察头部特征,推测为编译后的 LuaJIT文件;
        6、使用 ljd 这一工具,写了个批处理脚本,对所有 LuaJIT 文件进行反编译,得到 Lua 源码。
        7、通过对源码一番研究,找到了决定挂机能够启动与否的关键位置,将“ if not ”判定修改为“ if ”,应该可以实现既定目标,如图:
7-2 (2)_LI.jpg
然而问题在于,通过 ljd 反编译出来的 lua 源码并不完整, 源码的头几行都是类似于“err: unwarper.py assert isinstance(else_warp_out, nodes.EndWarp), ”一类的错误信息。正因为
lua 源码并不完整,单独修改Lua源码中的“if   not ”语句、并重新编译后的  LuaJIT 二进制文件无法正常使用。  所以通过“改完源码后再进行编译,然后替换原文件”这样的方式无法完成既定目标。


        8、联想到在 X86平台 下的机器码修改技术,尝试不反编译该LuaJIT文件,而是对其二进制代码直接进行修改。【注:以 X86 汇编中的跳转指令为例(因为很多时候 if 语句 在汇编语言中都会用跳转指令实现),JZ指令对应的机器码是 74,而 JNZ 指令对应的机器码是75 ,也就意味着只需要改动一个数值,就能实现逻辑上的反转。】 那么我们应该修改哪里呢?没有IDA 、C32ASM 这样的反汇编工具来辅助分析,我们又应该如何确定“if not ”对应的二进制代码的位置?确定了之后又如何将其改为“if”?
        通过观察,我发现lua脚本编译后的二进制文件和其源码是有一定对应关系的规律可循的。我们做个小实验找到它:
        首先把这个关键函数复制下来,粘贴到 LUA 的 IDE 里面并保存为脚本,然后 使用 LuaJIt.exe 将其编译成二进制文件;再把 if not 改成 if ,使用 LuaJIt.exe 将其编译成另一个二进制文件。
4-2 (2).png
然后用 010 editor 分别打开他俩,对比差异:
5 (2).png
由图可知,二者区别就是一个 0E -> 0F ,一个 03 -> 04 。那我们尝试修改真正的脚本二进制文件:通过在目标二进制文件中搜索图中标红的“020E0003005803”关键字(共找到了9个),结合其中的字符串和汉字的辅助定位,以及之前源码的参考,我确定了想要的那一个位置,并修改之:
7 (2)_LI.jpg      
然后按照 0E -> 0F , 03 -> 04  这么一改,然后替换 ZIP 中解压出来的原LuaJIT文件,重新打包(不用加密也可以),传到手机存储中的原位置替换原 ZIP,就可以实现"挑战地图挂机"这一功能了,看:
00000.png
当然,由于我们只修改了一处判定逻辑,这么改就导致普通地图没办法挂机了。因为本文只做可行性研究,后续代码的完善就不讲了。
【后续:将以上代码改为 0E 00 00 后  无论是正常地图还是挑战地图,都可以挂机了。详情见本帖 第15楼 】

免费评分

参与人数 12威望 +1 吾爱币 +33 热心值 +12 收起 理由
qtfreet00 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zhoumeto + 1 + 1 用心讨论,共获提升!
Brownbear + 1 + 1 热心回复!
RainH + 1 谢谢@Thanks!
pk8900 + 3 + 1 是个不错的思路,有时间好好学习一下,谢谢楼主分享。
zerglurker + 1 + 1 我很赞同!
印象主义协会 + 1 + 1 我很赞同!
mihacker + 1 谢谢@Thanks!
笙若 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
qq空空如也 + 1 + 1 谢谢@Thanks!
qaz003 + 2 + 1 有创意
dongfang155 + 2 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wangyujie96 发表于 2020-6-14 22:14
逆向功底有待提升,0E 00 03 改成0E 00 00或者0F 00 00 更好
monvvv 发表于 2020-6-14 12:16
dongfang155 发表于 2020-6-14 01:19
TANQIZHI 发表于 2020-6-14 01:40
谢谢楼主分享    辛苦了
radargo 发表于 2020-6-14 01:49
优秀的思路,学习了
话说lua的反编译还没有突破吗
君醉戏红颜 发表于 2020-6-14 02:16
谢谢分享
qaz003 发表于 2020-6-14 05:04
谢谢分享,没法成功重编时不失为一个好方法
gh0st_ 发表于 2020-6-14 07:13
学习了好思路
Skyfly 发表于 2020-6-14 08:08
不是直接把那个return删了就能实现挂机了吗
 楼主| SQLite 发表于 2020-6-14 09:09
本帖最后由 SQLite 于 2020-6-14 09:16 编辑
Skyfly 发表于 2020-6-14 08:08
不是直接把那个return删了就能实现挂机了吗

我们想要修改的  LuaJIT 二进制文件是看不到 return 这个指令的,无法实现你说的删除。本文中出现的 “return” 只能在反编译出来的Lua 文件中看到,并未存在于游戏中的原始文件。而在 该Lua文件中中删掉“return"固然简单,但是删掉之后没办法重新编译为LuaJIT 啊(因为源码不全,编译出来之后不能正常使用).只能修改原始文件的二进制代码。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 14:17

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表