- 精华
- 0
- 帖子
- 27
- 威望
- 0 点
- 积分
- 38 点
- 种子
- 0 点
- 注册时间
- 2009-11-20
- 最后登录
- 2013-6-28
|
国外黑客们的WII马里奥地图编辑器正在紧锣密鼓的开发中,将来势必能引领一场mod竞赛。
但目前不论在模拟器上还是真机上运行,都需要把编辑的关卡文件导入到ISO中,在真机上玩的话还要刻盘或者传输到硬盘,这样的话不只麻烦,也不方便朋友们分享别人制作的关卡。
如果能够将关卡放在SD卡里,让游戏读取里面的关卡的话那么这场mod游戏就更有意思了。
本Loader实现了这个目标,这个程序在neogamma r8 beta7版本基础上开发,但它和wiipower无关,所以对于它的问题不要提交给wiipower,由于使用这个软件带来的任何好处和可能的意外均没有人负责。
注意:它只对欧版的新超级马里奥兄弟有效。
使用方法:
下载网盘中提供的 boot.dol文件,放到你的sd卡的apps文件夹下的任意名的文件夹里
把你的关卡放到SD卡的LeiJi文件夹里,命名为ma_niao.arc,文件大小我限制在448K以下,一般关卡文件也就10K-30K,这个限制应该足够用了。
然后启动boot.dol程序,会出现neogamma的界面,正常进入游戏即可,关卡1-1会被替换为你SD卡里的关卡。
网盘地址:http://www.rayfile.com/files/cc1 ... -8bde-0014221b798a/
---------------
PS:国外那边我就不用GOOGLE翻译的鸟语虐老外了,版主有兴趣可以整理下语言翻译到国外论坛。
PS2:写了100多行WII汇编代码,打了快20处内存补丁,开发用了一天,调试用了一天,不过还好实现了功能,这两天的时间没白费。。。
==========
11月22日更新:
由于GPL开源许可证的传染性,本Loader同时成为GPL软件,补上源代码,希望任何分发此二进制程序的场合也一并带上。
网盘地址:
http://www.rayfile.com/files/5ba ... -bb6a-0014221b798a/
既然放了源代码那就说明一下基本执行原理和过程:
首先在config.c文件中的Load_Config()函数中增加代码,这个函数在软件初始化读取NEOGAMMA基本设置的时候被调用,增加代码为:
? ? //copy data to 0x90000000
? ? FILE* pFile = fopen("sd:/LeiJi/ma_niao.arc","rb");
? ? if(pFile)
? ? {
? ? ? ? fseek(pFile,0,SEEK_END);
? ? ? ? u32 usize = ftell(pFile);
? ? ? ? fseek(pFile,0,0); ? ?
? ? ? ? *(int*)0x90000000 = usize;
? ? ? ? fread((void*)0x90000004,usize,1,pFile);
? ? ? ? fclose(pFile); ? ?
? ? ? ? *(int*)(0x90000004+usize) = 0;
? ? ? ?
? ? ? ?
? ? ? ? const unsigned char codehandler_NSMB[] = {
? ? 0x94, 0x21, 0xff, 0xe0, 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x24, 0x90, 0x61, 0x00, 0x1c,
? ? 0x90, 0x81, 0x00, 0x18, 0x90, 0xa1, 0x00, 0x14, 0x90, 0xc1, 0x00, 0x10, 0x3c, 0xa0, 0x80, 0x00,
? ? 0x60, 0xa5, 0x18, 0x00, 0x38, 0x80, 0x00, 0x00, 0x90, 0x85, 0x00, 0x00, 0x80, 0x83, 0x00, 0x00,
? ? 0x3c, 0xc0, 0x2f, 0x53, 0x60, 0xc6, 0x74, 0x61, 0x7c, 0x04, 0x30, 0x00, 0x40, 0x82, 0x00, 0x20,
? ? 0x80, 0x83, 0x00, 0x08, 0x3c, 0xc0, 0x31, 0x2d, 0x60, 0xc6, 0x30, 0x31, 0x7c, 0x04, 0x30, 0x00,
? ? 0x40, 0x82, 0x00, 0x0c, 0x38, 0x80, 0x00, 0x01, 0x90, 0x85, 0x00, 0x00, 0x80, 0x01, 0x00, 0x24,
? ? 0x80, 0x61, 0x00, 0x1c, 0x80, 0x81, 0x00, 0x18, 0x80, 0xa1, 0x00, 0x14, 0x80, 0xc1, 0x00, 0x10,
? ? 0x7c, 0x08, 0x03, 0xa6, 0x38, 0x21, 0x00, 0x20, 0x39, 0x61, 0x00, 0x30, 0x4e, 0x80, 0x00, 0x20,
? ? 0x94, 0x21, 0xff, 0xe0, 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x24, 0x90, 0x61, 0x00, 0x1c,
? ? 0x90, 0x81, 0x00, 0x18, 0x90, 0xa1, 0x00, 0x14, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x18, 0x00,
? ? 0x80, 0x63, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x01, 0x40, 0x82, 0x00, 0x30, 0x3c, 0xa0, 0x80, 0x43,
? ? 0x60, 0xa5, 0xff, 0x20, 0x80, 0xc5, 0x00, 0x00, 0x80, 0x01, 0x00, 0x24, 0x80, 0x61, 0x00, 0x1c,
? ? 0x80, 0x81, 0x00, 0x18, 0x80, 0xa1, 0x00, 0x14, 0x7c, 0x08, 0x03, 0xa6, 0x38, 0x21, 0x00, 0x20,
? ? 0x90, 0xc4, 0x00, 0x34, 0x4b,0xd1,0x0a,0x18, 0x80, 0x01, 0x00, 0x24, 0x80, 0x61, 0x00, 0x1c,
? ? 0x80, 0x81, 0x00, 0x18, 0x80, 0xa1, 0x00, 0x14, 0x7c, 0x08, 0x03, 0xa6, 0x38, 0x21, 0x00, 0x20,
? ? 0x90, 0xa4, 0x00, 0x34, 0x4b,0xd1,0x09,0xf8, 0x94, 0x21, 0xff, 0xe0, 0x7c, 0x08, 0x02, 0xa6,
? ? 0x90, 0x01, 0x00, 0x24, 0x90, 0x61, 0x00, 0x1c, 0x90, 0x81, 0x00, 0x18, 0x90, 0xa1, 0x00, 0x14,
? ? 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x18, 0x00, 0x80, 0x63, 0x00, 0x00, 0x2c, 0x03, 0x00, 0x01,
? ? 0x40, 0x82, 0x00, 0x1c, 0x3c, 0x60, 0x80, 0x00, 0x60, 0x63, 0x18, 0x04, 0x90, 0x83, 0x00, 0x00,
? ? 0x90, 0xa3, 0x00, 0x04, 0x90, 0xc3, 0x00, 0x08, 0x48, 0x00, 0x00, 0x14, 0x3c, 0x60, 0x80, 0x00,
? ? 0x60, 0x63, 0x18, 0x04, 0x38, 0x80, 0x00, 0x00, 0x90, 0x83, 0x00, 0x00, 0x80, 0x01, 0x00, 0x24,
? ? 0x80, 0x61, 0x00, 0x1c, 0x80, 0x81, 0x00, 0x18, 0x80, 0xa1, 0x00, 0x14, 0x7c, 0x08, 0x03, 0xa6,
? ? 0x38, 0x21, 0x00, 0x20, 0x94, 0x21, 0xff, 0xe0, 0x4b,0xd1,0x0a,0xBC, 0x94, 0x21, 0xff, 0xe0,
? ? 0x7c, 0x08, 0x02, 0xa6, 0x90, 0x01, 0x00, 0x24, 0x90, 0x61, 0x00, 0x1c, 0x90, 0x81, 0x00, 0x18,
? ? 0x90, 0xa1, 0x00, 0x14, 0x3c, 0x80, 0x80, 0x00, 0x60, 0x84, 0x18, 0x04, 0x80, 0x84, 0x00, 0x00,
? ? 0x2c, 0x04, 0x00, 0x00, 0x40, 0x82, 0x00, 0x20, 0x80, 0x01, 0x00, 0x24, 0x80, 0x61, 0x00, 0x1c,
? ? 0x80, 0x81, 0x00, 0x18, 0x80, 0xa1, 0x00, 0x14, 0x7c, 0x08, 0x03, 0xa6, 0x38, 0x21, 0x00, 0x20,
? ? 0x4e, 0x80, 0x00, 0x20, 0x3c, 0xa0, 0x80, 0x43, 0x60, 0xa5, 0xff, 0x24, 0x3c, 0xc0, 0x80, 0x00,
? ? 0x60, 0xc6, 0x18, 0x08, 0x80, 0x66, 0x00, 0x00, 0x80, 0xc6, 0x00, 0x04, 0x7c, 0xa5, 0x32, 0x14,
? ? 0x7c, 0xa7, 0x2b, 0x78, 0x7c, 0x65, 0x1b, 0x78, 0x7c, 0x83, 0x23, 0x78, 0x7c, 0xe4, 0x3b, 0x78,
? ? 0x4b,0xb4,0xa1,0x45, 0x80, 0x01, 0x00, 0x24, 0x80, 0x61, 0x00, 0x1c, 0x80, 0x81, 0x00, 0x18,
? ? 0x80, 0xa1, 0x00, 0x14, 0x7c, 0x08, 0x03, 0xa6, 0x38, 0x21, 0x00, 0x20, 0x4e, 0x80, 0x00, 0x20
? ?
};
? ? const int codehandler_NSMB_size = sizeof(codehandler_NSMB);
? ? ? ? memcpy((void*)0x9007a120,codehandler_NSMB,codehandler_NSMB_size);
? ? }
WII 0x80000000起有24M MEM1内存空间,0x90000000起有64M MEM2内存空间,这里读取关卡文件,将文件长度写入0x90000000,从0x90000004起写入文件内容,在0x9007a120位置处写入codehandler_NSMB数据,这就是那100多行WII汇编代码对应的二进制数据,在源代码包里有code_handler_source压缩包,原来里面放的是gecko os的引擎汇编代码(包括调试器引擎和金手指引擎)和生成二进制的批处理以及相关工作环境,现在重定向关卡1-1的汇编代码也在里面,运行makecodehander_NSMB.bat批处理可以生成它,生成后需要搜索0x60,0x00,0x00,0x00(空指令nop的机器码),逐个替换为汇编代码中所注释的正确机器码,这样的地方大概有3-4处,原因是GCC编译时认为所要跳转到的地方非法,所以拿无用指令换过去,然后手工替换。
至于codehandler_NSMB做了什么下面会提到。
下面看apploader.c文件
NewSuperMarioBrosPatch(),这个函数负责给NSMB打内存补丁,来运行原版的游戏。
将此函数修改为:
bool NewSuperMarioBrosPatch(void *Address, int Size)
{
? bool bIsNSMB = false;
? ? if (memcmp("SMNP", (char *)0x80000000, 3) == 0)
? ? {
? ? ? ? u8 SearchPattern[32] = ? ? { 0x94, 0x21, 0xFF, 0xD0, 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x34, 0x39, 0x61, 0x00, 0x30, 0x48, 0x12, 0xD9, 0x39, 0x7C, 0x7B, 0x1B, 0x78, 0x7C, 0x9C, 0x23, 0x78, 0x7C, 0xBD, 0x2B, 0x78 };
? ? ? ? u8 PatchData[32] = ? ? ? ? ?{ 0x4E, 0x80, 0x00, 0x20, 0x7C, 0x08, 0x02, 0xA6, 0x90, 0x01, 0x00, 0x34, 0x39, 0x61, 0x00, 0x30, 0x48, 0x12, 0xD9, 0x39, 0x7C, 0x7B, 0x1B, 0x78, 0x7C, 0x9C, 0x23, 0x78, 0x7C, 0xBD, 0x2B, 0x78 };
? ? ? ? void *Addr = Address;
? ? ? ? void *Addr_end = Address+Size;
? ? ? ? while(Addr <= Addr_end-sizeof(SearchPattern))
? ? ? ? {
? ? ? ? ? ? ?if(memcmp(Addr, SearchPattern, sizeof(SearchPattern))==0)
? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? memcpy(Addr,PatchData,sizeof(PatchData));
? ? ? ? ? ? ? ? ? bIsNSMB = true;
? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ?}
? ? ? ? ? ? ?Addr += 4;
? ? ? ? }
? ? ? ?
? ? ? ? *(int*)0x801aaa58 = 0x3c60804e;
? ? ? ? *(int*)0x801aab00 = 0x3ca0804e;
? ? ? ? *(int*)0x802e9658 = 0x3c20804e;
? ? ? ? *(int*)0x802e96ec = 0x3c60804e;
? ? ? ? *(int*)0x80004234 = 0x3c20804d;
? ? ? ? *(int*)0x801aaaa8 = 0x3c60804e;
? ? ? ? *(int*)0x801aab34 = 0x3c60804e;
? ? ? ? *(int*)0x801b4a4c = 0x3c60804e;
? ? ? ? //stack addr fix.
? ? ? ?
? ? ? ? *(int*)0x801aab48 = 0x3C809008;
? ? ? ? *(int*)0x801AAB50 = 0x60000000;
? ? ? ? *(int*)0x801AAB5C = 0x60000000;
? ? ? ? //mem2 addr fix.
? ? ? ?
? ? ? ? *(int*)0x801CAC60 = 0x482EF4D8;//DVDRead Begin b
? ? ? ? *(int*)0x801CAD84 = 0x482EF428;//DVDRead End ?b
? ? ? ? *(int*)0x801CA7CC = 0x482EF875;//DVDConvertPathToEntrynum bl
? ? ? ? *(int*)0x801CAB28 = 0x482EF598;//DVDFastOpen this asm set file length b
? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ? *(int*)0x801AAE90 = 0x4BE56970;//OSInit end,jmp 0x80001800
? ? ? ?
? ? ? ? *(int*)0x80001800 = 0x9421ffe0;
? ? ? ? *(int*)0x80001804 = 0x7c0802a6;
? ? ? ? *(int*)0x80001808 = 0x90010024;
? ? ? ? *(int*)0x8000180c = 0x9061001c;
? ? ? ? *(int*)0x80001810 = 0x3c608043;
? ? ? ? *(int*)0x80001814 = 0x6063ff20;
? ? ? ? *(int*)0x80001818 = 0x3c809000;
? ? ? ? *(int*)0x8000181c = 0x3ca00007;
? ? ? ? *(int*)0x80001820 = 0x60A5A3DC;
? ? ? ? *(int*)0x80001824 = 0x48002b41;
? ? ? ? *(int*)0x80001828 = 0x80010024;
? ? ? ? *(int*)0x8000182c = 0x8061001c;
? ? ? ? *(int*)0x80001830 = 0x7c0803a6;
? ? ? ? *(int*)0x80001834 = 0x4e800020;
? ? ? ? //memcpy 500700 bytes 0x90000000 to 0x8043FF20
? ? }
? ? return bIsNSMB;
}
前面一大段动态汇编代码对搜索然后替换补丁汇编代码的指令是wiipower编写的,现在各loader软件也都是用这个补丁函数。
? ? ? ? *(int*)0x801aaa58 = 0x3c60804e;
? ? ? ? *(int*)0x801aab00 = 0x3ca0804e;
? ? ? ? *(int*)0x802e9658 = 0x3c20804e;
? ? ? ? *(int*)0x802e96ec = 0x3c60804e;
? ? ? ? *(int*)0x80004234 = 0x3c20804d;
? ? ? ? *(int*)0x801aaaa8 = 0x3c60804e;
? ? ? ? *(int*)0x801aab34 = 0x3c60804e;
? ? ? ? *(int*)0x801b4a4c = 0x3c60804e;
? ? ? ? //stack addr fix.
这八条指令,修正位于MEM1的堆栈起始地址,因为正常情况下,游戏中根本没有地方可以存放多余代码或者数据,即便存放了也会被原程序改写,或者导致程序运行出现问题,这里的八条指令一起,可以令堆栈空间后错1M地址,相当于从游戏程序手中克扣1M内存。
? ? ? ? *(int*)0x801aab48 = 0x3C809008;
? ? ? ? *(int*)0x801AAB50 = 0x60000000;
? ? ? ? *(int*)0x801AAB5C = 0x60000000;
? ? ? ? //mem2 addr fix.
这三条指令,修正位于MEM2的可用内存起始地址,正常情况下MEM2的可用内存起始地址为0x90000800,这里同样令其后撤,克扣等量内存。
这样做的原因是,如果将指令和数据直接写入MEM1里抢出来的内存里,那么程序一旦初始化,此片空间就被清空,所以前面的代码把数据先读到MEM2,然后修正MEM2空间,这样初始化后MEM1对应空间为0,但是MEM2数据还在,抓住时机将数据拷贝过去即可,至于为什么不直接使用MEM2内存而非要拷贝过去,这个一方面是个开发中的历史遗留问题,另一方面也许会有些麻烦。
? ? ? ? *(int*)0x801CAC60 = 0x482EF4D8;//DVDRead Begin b
? ? ? ? *(int*)0x801CAD84 = 0x482EF428;//DVDRead End ?b
? ? ? ? *(int*)0x801CA7CC = 0x482EF875;//DVDConvertPathToEntrynum bl
? ? ? ? *(int*)0x801CAB28 = 0x482EF598;//DVDFastOpen this asm set file length b
这4条指令在注释所说时刻拦截指令到我所编写的汇编代码位置上,分别是通过DVD句柄读取DVD数据函数的入口,出口,通过路径获取DVD文件编号,通过DVD文件编号快速打开DVD句柄。
最后:
? ? ? ? *(int*)0x801AAE90 = 0x4BE56970;//OSInit end,jmp 0x80001800
? ? ? ?
? ? ? ? *(int*)0x80001800 = 0x9421ffe0;
? ? ? ? *(int*)0x80001804 = 0x7c0802a6;
? ? ? ? *(int*)0x80001808 = 0x90010024;
? ? ? ? *(int*)0x8000180c = 0x9061001c;
? ? ? ? *(int*)0x80001810 = 0x3c608043;
? ? ? ? *(int*)0x80001814 = 0x6063ff20;
? ? ? ? *(int*)0x80001818 = 0x3c809000;
? ? ? ? *(int*)0x8000181c = 0x3ca00007;
? ? ? ? *(int*)0x80001820 = 0x60A5A3DC;
? ? ? ? *(int*)0x80001824 = 0x48002b41;
? ? ? ? *(int*)0x80001828 = 0x80010024;
? ? ? ? *(int*)0x8000182c = 0x8061001c;
? ? ? ? *(int*)0x80001830 = 0x7c0803a6;
? ? ? ? *(int*)0x80001834 = 0x4e800020;
? ? ? ? //memcpy 500700 bytes 0x90000000 to 0x8043FF20
第一条指令在系统初始化函数的出口处将代码劫持到0x80001800,此时MEM1对应空间清空,MEM2空间还是我们的数据。
0x80001800起是WII的STUB区域,一般来说被一些Loader用来存放一些保留性的数据,gecko os的引擎就放在这里,但是0x80001800起对它来说只是存放游戏名的缓冲区,覆盖了无所谓,0x800018a8起才是他的代码。
后面那些指令是几条汇编指令的机器码,作用就是把0x90000000的数据拷贝500700字节到0x8043ff20(从MEM1抢出来的1M自留地的起始地址)
在neogamma上添加的C代码就这么多。
汇编代码方面,codehandler_NSMB如下:
.text
.set r0,0; ?.set r1,1; ?.set r2,2; .set r3,3; ?.set r4,4
.set r5,5; ?.set r6,6; ?.set r7,7; ?.set r8,8; ?.set r9,9
.set r10,10; .set r11,11; .set r12,12; .set r13,13; .set r14,14
.set r15,15; .set r16,16; .set r17,17; .set r18,18; .set r19,19
.set r20,20; .set r21,21; .set r22,22; .set r23,23; .set r24,24
.set r25,25; .set r26,26; .set r27,27; .set r28,28; .set r29,29
.set r30,30; .set r31,31; .set f0,0; .set f2,2; .set f3,3
? ? ?
.globl _start
_start: ? ? ? ? #_DVDConvertPathToEntrynum:
? ? stwu r1,-32(r1)
? ? mflr r0, ? ?
? ? stw r0,36(r1)
? ? stw r3,28(r1)
? ? stw r4,24(r1)
? ? stw r5,20(r1)
? ? stw r6,16(r1)
? ? lis r5,0x8000
? ? ori r5,r5,0x1800
? ? li ?r4,0
? ? stw r4,0(r5)
? ? lwz r4,0(r3)
? ? lis r6,0x2f53
? ? ori r6,r6,0x7461
? ? cmpw r4,r6
? ? bne _backDVDConvertPathToEntrynum
? ? lwz r4,8(r3)
? ? lis r6,0x312d
? ? ori r6,r6,0x3031
? ? cmpw r4,r6
? ? bne _backDVDConvertPathToEntrynum
? ? li ?r4,1
? ? stw r4,0(r5)
_backDVDConvertPathToEntrynum:
? ? lwz r0,36(r1)
? ? lwz r3,28(r1)
? ? lwz r4,24(r1)
? ? lwz r5,20(r1)
? ? lwz r6,16(r1)
? ? mtlr r0 ? ?
? ? addi r1,r1,32
? ? addi r11,r1,0x30
? ? blr
_SetFileLength:
? ? stwu r1,-32(r1)
? ? mflr r0, ? ?
? ? stw r0,36(r1)
? ? stw r3,28(r1)
? ? stw r4,24(r1)
? ? stw r5,20(r1)
? ? lis r3,0x8000
? ? ori r3,r3,0x1800
? ? lwz r3,0(r3)
? ? cmpwi r3,1
? ? bne _backSetFileLength0
? ? lis r5,0x8043
? ? ori r5,r5,0xff20
? ? lwz r6,0(r5)
? ? ? ? lwz r0,36(r1)
? ? lwz r3,28(r1)
? ? lwz r4,24(r1)
? ? lwz r5,20(r1)
? ? mtlr r0 ? ?
? ? addi r1,r1,32
? ? stw r6,0x34(r4)
? ? nop ? ? ? ? ?#b 0x801cab2c | 0x4b,0xd1,0x0a,0x18
_backSetFileLength0:
? ? ? ? lwz r0,36(r1)
? ? lwz r3,28(r1)
? ? lwz r4,24(r1)
? ? lwz r5,20(r1)
? ? mtlr r0 ? ?
? ? addi r1,r1,32
? ? stw r5,0x34(r4)
? ? nop ? ? ? ? ?#b 0x801cab2c | 0x4b,0xd1,0x09,0xf8
_DVDRead_Begin:
? ? stwu r1,-32(r1)
? ? mflr r0 ? ?
? ? stw r0,36(r1)
? ? stw r3,28(r1)
? ? stw r4,24(r1)
? ? stw r5,20(r1)
? ? lis r3,0x8000
? ? ori r3,r3,0x1800
? ? lwz r3,0(r3)
? ? cmpwi r3,1
? ? bne _clearMEM
? ? lis r3,0x8000
? ? ori r3,r3,0x1804
? ? stw r4,0(r3) #0x80001804 buffer GAMEBuffer
? ? stw r5,4(r3) #0x80001808 length
? ? stw r6,8(r3) #0x8000180c offset
? ? b ? _backDVDRead
_clearMEM:
? ? lis r3,0x8000
? ? ori r3,r3,0x1804
? ? li ?r4,0
? ? stw r4,0(r3) #0x80001804 buffer NULL
_backDVDRead:
? ? lwz r0,36(r1)
? ? lwz r3,28(r1)
? ? lwz r4,24(r1)
? ? lwz r5,20(r1)
? ? mtlr r0 ? ?
? ? addi r1,r1,32
? ? stwu r1,-0x20(r1)
? ? nop ? ? ? ? ? ? ? ? ? #b 0x801cac64 | 0x4b,0xd1,0x0a,0xBC
_DVDRead_End:
? ? stwu r1,-32(r1)
? ? mflr r0 ? ?
? ? stw ?r0,36(r1)
? ? stw ?r3,28(r1)
? ? stw ?r4,24(r1)
? ? stw ?r5,20(r1)
? ? lis ?r4,0x8000
? ? ori ?r4,r4,0x1804
? ? lwz ?r4,0(r4)
? ? cmpwi r4,0
? ? bne ?_ReadSDLevel
? ? lwz r0,36(r1)
? ? lwz r3,28(r1)
? ? lwz r4,24(r1)
? ? lwz r5,20(r1)
? ? mtlr r0 ? ?
? ? addi r1,r1,32
? ? blr
_ReadSDLevel:
? ? lis ?r5,0x8043
? ? ori ?r5,r5,0xff24
? ? lis ?r6,0x8000
? ? ori ?r6,r6,0x1808
? ? lwz ?r3,0(r6) #length
? ? lwz ?r6,4(r6) ? ? #offset
? ? add ?r5,r5,r6 ?#source addr
? ? mr ? r7,r5
? ? mr ? r5,r3
? ? mr ? r3,r4
? ? mr ? r4,r7
? ? nop ? ? #bl 0x80004364 ?| 0x4b,0xb4,0xa1,0x45 ?# memcpy
? ? lwz r0,36(r1)
? ? lwz r3,28(r1)
? ? lwz r4,24(r1)
? ? lwz r5,20(r1)
? ? mtlr r0 ? ?
? ? addi r1,r1,32
? ? blr ? ?
_DVDConvertPathToEntrynum在游戏通过路径获得文件编号时会被劫持到这里执行,判断路径是不是/Stage/01-01.arc,是的话将0x80001800内存写为1,不然就是0
_SetFileLength:在游戏通过文件编号打开文件执行到填充某数据结构中表示文件长度的那一条指令时会被劫持到这里执行,判断0x80001800内存是否为1,是的话将长度设置为SD卡里那个关卡文件的长度,否则执行原逻辑
_DVDRead_Begin:在游戏读取DVD文件数据时会被劫持到这里,判断0x80001800内存是否为1,为1则记录游戏要把数据读到哪,读多长,从文件的什么位置读,在0x80001804内存顺序放置,然后执行原逻辑。
_DVDRead_End:在游戏读取DVD文件数据结束后会被劫持到这里,判断0x80001804内存是否为0,不为0则拷贝期望区域的期望大小的原SD卡里数据到目标内存。
--------------------
11月23日更新:(写给gbatemp过来的程序员)
的确,如你们一些人所感觉的,这个程序在游戏启动前就将SD卡的数据读取完毕,而不是游戏运行时重定向文件访问操作到SD卡,但并不意味那是不可能的,我曾经试图在bootmii的代码中提取出在IOS以上层面(不经过更多包装)读取SD卡FAT分区数据的函数,虽然后来放弃了但并不是这是无法做到的,尽管NSMB不像brawl那样游戏程序本身就有访问SD卡的时候(你们有些黑客利用这点实现了它的文件重定向到SD卡读取),但只要写出通过IOS(我的意思不是编写一个IOS,而是在应用软件层调用IOS对上层的函数接口)访问SD卡设备FAT文件系统的函数就能实现真正的游戏运行时文件重定向到SD卡,这将是对任何游戏通用的(指思路),由此可能带来的影响也许现在不好说,所以短期内我不打算研究这个,你们中的一些人应该对它感兴趣,祝你们好运。. |
|