ADVERTISEMENT
家用主機秘辛系列文章在此要進入尾聲,有點美中不足的是,這系列文章的完結篇主要聚焦在PlayStation Portable無線網路模組的程式碼與其漏洞,文章內容比較枯燥乏味,不過由於筆者需要尊重原始作者Acid_Snake的原文,所以還是在這集進行詳 實介紹。為了給讀者額外的「殺必死」,筆者將會額外撰寫2篇補充文章做為補償,讓我們先耐心地把下面這段故事看完吧。
前情提要:
深入無線網路模組
從上面提到的例子來看,這個安全檢查機制應該是很完善,Sony應該是有辦法能夠封堵越權存取核心記憶體的行為,所以邏輯上我們應該沒辦法碰觸到核心記憶體。但事實上,在kermit_wlan.prx這個無線網路的軟體模組中,Sony並不只是向平常一樣僅忘記1、2個檢查項目,而是完整地忽略了整個安全簡查。
我們來看看開發者frostgater是如何解釋這段出錯的程式碼。
ADVERTISEMENT
; Subroutine sceWlanDrv_lib_51B0BBB8 - Address 0x00004618
; Exported in sceWlanDrv_lib
sceWlanDrv_lib_51B0BBB8:
addiu $sp, $sp, -192
sw $s6, 168($sp)
addiu $s6, $sp, 63
ins $s6, $zr, 0, 6
sw $s5, 164($sp)
move $s5, $a1
li $a1, 64
sw $s3, 156($sp)
move $s3, $a0
move $a0, $s6
sw $s2, 152($sp)
move $s2, $k1
sll $k1, $k1, 11
sw $s4, 160($sp)
move $s4, $a2
sw $s1, 148($sp)
move $s1, $a3
sw $s0, 144($sp)
sw $ra, 176($sp)
jal sceKernelDcacheInvalidateRange
sw $s7, 172($sp)
sra $a1, $s6, 31
addiu $a0, $a1, 2
sll $v0, $a0, 29
lui $v1, 0x0
and $a1, $k1, $s1
or $s0, $s6, $v0
bltz $a1, loc_00004780
lw $s6, 32636($v1)
lui $t0, 0x0
lw $a3, 32480($t0)
bnez $a3, loc_000046D8
li $t1, -1
move $k1, $s2
move $v1, $zr
sw $t1, 0($s1)
以上這段程式做了很多事情,我們可以忽略一些不重要的地方,然後把它總結如下:
int sceWlanDrv_lib_51B0BBB8(u32 a0, u32 a1, u32 a2, u32 a3){
if ( (a3 & k1) < 0)
return ERROR;
some_code_here
*a3 = -1;
return something;
這是很標準的程式碼,我們來看一下a3這個指標,它並不是指向核心記憶體,如果我們執行這段程式碼,就可以將-1這個數值儲存到a3中,如此一來整段程式就會變成:
; Subroutine sceWlanDrv_lib_51B0BBB8 - Address 0x00004618
; Exported in sceWlanDrv_lib
sceWlanDrv_lib_51B0BBB8:
addiu $sp, $sp, -192
sw $s6, 168($sp)
addiu $s6, $sp, 63
ins $s6, $zr, 0, 6
sw $s5, 164($sp)
move $s5, $a1
li $a1, 64
sw $s3, 156($sp)
move $s3, $a0
move $a0, $s6
sw $s2, 152($sp)
move $s2, $k1
sll $k1, $k1, 11
sw $s4, 160($sp)
move $s4, $a2
sw $s1, 148($sp)
move $s1, $a3
sw $s0, 144($sp)
sw $ra, 176($sp)
jal sceKernelDcacheInvalidateRange
sw $s7, 172($sp)
sra $a1, $s6, 31
addiu $a0, $a1, 2
sll $v0, $a0, 29
lui $v1, 0x0
or $s0, $s6, $v0
lw $s6, 32636($v1)
lui $t0, 0x0
lw $a3, 32480($t0)
bnez $a3, loc_000046D8
li $t1, -1
move $k1, $s2
move $v1, $zr
sw $t1, 0($s1)
如此一來,整段程式就不會進行安全檢查,所以可以總結如下:
ADVERTISEMENT
int sceWlanDrv_lib_51B0BBB8(u32 a0, u32 a1, u32 a2, u32 a3){
some_code_here
*a3 = -1;
return something;
這段程式中的涵數,會將-1儲存到由指標a3所指向的記憶體位置,而且這段程式可以從使用者記憶體中執行,也不會受到系統的檢查或控制,所以這個涵數就可以用來將我們想要的數值避開檢查並存入特定位置。
另一方面,由於-1的二補數(2's complement是一種用二進位表示有號數的方法,也是一種將數字的正負號變號的方式)是0xFFFFFFFF,這時它會作為垂直同步的指令,所以可以被當做有效的指令去覆寫其他指令,基本上我們會像下面這樣去覆寫其他指令:
; Subroutine sceKernelLibcTime - Address 0x0000F718
; Exported in UtilsForUser
; Exported in UtilsForKernel
sceKernelLibcTime:
lui $v1, 0x4EB0
lw $a1, 22388($v1)
addiu $sp, $sp, -16
sw $s0, 0($sp)
sll $v1, $k1, 11
move $s0, $k1
sw $ra, 4($sp)
beqz $a1, loc_0000F750
move $a2, $zr
move $k1, $v1
and $v1, $v1, $a0
bgez $v1, loc_0000F764
nop
loc_0000F74C: ; Refs: 0x0000F76C
move $k1, $s0
loc_0000F750: ; Refs: 0x0000F734
lw $ra, 4($sp)
lw $s0, 0($sp)
move $v0, $a2
jr $ra
addiu $sp, $sp, 16
loc_0000F764: ; Refs: 0x0000F744
jalr $a1
nop
; Data ref 0x08003DD3
j loc_0000F74C
move $a2, $v0
ADVERTISEMENT
▲圖為PlayStation Portable無線網路硬體模組,但是在PlayStation Vita中,以軟體模組方式替代,也造成了這個破解漏洞。
疏忽檢查讓核心權限外流
如果我們執行上面的涵數,就可以將我們想要寫入的任何資料覆寫a1指標,所以我們能夠透過將指標寫入0x80000000取得核心權限。
這個手法有趣的地方在於,Sony忘記檢查kermit_wlan漏洞中的10個無線網路功能,讓我們取得10個以上的核心模式漏洞,這些漏洞大多由yosh/wth發現。Sony在發現問題後,當然也將漏洞修補,但是還是讓人覺得他們會犯這種低級錯誤相當好笑,尤其是Sony已經花了好多年的時間在加強PlayStation Portable的安全性,我只好猜想應該是Sony顧用了另外一組人馬來撰寫無線網路模組,沒有根據、隨便猜的。
ADVERTISEMENT
我希望大家都喜歡這篇做為補償Xbox 360的文章,也請大家保持關注,我們還有2台主機的破解介紹以及全系列文章的結論。
(譯者註:由於原文作者介紹Xbox 360的相關文章有些爭議,所以希望筆者跳過那個章節,並以ePSP做為補償。但是部分的文章刊登於2014年1月25日,直到現在原文作者都還沒有發表後續文章,去函詢問也沒有得到正面回應,所以這系列連載將會到此告一段落。
筆者將額外撰寫2篇後記,做為全系列文章的結尾。如果原文作者後續有更新的話,筆者也會再補上中文版文章。)
下集預告:
原文刊載於
感謝原文作者Acid_Snake同意轉載
Original article by Acid_Snake. Translate by konamigood.
延伸閱讀:
ADVERTISEMENT