首页
论坛
课程
招聘
[原创]就算Lua也hook给你看-Corona SDK 游戏魔女防御战的作弊插件
2013-3-1 17:25 39251

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

2013-3-1 17:25
39251
去年发了一个帖子是分析魔女防御战的存档校验. 当时貌似提到了这个程序是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, 搜索到一行这个:
  117 [-]: LOADK     R0 K64       ; R0 := 300
  118 [-]: SETGLOBAL R0 K63       ; GetCrystal := R0 


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

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

__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完整内容的内存映射指针.
写出替换函数如下:

[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"]可能是我们想要的东西.

   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的方式组合起来
100010010 100001111 00000001 001001
8943C049

将C的K15替换为K20后如下
100010010 100010100 00000001 001001
89450049

修改后运行, mp依然是300.
然后逐个寻找操作mp的, 最后在status.lu中发现了如下代码
    0 [-]: LOADK     R1 K0        ; R1 := "SELECT ratio, firstmp FROM information WHERE id=1 AND flag=0"
    1 [-]: LOADNIL   R2 R2        ; R2 := nil
    2 [-]: SELF      R3 R0 K1     ; R4 := R0; R3 := R0["nrows"]
    3 [-]: MOVE      R5 R1        ; R5 := R1
    4 [-]: CALL      R3 3 4       ; R3,R4,R5 := R3(R4,R5)

原来还有这一招, 每个地图初始化mp都是sqlite数据库中指定的, 存放在data\map\01\001.sqlite这样的路径里.
这里就有两种选择了, 要么hook读写地图数据地方, 提供虚假的数据库内容.
不过接着往下看

   34 [-]: DIV       R4 R4 K10    ; R4 := R4 / 100
   35 [-]: SETTABLE  R3 K8 R4     ; R3["EnemyScaleBase"] := R4
   36 [-]: GETGLOBAL R3 K2        ; R3 := _G
   37 [-]: GETTABLE  R4 R2 K12    ; R4 := R2["firstmp"]
// TODO: insert ADD R4 R4 R4 or MUL R4 R4 K10 or MUL R4 R4 R4
   38 [-]: SETTABLE  R3 K11 R4    ; R3["MP"] := R4


这里将数据库的查询结果, 存储到_G["MP"]中. 这时候我考虑补丁代码会造成后面的东西整体偏移, 不如自己做一个字节码文件, 额外执行一次, 专门修改_G["MP"]的值.

撰写lua文件如下, 并用luac编译.
module(..., package.seeall)
function Init()
  _G.MP = _G.MP * 2
end


编译后, 在执行status.lu后执行一次我们的bytecode. 结果是… 返回后没事, 执行其他lu时候崩掉了.

execute c02_becky08.lu
2013-03-01 05:34:35.332 D.Witches[10534:707] Lua Runtime Error: lua_pcall failed with status: 2, error message is: ?:0: attempt to index field '?' (a nil value)


没关系, 我们就费点事, 补丁掉37行的地方吧.
lua的每个函数块开头都有固定格式的头部.

[COLOR="Gray"]00 00 00 00 [/COLOR][COLOR="YellowGreen"]92 00 00 00[/COLOR] [COLOR="SeaGreen"]A2 00 00 00[/COLOR] 05 00 00 05 [COLOR="SandyBrown"]2A 00 00 00[/COLOR]


其中00000000是存储函数名的, 这里为空. 接着两个DWORD分别是代码开始行和结束行. 这个行指的是源码的行, 我们模拟在源码插入一行_G.MP = _G.MP + _G.MP, 顺便将结束行也加一为妙.

要补丁的有2A000000这个是属于bytecode代码块列表的数量字段, 描述的是虚拟机的字节码.
每条指令都是4字节, 这个数量必须改.
为了方便算字节码, 写了个小程序luaasm, 可以接收数字或者汇编输入
$ luaasm iABC 12 4 4 4
opcode: 0x0201010C

$ luaasm iABC ADD R4 R4 R4
12 4 4 4 -> opcode: 0x0201010C


其中12是ADD的编号, R4 = R4 + R4就会把300 MP给倍增.
原理类似于x86里面, 从某内存地址取值存在EDX中再放进目标地址, 此时我们倍增EDX的效果相同.

最后测试了插入2条MP*2代码也无误, 就没有继续测试MP*200了(第二条改为*100和第一条叠加)
最终代码如下:

[COLOR=blue][FONT=Consolas][COLOR=blue][COLOR=blue][COLOR=blue]int[/COLOR][COLOR=#000000] my_func_executelu([/COLOR][COLOR=blue]lua_State[/COLOR][COLOR=#000000] *state, [/COLOR][COLOR=blue]const[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000] *buffer, [/COLOR][COLOR=blue]int[/COLOR][COLOR=#000000] size, [/COLOR][COLOR=blue]const[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000] *subfilename)[/COLOR]
[COLOR=#000000]{[/COLOR]
[COLOR=#000000]    [/COLOR][COLOR=blue]if[/COLOR][COLOR=#000000] ([/COLOR][COLOR=green]strcmp[/COLOR][COLOR=#000000](subfilename, [/COLOR][COLOR=#666666]"status.lu"[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0[/COLOR][COLOR=#000000] && [/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000] == [/COLOR][COLOR=blue]NULL[/COLOR][COLOR=#000000]) {[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=green]logstderr[/COLOR][COLOR=#000000]([/COLOR][COLOR=#666666]"matched status.lu\n"[/COLOR][COLOR=#000000]);[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=#0080ff]// patch SETTABLE[/COLOR]
[COLOR=#000000]        [/COLOR][COLOR=blue]uint32_t[/COLOR][COLOR=#000000] start = ([/COLOR][COLOR=blue]uint32_t[/COLOR][COLOR=#000000])buffer;[/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 + size; ptr++) {[/COLOR]
[COLOR=#000000]            [/COLOR][COLOR=#0080ff]//92 00 00 00 A2 00 00 00 05 00 00 05 2A 00 00 00[/COLOR]
[COLOR=#000000]            [/COLOR][COLOR=blue]if[/COLOR][COLOR=#000000] (*([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)ptr == [/COLOR][COLOR=red]0x00000092[/COLOR][COLOR=#000000] && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]4[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x000000A2[/COLOR][COLOR=#000000] && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]8[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x05000005[/COLOR][COLOR=#000000] && *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)(ptr+[/COLOR][COLOR=red]12[/COLOR][COLOR=#000000]) == [/COLOR][COLOR=red]0x0000002A[/COLOR][COLOR=#000000]) {[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=green]logstderr[/COLOR][COLOR=#000000]([/COLOR][COLOR=#666666]"found Init chunk at 0x%08X\n"[/COLOR][COLOR=#000000], ptr);[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=#0080ff]// make backup[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000] = ([/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)[/COLOR][COLOR=green]malloc[/COLOR][COLOR=#000000](size + [/COLOR][COLOR=red]8[/COLOR][COLOR=#000000]); [/COLOR][COLOR=#0080ff]// expand for MP*2[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=green]memcpy[/COLOR][COLOR=#000000]([/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000], buffer, size);[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=green]memcpy[/COLOR][COLOR=#000000]([/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000] + (ptr + [/COLOR][COLOR=red]0xA8[/COLOR][COLOR=#000000] + [/COLOR][COLOR=red]8[/COLOR][COLOR=#000000] - ([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)start), ptr + [/COLOR][COLOR=red]0xA8[/COLOR][COLOR=#000000], size - (ptr + [/COLOR][COLOR=red]0xA8[/COLOR][COLOR=#000000] - ([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)start));[/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=green]atexit[/COLOR][COLOR=#000000]([/COLOR][COLOR=green]freestatuslu[/COLOR][COLOR=#000000]);[/COLOR]
[COLOR=#000000]                [/COLOR]
[COLOR=#000000]                *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)([/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000] + (ptr + [/COLOR][COLOR=red]0xA8[/COLOR][COLOR=#000000] - ([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)start)) = [/COLOR][COLOR=red]0x0201010C[/COLOR][COLOR=#000000]; [/COLOR][COLOR=#0080ff]// 300 * 2[/COLOR]
[COLOR=#000000]                *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)([/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000] + (ptr + [/COLOR][COLOR=red]0xA8[/COLOR][COLOR=#000000] + [/COLOR][COLOR=red]4[/COLOR][COLOR=#000000] - ([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)start)) = [/COLOR][COLOR=red]0x0201010C[/COLOR][COLOR=#000000]; [/COLOR][COLOR=#0080ff]// 600 * 2[/COLOR]
[COLOR=#000000]                [/COLOR]
[COLOR=#000000]                *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)([/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000] + (ptr + [/COLOR][COLOR=red]0x04[/COLOR][COLOR=#000000] - ([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)start)) = [/COLOR][COLOR=red]0x000000A4[/COLOR][COLOR=#000000];[/COLOR]
[COLOR=#000000]                *([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000]*)([/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000] + (ptr + [/COLOR][COLOR=red]0x0C[/COLOR][COLOR=#000000] - ([/COLOR][COLOR=blue]unsigned[/COLOR][COLOR=#000000] [/COLOR][COLOR=blue]char[/COLOR][COLOR=#000000]*)start)) = [/COLOR][COLOR=red]0x0000002C[/COLOR][COLOR=#000000];[/COLOR]
[COLOR=#000000]                [/COLOR]
[COLOR=#000000]                [/COLOR][COLOR=blue]return[/COLOR][COLOR=#000000] [/COLOR][COLOR=#804000]ms_func_executelu[/COLOR][COLOR=#000000](state, [/COLOR][COLOR=#804000]g_statuslu[/COLOR][COLOR=#000000], size + [/COLOR][COLOR=red]8[/COLOR][COLOR=#000000], subfilename); [/COLOR][COLOR=#0080ff]// with new buffer[/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_executelu[/COLOR][COLOR=#000000](state, buffer, size, subfilename);[/COLOR]
[COLOR=#000000]}[/COLOR]
[/COLOR][/COLOR][/FONT][COLOR=blue][/COLOR]
[/COLOR]


这段代码并未做到通用, 理想的方式是自带lua字节码反汇编功能, 能选择插入的位置同时修改所有位于修改点后的代码块对应的源码行数(其实不改也正常.)

hook的方式是用mobilesubstrate, 搜索函数头指纹并hook为替代函数. 代码丑可能还有拼写错误...

运行截图如下


可见初始化的300 MP经过两次翻倍, 变成了1200, 写好过滤条件打包为deb收工不提~~

附送luaasm.exe工具和源码. 没写完, 只认 ADD R4 R4 K10这种格式的iABC指令, 也可以输入4个数字.
$ luaasm iABC ADD R4 R4 R4
12 4 4 4 -> opcode: 0x0201010C

$ luaasm iABC MUL R4 R4 K10
14 4 4 266 -> opcode: 0x0242810E

[注意] 欢迎加入看雪团队!base上海,招聘安全工程师、逆向工程师多个坑位等你投递!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (31)
雪    币: 124
活跃值: 活跃值 (102)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
透明色 活跃值 2 2013-3-1 18:00
2
0
楼主强帖,学习了
雪    币: 170
活跃值: 活跃值 (12)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
CNNY 活跃值 1 2013-3-1 18:13
3
0
学习~~学习~~
雪    币: 2700
活跃值: 活跃值 (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wyufei 活跃值 2013-3-1 18:20
4
0
不懂 LUA的 飘过
雪    币: 417
活跃值: 活跃值 (6509)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2013-3-1 22:23
5
0
支持曾半仙~~
雪    币: 1066
活跃值: 活跃值 (91)
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
zhuliang 活跃值 5 2013-3-1 22:29
6
0
很有质量的帖子,顶一个。
另,附上DWitchesBooster.dylib的源码更好,让我们学习学习。
雪    币: 16
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Mikukon 活跃值 2013-3-1 22:53
7
0
来膜拜下半仙 23333  这才是真菊苣啊
雪    币: 1526
活跃值: 活跃值 (1141)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
曾半仙 活跃值 10 2013-3-1 22:57
8
0
已加了源码... 因为是只想研究lua这边的部分, 没好好的写, 见笑了
雪    币: 1294
活跃值: 活跃值 (56)
能力值: ( LV9,RANK:490 )
在线值:
发帖
回帖
粉丝
yijun8354 活跃值 12 2013-3-1 23:36
9
0
呵呵,友情支持一个~~~
雪    币: 46
活跃值: 活跃值 (384)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
hrpirip 活跃值 1 2013-3-2 07:38
10
0
很牛啊。前来膜拜!
雪    币: 304
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dbcoo 活跃值 2013-3-2 08:14
11
0
大牛大牛,学习学习...
雪    币: 113
活跃值: 活跃值 (90)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Fido 活跃值 2013-3-2 08:32
12
0
这个碉堡了...正好最近研究相关的东东...学习了..............
雪    币: 661
活跃值: 活跃值 (620)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
qyc 活跃值 4 2013-3-2 09:02
13
0
牛B,学习
雪    币: 38
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiaoAngel 活跃值 2013-3-2 13:49
14
0
我想调试一下这个dylib以了解工作原理,但不知道如何能在dylib的入口点下断点,请问如何能用gdb让它断在dylib的入口点呢?
雪    币: 728
活跃值: 活跃值 (131)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
房有亮 活跃值 3 2013-3-2 15:11
15
0
支持曾半仙~o~
雪    币: 1526
活跃值: 活跃值 (1141)
能力值: ( LV13,RANK:410 )
在线值:
发帖
回帖
粉丝
曾半仙 活跃值 10 2013-3-2 18:59
16
0
我放了源码了, 你可以编译个带符号的debug版, IDA看下最后一个constructor函数修饰后的名字, 然后gdb里面下断.
其实主要的工作原理就是那个替代函数, 寻找lua的函数块, 然后修改增加2条"lua汇编语句", 入口点只是十分普通的hook流程, 寻找要hook的函数, 调用MSHookFunction, MobileSubstrate就生成2个转发函数, 而且将目标函数头部改为绝对跳转,  第一个转发函数是透明的, 所有调用目标函数的代码, 都会跳转为调用我们的替代函数. 在替代函数中不可以调用原函数, 而是要调用第二个转发函数, 不但为了避免无限递归, 也为了补充被偷掉的函数头.
雪    币: 35843
活跃值: 活跃值 (153786)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
linhanshi 活跃值 2013-3-3 19:20
17
0
Thanks for share.
雪    币: 60
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
white、、 活跃值 2013-3-3 19:44
18
0
曾经看过其他半仙前辈的帖子,都很不错,每次有学习到新的内容,
雪    币: 755
活跃值: 活跃值 (87)
能力值: ( LV12,RANK:310 )
在线值:
发帖
回帖
粉丝
古河 活跃值 6 2013-3-3 23:32
19
0
标题这个句式很眼熟啊,楼主是型月厨?
雪    币: 124
活跃值: 活跃值 (39)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ouyangtian 活跃值 2013-3-4 09:13
20
0
强,学习ios hook技术
雪    币: 16
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Mikukon 活跃值 2013-3-4 11:32
21
0
半仙只是一只绅士而已,专注舔幼女20年
雪    币: 3219
活跃值: 活跃值 (471)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
sisess 活跃值 1 2013-3-4 22:17
22
0
神贴!!!!!
雪    币: 80
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hwhaocool 活跃值 2013-3-4 23:13
23
0
大牛啊,
慢慢看,学习一下
雪    币: 346
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
YwdxY 活跃值 2013-3-6 19:25
24
0
牛X~
感谢分享
雪    币: 299
活跃值: 活跃值 (48)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
cogito 活跃值 2013-3-7 18:10
25
0
顶啊!楼主lua确实玩得很high。
游客
登录 | 注册 方可回帖
返回