admin管理员组

文章数量:1533122

2023年12月13日发(作者:)

love2d引擎手游修改一例

love 2d 介绍

LÖVE是一个使用 Lua 作为编程语言的 2D 游戏框架,网络上关于此引擎的修改教程还是相对较少。此次下手的目标为王国保卫战,这个手游已

经有很多破解版本。这里还是记录一下我自己的摸索过程,从定位关键代码到修改。

1. 定位资源文件

一般手游的程序逻辑都是以脚本的形式存储在apk的资源文件中,这次目标apk是从 google play 下载,从 /data/app 目录中pull出apk,得到

apk的解压结果如下:

├──

├── META-INF

├── assets

├──

├── error_prone

├── fabric

├── jsr305_annotations

├── lib

├── res

├──

└── third_party

看了一下大小,才9.5m大小,zip包中没发现资源文件:

ls -l

-rw-r--r--@ 1 max admin 9469378

这就很奇怪了,看了一下空间占用了近 200m ,而且 /data/data 目录下也没有找到关键资源文件:

不过还是在一个名为 DownloadsDB 数据库文件中发现了一个下载链接

看到google的url,我怀疑是Play Store的特殊机制,因此在国内的应用中较为少见。网上查了一下,果不其然,这应该就是 obb 文件了,用于

资源文件分发,减小apk体积。

这样应用更新的时候就不必重新下载整个apk, 同时,google 的服务器在国外的稳定性与速度都不差,也可以为开发者节省部分cdn费用。打开

压缩包,果不其然,里面存放着游戏脚本,大小也有100m多,这就正好可以对上号了:

2. 定位关键代码

根据上一步资源文件的解压结果来看,这些 lua 脚本应该就是程序逻辑了。打开一个lua文件,先看看hex,为 luajit 文件:

使用 luajit-decompiler (/znixian/luajit-decompiler) 把 luajit 文件反编译成明文,使用方法如下:

python3 ./ --recursive ./ --dir_out ./ --catch_asserts

这样就可以得到明文 lua 脚本:

main_

手游里,想要定位钻石有关代码,一般都是搜索 gem 关键字,搜索到一个可疑文件 platform_services_ ,代码如下:

--- 观看广告时会调用

function ads:show_video_ad(provider, reward_amount)

local function cb_show_video_ad(status, req)

local success = status == 0

if success then

("ad complete: rewarding %s gems", reward_amount)

--- 获取存档中的物品

local slot = storage:load_slot()

if slot then

--- 观看广告后所得钻石增加 reward_amount 个

= + reward_amount

--- 把增加后的钻石再保存到存档中

storage:save_slot(slot, nil, true)

else

("error giving gems reward. slot could not be loaded")

end

end

(SGN_PS_AD_SHOW_VIDEO_FINISHED, "ads", success, reward_amount)

end

......

上面那段代码,在每次观看广告获取钻石时被调用,这样我们的修改思路就很明确了,只要让

storage:load_slot()

函数每次返回的钻石数为我们指

定的,就可以达到目的了。

3. 修改脚本

在 /all/ 中直接定位到

storage:load_slot()

的实现:

function storage:load_slot(idx, force)

... 参数检查

local input = self:load_lua((_FILE_FMT, idx), force)

... 参数检查

--- 读取 SLOT_ADDITIONAL_DATA 到 result,并返回

for k, v in pairs(SLOT_ADDITIONAL_DATA) do

if not input[k] then

input[k] = v

end

end

return input

end

再看一眼 SLOT_ADDITIONAL_DATA, gems 就是我们要动手的目标了:

local SLOT_ADDITIONAL_DATA = {

gems = 0,

bag = {}

}

直接 patch

storage:load_slot()

函数,添加两行代码,改的时候可以多尝试一下,改错了会导致游戏蓝屏或闪退:

function storage:load_slot(idx, force)

...

for k, v in pairs(SLOT_ADDITIONAL_DATA) do

if not input[k] then

input[k] = v

end

end

input["gems"] = 88888

print("[MaxLog]", input["gems"])

return input

使用 luajit 编译修改好的文件

luajit-2.1.0-beta3 -bg ./all/ ./

4. 测试运行

obb 文件是通过使用时 mount 到应用沙盒 /data/data 目录下,我在文件管理器中未找到真实文件,具体原理还没有研究 obb 机制。我的解

决方案是 Hook

open()

函数,把原脚本文件替换为我们修改过的的文件。

1. 把修改过的脚本文件放入 /data/local/tmp 中:

adb push /data/local/tmp

2. Hook libc 的

open()

函数:

int new_open(const char *name, int flags, ...) {

mode_t mode = 0;

if ((flags & O_CREAT) != 0) {

va_list args;

va_start(args, flags);

mode = static_cast(va_arg(args, int));

va_end(args);

}

LOGD("Tag", "open("%s", %d)", name, flags);

if (strstr(name, "all/")) {

// LOGD("Tag", "open("%s", %d)", name, flags);

return old_open("/data/local/tmp/", O_RDONLY);

}

return old_open(name, flags, mode);

}

3. 运行游戏,在 Lua 脚本中打的 Log ,也可以查看到:

4. 游戏里的钻石也成为指定的数额:

总结

其实破解修改手游大致都可以总结以下几个套路:

1. 解密脚本

常见的几个游戏引擎u3d、cocos2dx,都可以解出游戏逻辑脚本,这些脚本也是我们主要关注的目标。需要注意的是可能存在jit、aot等情

况,这时候就需要进行加密解密操作。

2. 定位代码

通过搜索可以关键字,分析代码逻辑,找到需要修改的地方。

3. 修改测试

明文脚本可以直接修改,密文脚本注意还原,还可以使用Hook等手段直接动态修改内存。

本文标签: 文件修改脚本钻石代码