Sep 29, 2005

Hack Primer 编外篇—简单Hack集

Hack Primer (5) 0832 The King Of Fighters EX2 Howling Blood +隐藏要素


  把2010228h和229h置为FFh打开隐藏模式,拦截到这里的写入操作,然后我选择在809c1a4h跳转(因为这时r4刚好有需要的值)。这是添加的代码:



080A8122>B5FF push r0-r7,lr
080A8124 20FF mov r0,0FFh
080A8126 7020 strb r0,[r4]
080A8128 7060 strb r0,[r4,1h]
080A812A BCFF pop r0-r7
080A812C 46C0 nop
080A812E BD00 pop pc



----------------------------------
Hack Primer (5) 1959 - Killer 3D Pool (E) +所有人物


  从内存的3001030h到300103Fh都设置为1可以打开隐藏人物。由于没有拦截到程序写这一段内存,所以我们找一段代码来跳转。



08006A64 4684 mov r12,r0
08006A66 2784 mov r7,84h
08006A68 063F lsl r7,r7,18h
08006A6A 1AF1 sub r1,r6,r3
08006A6C 4561 cmp r1,r12
08006A6E D901 bls 8006A74h
08006A70 2180 mov r1,80h
08006A72 0109 lsl r1,r1,4h
08006A74 4A0A ldr r2,=40000D4h
08006A76 6015 str r5,[r2]
08006A78 6054 str r4,[r2,4h]
08006A7A F041FF81 bl 8048980h <<<<<这里的语句我们替换了.
08006A7E DA00 bge 8006A82h
08006A80 1CC8 add r0,r1,3
08006A82 1080 asr r0,r0,2h
08006A84 4338 orr r0,r7
08006A86 6090 str r0,[r2,8h]
08006A88>6890 ldr r0,[r2,8h]
08006A8A 185B add r3,r3,r1
08006A8C 186D add r5,r5,r1
08006A8E 1864 add r4,r4,r1
08006A90 42B3 cmp r3,r6
08006A92 D3EA bcc 8006A6Ah
08006A94 BCF0 pop r4-r7
08006A96 BC01 pop r0
08006A98 4700 bx r0



  为什么要这一段呢?EC里面的数据是被锁定的,这一段代码应该是和图像显示有关的代码(我不确定)。我发现它不停的运行,所以要是我们在这里插入我们的代码就可以实现类似的锁定效果。



08048980 B5FF push r0-r7,lr
08048982 4A1F ldr r2,=3001030h
08048984 2001 mov r0,1h
08048986 2100 mov r1,0h
08048988 7010 strb r0,[r2]
0804898A 3201 add r2,1h
0804898C 3101 add r1,1h
0804898E 2910 cmp r1,10h
08048990 D1FA bne 8048988h
08048992 BCFF pop r0-r7
08048994 1C08 mov r0,r1<<<<<<<这里是我们原来替换的代码
08048996 2900 cmp r1,0h<<<<<<<
08048998 BD00 pop pc



  这个时候密码随便输入吧~~反正人物都出来了。

Hack Primer (4) Hack的一般过程


  Hack是一个很复杂的过程。从有人Hack成功后,就有人开始学习如何Hack。我们通常所看到的是对于方法的提问,固然方法是重要的,但是对于过程我们也应该关注一下。
  就像我们为了得到一个结果,可以采用不同的算法或者模式。但是面对同样的算法或者模式的时候,不同的结果也不停的出现。这不能不说是过程在这中间起了非常重要的作用。


  我也是才开始研究Hack,不能说有什么深入的了解。不过是我对Hack的一点认识。(后面一我的一个例子)Hack的一般过程:


1。Hack的工具。


  动态调试器:No$Gba 1。4。这个没有过多的选择,而且这个的功能已经够用了。16进制编辑器:把调试好的程序写入rom。这种工具很多。WinHex,UE,Hex workshop;
  模拟器:用来测试游戏,当然调试器也可以完成,但是会有一些不方便的地方。一般都是用的VBA;
  补丁工具:IPS或者CodeFusion,其他的当然也可以。


  这些我们只要准备好就可以了。


2。确定目标


  Hack不可能是随机的无目标的过程。我们不可能说用调试器来运行游戏,玩着玩着就Hack一个。通常是这样的,我们先是正常的游戏(指大多数的人)。然后有了一个Hack的想法,然后确定Hack后的目标。所以我们可以在这里完成这些事:


2-1。要Hack的rom:这个当然有机种,rom的名字。美日的不要混用,不确定能通用的时候最好弄清楚版本
2-2。Hack后要达到的目标:比如不死,时间无限,不遇敌之类的。没有目标怎么hack呢?


3。地址搜索


  这个方法很多,比如使用EC里面已经提供的。或者用模拟器自带的,或者用什么其他的东西。因为游戏的数据都是保存在内存里面的(99。9%的情况)。所以要找到我们需要的那些内存地址。用VBA找到的地址可以在调试器里面直接用。EC的地址要通过一个简单的转换:
04XXXX的地址变换成0300XXXX
  其他的直接在前面加2就可以了,然后确定不同的值对游戏的影响。


  所以我们在这里要确定的就是这些:
3-1。查找到我们Hack内容相关的内存地址
3-2。确定不同的值所对游戏的影响
  另外,如果没有超强的记忆力,最好把这些都记下来。


4。确定关键代码


  简单的我们可以直接下中断[XXXXXXX]!,让游戏在改变值的时候暂停,很多游戏都可以,然后可以单步返回调用的地方或者直接修改代码。也可以r0=XXXXXXX之类的让寄存器。准备读取的时候来中断。这里的所采用方法要按照不同的情况来灵活运用。


  这个目标比较简单,就是确定代码的位置,实际操作起来比较困难。(Hack难点)


5。确定修改方法


  要达到同样的目的有很多方法,但是我们要按照不同的情况来选择,比如是赋值以后我们来修改,还是直接拦截原来的赋值。这些都是我们要考虑的,原则就是稳定,简单,对程序改动少。要添加自己的程序的时候,建议在开始的地方push r0-r7,lr,返回的时候pop r0-r7,然后是原来的语句,最后用pop pc来返回。


  如果代码都确定了,那么这里比较的简单。不过建议初学者把寄存器表示的意义写下来。


6。初步调试,写入代码


  当我们在调试器里面把代码写好以后,直接在调试器里面进行游戏。这里体现出调试器的一个好处:如果程序有错,模拟器可能还是能够执行,但是调试器会出错。当我们的代码运行没有错误,用16进制工具把代码代码写进rom里面


7。最后调试,制作补丁


  这个是防止代码写入rom的时候出错,所以我们把代码写入以后需要最后调试一下。没有问题就作补丁吧。

  一般的过程就是这样的。这里我贴出我的一个例子:


恶魔城-晓月 +不同名字对应不同能力


(为了对应上面的,故把工具的编号留出。)
2-1。Rom:恶魔城-晓月(中文版)
2-2。目标:不同名字对应不同能力。
DRACULA:拥有全部能力
LUCKYDOG:幸运值最高,其他能力为一半,带有稀有物品,魂出现上升戒指
3。人物标志201325ah:0-Soma;1-Julius
名字存放的地址:02000090h
字母对照表:
恶魔城晓月(中文版)字母对照表
A 02 B 03 C 04 D 05
E 06 F 07 G 08 H 09
I 0A J 0B K 0C L 0D
M 0E N 0F O 10 P 11
Q 12 R 13 S 14 T 15
U 16 V 17 W 18 X 19
Y 1A Z 1B @ 1C 。 1D
- 1E ' 1F ! 20 (Skull) 21
(Cross) 22



名字对应的值
JULIUS 0B160D0A 1614
DRACULA 05130204 160D02
LUCKYDOG 0D16040C 1A051008



魂出现几率上升戒指 201330A
稀有物品出现几率上升戒指 201330B



4。名字判断代码大智位置:80078fc
r0 读入一个输入的字符
r1 读入一个特定名字字符
r2 输入名字的地址(这个地址在程序转入之前已经赋值)
r3 特定名字的地址(初始化为08143EB0)
r4 人物标志(初始化为1)
r5 循环次数(名字最动为8个字母,所以固定为8)
r6 自定义的人物标志位(03000c60)



初始化能力代码这个笔记丢了)



5。插入子程序。替代原来的代码。(具体代码如有兴趣请参看Hack Primer (2))
6,7(略)



  这是我的一点心得,我觉得初学最好有一个步骤来Hack。如果有不对的地方请大家包含


Hack Primer (3) 恶魔城—晓月 +SOMA使用JULIUS能力

  首先我们要找到魂使用的代码位置,我们很容易知道201325d存放的是魂(上+B)的地址,所以我们下中断r0=201325d。这时我们上+B的时候游戏中断.用F7执行到pop返回调用的地方,然后我们看到这样的代码(再返回位置的上面一点点)。



0801B3F8 483B ldr r0,=84BCA78h
0801B3FA 6802 ldr r2,[r0]
0801B3FC 8B91 ldrh r1,[r2,1Ch] 读取按钮,组合的按钮值
0801B3FE 2040 mov r0,40h
0801B400>4008 and r0,r1
0801B402 2800 cmp r0,0h 如果不是"上+其他键",那么就r0等于0
0801B404 D010 beq 801B428h
0801B406 493F ldr r1,=1338Ch
0801B408 1850 add r0,r2,r1
0801B40A 8BD1 ldrh r1,[r2,1Eh] 读取按键的值


>>>0801B40C 8800 ldrh r0,[r0]
>>>0801B40E 4008 and r0,r1 201338c里面保存的是和上组合的另外一个键的值


0801B410 2800 cmp r0,0h
0801B412 D009 beq 801B428h
0801B414 6930 ldr r0,[r6,10h]
0801B416 21A8 mov r1,0A8h
0801B418 00C9 lsl r1,r1,3h
0801B41A 4008 and r0,r1
0801B41C 2800 cmp r0,0h
0801B41E D103 bne 801B428h


0801B420 1C30 mov r0,r6
0801B422 2100 mov r1,0h
0801B424 F7FDF8DA bl 80185DCh 我们要调用的函数



  这里要说明200001c和200001e的区别。1c保存的是组合按键的值,比如"上+R"是0140h,"上+B"是42h.。不过这样不能区分这样两种方式形成的组合,即:先按住上,再按B;还是按住B再按上.。而1e里面放的值就是后按的按钮,同时按下的话值就是6A。


  本来想使用:




  • "下+R"-切换附加武器

  • "上+R"-发动附加武器



  但是既然代码这样,不如我就改成:



  • "上+L"-切换附加武器

  • "上+R"-发动附加武器


  把>>>改成bl 814B200,另外
80185f6 bl 802c3e8
  是附加武器的函数,r0的值是入口函数,指定为特殊武器。不过遗憾的是不能直接调用这个函数,调用了也没有结果。所以我们调用814b200的父函数,不过输入参数没有武器参数。所以我在内存(3000000h)里面自己找一个地方存放Julius的附加武器的值。当执行上+B时,首先判断人物,如果是soma的话就把人物代码改为1(soma的值是0)。然后交换20135dh和3000000h的值,接着就调用函数嘛。函数返回再把值填回来,很简单吧。


  当人物为julius时,r0的值对应武器:



  • 0 回力镖

  • 1 圣水

  • 2 斧头

  • 3 十字架


  我们可以在执行之前设置201325A的值为1,执行了再设置为0 。



0814B200 B5FF push r0-r7,lr
0814B202 2002 mov r0,2h
0814B204 0202 lsl r2,r0,8h 如果是L
0814B206 400A and r2,r1
0814B208 2A00 cmp r2,0h
0814B20A D019 beq 814B240h
0814B20C 2303 mov r3,3h
0814B20E 061B lsl r3,r3,18h
0814B210 781C ldrb r4,[r3]
0814B212 2C03 cmp r4,3h
0814B214 D001 beq 814B21Ah
0814B216 3401 add r4,1h
0814B218 E000 b 814B21Ch
0814B21A 2400 mov r4,0h
0814B21C 701C strb r4,[r3]
0814B21E F000F807 bl 814B230h
0814B222 0000 lsl r0,r0,0h
0814B224 0000 lsl r0,r0,0h
0814B226 0000 lsl r0,r0,0h
0814B228 0000 lsl r0,r0,0h
0814B22A 0000 lsl r0,r0,0h
0814B22C 0000 lsl r0,r0,0h
0814B22E 0000 lsl r0,r0,0h
0814B230 BCFF pop r0-r7
0814B232 8800 ldrh r0,[r0]
0814B234 4008 and r0,r1
0814B236 BD00 pop pc
0814B238 0000 lsl r0,r0,0h
0814B23A 0000 lsl r0,r0,0h
0814B23C 0000 lsl r0,r0,0h
0814B23E 0000 lsl r0,r0,0h
0814B240 2001 mov r0,1h
0814B242 0202 lsl r2,r0,8h
0814B244 400A and r2,r1 如果是R
0814B246 2A00 cmp r2,0h
0814B248 D0F2 beq 814B230h
0814B24A 2303 mov r3,3h
0814B24C 061B lsl r3,r3,18h
0814B24E 4A04 ldr r2,=201325Ah
0814B250 7811 ldrb r1,[r2]
0814B252 2900 cmp r1,0h
0814B254 D1EC bne 814B230h
0814B256 8010 strh r0,[r2]
0814B258 78D1 ldrb r1,[r2,3h]
0814B25A 8259 strh r1,[r3,12h]
0814B25C 7819 ldrb r1,[r3]
0814B25E E004 b 814B26Ah
0814B260 325A add r2,5Ah
0814B262 0201 lsl r1,r0,8h
0814B264 0000 lsl r0,r0,0h
0814B266 0000 lsl r0,r0,0h
0814B268 0000 lsl r0,r0,0h
0814B26A 70D1 strb r1,[r2,3h]
0814B26C 1C30 mov r0,r6
0814B26E 2100 mov r1,0h
0814B270 F6CDF9B4 bl 80185DCh
0814B274 2300 mov r3,0h
0814B276 4C12 ldr r4,=201325Ah
0814B278 7023 strb r3,[r4]
0814B27A 2203 mov r2,3h
0814B27C 0612 lsl r2,r2,18h
0814B27E 46C0 nop
0814B280 7C13 ldrb r3,[r2,10h]
0814B282 70E3 strb r3,[r4,3h]
0814B284 E7D4 b 814B230h



代码很简单,不用多的说明。
  不过很遗憾的是发出的都是黑色的,遗憾呐。弄了半天也没有找到怎么把图像也弄出来。不过soma用十字架的样子很好看。有一个……自己看吧。:-)





Hack Primer (2) 恶魔城—晓月 +不同名字对应不同能力

1。


  当然我们可以这么搜索,这个是一个很传统的做法,因为我们最后肯定是要通过一个按键来结
束名字的输入。


  而我们又知道这个地址。所以我们可以追这个地址。不过传统的东西虽然通常有不错的通用型
(因为新事物往往有很大的局限性或者是传统方法的延伸),但是往往很麻烦。所以我们在这里
要用其他的方法得到人物初始化的代码和名字判断的代码。


  其实我们可以发现SOMA和JULIUS的HP是不同的,而且又很容易从EC找到HP的地址是多少(我的
前一篇教程和前辈的文章里面有如何从EC的地址得到实际的内存地址),我们在这个地址上中
断,所以呢~,很容易吧。


  然后我们仔细看能力初始化代码的开始部分,会发现人物的标志位,所以我们同样的可以很容易找到人物名字的判断代码。


2。
r0 读入一个输入的字符
r1 读入一个特定名字字符
r2 输入名字的地址(这个地址在程序转入之前已经赋值)
r3 特定名字的地址(初始化为08143EB0)
r4 人物标志(初始化为1)
r5 循环次数(名字最动为8个字母,所以固定为8)
r6 自定义的人物标志位(03000c60)




  在这里跳转,刚好r2放有我们需要的地址。


80078fc:ldrb r0,[r4]
cmp r1,r0

  改为 bl 8143f40 。


  这里的代码很简单,没有什么可以说的。要是有问题就给我Message 。



08143F40>B4FF push r0-r7
08143F42 4E07 ldr r6,=30007FFh
08143F44 4B07 ldr r3,=8143EB0h
08143F46 2500 mov r5,0h
08143F48 2401 mov r4,1h
08143F4A E019 b 8143F80h
08143F4C 2C03 cmp r4,3h
08143F4E D027 beq 8143FA0h
08143F50 2500 mov r5,0h
08143F52 3310 add r3,10h
08143F54 3401 add r4,1h
08143F56 E013 b 8143F80h
----------------
08143F60 07FF lsl r7,r7,1Fh
08143F62 0300 lsl r0,r0,0Ch
08143F64 3EB0 sub r6,0B0h
08143F66 0814 lsr r4,r2,20h
----------------
08143F80 5D50 ldrb r0,[r2,r5]
08143F82 5D59 ldrb r1,[r3,r5]
08143F84 4288 cmp r0,r1
08143F86 D1E1 bne 8143F4Ch
08143F88 3501 add r5,1h
08143F8A 2D08 cmp r5,8h
08143F8C D1F8 bne 8143F80h
08143F8E 7034 strb r4,[r6]
08143F90 2C01 cmp r4,1h
08143F92 4D02 ldr r5,=201325Ah
08143F94 702C strb r4,[r5]
08143F96 E003 b 8143FA0h
08143F98 0000 lsl r0,r0,0h
08143F9A 0000 lsl r0,r0,0h
08143F9C 325A add r2,5Ah
08143F9E 0201 lsl r1,r0,8h
08143FA0 BCFF pop r0-r7
08143FA2 7820 ldrb r0,[r4]
08143FA4 4770 bx r14



3。
  存放名字的地址:02000090h
恶魔城晓月(中文版)字母对照表
A 02 B 03 C 04 D 05
E 06 F 07 G 08 H 09
I 0A J 0B K 0C L 0D
M 0E N 0F O 10 P 11
Q 12 R 13 S 14 T 15
U 16 V 17 W 18 X 19
Y 1A Z 1B @ 1C 。 1D
- 1E ' 1F ! 20 (Skull) 21
(Cross) 22


名字对应的值
JULIUS 0B160D0A 1614
DRACULA 05130204 160D02
LUCKYDOG 0D16040C 1A051008



4。




0813FF44>B500 push lr





0813FF46 493E ldr r1,=2013250h
0813FF48 2001 mov r0,1h
0813FF4A 7748 strb r0,[r1,1Dh] 这里的nop是因为发现了人物标志只能是0,1
0813FF4C 46C0 nop 所以把存放的位置改变了,放在30007FFh
0813FF4E 46C0 nop 原来的赋值语句太原始了,不便于阅读
0813FF50 46C0 nop
0813FF52 46C0 nop
0813FF54 7A88 ldrb r0,[r1,0Ah]
0813FF56 46C0 nop



0813FF58 2802 cmp r0,2h 如果名字是LUCKYDOG
0813FF5A D10E bne 813FF7Ah
0813FF5C 20A0 mov r0,0A0h
0813FF5E 0040 lsl r0,r0,1h
0813FF60 8448 strh r0,[r1,22h]
0813FF62 2050 mov r0,50h
0813FF64 8488 strh r0,[r1,24h]
0813FF66 2005 mov r0,5h
0813FF68 84C8 strh r0,[r1,26h]
0813FF6A 2006 mov r0,6h
0813FF6C 8508 strh r0,[r1,28h]
0813FF6E 2006 mov r0,6h
0813FF70 8548 strh r0,[r1,2Ah]
0813FF72 20FA mov r0,0FFh
0813FF74 0080 lsl r0,r0,2h
0813FF76 8588 strh r0,[r1,2Ch]
0813FF78 E031 b 813FFDEh



0813FF7A 2801 cmp r0,1h 如果名字是JULIUS
0813FF7C D10E bne 813FF9Ch
0813FF7E 20C8 mov r0,0C8h
0813FF80 0080 lsl r0,r0,2h
0813FF82 8448 strh r0,[r1,22h]
0813FF84 20FF mov r0,0FFh
0813FF86 0040 lsl r0,r0,1h
0813FF88 8488 strh r0,[r1,24h]
0813FF8A 200F mov r0,0Fh
0813FF8C 84C8 strh r0,[r1,26h]
0813FF8E 200C mov r0,0Ch
0813FF90 8508 strh r0,[r1,28h]
0813FF92 200A mov r0,0Ah
0813FF94 8548 strh r0,[r1,2Ah]
0813FF96 2014 mov r0,14h
0813FF98 8588 strh r0,[r1,2Ch]
0813FF9A E020 b 813FFDEh



0813FF9C 20A0 mov r0,0A0h 初始化SOMA的能力
0813FF9E 0040 lsl r0,r0,1h
0813FFA0 8448 strh r0,[r1,22h]
0813FFA2 2050 mov r0,50h
0813FFA4 8488 strh r0,[r1,24h]
0813FFA6 200A mov r0,0Ah
0813FFA8 84C8 strh r0,[r1,26h]
0813FFAA 200C mov r0,0Ch
0813FFAC 8508 strh r0,[r1,28h]
0813FFAE 200B mov r0,0Bh
0813FFB0 8548 strh r0,[r1,2Ah]
0813FFB2 2009 mov r0,9h
0813FFB4 8588 strh r0,[r1,2Ch]
0813FFB6 7A88 ldrb r0,[r1,0Ah]



0813FFB8 2803 cmp r0,3h 如果名字是DRACULA,则打开所有的能力
0813FFBA D110 bne 813FFDEh
0813FFBC 2303 mov r3,3h
0813FFBE 21FF mov r1,0FFh
0813FFC0 2002 mov r0,2h
0813FFC2 0300 lsl r0,r0,0Ch
0813FFC4 3013 add r0,13h
0813FFC6 0200 lsl r0,r0,8h
0813FFC8 3038 add r0,38h
0813FFCA 0100 lsl r0,r0,4h
0813FFCC 3006 add r0,6h
0813FFCE 7001 strb r1,[r0]
0813FFD0 3001 add r0,1h
0813FFD2 3B01 sub r3,1h
0813FFD4 2B00 cmp r3,0h
0813FFD6 D1FA bne 813FFCEh
0813FFD8 3001 add r0,1h
0813FFDA 213F mov r1,3Fh
0813FFDC 7001 strb r1,[r0]



0813FFDE 2020 mov r0,20h
0813FFE0 0200 lsl r0,r0,8h
0813FFE2 3013 add r0,13h
0813FFE4 0200 lsl r0,r0,8h
0813FFE6 3025 add r0,25h
0813FFE8 0100 lsl r0,r0,4h r0=201325Ah,r1本来是这个值,可惜被改变了。又不想
0813FFEA 300A add r0,0Ah 改变很多寄存器,所以就麻烦一点,幸好空间很多



0813FFEC 2100 mov r1,0h
0813FFEE 7803 ldrb r3,[r0]
0813FFF0 2B01 cmp r3,1h 201325A的值一定只能是0或者1,
0813FFF2 D000 beq 813FFF6h 否则会初始化图像的时候出错
0813FFF4 7001 strb r1,[r0]



0813FFF6 2B02 cmp r3,2h 如果是LUCKYDOG,送两枚戒指
0813FFF8 D103 bne 8140002h
0813FFFA 30B0 add r0,0B0h r0=201330A
0813FFFC 2101 mov r1,1h
0813FFFE 7001 strb r1,[r0]
08140000 7041 strb r1,[r0,1h]



08140002 BC01 pop r0 返回
08140004 4700 bx r0



魂出现几率上升戒指 201330A
稀有物品出现几率上升戒指 201330B




5。
  在打补丁后会出现人物走动时候有些地方会间歇的花瓶,不过不影响游戏的进行。这个应该是我们的代码覆盖到这些图形的原因。不过我也没有找到其他的位置放。


  我想说的是人物的标志位的值。为什么我用了一个其他的内存地址来存放新加入的人物?
  我们常这样写一个程序(我本身是作软件开发) :在一个地方设置一个判断标志,如果这个标志的值是0,那么我们跳转到一个地方执行,如果是1我们的代码会到另外一个地方执行。但是我们往往会一厢情愿的认为我们加入一个新的值,然后跳到我们所希望的地方。当然这是一个方法。但是具体的要按照实际情况来分析。在这里如果我们把201325a的值设置为0,1之外的值,那么程序会出现异常。但是我们往往开始怀疑
的是我们自己添加的代码的正确性,所以我们不停的修改,但是还是不行。


  Hack所需要的不仅是技术,耐心。也同样需要自信。我们要对自己的代码自信。


  所以我们不如假设标志值只能是0或者1,这样我们就能解决这个问题。

  我自己是一个Hack的初学者,在这里感谢Lordquest对ldr r3,=8015340h这类代码的耐心解释。如果大家对我写的东西有任何问题可以给我message,我不定期上网。我会对我的Hack心得全部写出来


Hack Primer (1) 恶魔城-晓月圆舞曲 +Special +全能力

  首先我们需要得工具是:




  • 调试器:no$gba 1。4c

  • 模拟器+rom:vba1。2+晓月中文版

  • 16进制编辑器:UE5。4



  上面得只是我用得,当然可以用其他同样功能得工具。


  我改游戏有个习惯,不喜欢改得很变态。所以改得地方都是一些不影响游戏性得东西(我认为)。游戏里面有个special模式。不过要打穿一次才出现。那我们首先把这个弄出来。我们首先找到关键得地址是2000060h,为3h得时候就有special模式。至于这个地址怎么得到得。建议在修改之前看看ec得作弊码,类似000060h这些就直接在前面加一个2就可以了。


  打开调试器。下断点[2000060h]!。中文版会在08000820h停下(其他版本我没有弄,不知道),当然这里不是。继续080006e4h又停了,当然还是不是。最后在030021d6h停下。这里就是真正得初始化得程序了。至于为什么我知道那里是,自己多看看就明白了。


  不过千万不要在这里(030021d6)改动。因为gba游戏得rom代码得起始地址为08000000h,所以只要小于这个的都不能修改。用单步调试发现这里初始化了不只一个数据(快捷键F7是单步,这个是个很常用的键)。为了不改动到其他的数据,我们干脆在初始化了以后再给02000060h赋值为3h,这样就达到我们的目的了。


  一直F7(这里有个循环,可以用run to cursor,来直接跳出循环)到这段代码返回。返回的地方代码是这样的:



080129CC 6803 ldr r3,[r0]
080129CE 4806 ldr r0,=0E001AF8h
080129D0 2204 mov r2,4h
080129D2 F0C6F9D7 bl 80D8D84h
----------------------
080129D6>1C20 mov r0,r4
080129D8 BC30 pop r4,r5
080129DA BC02 pop r1 这里的几句是我们关心的
080129DC 4708 bx r1
---------------------
080129DE 0000 lsl r0,r0,0h
080129E0 CA78 ldmia [r2]!,r3-r6



  那个>符号就是我们下一步要执行的语句,080129D6>1C20 mov r0,r4上面的代码肯定调用了刚才的那段程序。但是这个和我们无关。那我们要自己写一段给02000060h赋值的语句,所以我们先找到一个空白的地方(一般都是0000)来放我们的代码,我找到的地方是813bc44h,所以我们修改下上面的代码。


  把原来的代码记下来,把上面的代码改成这样:



080129CC 6803 ldr r3,[r0]
080129CE 4806 ldr r0,=0E001AF8h
080129D0 2204 mov r2,4h
080129D2 F0C6F9D7 bl 80D8D84h
--------------
080129D6>B530 push r4,r5,lr
080129D8 F129F934 bl 813BC44h
080129DC 4708 bx r1
--------------
080129DE 0000 lsl r0。r0。0h
080129E0 CA78 ldmia [r2]!。r3-r6



其实写的语句只有两句。好了。跳转语句写好了。让我们跳到813bc44h来写我们的代码吧。



0813BC44>2202 mov r2。2h
0813BC46 0612 lsl r2。r2。18h
0813BC48 3260 add r2。60h
0813BC4A 2103 mov r1。3h
0813BC4C 7011 strb r1。[r2]
0813BC4E BC30 pop r4。r5 <-恢复原来的r4。r5的值
0813BC50 1C20 mov r0。r4 <---这里是我们改代码的时候覆盖的部分
0813BC52 BC30 pop r4。r5
0813BC54 BC02 pop r1
0813BC56 BD00 pop pc



  上面就是我添加的代码。很简单吧。然后用*键重新启动游戏。看看会不会出错。不会的话。就用UE打开rom。修改代码吧。这里只有一点要提醒。高低位要颠倒过来。比如这里我们添加的 2202 0612 。写的时候就要写成 0222 1206。反正4位(16进制的)一组。


  这样。我们的第一个就改好了。 改能力与这个基本相同。我只说不同的。也是关键的部分下断点以后。选择存档的时候会中断。同样是03开头的地址。而且也是多个初始化。我们F7返回到rom的代码。



08011978 1C38 mov r0。r7
0801197A F0C7FA03 bl 80D8D84h
-------------------
0801197E>4917 ldr r1。=0E0001A0h
08011980 1868 add r0。r5。r1
08011982 4642 mov r2。r8
08011984 6811 ldr r1。[r2]
08011986 3194 add r1。094h
08011988 6823 ldr r3。[r4]
0801198A 2220 mov r2。20h
0801198C F12AF966 bl 80D8D84h
------------------
08011990 4913 ldr r1。=0E0001C0h
08011992 1868 add r0。r5。r1



  这里怎么办呢?发现到这里有一个跳转指令。bl 80D8D84h。我们就干脆在这里改吧。同样的。在813BC5Ch找到空白(Konami真好。有那么多空白的地方)。bl 80D8D84h 改为 bl 813BC5Ch 然后在813BC5Ch写我们代码。


  不过看跳转指令上面的代码。有很多有用的值保存在寄存器里面,所以我们干脆把r0到r7都push。保存起来。



0813BC5C>B4FF push r0-r7
0813BC5E 2303 mov r3。3h
0813BC60 21FF mov r1。0FFh
0813BC62 2202 mov r2。2h
0813BC64 0312 lsl r2。r2。0Ch
0813BC66 3213 add r2。13h
0813BC68 0212 lsl r2。r2。8h
0813BC6A 3238 add r2。38h
0813BC6C 0112 lsl r2。r2。4h
0813BC6E 3206 add r2。6h
0813BC70 7011 strb r1。[r2]
0813BC72 3201 add r2。1h
0813BC74 3B01 sub r3。1h
0813BC76 2B00 cmp r3。0h
0813BC78 D1FA bne 813BC70h
0813BC7A 3201 add r2。1h
0813BC7C 213F mov r1。3Fh
0813BC7E 7011 strb r1。[r2]
0813BC80 BCFF pop r0-r7
0813BC82 F79DF87F bl 80D8D84h <-原来要跳转的地方
0813BC86 F6D5FE83 bl 8011990h



  这个就是我们添加的代码了。有人会问。和能力有关的不是只有02013386h到020133883h个地方吗?当然是这样。不过进入游戏以后这些能里没有默认打开。所以在0201338ah。把数据改成3fh(其实就是二进制的6个1)。那么就默认打开了。


  不过这里要提出关键的一点。就是最有一句bl 8011990h。这是原来跳转指令的下面一条指令。为什么在这里要加一句呢?因为在03XXXXXX返回的时候。是按照调用的指令寄存器的值来返回。也就是说。原来的80118c0h F79DF87F bl 80D8D84h。执行这一句前的时候。指令寄存器的地址是80118c0h。所以返回的时候就直接是8011990h(就自动返回到了他的下面一条指令)。但是我们改动了代码。所以调用指令的时候寄存器的值已经改变了。他会回到我们调用的下面一条指令的地址。就是0813BC86。所以我们要手动的让程序跳转到原来的8011990h那里。


  补一句。bl和bx的差别就像是用goto语句和调用函数的差别。函数要返回到原来的下一条指令继续执行。goto就不用。


  好拉。就这样。不知道大家明白没有。Have Fun。

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Powered by Blogger