Showing posts with label Games. Show all posts
Showing posts with label Games. Show all posts

Dec 9, 2010

IIDX高手《灼熱Beach Side Bunny》AAA过关录像

说实话,虽然自己以前玩儿VOS在本地还是小有名气,但是看到这个还是傻了⋯⋯

Dec 2, 2010

TAS-FC《合金装备(潜龙谍影)》23分33秒77 最速通关

Metal Gear 早期在FC上的版本。这个游戏我很小的时候就开始玩儿,无奈英语看不懂,完全没法玩儿……

Dec 1, 2010

异型对铁血战士连技讲解视频

国外的玩家制作的介绍《异性对铁血战士》连招视频。这个游戏在中国不火,不过自己在模拟器上玩儿过,觉得还是很有意思的

Nov 15, 2010

TAS-ARC《街霸ZERO3》伯迪(BIRDIE)最高难度V-ISM 华丽表演通关录像

这个角色是我最头痛的——因为完全不会玩儿……
视频太华丽了

Sep 21, 2010

KOF 98 Editor 0.1

闲手动改麻烦,自己写的工具,不过还差的很远,BUG很多,而且还不能修改……囧

不过马上要去香港考CCIE Security,短时间内可能没时间更新了……囧囧

下载地址

Aug 25, 2010

[转]DS ROM深度HACK教程--动态调试操作挂钩篇

原文地址:http://www.ndsbbs.com/read.php?tid=180038

最近因为方向键坏掉~又想玩RY传说~于是开始着手研究DS的操作挂钩~
简单点说~就是把RY传说这个本来不能用触摸的游戏改成全程触摸版~

〇,修改必备
1,必备工具:IDEAS模拟器(本人用的1020版~因为速度比1024快~),16位修改器,静态反汇编工具,编译工具
之所以要IDEAS是因为在主流模拟器里只有IDEAS提供免费的调试功能~虽然十分的简陋(可以说啥功能都没有)~但是总比没有要强几倍~
16位修改器和静态反汇编工具~本人推荐用CT2的那个专为DS ROM优化后的版本~那个版本直接支持ARM指令反汇编~

一,思路分析
要挂钩操作无疑要做以下几件事情
1,找到按键的程序可识别地址
2,找到触摸屏的程序可识别地址
3,找到合适的地方下断
为了解决前2项问题~首先想到的最简单的方法当然是用EC直接搜~

二,EC搜索
相信有一定模糊搜索基础的人可以很快找到方案来搜索按键判定和触摸判定~也就是说~这个步骤理论上来说应该是一点难度没有的可以快速解决的~可是事实上的情形却复杂的多~
1,按键部分:用EC顺利搜索出几个地址表现出按键的变化~但是试着锁定后发现~无论哪一个都无法对游戏内容产生影响~也就是说用EC搜到的这几个变量仅仅是程序可表现的~而非程序可识别的~简单点说就是你可以看他来判断按了啥键~但是不能通过改变他来改变按的键~
2,触摸部分:用EC直接啥都搜不到~
在按键和触摸2个方面皆碰壁~给人的唯一结论是~用这种只就其表不问其根的方法来搜索本质就行不通~于是下面俺开始介绍文章的正式部分~
通过DEBUGGER来动态调试ROM~

三,关于DS的输入识别所必须具备的知识
别以为这个只是科普讲座~这个可是后面DEBUG过程中最重要的依据~所以请仔细看过这段~

DS是由2个处理器同时处理程序的系统~ARM9为主处理器~ARM7为协处理器~ARM9用来处理游戏的绝大部分信息~而ARM7辅助处理声音~I/O等一些底层信息~
关于ARM9和ARM7的分工我暂不多说~但是需要注意的是~在很多底层方面的东西ARM9是无法正常访问的~

接着说说DS的按键和触摸屏输入的过程~
按键部分~DS有一个16位的只读按键寄存器~其作用就是识别按键并将按键信息存放其内~而这个寄存器映射在内存空间上的地址是0x04000130 意思就是说~游戏只要检查这个地址的值~就可以很轻松的判定所按的键了~
不 过事实上还少许有一点麻烦的部分~就是这个寄存器所对应的键并不是DS上的全部键~X,Y键并未被对应在这个寄存器中~而是另外一个入口为 0x04000136的只读寄存器~有趣的是~这个寄存器除了对应X,Y键以外~还对应了触摸屏的状态~也就是说要检查触摸屏也是要访问这个寄存器的~

或许你会说~那么只要检查这2个寄存器岂不就可以很轻松的获得按键和触屏信息了~
但是事实上有2点问题~
1,这2个寄存器都是只读寄存器~也就是说虽然可以得到信息~但是仍然改不了~
2,最烦躁的问题在于~0x04000136这个寄存器是仅能由ARM7访问的~而通常游戏的程序是写在ARM9当中的~……

因此现在面临的问题就是:X,Y,触摸屏无法通过ARM9访问~
那么现在那么多DS游戏又是怎样访问这些部分的呢~
其实很简单~在ARM7程序中会有一部分代码专门用来处理这个寄存器~并将按键和触摸信息插入一个叫IPC的共享内存结构中上报给ARM9
也就是说这样问题就转换到了寻找IPC地址和按键识别程序所处地址了~

四,调试程序必备知识
这一段不同于上面一段主要介绍理论~这部分主要要介绍的是调试一个程序所常常会用到的一些操作技巧~

作为一个调试器(DEBUGGER)最重要的几个功能在于:
1,跟踪 2,下断点 3,动态修改状态
然而IDEAS提供的这个免费DEBUGGER很不幸的少了最方便的一个功能~下断~……
这无疑会给我们的工作带来很多不必要的麻烦~但是这些麻烦往往也并非不可解决~

接下来我要讲讲调试最基础操作~跟踪~所具有的一些技巧~
1,步入:简单的来说就是顺着程序的正常流程一条一条的往下执行~这个流程包括跳转和调用~这是任何一个调试器都肯定具备的功能~(IDEAS对应快捷键F8)
2,步过:这个在大致上~和上面一种差不多~但是有个很根本的区别:步过的话在碰到调用指令的时候并不会跟踪进入所调用的函数~而是一次执行完该函数~在调用指令的物理下一行才停止下来~事实上这种跟踪模式比起步入来说~用的更加广泛~
但是十分不幸的是~……IDEAS又没有步过功能~……所以这时候我们就要找到代替手段~

IDEAS除了步入以外~唯一提供的一个功能是~运行到指定行~(对应F6)
这个功能可以简单的理解为在光标所指定的地方下一个断点~然后放程序运行~当运行到指定地方的时候~自然就会被断下~这个功能是唯一取代下断的方法~不过遗憾的是~这样全程序就只能下一个断点~很多逻辑结构就无从分清~
另外这个功能还可以用来事先步过~在跟踪看到调用命令时(ARM里的调用命令是bl *****)将光标指定到该命令下一行~然后F6~然后就顺利步过了~

五,开始着手实际调试吧~
对于一个刚刚上手的程序~我们对其结构~特征地址~重要子程序~重要内存标示~都一无所知~所以我们需要选择一个尽量单纯的和确定性的地方开始我们的调试~
按照经验来说~最符合这个条件的地方便是程序的开头~

先试试一路步过~让程序跑跑会怎样~
一 路F8,F6~在顺利通过几个调用指令后~出现了异常情况~:某个调用指令一步过后游戏的开头LOGO便播出来了~这便说明~OP的处理程序在这里调用的 那个子程序之中~因为OP中有识别A键跳过LOGO的功能~所以就是说在这段OP程序里肯定能找到我们需要找的按键识别程序~
记下这个调用指令的地址和调用的地址~重置调试器~直接F6到该指令~然后F8步入~

继续对于子程序内的代码步过~发现需要的内容后便步入~并一路记录进入的地址~
最后可以找到一个子程序~在LOGO显示出来后~游戏调用这个子程序~对其直接步过的话~进入一段时间的延时~而且延时中途可以按键取消~
很显然这个就是我们要找的程序了~

大致记录一路过来的地址~大致会像这样~:
2000bec OP LOGO

206e1c8 bl 0x0206e24c ;r12=3ff(调用26b30),亮屏

206e1dc logo1
206e3ec
206e47c blt 0x0206E440 按键延时
最后这行的调用便是延迟部分了~

六,寻找按键输入识别程序
刚才的部分我们找到了开头LOGO里的延时程序~接下来我们要从这段程序里找到按键识别用的程序~
前面之所以要从开头下手~就是因为在这段相对单纯的LOGO处理程序里找我们的目标~肯定比在游戏进程中找要来的简单的多~

要找东西~就要有明确的标志来告诉我们~要找的东西究竟是还未到~还是已经过了~因为这次我们是在延迟程序里搜按键的处理程序~所以当然是看延迟是否跳过来判断按键处理程序的位置了~

具体的操作比较有意思:
从 延迟程序开始~一路往下F8~看到bl,blt等调用指令的时候停住~把光标落到下一行准备步过~这个时候按住模拟器设定的DS的A键位~然后再按下 F6~然后松开A键~这样~如果按键识别程序是在步过的这个调用里的话~那么马上F5放开程序任其运行~应该游戏就马上跳过LOGO了~相反~如果说要找 的那程序不在这段调用里~那么F5放行后~应该还照常有一段延迟~LOGO才过去~
因此很方便就能判定按键识别程序是否在这某个调用里~一路用这个方法找进去~并且记录下地址~应该就能像以下这样~
206e440: bl 0x02026b30 ;call 按键检测
2026b6c: bl 0x02026c54 ;检测按键·里
2026c5c: bl 0x01ff84f0 ;检测按键·里2
读键部分:
1ff84f0(20a1ff0): ldr r2,0x04000130
....
1ff84f8(20a1ff8): ldrh r12,[r2]
最终发现~就是以上的最后一行~在对于按键的检测起作用~这行的意思是:
把r2寄存器所指定的地址的内容读入r12寄存器~而r2的内容就是上面那行所指定的0x0400130
这样便清晰了~这条就是读按键寄存器4000130来检查按键的语句了~
无疑~只要在这里下断放入我们的修改程序~虽然不能改变4000130的内容~但是只要窜改r12的内容~对于后面程序的影响也无异于改按键了~所以这个地址就是我们HACK ROM的入口地址了~请一定记住~

但是相信稍微有点DS程序经验的人看到这个地址一定会觉得十分的奇怪~按道理来说~DS的内存空间是从地址0x02000000开始的~但是这个程序的地址却是0x01ff84f8~居然在内存空间之前~
其 实这个地址所在的区域叫做ITCM 简单的说~就是DS所提供的一块高速缓存~因为只靠一味提高CPU主频速度来增加代码的运行速度~只能导致严重的发热和耗电问题~这个对于掌机是十分不利 的~所以滑头的老N在DS里提供了大量的高速缓存部分用以存放一些需要频繁访问的内容~以上这段按键识别命令无疑符合这个前提~所以被载入了ITCM而非 内存中~
那么这段代码本来如果要线性载入会被载入哪里呢?~这个问题关系到修改ROM的时候要在ROM文件的哪里来找这个代码的问题~
解决方法是~随意找一段该部分的16进制代码~然后在CT2中搜索~搜到后~切换到反汇编模式~这时候看到的这个代码前面对应的地址就是线性载入时候对应的地址了~俺前面那个记录里括号里的(20a1ff8)就是这个线性地址~

不过这样只是解决了除了X,Y以外的其他按键的问题~那么X,Y和触摸屏的问题如何解决呢?~

接着我们顺便看看刚才找到的那段识别按键的代码~
01ff84f0: ldr r2,0x4000130
01ff84f4: ldr r1,0x27fffa8
01ff84f8: ldrh r12,[r2]
01ff84fc: ldrh r3,[r1]
这里的第1和第3行就是刚才分析的读4000130的代码~相信大家都注意到这里第2和第4行~形式和1~3差不多~功能就是读取0x027fffa8这个地址的内容到r3~
基于这里是按键识别程序~而且4000130只能读出部分按键~不难猜测出~这个27fffa8定然是用来读取剩下的X,Y按键的地址~
继续分析这个地址~27fffa8~和4000130一样~都不在正常的内存空间之内~但是4000130是I/O寄存器~而这个27fffa8所在的地方是DS内一段ARM7与ARM9共享的内存区域~也就是说~这里的数据通常都是用于ARM7和ARM9通信之用的~
那么结合我前面介绍的基本知识~不难得出结论~这个27fffa8所在的地方必然是通信用IPC结构的地址~

用上面的方法~我们无法找到触摸的识别程序或者识别地址~因为游戏里没有任何一个部分会对触摸进行实际响应~
但是通过上面的部分~我们找到了IPC结构的地址~这个非常重要~因为X,Y键信息是和触摸屏信息一起被放入IPC的~所以触摸信息必然在27fffa8周围~
(而且最重要的一点在于~似乎不同ROM~不同游戏所用的IPC结构都是一模一样的~也就是说在共享内存中的地址都是一样~这个对于其他ROM的调试来说~无疑是找到了一条超便利的捷径~)

通过按下X,Y键~观察IPC中的数据变化~很快找到了按键与那个地址内容的对应情况~但是让人十分费解的一点是~无论如何点击触摸屏~对于该块数据都毫无影响~
难道说是之前的推论错误嘛?~显然应该不是这个原因~真正的原因在于~由于RY传说从头到尾都没有使用过触摸屏~所以这个功能根本一开始就被封印了~……

七,研究触摸~就需要研究能触摸的游戏~
刚才的研究无疑收获不浅~相当多有用的信息都顺利得到~甚至可以说除了触摸以外的所有问题都顺利解决了~但是无法忽视的是~那个结果确实也给人当头一棒~:
RY传说压根就没有触摸识别程序~……

为了确认这点~并且深度研究触摸的作用过程~当然我们首先需要的就是一款能够触摸的游戏~我选用的是过去的一款电击文库~因为是单纯的电子小说~所以代码应该相对比较简单~而且该游戏是支持全程触摸的~

打开游戏~随意运行下后暂停在开始的标题菜单选项那里~其实放哪里都无所谓~只是我觉得这里因为只要不点中选项可以一直保持状态~所以很方便~
先F5放行~随意点住触摸屏上一个点~然后F4暂停~因为刚才我们已经找到IPC地址了~所以这次当然省掉了不少麻烦的步骤~直接将内存观测窗切到27fff80来观察一下这部分数据~
就算一次看不出来~多点几次也能很快发现~原本在RY传说里对应XY识别的27fffa8,a9两格之后是一串00的~但是这次后面4格里却有了数据~
在不点触摸屏的时候是 00 00 00 06 而当点住后便是 ** ** ** 01 上面**之处的数据稍微分析下可以发现 *a b* cd 01 里面 ba 组成X轴坐标 cd 组成Y轴坐标~而最后那个01当然就是指的触摸屏被按下的状态~

到此~关于触摸的IPC也找到了~欣然以为问题都解决了?~可是面前还有个超严峻的问题~……RY传说的触摸屏可是被关闭的啊~……
为了解决这个问题~俺的第一反映是去ARM7里找答案~

八,对于ARM7的种种研究
因为要研究触摸屏~所以依旧使用电子小说的ROM~将调试器切换到ARM7模式~F5放行一下~不同于ARM9~并不会有什么明显的反映~

随意暂停一下~会发现有很大几率程序会停在BIOS段里的一个返回指令bx lr上~而且虽然lr寄存器有值~但是无论怎么F8~都无法继续跟踪~这种现象叫做软中断简称swi~是底层程序所惯用的一种手段~暂时不用深究~

偶尔暂停会停在可以跟踪的地方~这时候一路遇见bl就F6步过~遇见bx lr就F8跟出~应该很快就可以跟踪到一个循环执行的程序~找到循环后记下其实和循环跳转的地址~然后再多试几次暂停~

非常奇怪的是有一点~似乎暂停后跟踪到的主循环~还有很多不同版本~……可能几次跟踪出来的循环的地址和内容都不同~而且每一个循环都无疑是最外层主循环~没有跳转出去的指令~

因为之前已经记录下地址~所以用F6分别到不同的循环进行功能考察~
具 体做法其实也很简单~因为ARM7是直接访问硬件~然后把信息写入IPC的~所以只用故意窜改IPC的内容和实际不符合~然后观察何时被修正回来~就知道 起作用的指令在哪里了~因为我们要考察的是触摸屏~所以选择了27fffad这个地址~因为这个地址在没有触摸的时候为06有的时候为01~
在循环之初把该地址强制设定为01~然后对每一个bl调用都F6步过~因为现在的状况是没有触摸的~所以一旦到达触摸判定的程序~必然会导致该地址由01变成06~

对于几个循环都分别测试后~发现了很奇怪的结论~
大多循环在循环的过程中01都会变成06~但是时机却完全没有一点规律~在每一个bl处都有可能会变掉~……
不过有奇怪的当然也会有正常的~在找到的几个循环里有一个~他的01到06的切换是非常严格的符合在某个调用语句内的~顺着这个调用一路找~最终不难找到了ARM7真正的识别触摸屏的程序~
3804628(238C7D8)~3804678

3804634: bl 37fcccc   ;key

380465c: bl 3804b74   ;touch
3804c18: bl 380516c   ;touch code to 380a878
28055c4: ldr r1,40001c0
38055c8: ldrh r0,[r1] ;read touch by reg
这个循环不但处理触摸~按键的处理也在这里完成~无疑~这个循环就是ARM7的输入处理程序了~

因此抱着试一试的心态~俺把这个电子小说的ARM7给替换了RY传说原本的ARM7~然后调试替换后的RY传说的ROM~

游戏在载入后存档处有点不顺(卡在初始存档那)~这个是换ARM7在模拟器上经常出现的症状~而且我们在乎的也不是这个~于是无视就可以了~

进 入调试模式~看IPC~……非常遗憾~在本应该是触摸信息的那个地方依旧是一串00~……于是~继而切换到ARM7调试模式~找到刚才的那个输入处理循 环~F6~下断~等着程序暂停到那里方便研究~可是一等不停~二等不停~……事实上就是根本不会停在那里~……结论是~这个循环压根就没被执行~……
为什么?~明明这个ARM7在之前的ROM里会很好的处理触摸~为啥在RY传说里就根本不执行那段了呢?~

于 是俺找到原RY传说的ARM7~对一些特征指令进行搜索后惊讶的发现~虽然地址和极小部分细节不同~但是其实原ARM7里也有处理触摸的那段程序~不仅如 此~可以说2个ARM7除了一些无关紧要的细节和程序对应的地址有差异以外~根本就是一模一样的~……也就是说决定那段代码是否运行的~是ARM7的代码 之外的其他某些原因~……

为了搞清这个外因是什么~我们再回到对电子小说的ROM的研究~
之前研究ARM7~一直是从中途来找循环的~这次我们从开头开始~
因为ARM7的代码十分有趣~虽然刚进入程序的时候是被载入在2380000开头的区域的~但是跟踪一段后~会发现前面的部分为类似解压的功能~将真正的arm7代码载入到3800000开头的一段区域里~
继续跟踪一段后~终于进入了主循环~这次的主循环是真正意义上的ARM7根循环~不同于前面找到的那些~某种程度上只是中断调用~
让我们看看主循环的代码~除了几个无关紧要的数据处理程序外~有一个调用十分有趣~这段代码里起作用的只有一句~
3804502: swi 0x06
这个swi语句~就俺来说是十分陌生的~上网GOOGLE了一番后得知~这个就是ARM的软中断调用指令~而swi 06具体对应的功能是swiHalt~也就是暂停~……
也就是说对于主循环来说~他真正在做的事情~只是维护少部分数据~然后暂停进程~并进入等待~等待其他中断处理程序给他解禁~……

事到如此~貌似一点进展都没有~依旧没能搞清楚~究竟是什么原因导致重要的触摸循环没被执行~但是事到如此~却有个非常暴力的解决方法~:在ARM7主循环里强制插入对触摸识别程序的调用~

3803c90(0238be78):读输入循环
3803cc4(0238beac):调用读TOUCH
37f842c(02380614):主循环开头
37f8450(0238063c):主循环结束跳转
具体做法倒是比较简单~把主循环的循环跳转指令依照上先前记录的数据(括号里是线性载入地址~也就是ROM文件里的线性地址)~重新定位到识别触摸的程序调用那里~然后把调用的下一行改成跳转~重新指回主循环的开头~

因为不同ROM的ARM7文件本质上都是一样的~但是随意替换会导致模拟器或者烧录卡的兼容问题~所以俺修改的是RY传说的原始ARM7~

到 现在~之前说的3个问题~按键识别地址~触摸识别地址~下断地址~以及中途出现的新问题~触摸被关闭的问题~全部解决~这样用ARM汇编简单的写段将屏幕 不同区域和按键进行对位的小程序~然后插到arm9的空白部分~设定好跳转后~配合之前修改的arm7~打包成新ROM~

放到IDEAS 上运行~BINGO!~一切顺利~顺利的用触摸屏控制按键~正准备烧到机器上玩的时候~随手用NO$GBA运行了一下~……结果只有一个字~艹!~……居 然完完全全的一点用没有~……触摸部分依旧被完全关闭……然后俺又不甘心的给烧到了卡上……果然还是没用……触摸依然不行~……结论只有一个~因为 ARM7的作用机理十分复杂~强制对其进行暴力修改~虽然在某些模拟器上可以正常运作~但是在实际DS上却是无法行的通的~……

九,回到ARM9~换个思路找出路~
受到刚才ARM7修改的打击~只好重新将思路转回ARM9~因为还是触摸问题~所以依旧是研究电子小说的ROM~

用刚才在ARM7曾用过的找触摸程序的改27fffad的方法~来跟踪arm9代码~因为有之前的种种经验~这次很顺利的找到了触摸的IPC改变前后~在ARM9执行的程序~
2000d84: bl 0x0200b070 ;key & touch
200b128: bl 0x0204e1a8 ;touch->
204e1b4: bl 0x0204ddf0 ;touch-->
从最后一行的那里跟入~会发现204ddf处所对应的程序是一个类似死循环的部分~
204ddf0: ldr r1,0x2094568
204ddf4: ldrh r2,[r1+0x36]
204ddf8: ands r2,r2,r0
204ddfc: bne 0x0204ddf4
204de00: bx lr
以上就是这个子程序的完整代码~唯一的功能只有不断的检查某个内存的值~不符合则继续循环~……
然而奇怪的是~这个程序明明只有读取没有写入~应该不会改变任何内存的值~也就是说这个循环应该永远不可能跳出的啊~可是事实上在bx lr处按F6却顺利出来了~而且就是在出来的这个时候~IPC上被强制改错的触摸值~也会被修正过来~
因此推测出这个程序的功能是等待ARM7的触摸识别程序处理完而已~
在这里等待~就表示在这不久前面就会是从ARM9发向ARM7的读触摸的请求~
因此回到外层的子程序里~留心一点~不难发现~在这层里有按键处理程序~而且整个的大致结构和RY传说的按键处理程序几乎一模一样~只有一个非常显著的区别~就是在程序尾处多了以下几个调用~
200b120: bl 0x0204e200
200b124: mov r0,r4
200b128: bl 0x0204e1a8
显然~最下面的第二个调用就是刚才跟踪进去的那个~用于等待ARM7处理结束的程序~那么很自然的就能推测出~第一个调用的功能向ARM7发送读触摸请求的了~

对于这个程序步入跟踪~得到一下的内容~
200b120: bl 0x0204e200 ;FIFO SEND
204e21c: bl 0x0204c458 ;FIFO SEND->
204c490: ldr r2,0x4000184
204c4e8: ldr r1,0x4000188
程序里分别使用了4000184和4000188这2个接口~看是4打头的就该知道~这2个是I/O接口的寄存器了~而实际上这2个寄存器正是FIFO队列的2个重要寄存器~
关于这个FIFO队列~要说清楚比较麻烦~但是这里只需要搞清楚一点~就是FIFO的用途是ARM7和ARM9的相互通信~这样程序就明了了~204c458这段程序无疑就是向ARM7发送触摸请求的代码了~

十,完事具备~只欠东风
事情到这里~问题都已经解决了~
1,按键的修改:除了X,Y键以外的~在将按键寄存器读入r12的时候~修改r12的值实现按键修改~而X,Y键则可以直接修改IPC上对应的地址~
2,触摸的识别:直接检测IPC上触摸对应的地址~
3,合适的断点:当然只能是在将4000130读入r12的这一句处~因为是要修改r12~所以若不在这里就一点意义都没有了~
4,触摸屏解封:调用其他rom里的FIFO处理程序向ARM7发送触摸请求~

现在就是要实际完成ROM修改的时候了~

主要介绍下如何给触摸屏解封~:
1,首先是从电子小说的ROM中提取FIFO处理程序~地址是204c458的这段程序~值得注意的是他还调用了2个子程序~一次都要提取出来~
2,在自己的修改代码里调用提取出来的程序~值得注意的是~这个子程序是带参数传递的~调用的时候别忘了~
3,设置一个等待程序~用来等待ARM7处理结束~因为原本的标识位涉及到很复杂的工作~所以俺放弃了原程序的等待程序~而是事先给IPC的触摸位赋错值~然后检测何时被更正~来判定ARM7是否执行完成~
4,还原环境~因为FIFO程序比较复杂~基本改变了从r0到r14的所有寄存器~所以在前面的工作都完成后~为了后面的不受到影响~一定要还原之前的环境~

之后的代码便是简单的捣弄下各个数据之间的转换~完成按键到触摸的映射就可以了~

等待程序r_wait的代码如下:
S:
stmdb r13!,{r0-r7}
ldr r0,ab1
L:
ldrb r1,[r0]
cmp r1,#0x0
beq L

ldmia r13!,{r0-r7}
bx lr
ab1: .long 0x027fffad

主程序main1的代码如下:
S:
stmdb r13!,{r0-r12,r14}
ldr r0,ab1
mov r1,#0x0
strb r1,[r0]

mov r4,r0
mov r0,#0x6
mov r1,#0x3000000
mov r2,#0x0
bl FIFO_snd
mov r0,r4
bl r_wait
ldmia r13!,{r0-r12,r14}

ldrh r12,[r2]
stmdb r13!,{r0-r7}
ldr r0,ab1
ldrb r1,[r0]
cmp r1,#0x01
bne ed1

ldr r0,ab2
ldrh r1,[r0]
mov r3,r1,lsr #0x4
and r3,#0xff
ldr r0,ab3
ldrb r4,[r0]
ldrb r5,x1
ldrb r6,x2

cmp r4,r5
bcs row2
row1:
cmp r3,r5
bcs c2
c1:
ldrh r12,cm1
b ed1
c2:
cmp r3,r6
bcs c3
ldrh r12,cm2
b ed1
c3:
ldrh r12,cm3
b ed1
row2:
cmp r4,r6
bcs row3
cmp r3,r5
bcs c5
c4:
ldrh r12,cm4
b ed1
c5:
cmp r3,r6
bcs c6
ldrh r12,cm5
b ed1
c6:
ldrh r12,cm6
b ed1
row3:
cmp r3,r5
bcs c8
c7:
ldr r0,ab4
mov r1,#0x24
str r1,[r0]
b ed1
c8:
cmp r3,r6
bcs c9
ldrh r12,cm7
b ed1
c9:
ldr r0,ab4
mov r1,#0x28
str r1,[r0]

ed1:
ldmia r13!,{r0-r7}
b 1ff84fc

ab1: .long 0x027fffad
ab2: .long 0x027fffab
ab3: .long 0x027fffac
ab4: .long 0x027fffa9
x1: .byte 0x50
x2: .byte 0xb0
y1: .byte 0x50
y2: .byte 0xb0
cm1: .int 0x03fd
cm2: .int 0x03bf
cm3: .int 0x02ff
cm4: .int 0x03df
cm5: .int 0x03fe
cm6: .int 0x03ef
cm7: .int 0x037f

代码全部写完也编译好了后~接下来就要LINK链接了~因为格式很不规范~所以么办法用程序来链接~只能手动来完成~
先 用DOS的COPY命令将主要程序main1.o 提取出来的FIFO程序FIFO_snd.o 一同提取出来的FIFO_snd所调用的2个子程序sx2.o 等待程序r_wait.o 全部顺序合成一个文件~然后用CT2打开~找到每个bl调用指令~然后把调用指令的调用地址全部修改正确~这个部分就算完成了~

最后将之 前完成的那整段程序~全部插入到ARM9文件的空白处(这还不能乱插……程序有点大~势必要覆盖掉一部分东西~找个都是无用信息的地方给塞进去~)~俺插 的是2092800处~然后在20a1ff8处改成跳转到我们代码的指令~(需要注意的是这里实际是被载入到1ff84f8~所以计算跳转差量的时候要用 这个值)~再把我们插入的代码的回跳指令指向那个的下一行~一切就算修改完成了~

十一,完成~
把这个修改好的ARM9文件~替换原ROM里的ARM9~然后打包运行~所有模拟器~DS实机~皆运行无误~修改成功!~

Aug 24, 2010

[转]不求人!DIY 自己找寻 NDS 游戏金手指密码_2 (ARDS 条件判断式指令)

原文地址:http://www.ndsbbs.com/read.php?tid=119933

前 言
在第一篇教程推出后,有朋友反映了一个问题,就是使用过 HasteDS ,发现连系模拟器后,
0x02000000 的定址不准确。
另外有朋友说所用的烧录卡不支援金手指,只能使用作弊补丁。
有关 HasteDS 定址问题,大家可转用其他习惯使用的搜寻工具来搜寻作弊码,
而作弊补丁是以工具对修改后的 Rom 比较原 Rom 后产生的文件,
使用者只需以补丁工具使用该作弊补丁文件写入到原 Rom 即可,
本文(或往后的续篇)将不会详述及示范补丁工具的使用,只示范修改 Rom 的例子,
有关补丁工具的使用,请大家在网上查找一下,很容易就能找到补丁工具及使用说明的了。

另外有朋友向本人介绍一个搜寻工具 Renegade v1.67
优点 - 是支援 No$gba 2.4a、搜寻选项及过滤条件很多,与及可以在该工具使用金手指码...
缺点 - (个人认为)是界面复杂及太多与 NDS 无关的功能选项。
有兴趣使用的朋友可在网上找来测试使用。

本来前天就已写好这第二篇的内容,示范把作弊码找出后转为 DipStar 金手指,
并配合 Slot-2 卡使用,及验证 HasteDS 定址的准确性,当完成原稿及截图后,
在版区看到有另外的热心朋友曾发布修改教程,用的是 GM8,从回帖中也看到此作弊修改工具,
颇受大家欢迎,也很多朋友长期使用这个,而且,似乎更多朋友对静态修改感兴趣,
因此,本人把已写好的原稿及截取的图片删除,重新编写本篇内容,题材也改变了,
不进行验证 HasteDS 定址的准确性了。(反正验证后的结果就是确定间中会出现定址错误),
DipStar 范例也不要了,有使用支援 DipStar 烧录卡的玩家,应该早已懂得使用的了。




Action Replay DS 条 件 判 断 式 指 令
依照第一篇教程的范例,相信学习者都已懂得自己找寻作弊码了,
但若果只能单调地反覆不停对记忆体写入数据,显然不足以应付不同情况下的使用需要,
幸好 ARDS 提供条件判断式指令,这就令 ARDS 金手指的应用范围大大提高,
现在就先来介绍一些常用的条件判断式指令。

9XXXXXXX ZZZZYYYY ( 等 于 )

这是条件断判式指令中最常用的一个,检查 0XXXXXXX 位址上的值是否等如 YYYY

使用场合:
1.依按键值来启动作弊码 (这里的 "作弊码" 狭义解作 "直接写入记忆体" 的金手指码)。
2.当变量达到指定的值才启动作弊码。

使用例子:94000130 000001BB  检查使用者是否按下 Select + L + Up 键
220031C0 000000FF  把 1 Byte 数据 0xFF 写入到位址 0x020031C0
D0000000 00000000  结束

指令原型:if YYYY == (not(ZZZZ) & [XXXXXXXX])
指令意思:假如 2 byte 数据 YYYY 等如 not(ZZZZ) & XXXXXXXX 位址上的 2 byte 数据。

== 是 "等如" 的意思,not& 是运算符,& 也等同 AND,用法如下:

Not 参数只有一个,用来把真假值反转,
Not(1) = 0
Not(0) = 1

AND 的参数有两个,要两个都为真值结果才会是真,否则就是假。
1 AND 1 = 1
1 AND 0 = 0
0 AND 1 = 0
0 AND 0 = 0

就以上面的例子 94000130 000001BB 来详细说明,
4000130 即是位址 0x04000130 ,也就是键盘I/O影射区的位址,
0x01BB 是 Select + L + Up 的按键值。
NOT(0000) = FFFF  
(不要误认为应该是 1111 ,因为 0x0000 是 16 bit,二进位是 0000000000000000,
反转成为 1111111111111111,转换为十进位是 65535,转换为十六进位就是 FFFF。)
FFFF 的二进位表示式是 1111111111111111
01BB 的二进位表示式是 0000000110111011
FFFF01BB 进行 AND 运算,如下:
1111111111111111 (0xFFFF)
0000000110111011 (0x01BB)
-------------------------    
0000000110111011 (0x01BB)

如果执行指令 94000130 000001BB 时,使用者是按了 Select + L + Up 键的话,
代入数值 01BB == (not(0000) & 01BB)
就合乎了 YYYY == (not(ZZZZ) & [XXXXXXXX]) 的比较条件,所以能执行下面其他的指令。

好像挺复杂般,其实不然,大家只要把 9XXXXXXX ZZZZYYYY 理解成这样:
( 在 ZZZZ0000 的情况下 )
假如 2 byte 数据 YYYY == (等于) 位址 0XXXXXXX 上的 2 byte 数据,
就执行其下的指令。
这样去理解是否立即简单了许多呢?

本例子中的 D0000000 00000000 用作条件判断式指令下的结束,
作用是载入先前的执行状态 (如果不存在,就保持在上面指令执行时的状态),
很多朋友都曾见过这类金手指,都是以这个或是 D2000000 00000000 作结束的,
由于作出比较时,得到的结果会影响状态位,所以当一个比较条件下其他的指令中,
又包含条件判断指令,这时候状态位对指令的执行权会作出影响,
所以就要决定因应状态位的应用,而决定使用不同的结束指令。
D2000000 00000000 它的其中一个作用是结束时清空状态位、偏移值及 C 码设定。
C 码配合的话 Dx 的值作为设置,挺复杂的说,由于不常用,故对于 C 码及 Dx 的配合,
就不予以解说了。

好像又越说越乱了,大家除非像编程般的运用他们,才要彻底的理解他们的分别及作用,
否则一般使用上,习惯以 D2000000 00000000 作为条件判断式指令下的结束就可以了。


*** 下面的指令不再以上面那种麻烦的方式作详述,只以最简单、最易理解的方式去说明***


3XXXXXXX YYYYYYYY ( 大 于 )
假如 4 byte 数据 YYYYYYYY > (大于) 位址 0XXXXXXX 上的 4 byte 数据

4XXXXXXX YYYYYYYY ( 小 于 )
假如 4 byte 数据 YYYYYYYY < (小于) 位址 0XXXXXXX 上的 4 byte 数据

5XXXXXXX YYYYYYYY ( 等 于 )
假如 4 byte 数据 YYYYYYYY == (等于) 位址 0XXXXXXX 上的 4 byte 数据

6XXXXXXX YYYYYYYY ( 不 等 于 )
假如 4 byte 数据 YYYYYYYY != (不等于) 位址 0XXXXXXX 上的 4 byte 数据

7XXXXXXX ZZZZYYYY ( 大 于 )
( 在 ZZZZ0000 的情况下 )
假如 2 byte 数据 YYYY > (大于) 位址 0XXXXXXX 上的 2 byte 数据

8XXXXXXX ZZZZYYYY ( 小 于 )
( 在 ZZZZ0000 的情况下 )
假如 2 byte 数据 YYYY < (小于) 位址 0XXXXXXX 上的 2 byte 数据

AXXXXXXX ZZZZYYYY ( 不 等 于 )
( 在 ZZZZ0000 的情况下 )
假如 2 byte 数据 YYYY != (不等于) 位址 0XXXXXXX 上的 2 byte 数据

BXXXXXXX 00000000 ( 读取记忆体数据设为偏移值 )
把位址 0x0XXXXXXX 上的 4 byte 数据,读取成为偏移值

这个是很实用的一个指令,希望大家能了解及活用它。

使用场合:
1.如果在游戏中要锁定很多变量值(例如道具、收集品)时,用这个很方便的。
2.如果同一变量的位置不固定时,先找出变化位址的存放点,用 B 码读取成为偏移值,
(其实个人认为这个称为变量基址才更贴切,以这个变量基址 + 偏移值访问不同的变量)
就不怕下次再玩时,作弊码失效的了。

使用例子:
(以 Mario Kart DS 的作弊功能 "按 X 获得道具 <雷暴>" 来说明)
Press X for Thunderbolt
923d629a 00000400  读取 (被游戏程序处理过的)按键值来作判断
6217bc2c 00000000  假如位址 0x0217BC2C 上的值不等于 0x00000000  
b217bc2c 00000000  在位址 0x0217BC2C 读取 4 byte 数据作为偏移值 (变量基址)
2000004c 00000008  到变量基址 + 0x4C 偏移值的位址,写入 1 byte 数据 0x08
20000054 00000001  到变量基址 + 0x54 偏移值的位址,写入 1 byte 数据 0x01
d2000000 00000000  结束

补充:
1.在本例子的游戏中查看位址 0x023d629a 的值,当按下不同的键,这个值就会改变的。
2.使用 B 码后,如未遇到结束指令,其后的 "直接写入记忆体指令" ,
都会一直以变量基址 + 偏移来定址及写入的。 

EXXXXXXX YYYYYYYY
从现时的指令位置 + 8 的位址,读取 YYYYYYYY byte 数据到 0x0XXXXXXX + 偏移值的位址上。

FXXXXXXX YYYYYYYY
从偏移值的位址,读取 YYYYYYYY byte 数据复制到位址 0x0XXXXXXX
使用 F 码前,需要先使用 D3DCB 码以取得偏移值。
D3000000 ZZZZZZZZ  设 4 byte 数据 ZZZZZZZZ 为偏移值。
DC000000 ZZZZZZZZ  偏移值 = 偏移值 + ZZZZZZZZ (offset = offset + ZZZZZZZZ)

活用上面的条件判断式指令,一般的应用上来说,是够用有余的了,就说到这里好了。




p.s. 本来跟部份朋友说了将在本篇中讲述修改 Rom 的,不过写完上面这些巳实在太累了,只能留待下一篇才继续了,抱歉!

Aug 22, 2010

[转]【新手入门】不求人!DIY 自己找寻 NDS 游戏金手指密码_1 (基本修改)

原帖地址:http://www.ndsbbs.com/read.php?tid=119029

【新手入门】不求人!DIY 自己找寻 NDS 游戏金手指密码_1 (基本修改)

很多人都喜欢使用金手指密码,无论是为了令游戏难度降低也好,或是希望在某些游戏中的收集品全部齐全也好,或是希望能出现一些游戏中原本不会出现的特殊情况也好(例如 MoonJump),总之就是想透过金手指来获得一些乐趣,虽则有朋友认为玩游戏应该用实力,不该借助作弊码的帮助,有些更说使用金手指会令游戏性降低,怎样也好,对于应否使用金手指,并不是本文的主旨,总之喜欢的就使用,不喜欢的不使用就可以,随各位喜好。

好了!言归正传,开始运用工具来找寻金手指密码 (作弊码)。

使用工具:
1)NDS 模拟器 (例如 DeSmuME / iDeaS / No$gba)
2)HasteDS   (一个用作搜寻作弊码的工具)

模拟器方面由于 DeSmuME 0.6.0 及 No$gba 2.4a 现时对游戏的支援度较高,建议使用此两种模拟器来找寻。HasteDS 原本是一个日文介面的程序,本人已把其繁体中文化,各位可以于本帖提供的连结下载。

【 找 寻 步 骤 】
1.先执行模拟器,并载入游戏,然后才执行 HasteDS。(由于 HasteDS 与模拟器的连系原理是搜寻记忆体中的字串/数据,如果未有载入游戏,视乎使用的模拟器,有可能连系不到,或连系后的记忆体位址是错误的。)

2.HasteDS 的搜寻模式,可分为‘输入值’及‘与旧值作比较’,‘输入参数值’是在游戏中,直接看到的数字,‘与旧值作比较’通常用于能源棒或其他不是数字显示的变量。本例子中,在游戏画面见到时间是 1800,在 HasteDS 中参考过“输入参数格式”后,输入 M1800,就会在下面的列表出现很多合乎搜寻条件之位址,但实在太多,不知哪个才是,回到游戏中待时间被减去一些后,依照看到的数字再次输入搜寻,合乎条件的记录便会减少,几次之后,通常就会只剩下 1 笔或几笔记录,就可以进行作弊码测试。

3.在列表中对作弊码按滑鼠一下,HasteDS 的记忆体检视区会立即跳到该位址行,我们可以对其修改,使用 [ 修改写入记忆体 ] 功能写入位址值及资料值就可以进行修改,然后回到游戏中,看看数字是否成为自己修改的那样;另一个测试方法是把列表中的作弊码,用滑鼠双按,就会自动把作弊码添加到左面的【 检 查 作 弊 码 】区,然后把“自动锁定作弊码”功能选取,回到游戏看看是否数字被锁定不再减少。

4.好了!作弊码找到了,相信很多朋友都希望能在 DS 主机上使用而不是只用于模拟器,那就要进行下面的格式转换,由于现在找到的是 Raw Code,对于 Raw Code 的意义,网上有很多说明,大家只要明白 Raw Code 就是最原始状态的码就成了,既然是最原始,就是未有加密,未有加入不同金手指功能所支援的判断码,因此 Raw Code 只要稍加转换,就能用于所有支援金手指功能的(甚至不支援金手指的)烧录卡上,由于 R4 烧录卡现已支援,现在就简单一点以 R4 作为范例说明。 (转为 R4 支援的 Action Replay DS 格式金手指密码)刚才找到的金手指密码位址是 0x0211BCEE ,0x 是十六进位的意思,如果数值中含有英文字,当然一看就明白,如果全是数字,又没特别注明的话,会很容易混淆的,所以最好用 0x 注明,刚才锁定的数字是 0x0302 ,在记忆体检视区看到的不是 02 03 么?为何会交换了位置?由于变量值的存放是由最低位开始、最高位在最后面的,由此例如 0x01020304 存放在档案、或在记忆体时,位置就会是 04 03 02 01,大家可以用 Windows 自带的【小算盘】,以 16 进位的模式下,输入 0302,然后切换为 10 进位的话,就会见到该数值是 770 的了。由于之前在测试中用了不少时间,所以现在被锁定的的数字并不是全满的,为了美观一点,我们就把数值定为第一次搜寻时,时间全满的值 1800 (0x0708)。
Action Replay DS 金手指密码可分为“条件判断式指令”及“直接写入记忆体指令”,此例子中只需使用简单的“直接写入记忆体指令”就可以,指令格式是:

0XXXXXXX YYYYYYYY  把 4 byte 数据 YYYYYYYY 写入到位址 XXXXXXX 上。
1XXXXXXX 0000YYYY  把 2 byte 数据 YYYY   写入到位址 XXXXXXX 上。
2XXXXXXX 000000YY  把 1 byte 数据 YY    写入到位址 XXXXXXX 上。

为了不会错误地把不想修改的数据也修改覆盖掉,请注意使用适当的使用 0 1 2 作头码,
参照以上格式,刚才找到的作弊码就可以写成 1211BCEE 00000708,用 R4 官网提供的 Cheat Code Editor 加入此密码到金手指数据库 usrcheat.dat 内,然后复制到烧录卡上就可以在游戏中使用此金手指密码。

【 备 注 】
1.有关 HasteDS 的使用,本文只举出一个简单的例子,其他的功能例如‘跳到指定位址’、‘汇出记忆体数据’,和‘与旧值作比较’之搜寻方式,或界面上的其他未提及的设定,这些看界面就已经知道是用来做什么的了,在此就不多说明了,如有需要大家可自行尝试。

2.如想更详细的了解 HasteDS 有关输入参数格式的标准与限制,可参看下载的档案中,内里的 HasteDS_manual.htm。

3.HasteDS 可支援找寻的模拟器,就如 HasteDS 界面上看到的,但实际支援的版本没有注明,本人只试过 DeSmuME 0.6.0 及 No$gba 2.4a 免费版,这些暂时来说的已是最新版本了。

4.本文作为一个入门级的找寻金手指范例,只适合新手看的,对于动态分配记忆体给变量的游戏,即是找到的密码下次再玩就巳经失效,或想依照找到的密码,对游戏 Rom 作静态修改,把运算该变量的指令修改,以求达到与锁定记忆体位址方式有相同效果的做法并未提及,
有兴趣者请自行研究。


下载 HasteDS v1.12 (繁体中文版)
http://www.veevee.net/koch/hack/hasteDS.rar

口袋妖怪 银灵

首先,我不是口袋饭。玩儿这个只是为了打发时间。但是……这剧情……和没有差不了多少了。

Aug 15, 2010

口袋妖怪 空之援助队

……
这就是我要说的。

本身对这类游戏不是很感兴趣。抱着试试的心态玩儿了这游戏,结果,觉得很无聊。

Aug 8, 2010

心灵传说

说实话,比那个什么风雨传说好多了。不过,情节依然没什么意思。不知道是不是因为提供了地图的原因,场景做的很大,但是东西却不多。感觉像是在跑地图玩儿。

我觉得RPG做重要的还是剧情。剧情差,其他再好也没意思。

Aug 6, 2010

勇者斗恶龙怪物篇 Joker2

说来DQ也是日本国民RPG,其外传性质的怪物篇应该感觉不差。

我没有玩过第一作,看到电玩巴士那么高的评价,下载一个Joker2想体验一下。

结果很失望啊,基本就是小学生水平的剧情,感觉和PSP的怪物猎人差不多,不过就是武器合成系统变成了怪物交配系统。确实很无聊啊。不明白啊,这种游戏也能火?

那中文版的翻译……基本看得很不爽。

总的来说,不是fans就不推荐大家玩这个了。

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