ADVERTISEMENT
本系列文章的原文作者Acid_Snake在介紹PSP破解時,相當用心地了挑選了2個漏洞的實例,雖然這部分的文章比較艱澀,但是筆者還是在這邊把第二個案例介紹一下。下篇連載主題將是Wii的破解,內容就會比較有趣啦。
前情提要:
忘記檢查參數
第二個要說明的PSP破解案例,是由Total_Noob公布的6.20版韌體核心漏洞,davee在這裡http://lolhax.org/2010/12/23/arcanum寫到了該漏洞的深入說明。這個漏洞位於sceUtility_private_764F5A3C,我將程式有趣的部分節錄於下。
sceUtility_private_764F5A3C:
...
0x00002800: 0x0C002229 ')"..' - jal scePower_driver_1A41E0ED
0x00002804: 0x001BDAC0 '....' - sll $k1, $k1, 11
...
這段程式會將k1向左推移11個bit,這是Sony用來過濾掉核心記憶體位置中不想要的指標,核心記憶體位置永遠會從0×8(也就是2進位的1000)開始。當我們從使用者模式中呼叫核心函數,去中斷記憶體管理,將k1設為0×100000,然後當該函數被向左推移了11個bit之後,它就會變成0×80000000,如果你將1個指標傳入核心記憶體位置,它看起來就會像0x8XXXXXXX。
ADVERTISEMENT
接下來如果你把這個指標和k1的值做AND的邏輯運算,得到的結果將會是0×80000000,然而當該指標的開頭不是8,或是數字更大,進行邏輯運算得到的結果就會是0。
PSP會檢查這個運算結果,並透過two’s complement(以2進位表現其正負號的方式)檢驗其正負值,當所有開頭為0的數值為正數,開頭為1則為負數。如果我們輸入1個核心記憶體位置指標,然後得到的數質為負數,核心就會回傳錯誤訊息。關鍵來了,Sony必需檢查每一個回傳訊息,然而他們偶爾會忘記要這樣做。
在這個案例中,Sony忘了某些檢查工作,然而當我們在k1推移後馬上檢查該函數的話,我們就會看到下面的樣子。
ADVERTISEMENT
scePowerRegisterCallback:
...
0x00000800: 0x001BDAC0 '....' - sll $k1, $k1, 11
...
這個函數將會重覆進行1次k1推移,如果先前k1的值是0×80000000的話,第二次推移後會變成0×40000000000,然而PSP是台32bit的機器,k1的暫存空間也是32bit,所以它無法處理這個數值,該數值就會溢出並變成0,所以可以讓所有的檢查都強制通過,最後可以引導至下方的程式片段。
loc_000008D8: ; Refs: 0x000008A4
0x000008D8: 0xAC710000 '..q.' - sw $s1, 0($v1)
0x000008DC: 0x02202021 '! .' - move $a0, $s1
0x000008E0: 0x00008021 '!...' - move $s0, $zr
0x000008E4: 0xAC600004 '..`.' - sw $zr, 4($v1)
0x000008E8: 0x8CB10204 '....' - lw $s1, 516($a1)
0x000008EC: 0xAC60000C '..`.' - sw $zr, 12($v1)
0x000008F0: 0xAC710008 '..q.' - sw $s1, 8($v1)
0x000008F4: 0x8CA50204 '....' - lw $a1, 516($a1)
這段程式會在指標$v1所指向的記憶體位置儲存許多數值,由於我們可以控制這些記憶體位置,所以我們可以隨心所欲覆寫核心記憶體位置。
接下來談談最後一個例子,這是由some1在httpstorage中發現的漏洞。sceHttpStorageOpen這個函數只會檢查其中的參數(arg),不會對k1進行任何檢查,當結果數值不是0或1的時候,函數「應該」要回傳錯誤訊息,還是說「這個函數有這樣做」嗎?
ADVERTISEMENT
我們來看看函數「應該」要回傳錯誤訊息的例子。
loc_0000005C: ; Refs: 0x00000034 0x000000D4
; Data ref 0x000009F0 ... 0xFFFFFFFF 0xFFFFFFFF 0x00000000 0x00000000
0x0000005C: 0x267409F0 '..t&' - addiu $s4, $s3, 2544
0x00000060: 0x02348821 '!.4.' - addu $s1, $s1, $s4
0x00000064: 0x8E240000 '..$.' - lw $a0, 0($s1)
0x00000068: 0x04820005 '....' - bltzl $a0, loc_00000080
0x0000006C: 0x0240D821 '!.@.' - move $k1, $s2
0x00000070: 0x0C0001B3 '....' - jal IoFileMgrForKernel_810C4BC3
0x00000074: 0x2413FFFF '...$' - li $s3, -1
0x00000078: 0xAE330000 '..3.' - sw $s3, 0($s1)
0x0000007C: 0x0240D821 '!.@.' - move $k1, $s2
程式會讀取1個全域的值,並將它加到$s1之中,然後把-1存到該記憶體位置,這個核心漏洞就是修改這個全域的值,讓$s1的結果成為我們想要修改的核心記憶體位置,然後讓VFPU可以把-1(2進位中的0xFFFFFFFF)當做vsync 0xFFFF指令使用。
我不懂如果Sony知道某些參數是他們不希望看到的情況,為何還會寫出這種程式,不過也感謝他們再一次失誤,讓我們有核心漏洞與6.39版韌體的降級程式可以用。Sony真的犯下太多愚蠢失誤,讓我們可以完全取得核心權限,整個kermit_wlan模組也充分問題,Sony沒有對任何我們輸入的arg、k1進行檢查,這就像他們把整個PSP部門的工作人員炒魷魚,留下的聘顧人員對PSP系統安全一無所知。在這邊我只講到PSP的破解部分,至於深入PS Vita的部分就先跳過。
ADVERTISEMENT
▲感謝Sony一直在各版本韌體提供破解漏洞,讓玩家可以執行各種自製程式。圖中為修改佈景主題的CXMB。
▲玩家也可以使用類似Free Cheat之類的工具程式,修改遊戲金錢或體力等數值。
下集預告:
原文刊載於
感謝原文作者Acid_Snake同意轉載
Original article by Acid_Snake. Translate by konamigood.
延伸閱讀:
ADVERTISEMENT