距离上一次写PSP破解方面的东西已经过了3年了,这是何等的跨度啊~~~好了,前面两篇算是基础的基础,可以说不管你是想开发自己的程序在自制固件上运行,还是打算走开发自制固件的路,那些都是必备的东西,这篇文章主要是给有兴趣的朋友一个引导,想必有些童鞋对当年L大怎么找到游戏的关键密钥从而破解新的游戏EBOOT.BIN有点好奇吧,现在就来揭开这个秘密。
貌似我忘了规矩,首先感谢在我研究期间帮助过我的1位朋友(之所以这样说的确是破解圈没什么人会告诉你怎么继续下去,很多时候都只能靠你自己不厌其烦的去摸索)noname120,他人很好,虽然在寻找key的研究中并没有其太大作用,但是给了其他很多辅助。其次是一直不知道如何联系到L大,所以只能利用他留下来的一些开源资源去研究;好了,接下来是前期回顾:
∵传送门∴
这里是当年L大破解和平行者的记录,我们可以了解一下顺序。
【版权】转帖请著名出处,本人只在私人博客发布,如果有需要转载请尊重他人的劳动成果!
首先说一下逻辑,根据L大所说,opnssmp.bin是解密的关键,他类似一个密保卡,新的游戏会传递自己EBOOT.BIN偏移0xD0位置大小4位的一个flag去opnssmp.bin,然后利用这个密保卡里面给出的一段120位长度的数据去调用sceMesgLed模组(来自mesg_led_02g.prx)中的一个函数,当然这个模块是6.xx的新功能,所以低于6.xx版本的固件就玩不了新游戏,所以L大才需要对自己开发的prometheus固件的修改让广大的游戏爱好者能玩到6.xx版本下的游戏。
开始分析,首先我们先利用L大工具PSPCipher或者jas0nuk写的PRXDecrypter解密opnssmp.bin文件,当然解密这个固件也需要钥,但是这个密钥可以通过逆向memlmd_??g.prx得到,十分容易。但是如何得到解密memlmd_??g.prx呢?这个密钥需要dump内核内存分析,这个超出本文的畴,就不多赘述了。
module_start:
0x00000000: 0x27BDFFF0 '...'' - addiu $sp, $sp, -16
0x00000004: 0xAFBF0004 '....' - sw $ra, 4($sp)
0x00000008: 0xAFB00000 '....' - sw $s0, 0($sp)
0x0000000C: 0x0C000017 '....' - jal SysMemUserForUser_D8DE5C1E
0x00000010: 0x8CB00000 '....' - lw $s0, 0($a1)
0x00000014: 0x14400008 '..@.' - bnez $v0, loc_00000038
0x00000018: 0x8FBF0004 '....' - lw $ra, 4($sp)
; Data ref 0x00000150 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x0000001C: 0x3C020000 '...<' - lui $v0, 0x0
0x00000020: 0x24030012 '...$' - li $v1, 18
0x00000024: 0x12030009 '....' - beq $s0, $v1, loc_0000004C //这里判断tag是不是0x12
; Data ref 0x00000150 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x00000028: 0x24440150 'P.D$' - addiu $a0, $v0, 336
0x0000002C: 0x24030013 '...$' - li $v1, 19
0x00000030: 0x12030005 '....' - beq $s0, $v1, loc_00000048 //这里判断tag是不是0x13
; Data ref 0x000001C8 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x00000034: 0x3C050000 '...<' - lui $a1, 0x0
loc_00000038: ; Refs: 0x00000014 0x00000054
0x00000038: 0x8FB00000 '....' - lw $s0, 0($sp)
0x0000003C: 0x24020001 '...$' - li $v0, 1
0x00000040: 0x03E00008 '....' - jr $ra
0x00000044: 0x27BD0010 '...'' - addiu $sp, $sp, 16
loc_00000048: ; Refs: 0x00000030
; Data ref 0x000001C8 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x00000048: 0x24A401C8 '...$' - addiu $a0, $a1, 456
loc_0000004C: ; Refs: 0x00000024
0x0000004C: 0x0C000019 '....' - jal sceResmgr_8E6C62C8 //这里传一个120bytes的buf,buf的地址起始是0x1C8,其实就是上一句的a0
0x00000050: 0x00000000 '....' - nop
0x00000054: 0x0800000E '....' - j loc_00000038
0x00000058: 0x8FBF0004 '....' - lw $ra, 4($sp)
; ======================================================
; Subroutine SysMemUserForUser_D8DE5C1E - Address 0x0000005C
; Imported from SysMemUserForUser
SysMemUserForUser_D8DE5C1E: ; Refs: 0x0000000C
0x0000005C: 0x03E00008 '....' - jr $ra
0x00000060: 0x00000000 '....' - nop
; ======================================================
; Subroutine sceResmgr_8E6C62C8 - Address 0x00000064
; Imported from sceResmgr
sceResmgr_8E6C62C8: ; Refs: 0x0000004C
0x00000064: 0x03E00008 '....' - jr $ra
0x00000068: 0x00000000 '....' - nop
0x0000006C: 0x00000000 '....' - nop
; ==== Section .rodata - Address 0x00000070 Size 0x000001D0 Flags 0x0002
- 00 01 02 03 | 04 05 06 07 | 08 09 0A 0B | 0C 0D 0E 0F - 0123456789ABCDEF
-------------------------------------------------------------------------------------
0x00000070 - 00 00 00 00 | 00 00 00 00 | 00 00 00 80 | 04 03 01 00 - ................
0x00000080 - 14 01 00 00 | 00 00 00 00 | 00 00 00 00 | F0 00 00 00 - ................
0x00000090 - 11 00 00 40 | 05 00 01 00 | 34 01 00 00 | 5C 00 00 00 - ...@....4...\...
0x000000A0 - 08 01 00 00 | 11 00 09 40 | 05 00 01 00 | 38 01 00 00 - .......@....8...
0x000000B0 - 64 00 00 00 | 00 00 00 00 | 00 00 13 01 | 6F 70 6E 73 - d...........opns
0x000000C0 - 73 6D 70 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 - smp.............
0x000000D0 - 00 00 00 00 | 00 00 00 00 | 30 82 00 00 | 74 00 00 00 - ........0...t...
0x000000E0 - 84 00 00 00 | 8C 00 00 00 | B4 00 00 00 | 00 00 00 00 - ................
0x000000F0 - 53 79 73 4D | 65 6D 55 73 | 65 72 46 6F | 72 55 73 65 - SysMemUserForUse
0x00000100 - 72 00 00 00 | 00 00 00 00 | 73 63 65 52 | 65 73 6D 67 - r.......sceResmg
0x00000110 - 72 00 00 00 | DB AC 32 D6 | A7 73 1D F0 | 06 75 B9 11 - r.....2..s...u..
0x00000120 - 6C 27 7C 0F | 00 00 00 00 | B8 00 00 00 | 3C 01 00 00 - l'|.........<...
0x00000130 - 40 01 00 00 | 1E 5C DE D8 | C8 62 6C 8E | 10 00 00 06 - @....\...bl.....
0x00000140 - 03 00 00 00 | 10 00 00 00 | 00 04 00 00 | 00 00 00 00 - ................
0x00000150 - 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 - ................
0x00000160 - C5 D4 EE C0 | C4 B8 37 6F | 59 E1 D3 55 | 66 0F 67 6C - ......7oY..Uf.gl
0x00000170 - A6 E9 45 F7 | 83 14 62 0C | CC DC E6 D9 | FC 1B 6A E3 - ..E...b.......j.
0x00000180 - 6C 92 19 47 | 37 E7 41 82 | 66 BF 20 7A | 8F 73 93 1D - l..G7.A.f. z.s..
0x00000190 - C2 19 ED 27 | 33 68 F8 F1 | 35 08 D0 5A | 1A BD 5B 9D - ...'3h..5..Z..[.
0x000001A0 - 6A 70 40 D3 | 10 DA D4 4B | E8 A8 AF D0 | 81 4E A9 FA - jp@....K.....N..
0x000001B0 - D7 33 11 AD | BE E5 2A F8 | 62 B6 98 4B | 54 FC 5D CA - .3....*.b..KT.].
0x000001C0 - 0A F8 E1 0E | B0 07 EC 2B | 00 00 00 00 | 00 00 00 00 - .......+........
0x000001D0 - 00 00 00 00 | 00 00 00 00 | 4D DE 2D EB | 5E 1F 6F DB - ........M.-.^.o.
0x000001E0 - 4A 52 33 79 | FF AF DC 5C | BE EC 3E 9E | 38 7E 55 C7 - JR3y...\..>.8~U.
0x000001F0 - F5 84 BD D1 | 68 73 8A 58 | 3F EE FF 83 | 57 D7 0D 48 - ....hs.X?...W..H
0x00000200 - 27 4B 63 C7 | B7 9B E0 83 | 5B 03 97 7B | 11 F3 A1 D0 - 'Kc.....[..{....
0x00000210 - 11 C5 77 B2 | AB 83 79 21 | CA ED 2E 82 | AE 78 17 2C - ..w...y!.....x.,
0x00000220 - 1D A3 7C CF | 78 DC 70 D0 | 11 50 38 C2 | 16 8D B7 56 - ..|.x.p..P8....V
0x00000230 - 19 84 EF 4B | 9F 49 EE EA | 5B 90 81 7E | 76 1D 97 31 - ...K.I..[..~v..1
可以看到和平行者的密保卡还是很简单的,就这么一点点,我看过寄生前夜的,虽然看起来比这个复杂多了,可惜依然是换汤不换药。通过上面我们知道了传递的是一个0x1C8起始地址的120位buf,看看.rodata部分的数据,我们看看偏移0x1C8……嗯嗯,对,就是前16位都是0开始的那个位置一直到结束,正好120位,好了,我们找到buf后下一步是要分析一下那个用密保卡的函数了,继续逆向mesg_led_02g.prx并找到密保卡中调用的函数sceResmgr_8E6C62C8,因为该函数的内容太长了,我就挑几个重点说一下,先来看MIPS代码
; Data ref 0x00008E6C ... 0x00000000 0x00000000 0x00000000 0x00000000
0x0000677C: 0xAEC28E6C 'l...' - sw $v0, -29076($s6)
; Data ref 0x00009414 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x00006780: 0x3C030001 '...<' - lui $v1, 0x1
; Data ref 0x00008E00 ... 0xD91611F0 0x58C0B061 0xFAD95771 0x5C0E6774
0x00006784: 0x3C020001 '...<' - lui $v0, 0x1
; Data ref 0x00009414 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x00006788: 0x24669414 '..f$' - addiu $a2, $v1, -27628 //这里拿到偏移0x9414的地址
; Data ref 0x00008E00 ... 0xD91611F0 0x58C0B061 0xFAD95771 0x5C0E6774
0x0000678C: 0x24478E00 '..G$' - addiu $a3, $v0, -29184 //这里拿到偏移0x8E00的地址
0x00006790: 0x00002821 '!(..' - move $a1, $zr
loc_00006794: ; Refs: 0x000067A8 //这个是一个循环,循环次数是4,把偏移0x8E00地址开始的4位数据仍到偏移0x9414的位置去,在C语言里面相当于memcpy函数吗,当然后面还会有16位,4位,再16位,一共4次循环,其实就是把tag1,key1,tag2,key2临时保存起来。
0x00006794: 0x00A71021 '!...' - addu $v0, $a1, $a3
0x00006798: 0x90440000 '..D.' - lbu $a0, 0($v0)
0x0000679C: 0x00A61821 '!...' - addu $v1, $a1, $a2
0x000067A0: 0x24A50001 '...$' - addiu $a1, $a1, 1
0x000067A4: 0x2CA20004 '...,' - sltiu $v0, $a1, 4
0x000067A8: 0x1440FFFA '..@.' - bnez $v0, loc_00006794
0x000067AC: 0xA0640000 '..d.' - sb $a0, 0($v1)
再来一段
; Data ref 0x00008E00 ... 0xD91611F0 0x58C0B061 0xFAD95771 0x5C0E6774
0x00006840: 0x3C020001 '...<' - lui $v0, 0x1
; Data ref 0x000091C0 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x00006844: 0x3C030001 '...<' - lui $v1, 0x1
; Data ref 0x00008E00 ... 0xD91611F0 0x58C0B061 0xFAD95771 0x5C0E6774
0x00006848: 0x24468E00 '..F$' - addiu $a2, $v0, -29184 //这里拿到偏移0x8E00的地址
; Data ref 0x000091C0 ... 0x00000000 0x00000000 0x00000000 0x00000000
0x0000684C: 0x246791C0 '..g$' - addiu $a3, $v1, -28224 //这里拿到偏移0x91C0的地址
0x00006850: 0x00002821 '!(..' - move $a1, $zr
loc_00006854: ; Refs: 0x00006868 //这也是个循环,但是是把偏移0x91C0位置生成的新key拷贝到0x8E00处替换老的key
0x00006854: 0x00A71021 '!...' - addu $v0, $a1, $a3
0x00006858: 0x90440000 '..D.' - lbu $a0, 0($v0)
0x0000685C: 0x00A61821 '!...' - addu $v1, $a1, $a2
0x00006860: 0x24A50001 '...$' - addiu $a1, $a1, 1
0x00006864: 0x2CA20004 '...,' - sltiu $v0, $a1, 4
0x00006868: 0x1440FFFA '..@.' - bnez $v0, loc_00006854
0x0000686C: 0xA0640000 '..d.' - sb $a0, 0($v1)
好了,我们已经彻底弄明白了整个流程,接着只需要一个很简单的功能函数就可以得到游戏的key了。整个逻辑就是这样,代码我就不放出来了。
最后顺便说一下sceResmgr_8E6C62C8里面的其他功能,其实这个key的计算是kirk加密算法,这个是早先时候被某只破解小组搞定的,但是在开源的一些kirk-engine项目里面我并没有找到kirk key_type为0×56的密钥,至于这个key相信也可以在psp的内核破解中找到,但是工作量是很大的,如果找到了就可以编写出在脱离psp计算密钥的方法,可能PSP破解圈里面的一些前辈已经掌握了,但是并没有流出,好了,到此结束,各位愉快~~
本文揭示了PSP游戏破解的关键步骤,介绍了如何利用opnssmp.bin和mesg_led_0X.prx解密游戏EBOOT.BIN。L大的破解方法涉及通过opnssmp.bin中的数据调用sceMesgLed模组,使用特定函数sceResmgr_8E6C62C8进行密钥计算,该过程与kirk加密算法相关。虽然核心部分的详细代码未提供,但文章提供了基本的破解逻辑和流程。
547





