http://bbs.pspchina.net/forum.php?mod=viewthread&tid=290484&highlight=psplink
函数定位:
如果无法获得目标函数的入口信息,庞大的反汇编清单会把我们淹没。
我们找出解压函数的地址是基于下面的假设:
任何访问(读)压缩数据地址的指令,都和解压函数相关。(这个假设不会总成立,你可以为他的成立创造条件)
首先在游戏启动的时候通过psplink,hook住下面6个API函数:
sceIoOpen
sceIoOpenAsync
sceIoRead
sceIoReadAsync
sceIoLseek
sceIoLseekAsync
游戏启动时会看到下面显示:
host0:/> |
其中sceIoLseek里的00055FC0这个数值是指在ISO文件中偏移的扇区个数,sceIoRead里的0x00000005是说读入了5个扇区的信息量(2048*5Bytes)到内存地址0x08BE47C0
0x55FC0 = 352192
从UMDGen导出的ISO 结构文件中可以找到下面对应项:
0352192 , /PSP_GAME/USRDIR/xbdata/kuwa/loading/loading.xb
这是游戏启动加载的第一个xb文件。
经过多次试验发现0x08BE47C0这个地址是固定的。所以我们可以通过设置硬件读访问断点来获取算法的地址。
首先我们来分析那个用于文件名列表的lzss类压缩算法。用WinHex打开loading.xb,确认偏移量0x44的地址(0x40已经是文件名列表了,设置到这里也没问题)是经过压缩过的文件名列表。
Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F |
0x08BE47C0 + 0x44 = 0x8BE4804
于是设置下面断点:(注意这里的地址需要4字节对齐)
host0:/> bpset 0x8BE4804 r |
同时也可以获得当前的函数调用关系,以便于分析:
host0:/> bt done! |
于是可以看出下面的调用流程:
882add4 <- 882aec0 <- 882a860 <- 882f4d0 <- 882f078
经过上面的分析,我们怀疑0x882add4就是目标函数。
通过分析caller的调用:
.text:0882AF08 addiu $a1, $s3, 8 |
发现寄存器a0,a1,a2被赋值,而没有在函数调用完成后没有处理v1,我们可以猜测函数的原型为:
void lzss_decoder(u32 a0, u32 a1, u32 a2); |
为确认函数的功能,我们在函数的入口地址和出口地址上设置断点,然后分析函数运行前后参数的变化情况:
先看入口:
host0:/> bpset 0x882add4 |
这个时候在函数返回的地址设置断点:
host0:/> bl
Breakpoint List:
1 : Addr:0x0882AEB8 Inst:0x03E00008 Flags:---
这时我们看到,数据已经解压缩完成了。
host0:/> memdump 0x08B39798 |
void lzss_decoder(u8* dst, u8* src, int len);
而且这个len,表示的解压后的长度,于是记做dst_len。
这时保存一份当前PSP上的内存信息,以便于后面进行分析。
host0:/> savemem 0x08800000 25165824 host0:/leaveLzssDecoder.bin |
下面是从IDA中取出的该函数的反汇编代码:
=============== S U B R O U T I N E ======================================= |