- 积分
- 257
- 实力分
- 点
- 金钱数
- 两
- 技术分
- 分
- 贡献分
- 分
|

楼主 |
发表于 2005-10-18 15:26:49
|
显示全部楼层
PetFish修正教程:
PetFish存在存档问题,原版会将进度存档存入C:\petfish.sav中,但是读取存档却从程序安装目录下读取,比如E:\system\apps\PetFish\petfish.sav。这样就造成了每次读取进度都会失败的问题。
用UE打开PetFish.app,找到PetFish.sav,尝试改为E:\Fish.sav,运行结果是存档的确存入了E:\Fish.sav,但是依然不能正确读取。
于是再次修改,将E:\system\apps\petfish\petfish.sav。这样修改由于原本字节空间不足,所以需要从其他资源的地方借用一部分字节,并且注意将头四个字节的0B修改成21,即资源扩张后的有效长度。
按道理说,如果将这里修改了,存档文件直接写入安装目录,读取的时候就应该可以了,可是试验的结果很令人沮丧...在读取进度的时候程序会报错。
看来简单的用UE修改解决不了这个问题,于是用IDA反编译petfish.app,从代码内核进行分析。
首先找到petfish.sav的资源地址:
.text:10026E70 dword_10026E70 DCD 0xB, 0x650050, 0x660074, 0x730069, 0x2E0068, 0x610073
.text:10026E70 ; DATA XREF: sub_10009338:off_10009414o
.text:10026E70 ; .text:off_1000A884o
因为是UNICODE,这里没有直接解析成String,你可以对此段Undefine,就可以看到内容。
这个资源被两次调用,先看 DATA XREF: sub_10009338:off_10009414o
text:100093B4 MOV R0, #0x174
.text:100093B8 BL NewL__6HBufC8i ; HBufC8::NewL(int)
.text:100093BC MOV R6, R0
.text:100093C0 ADD R0, SP, #0x328+var_120
.text:100093C4 MOV R1, #0x80
.text:100093C8 BL __10TBufBase16i
.text:100093CC MOV R4, SP
.text:100093D0 MOV R0, R4
.text:100093D4 LDR R1, =dword_10026E70 ;这里是PetFish.sav调用
.text:100093D8 BL sub_1000E25C
.text:100093DC ADD R0, SP, #0x328+var_120
.text:100093E0 MOV R1, R4
.text:100093E4 BL Copy__6TDes16RC7TDesC16
.text:100093E8 MOV R0, R6
.text:100093EC ADD R1, SP, #0x328+var_120
.text:100093F0 BL sub_1000DD8C
.text:100093F4 CMP R0, #0
.text:100093F8 BEQ loc_10009418
.text:100093FC MOV R0, R6
.text:10009400 BL Ptr__C6TDesC8 ; TDesC8::Ptr(void)
.text:10009404 MOV R1, R0
.text:10009408 MOV R0, R5
.text:1000940C BL sub_10009234
.text:10009410 B loc_10009420
这段代码的大致含义是将PetFish.sav与sub_1000E25C调用得到的内容进行拼接。然后调用 sub_1000DD8C及其后的代码。
我们先看看sub_1000E25C是什么:
STMFD SP!, {R4-R7,LR}
.text:1000E260 SUB SP, SP, #0x420
.text:1000E264 SUB SP, SP, #8
.text:1000E268 MOV R7, R0
.text:1000E26C MOV R6, R1
.text:1000E270 ADD R5, SP, #0x43C+var_234
.text:1000E274 MOV R0, R5
.text:1000E278 BL __6TParse
.text:1000E27C MOV R4, SP
.text:1000E280 MOV R0, R4
.text:1000E284 BL sub_1000E1F4
.text:1000E288 MOV R0, R5
.text:1000E28C MOV R1, R4
.text:1000E290 MOV R2, R6
.text:1000E294 MOV R3, #0
.text:1000E298 BL Set__6TParseRC7TDesC16PC7TDesC16T2 ; TParse::Set(TDesC16 const &,TDesC16 const *,TDesC16 const *)
.text:1000E29C MOV R0, R5
.text:1000E2A0 BL FullName__C10TParseBase ; TParseBase::FullName(void)
.text:1000E2A4 MOV R1, R0
.text:1000E2A8 MOV R0, R7
.text:1000E2AC MOV R2, #0x100
.text:1000E2B0 BL __10TBufBase16RC7TDesC16i
.text:1000E2B4 MOV R0, R7
.text:1000E2B8 ADD SP, SP, #0x28
.text:1000E2BC ADD SP, SP, #0x400
.text:1000E2C0 LDMFD SP!, {R4-R7,LR}
.text:1000E2C4 BX LR
很显然,这段代码是用来得到程序运行的当前路径。
那么拼接的结果就是 当前路径+petfish.sav。
再看 sub_1000DD8C
.text:1000DD8C STMFD SP!, {R4-R8,LR}
.text:1000DD90 SUB SP, SP, #0x2C
.text:1000DD94 MOV R8, R0
.text:1000DD98 MOV R6, R1
.text:1000DD9C ADD R4, SP, #0x44+var_28
.text:1000DDA0 MOV R7, #0
.text:1000DDA4 STR R7, [SP,#0x44+var_28]
.text:1000DDA8 ADD R5, SP, #0x44+var_30
.text:1000DDAC STR R7, [SP,#0x44+var_30]
.text:1000DDB0 STR R7, [R5,#4]
.text:1000DDB4 MOV R0, R4
.text:1000DDB8 MOV R1, #4
.text:1000DDBC BL Connect__3RFsi ; RFs::Connect(int)
.text:1000DDC0 BL LeaveIfError__4Useri ; User::LeaveIfError(int)
.text:1000DDC4 LDR R3, =loc_10026604
.text:1000DDC8 STR R3, [SP,#0x44+var_38]
.text:1000DDCC STR R4, [SP,#0x44+var_34]
.text:1000DDD0 ADD R3, SP, #0x44+var_38
.text:1000DDD4 LDMIA R3, {R0,R1}
.text:1000DDD8 BL PushL__12CleanupStackG12TCleanupItem ; CleanupStack::PushL(TCleanupItem)
.text:1000DDDC MOV R0, R5
.text:1000DDE0 MOV R1, R4
.text:1000DDE4 MOV R2, R6
.text:1000DDE8 MOV R3, R7
.text:1000DDEC BL Open__5RFileR3RFsRC7TDesC16Ui ; RFile::Open(RFs &,TDesC16 const &,uint)
.text:1000DDF0 CMP R0, R7
.text:1000DDF4 BEQ loc_1000DE04
.text:1000DDF8 BL PopAndDestroy__12CleanupStack ; CleanupStack::PopAndDestroy(void)
.text:1000DDFC B loc_1000DE78
没错了,这段代码是在读取文件内容。
也就是说,这段代码是处理读进度的功能。
回过头来,在看看对PetFish.sav的另一个调用
.text:1000A7D0 CMP R5, #0
.text:1000A7D4 BEQ loc_1000A810
.text:1000A7D8 ADD R4, SP, #0x1DC+var_1D4
.text:1000A7DC MOV R0, R4
.text:1000A7E0 MOV R1, R5
.text:1000A7E4 BL Des__6HBufC8 ; HBufC8::Des(void)
.text:1000A7E8 MOV R0, R4
.text:1000A7EC ADD R1, SP, #0x1DC+var_188
.text:1000A7F0 MOV R2, #0x174
.text:1000A7F4 BL Copy__5TDes8PCUci ; TDes8::Copy(uchar const *,int)
.text:1000A7F8 MOV R0, R5
.text:1000A7FC LDR R1, =dword_10026E70;这里是PetFish.sav调用
.text:1000A800 BL sub_1000DCA0
.text:1000A804 MOV R7, R0
.text:1000A808 MOV R0, R5
.text:1000A80C BL __builtin_delete
.text:1000A810
这段代码调用了PetFish.sav直接又调用了sub_1000DCA0,我们看看sub_1000DCA0是什么:
text:1000DCA0 STMFD SP!, {R4-R7,LR}
.text:1000DCA4 SUB SP, SP, #0x60
.text:1000DCA8 MOV R7, R0
.text:1000DCAC MOV R5, R1
.text:1000DCB0 ADD R4, SP, #0x74+var_54
.text:1000DCB4 MOV R3, #0
.text:1000DCB8 STR R3, [SP,#0x74+var_54]
.text:1000DCBC ADD R6, SP, #0x74+var_5C
.text:1000DCC0 STR R3, [SP,#0x74+var_5C]
.text:1000DCC4 STR R3, [R6,#4]
.text:1000DCC8 MOV R0, R4
.text:1000DCCC MOV R1, #4
.text:1000DCD0 BL Connect__3RFsi ; RFs::Connect(int)
.text:1000DCD4 BL LeaveIfError__4Useri ; User::LeaveIfError(int)
.text:1000DCD8 LDR R3, =loc_10026604
.text:1000DCDC STR R3, [SP,#0x74+var_64]
.text:1000DCE0 STR R4, [SP,#0x74+var_60]
.text:1000DCE4 ADD R3, SP, #0x74+var_64
.text:1000DCE8 LDMIA R3, {R0,R1}
.text:1000DCEC BL PushL__12CleanupStackG12TCleanupItem ; CleanupStack::PushL(TCleanupItem)
.text:1000DCF0 MOV R0, R6
.text:1000DCF4 MOV R1, R4
.text:1000DCF8 MOV R2, R5
.text:1000DCFC MOV R3, #0x200
.text:1000DD00 BL Replace__5RFileR3RFsRC7TDesC16Ui ; RFile::Replace(RFs &,TDesC16 const &,uint)
.text:1000DD04 SUBS R5, R0, #0
.text:1000DD08 BNE loc_1000DD78
.text:1000DD0C LDR R3, =loc_10026608
.text:1000DD10 STR R3, [SP,#0x74+var_6C]
.text:1000DD14 STR R6, [SP,#0x74+var_68]
.text:1000DD18 ADD R3, SP, #0x74+var_6C
.text:1000DD1C LDMIA R3, {R0,R1}
.text:1000DD20 BL PushL__12CleanupStackG12TCleanupItem ; CleanupStack::PushL(TCleanupItem)
.text:1000DD24 ADD R4, SP, #0x74+var_50
.text:1000DD28 MOV R0, R4
.text:1000DD2C MOV R1, R6
.text:1000DD30 MOV R2, R5
.text:1000DD34 BL __16RFileWriteStreamR5RFilei
.text:1000DD38 LDR R3, =loc_10026600
.text:1000DD3C STMEA SP, {R3,R4}
.text:1000DD40 MOV R3, SP
.text:1000DD44 LDMIA R3, {R0,R1}
.text:1000DD48 BL PushL__12CleanupStackG12TCleanupItem ; CleanupStack::PushL(TCleanupItem)
.text:1000DD4C MOV R0, R4
.text:1000DD50 MOV R1, R7
.text:1000DD54 BL WriteL__12RWriteStreamRC6TDesC8 ; RWriteStream::WriteL(TDesC8 const &)
.text:1000DD58 BL PopAndDestroy__12CleanupStack ; CleanupStack::PopAndDestroy(void)
.text:1000DD5C BL PopAndDestroy__12CleanupStack ; CleanupStack::PopAndDestroy(void)
.text:1000DD60 BL PopAndDestroy__12CleanupStack ; CleanupStack::PopAndDestroy(void)
.text:1000DD64 MOV R0, #1
.text:1000DD68 B loc_1000DD80
很长,不过很好看懂...这里显然是在写文件,那么就应该是存储进度的地方。
好了,我们回想一下,读写操作有什么不同呢?唯一的差别就是读进度的时候进行了 当前路径+ petfish.sav 的操作。
可以动手修改了,我们可以吧 当前路径+ petfish.sav 去掉,让他和写的时候进行同样的操作。
将一下标记为已注释的部分用NOP指令替换掉,就可以完成修正工作了。
修正之后记录存放在c:\petfish.sav,如果觉得不爽可以自己用UE改成e:\fish.sav
text:100093B4 MOV R0, #0x174
.text:100093B8 BL NewL__6HBufC8i ; HBufC8::NewL(int)
.text:100093BC MOV R6, R0
.text:100093C0 ADD R0, SP, #0x328+var_120 ; 已注释
.text:100093C4 MOV R1, #0x80
.text:100093C8 BL __10TBufBase16i ; 已注释
.text:100093CC MOV R4, SP ; 已注释
.text:100093D0 MOV R0, R4
.text:100093D4 LDR R1, =dword_10026E70
.text:100093D8 BL sub_1000E25C ; 已注释
.text:100093DC ADD R0, SP, #0x328+var_120 ; 已注释
.text:100093E0 MOV R1, R4 ; 已注释
.text:100093E4 BL Copy__6TDes16RC7TDesC16 ; 已注释
.text:100093E8 MOV R0, R6
.text:100093EC ADD R1, SP, #0x328+var_120 ; 已注释 |
|