|
本帖最后由 jiangzhengwenjz 于 2015-3-25 22:27 编辑
原作者FBI agent,这次debug的难度个人觉得显著小,但作者认为其难度高于上一篇。
拒绝转载,这篇不是教程是手记,仅作记录和分享之用,若要转载请转原帖。
这一篇的内容是扩充道具名称字母数量。
第一部分:目的介绍
目的:扩充道具名称字母数量
基本想法:读取道具名称的地址时,设置新程序,若第一个字节为FF转而读取道具名称的指针,以突破原表格的限制。
第二部分:认识数据表格
由于bulbapedia上有现成的道具数据结构的资料,所以可以查资料。或是通过搜索道具名称的ASCII码来找到表格。
顺便,给出道具表格的数据结构:(来自bulbapedia)
Offset Field Size
0 Name 14 bytes
14 Index number 2 bytes
16 Price 2 bytes
18 Hold effect 1 byte
19 Parameter 1 byte
20 Description pointer 4 bytes
24 Mystery value 2 bytes
26 Pocket 1 byte
27 Type 1 byte
28 Pointer to field usage code 4 bytes
32 Battle usage 4 bytes
36 Pointer to battle usage code 4 bytes
40 Extra parameter 4 bytes
这样,限制一清二楚。
第三部分:debug
以下以burn heal作为例子(火红U)
首先如何下断这个太容易了,在burn heal的地址那里添加bpr即可(no$gba应该是"?")
打开背包转到burn heal的那一页,会被断到。
那么接下来自然是反汇编,利用vba的反汇编功能或vba-sdl-h的dt指令即可。
游戏在0x8D90被断,而在0x8D84注意到push {lr}指令。
那么自然是先分析下这个程序:
- MAIN:
- ROM:08008D84 PUSH {LR}
- ROM:08008D86 MOV R3, R0
- ROM:08008D88 B SECTION
- SECTION2:
- ROM:08008D8A STRB R2, [R3]
- ROM:08008D8C ADDS R3, #1
- ROM:08008D8E ADDS R1, #1
- SECTION:
- ROM:08008D90 LDRB R2, [R1]
- ROM:08008D92 MOV R0, R2
- ROM:08008D94 CMP R0, #0xFF
- ROM:08008D96 BNE SECTION2
- ROM:08008D98 MOV R0, #0xFF
- ROM:08008D9A STRB R0, [R3]
- ROM:08008D9C MOV R0, R3
- ROM:08008D9E POP {R1}
- ROM:08008DA0 BX R1
复制代码
这是一个典型的读取-存入-循环-判断的例子,做的事情也很清楚:
从ROM读取名称数据→写入内存(如果注意下内存地址的话是0x020041F1,对应于r0,而r1对应于文本的指针,相当于拿这两个寄存器的值作参数)
分析完毕,那么接下来不妨在0x08008D8A下断,看看这段程序如何被调用(注意r1来确保在合适的地方断了)
发现前面是bl指令,在8db4的位置。(注意bl占用4字节的特性)
而这里又是对应了一段程序:
- ROM:08008DA4 PUSH {LR}
- ROM:08008DA6 MOV R2, R0
- ROM:08008DA8 B 08008DAC
- ROM:08008DAA ADDS R2, #1
- ROM:08008DAC LDRB R0, [R2]
- ROM:08008DAE CMP R0, #0xFF
- ROM:08008DB0 BNE 08008DAA
- ROM:08008DB2 MOV R0, R2
- ROM:08008DB4 BL 08008D84
- ROM:08008DB8 POP {R1}
复制代码
显然,此处的作用是找到FF的位置,然后把它存在R0。而这个程序的参数也是R0。可能是用于在内存中完成单词的拼合。
那么在8DA4下断,依然通过r1来确保在合适地方断掉。
发现是在0x108596通过bl指令被调用,查看这个指令属于哪个程序。(反汇编)
程序稍显复杂:
- ROM:08108560 PUSH {R4,R5,LR}
- ROM:08108562 MOV R4, R0
- ROM:08108564 LSL R1, R1, #0x10
- ROM:08108566 LSR R5, R1, #0x10
- ROM:08108568 LDR R0, =0xFE940000
- ROM:0810856A ADDS R1, R1, R0
- ROM:0810856C LSR R1, R1, #0x10
- ROM:0810856E CMP R1, #1
- ROM:08108570 BHI SECTION
- ROM:08108572 LDR R1, =a489
- ROM:08108574 MOV R0, R4
- ROM:08108576 BL 08008D84
- ROM:0810857A B 0810858C
- ----------------------- 一些指针
- SECTION:
- ROM:08108584 LDR R1, =a423
- ROM:08108586 MOV R0, R4
- ROM:08108588 BL 08008D84
- ROM:0810858C MOV R0, R5
- ROM:0810858E BL 0809A8BC
- ROM:08108592 MOV R1, R0
- ROM:08108594 MOV R0, R4
- ROM:08108596 BL 08008DA4
- ROM:0810859A POP {R4,R5}
- ROM:0810859C POP {R0}
- ROM:0810859E BX R0
复制代码
其中跳转的两个地方都已经分析过是干什么的了,注意到在10858E有未知程序。
根据ROM中程序的一般规律,结合mov r1, r0可以推测这个程序把内存中文本的指针写入r0。
当然我们还是反汇编来看看:
- push {lr}
- lsl r0, r0, #0x10
- lsr r0, r0, #0x10
- bl 0x809A8A4
- lsl r0, r0, #0x10
- lsr r0, r0, #0x10
- mov r1, #0x2C
- mul r0, r0, r1
- ldr r1, =(0x83DB028)
- add r0, r0, r1
- pop {r1}
- bx r1
复制代码
注意到其中又有bl跳转,那不妨在跳转的地址下断(0809A8A4)
依然忽略掉不符合条件的break,注意到此时r0的值极为特殊恰好是0xF,对应burn heal的道具ID!(如何确定不是巧合?多次测试即可)
在09A8A4反汇编,得到程序代码(标签版)
- main:
- push {lr}
- lsl r0, r0, #0x10
- lsr r1, r0, #0x10
- mov r0, #0xBB
- lsl 0, r0, #0x1
- cmp r1, r0
- bhi return_zero
- add r0, r1, #0x0
- b end
- return_zero:
- mov r0, #0x0
- end:
- pop {r1}
- bx r1
复制代码
而其中- lsl r0, r0, #0x10
- lsr r1, r0, #0x10
复制代码 不过是清空寄存器中数据的两个高位并存入r0罢了。不难看出这程序不过是个防止ID超出范围的辅助程序。
那么,原程序的意义就清楚了,撇开不重要的就是得到道具名称的地址。
第四部分:强设跳转
这部分比较容易,注意到pop{r1}后bx r1,相当于pop{r15},所以不妨干脆就在这里设跳转
然后程序必须从结尾为0,4,8,C的地方开始。(否则那个word会misaligned,不过个人认为这个问题编译器能解决,只不过地方稍稍浪费)
(从mul r0, r0, r1的地方开始写)
.thumb
ldr rX, label
bx rX
.align 2
label: .word 0xXXXXXXXX
注:此处跳转个人认为最好能push和pop rX,否则可能造成问题,但作者没这么做而是直接用了r2。当我没说,一时脑子没转过来
第五部分:编写程序
极为容易,不多啰嗦了
- .text
- .align 2
- .thumb
- main:
- mul r0, r0, r1
- ldr r1, label
- add r0, r0, r1
- ldrb r1, [r0]
- cmp r1, #0xFF
- bne end
- readPointer:
- ldr r0, [r0, #0x4]
-
- end:
- pop {r1}
- bx r1
- .align 2
- label: .word 0x83DB028
复制代码
注意新增指针的位置前是FF000000以使其word-aligned
注:这种方法依然有严重缺陷, 那就是道具在背包中无法正常显示!问题应该是出在向内存中存道具名称的过程,具体是什么问题大家可以测试。但是,脚本中bufferitem命令可用。
如有错误,望指正 |
|