首页
社区
课程
招聘
7
[原创]就算Lua也hook给你看-Corona SDK 游戏魔女防御战的作弊插件
发表于: 2013-3-1 17:25 47351

[原创]就算Lua也hook给你看-Corona SDK 游戏魔女防御战的作弊插件

2013-3-1 17:25
47351

去年发了一个帖子是分析魔女防御战的存档校验. 当时貌似提到了这个程序是Corona SDK, 逻辑核心是lua完成的.


废话不说, 今天我们就来实现针对游戏中lua逻辑的修改.


下载了1.8.0版的Defense Witches, 照例用decar解压(decar -x resource.car .\lu), 得到一堆lu文件.


这些.lu文件+0C的地方开始就是lua字节码, +8是大小.


今天下手的目标决定是初始化的300点, 这里还有个小插曲, 因为一开始以为那个叫做水晶点, 所以费了一番工夫, 各种修改都无效果.


一开始将main.lu反汇编成为main_luadec.asm, 在里面搜索300, 搜索到一行这个:


1
2
117 [-]: LOADK     R0 K64       ; R0 := 300
118 [-]: SETGLOBAL R0 K63       ; GetCrystal := R0



K63/K64都是常量, 存储在这段代码块后面的常量表里面. 在main.lu搜索GetCrystal得到如下数据:



1
2
0A37h: [COLOR=red]04[/COLOR] 0B 00 00 00 47 65 74 43 72 79 73 74 61 6C 00  .....GetCrystal.
0A47h: [COLOR=red]03[/COLOR] [COLOR=darkorange]00 00 00 00 00 C0 72 40[/COLOR]                       ......Àr@


注意橙色标注的部分. 常量表的结构是开头是常量的总数的DWORD, 然后后面跟每条记录. 记录有一个字节的类型和后面的数据构成, 类型这里出现了2种, 03 = Number, 04 = String.



lua的字节码里面, Number是用标准的IEE 754编码的double, 占8个字节. 这个长度从lua头部也可以看出.


顺便八一下字节码文件的头部 前五个字节分别是, 0x1B,Lua, 0x51这里的51指定了是5.1, 后面还有是否是正式版本和Endian/各数据类型长度, 简单的说这个arm游戏的字节码跟x86是一样的.



想要折腾这个SDK的推荐一本pdf叫做ANoFrillsIntroToLua51VMInstructions.pdf, 网上也有各种不同的翻译版本, 里面描述了字节码文件和函数块常量数据, 指令等二进制编码方式.



在010Editor中把光标定位在橙色部分的首字节, 在Data Inspector里面, 在Double一栏将数据从300修改为2300, 保存.


尝试将resource.car做同样修改, 覆盖回程序目录, 试验运行, 果断闪退. 原因吗, 是因为_CodeSignature\CodeResources里面有每个资源文件的签名.



不过这个难不倒我们, 我们可以hook呀. 说干就干, 先用dumpdecrypted.dylib来dump出未加密的主程序, 打开IDA, 在字串列表里查找main.lu



1
2
3
4
5
6
7
8
__text:0008677A 61 6B                                   LDR             R1, [R4,#0x34]
__text:0008677C 01 23                                   MOVS            R3, #1  ; flag
__text:0008677E 20 6C                                   LDR             R0, [R4,#0x40] ; obj
__text:00086780 09 68                                   LDR             R1, [R1] ; a2
__text:00086782 4A F6 F2 42 C0 F2 09 02                 MOV             R2, (aMain_lu - 0x8678E) ; "main.lu"
__text:0008678A 7A 44                                   ADD             R2, PC  ; "main.lu"
__text:0008678C E3 F7 46 FC                             BL              func_executebytecodefile
__text:00086790 80 46                                   MOV             R8, R0





这个被调用的函数定义是这样的


int func_executebytecodefile(ResourceObjRef resource, lua_State *state, const char *filename, int flag)


其中ResourceObjRef是我的定义的类型指针, +0C地方是resource.car完整内容的内存映射指针.


写出替换函数如下:



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[FONT=Consolas][COLOR=blue][COLOR=blue]int[/COLOR][COLOR=#000000] my_func_exebytecodefile([/COLOR][COLOR=blue]ResourceObjRef[/COLOR][COLOR=#000000] resource, [/COLOR][COLOR=blue]lua_State[/COLOR][COLOR=#000000] *state, [/COLOR][COLOR=blue]const[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000] *filename, [/COLOR][COLOR=blue]int[/COLOR][COLOR=#000000] flag) {[/COLOR]
[COLOR=#000000]    [/COLOR][COLOR=blue]if[/COLOR][COLOR=#000000] ([/COLOR][COLOR=green]strcmp[/COLOR][COLOR=#000000](filename, [/COLOR][COLOR=#666666]"main.lu"[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0[/COLOR][COLOR=#000000]) {[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=green]logstderr[/COLOR][COLOR=#000000]([/COLOR][COLOR=#666666]"matched main.lu\n"[/COLOR][COLOR=#000000]);[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=#0080ff]// patch carbuf[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=#0080ff]// 04 0B 00 00 00 47 65 74  43 72 79 73 74 61 6C 00[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=#0080ff]// 03 00 00 00 00 00 C0 72  40[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=blue]uint32_t[/COLOR][COLOR=#000000] start = ([/COLOR][COLOR=blue]uint32_t[/COLOR][COLOR=#000000])resource->[/COLOR][COLOR=#804000]carbuffer[/COLOR][COLOR=#000000];[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=blue]for[/COLOR][COLOR=#000000] ([/COLOR][COLOR=blue]const[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]* ptr = ([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)start; ptr < ([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)start + [/COLOR][COLOR=red]0x100000[/COLOR][COLOR=#000000]; ptr++) {[/COLOR]
[COLOR=#000000]            [/COLOR][COLOR=#0080ff]// B0 B5 02 AF 1C 46 0D 46[/COLOR]
[COLOR=#000000]            [/COLOR][COLOR=blue]if[/COLOR][COLOR=#000000] (*([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)ptr == [/COLOR][COLOR=red]0x00000B04[/COLOR][COLOR=#000000] && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]4[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x74654700[/COLOR][COLOR=#000000] && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]8[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x73797243[/COLOR][COLOR=#000000] && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]12[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x006C6174[/COLOR]
[COLOR=#000000]                && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]16[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x00000003[/COLOR][COLOR=#000000] && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]20[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x72C00000[/COLOR][COLOR=#000000] && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]24[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x40[/COLOR][COLOR=#000000]) {[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=#0080ff]// patch + 17[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=green]logstderr[/COLOR][COLOR=#000000]([/COLOR][COLOR=#666666]"found GetCrystal at 0x%08X\n"[/COLOR][COLOR=#000000], ptr);[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=green]hexdump[/COLOR][COLOR=#000000](ptr, [/COLOR][COLOR=red]25[/COLOR][COLOR=#000000]);[/COLOR]
[COLOR=#000000]                *([/COLOR][COLOR=blue]double[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]17[/COLOR][COLOR=#000000]) = [/COLOR][COLOR=red]800[/COLOR][COLOR=#000000];[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=green]hexdump[/COLOR][COLOR=#000000](ptr, [/COLOR][COLOR=red]25[/COLOR][COLOR=#000000]);[/COLOR]
[COLOR=#000000]            }[/COLOR]
[COLOR=#000000]        }[/COLOR]
[COLOR=#000000]    }[/COLOR]
[COLOR=#000000]    [/COLOR][COLOR=blue]return[/COLOR][COLOR=#000000] [/COLOR][COLOR=#804000]ms_func_exebytecodefile[/COLOR][COLOR=#000000](resource, state, filename, flag);[/COLOR]
[COLOR=#000000]}[/COLOR]
[/COLOR][/FONT]



因为对resource.car映射的内容写将引发bus error, 虽然有办法强写, 不过还是用了更简单的办法, 先复制一份再修改调用. 同时找到更内层的函数进行截取, 但是结果很遗憾, 和一开始说的一样, 这个GetCrystal是水晶也就是内购的货币, 我改错对象了.


然后再次把每个lu文件里面都搜索300.0过程中, 发现game.lu里面的_G["MP"]可能是我们想要的东西.



1
2
3
4
36 [-]: GETGLOBAL R1 K3        ; R1 := _G
37 [-]: SETTABLE  R1 K18 K15   ; R1["MP"] := 0
38 [-]: GETGLOBAL R1 K3        ; R1 := _G
39 [-]: SETTABLE  R1 K19 K20   ; R1["HP"] := 20



这段就是_G.MP = 0; _G.HP = 20; 对应的是画面可以用来购买和升级己方单位的点数和剩余塔的攻击剩余次数.



当时想法是, 初始化是0, 在什么地方被添加成了300吧, 那么我们把初始化的地方改为20, 不就变为320了么?



为什么非要用20, 那是因为SETTABLE opcode里面没有立即数寻址, 只有寄存器和常量寻址.



这个时候要了解一下lua的opcode编码方式了.



SETTABLE R1 K18 K15 是iABC格式的编码, 我们今天所用到的所有修改都是这个格式.


其中SETTABLE(助记符编号)是i, R1(目标) K18(源1) K15(源2)是A B C. 其中B/C可以使用常数和寄存器编号, 使用常数表编号时候, 最高bit置1, 也就是+256.



i的值查表可以得到, 每个opcode对应一个索引, SETTABLE是9, ADD是12.



手动换算的话, 就是9, 1, 256+18, 256+15


将这四个数字化为2进制, 然后按照


B:9 C:9 A:8 i:6的方式组合起来


1
2
100010010 100001111 00000001 001001
8943C049

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞 7
支持
分享
赞赏记录
参与人
雪币
留言
时间
Youlor
看雪因你而更加精彩!
2024-7-24 02:52
伟叔叔
为你点赞~
2024-5-31 07:11
心游尘世外
为你点赞~
2024-5-31 04:07
QinBeast
为你点赞~
2024-5-31 03:57
飘零丶
为你点赞~
2024-4-3 00:03
shinratensei
为你点赞~
2024-2-4 04:05
PLEBFE
为你点赞~
2023-3-7 00:36
最新回复 (31)
雪    币: 143
活跃值: (263)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
2
楼主强帖,学习了
2013-3-1 18:00
0
雪    币: 183
活跃值: (107)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
学习~~学习~~
2013-3-1 18:13
0
雪    币: 2700
活跃值: (63)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
不懂 LUA的 飘过
2013-3-1 18:20
0
雪    币: 56043
活跃值: (21220)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
5
支持曾半仙~~
2013-3-1 22:23
0
雪    币: 1098
活跃值: (193)
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
6
很有质量的帖子,顶一个。
另,附上DWitchesBooster.dylib的源码更好,让我们学习学习。
2013-3-1 22:29
0
雪    币: 16
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
来膜拜下半仙 23333  这才是真菊苣啊
2013-3-1 22:53
0
雪    币: 3759
活跃值: (3432)
能力值: ( LV15,RANK:500 )
在线值:
发帖
回帖
粉丝
8
已加了源码... 因为是只想研究lua这边的部分, 没好好的写, 见笑了
2013-3-1 22:57
0
雪    币: 1925
活跃值: (906)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
9
呵呵,友情支持一个~~~
2013-3-1 23:36
0
雪    币: 55
活跃值: (531)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
10
很牛啊。前来膜拜!
2013-3-2 07:38
0
雪    币: 304
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
大牛大牛,学习学习...
2013-3-2 08:14
0
雪    币: 107
活跃值: (424)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
这个碉堡了...正好最近研究相关的东东...学习了..............
2013-3-2 08:32
0
雪    币: 707
活跃值: (1301)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
13
牛B,学习
2013-3-2 09:02
0
雪    币: 38
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
我想调试一下这个dylib以了解工作原理,但不知道如何能在dylib的入口点下断点,请问如何能用gdb让它断在dylib的入口点呢?
2013-3-2 13:49
0
雪    币: 773
活跃值: (442)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
15
支持曾半仙~o~
2013-3-2 15:11
0
雪    币: 3759
活跃值: (3432)
能力值: ( LV15,RANK:500 )
在线值:
发帖
回帖
粉丝
16
我放了源码了, 你可以编译个带符号的debug版, IDA看下最后一个constructor函数修饰后的名字, 然后gdb里面下断.
其实主要的工作原理就是那个替代函数, 寻找lua的函数块, 然后修改增加2条"lua汇编语句", 入口点只是十分普通的hook流程, 寻找要hook的函数, 调用MSHookFunction, MobileSubstrate就生成2个转发函数, 而且将目标函数头部改为绝对跳转,  第一个转发函数是透明的, 所有调用目标函数的代码, 都会跳转为调用我们的替代函数. 在替代函数中不可以调用原函数, 而是要调用第二个转发函数, 不但为了避免无限递归, 也为了补充被偷掉的函数头.
2013-3-2 18:59
0
雪    币: 102429
活跃值: (201684)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
17
Thanks for share.
2013-3-3 19:20
0
雪    币: 60
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
曾经看过其他半仙前辈的帖子,都很不错,每次有学习到新的内容,
2013-3-3 19:44
0
雪    币: 822
活跃值: (380)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
19
标题这个句式很眼熟啊,楼主是型月厨?
2013-3-3 23:32
0
雪    币: 130
活跃值: (76)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
强,学习ios hook技术
2013-3-4 09:13
0
雪    币: 16
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
半仙只是一只绅士而已,专注舔幼女20年
2013-3-4 11:32
0
雪    币: 8624
活跃值: (4303)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
22
神贴!!!!!
2013-3-4 22:17
0
雪    币: 60
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
大牛啊,
慢慢看,学习一下
2013-3-4 23:13
0
雪    币: 347
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
牛X~
感谢分享
2013-3-6 19:25
0
雪    币: 320
活跃值: (313)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
25
顶啊!楼主lua确实玩得很high。
2013-3-7 18:10
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册