Updater: Difference between revisions
CelesteBlue (talk | contribs) |
|||
Line 235: | Line 235: | ||
== SceSblSsUpdateMgr == | == SceSblSsUpdateMgr == | ||
== Types == | |||
<source lang="C"> | |||
typedef char SceUpdateMode; | |||
typedef struct { | |||
int unk_0x00; | |||
int sysver; | |||
int unk_0x08; | |||
int unk_0x0C; | |||
} SceSblUsSpkgInfo; | |||
</source> | |||
=== sceSblUsGetUpdateModeForUser === | === sceSblUsGetUpdateModeForUser === | ||
Line 244: | Line 259: | ||
Temp name was sceSblSsUpdateMgrGetBootMode. | Temp name was sceSblSsUpdateMgrGetBootMode. | ||
<source lang="C">int sceSblUsGetUpdateModeForUser(SceUpdateMode *mode);</source> | |||
=== sceSblUsSetUpdateModeForUser === | === sceSblUsSetUpdateModeForUser === | ||
Line 253: | Line 270: | ||
Temp name was sceSblSsUpdateMgrSetBootMode. | Temp name was sceSblSsUpdateMgrSetBootMode. | ||
<source lang="C">int sceSblUsSetUpdateModeForUser(SceUpdateMode mode);</source> | |||
=== sceSblUsPowerControlForUser === | === sceSblUsPowerControlForUser === | ||
Line 262: | Line 281: | ||
Temp name was sceSblSsUpdateMgrSendCommand. | Temp name was sceSblSsUpdateMgrSendCommand. | ||
<source lang="C">int sceSblUsPowerControlForUser(int arg1, int arg2);</source> | |||
=== sceSblUsGetSpkgInfoForUser === | === sceSblUsGetSpkgInfoForUser === | ||
Line 271: | Line 292: | ||
Temp name was sceSblSsUpdateMgrGetSpkgInfo. | Temp name was sceSblSsUpdateMgrGetSpkgInfo. | ||
<source lang="C">int sceSblUsGetSpkgInfoForUser(int arg1, SceSblUsSpkgInfo *arg2);</source> | |||
=== sceSblUsVerifyPupForUser === | === sceSblUsVerifyPupForUser === | ||
Line 278: | Line 301: | ||
| 0.940-3.60 || 0x6F5EDBF4 | | 0.940-3.60 || 0x6F5EDBF4 | ||
|} | |} | ||
path max len : 0x3FF, path len >= 0x400 : error | |||
<source lang="C">int sceSblUsVerifyPupForUser(const char *path);</source> | |||
=== sceSblUsVerifyPupAdditionalSignForUser === | === sceSblUsVerifyPupAdditionalSignForUser === | ||
Line 285: | Line 312: | ||
| 3.60 || 0xB19366CB | | 3.60 || 0xB19366CB | ||
|} | |} | ||
path max len : 0x3FF, path len >= 0x400 : error | |||
<source lang="C">int sceSblUsVerifyPupAdditionalSignForUser(const char *path);</source> | |||
=== sceSblUsVerifyPupHeaderForUser === | === sceSblUsVerifyPupHeaderForUser === | ||
Line 292: | Line 323: | ||
| 0.940-3.60 || 0x9BE17A06 | | 0.940-3.60 || 0x9BE17A06 | ||
|} | |} | ||
path max len : 0x3FF, path len >= 0x400 : error | |||
<source lang="C">int sceSblUsVerifyPupHeaderForUser(const char *path);</source> | |||
=== sceSblUsVerifyPupSegmentForUser === | === sceSblUsVerifyPupSegmentForUser === | ||
Line 299: | Line 334: | ||
| 0.940-3.60 || 0xD47FD33E | | 0.940-3.60 || 0xD47FD33E | ||
|} | |} | ||
path max len : 0x3FF, path len >= 0x400 : error | |||
Since arg2 is internally rewritten to 0x4000001, it is set to 0. | |||
<source lang="C">int sceSblUsVerifyPupSegmentForUser(const char *path, void *arg2, int seg_id, int arg4);</source> | |||
=== sceSblUsVerifyPupSegmentByIdForUser === | === sceSblUsVerifyPupSegmentByIdForUser === | ||
Line 306: | Line 346: | ||
| 0.940-3.60 || 0x95FC1A0A | | 0.940-3.60 || 0x95FC1A0A | ||
|} | |} | ||
path max len : 0x3FF, path len >= 0x400 : error | |||
Since arg2 is internally rewritten to 0x4000001, it is set to 0. | |||
<source lang="C">int sceSblUsVerifyPupSegmentByIdForUser(const char *path, void *arg2, int seg_id, int arg4);</source> | |||
=== sceSblUsVerifyPupWatermarkForUser === | === sceSblUsVerifyPupWatermarkForUser === | ||
Line 313: | Line 358: | ||
| 0.940-3.60 || 0xC6CDEB8D | | 0.940-3.60 || 0xC6CDEB8D | ||
|} | |} | ||
path max len : 0x3FF, path len >= 0x400 : error | |||
<source lang="C">int sceSblUsVerifyPupWatermarkForUser(const char *path);</source> | |||
=== sceSblUsUpdateSpackageForUser === | === sceSblUsUpdateSpackageForUser === | ||
Line 320: | Line 369: | ||
| 0.990-3.60 || 0x6E8DDAC4 | | 0.990-3.60 || 0x6E8DDAC4 | ||
|} | |} | ||
<source lang="C">int sceSblUsUpdateSpackageForUser(int arg1, void *arg2, void *arg3);</source> | |||
=== sceSblUsInspectSpackageForUser === | === sceSblUsInspectSpackageForUser === | ||
Line 327: | Line 378: | ||
| 0.990-3.60 || 0x1A39F6EE | | 0.990-3.60 || 0x1A39F6EE | ||
|} | |} | ||
<source lang="C">int sceSblUsInspectSpackageForUser(int arg1, void *arg2, void *arg3);</source> | |||
=== sceSblUsExtractSpackageForUser === | === sceSblUsExtractSpackageForUser === | ||
Line 334: | Line 387: | ||
| 0.990-3.60 || 0xC1792A1C | | 0.990-3.60 || 0xC1792A1C | ||
|} | |} | ||
<source lang="C">int sceSblUsExtractSpackageForUser(int arg1, void *arg2, void *arg3);</source> | |||
=== sceSblUsGetExtractSpackageForUser === | === sceSblUsGetExtractSpackageForUser === | ||
Line 341: | Line 396: | ||
| 0.990-3.60 || 0x4897AD56 | | 0.990-3.60 || 0x4897AD56 | ||
|} | |} | ||
<source lang="C">int sceSblUsGetExtractSpackageForUser(int arg1, void *arg2, void *arg3);</source> | |||
=== sceSblUsAllocateBufferForUser === | === sceSblUsAllocateBufferForUser === | ||
Line 348: | Line 405: | ||
| 0.990-3.60 || 0x4C06F41C | | 0.990-3.60 || 0x4C06F41C | ||
|} | |} | ||
<source lang="C">int sceSblUsAllocateBufferForUser(int arg1, void *arg2);</source> | |||
=== sceSblUsReleaseBufferForUser === | === sceSblUsReleaseBufferForUser === | ||
Line 355: | Line 414: | ||
| 0.990-3.60 || 0xBD677F5A | | 0.990-3.60 || 0xBD677F5A | ||
|} | |} | ||
<source lang="C">int sceSblUsReleaseBufferForUser(int arg1);</source> | |||
=== sceSblUsGetStatusForUser === | === sceSblUsGetStatusForUser === | ||
Line 362: | Line 423: | ||
| 0.990-3.60 || 0xF403143E | | 0.990-3.60 || 0xF403143E | ||
|} | |} | ||
<source lang="C">int sceSblUsGetStatusForUser(int arg1, int arg2, void *arg3);</source> | |||
=== sceSblUsCheckSystemIntegrityForUser === | === sceSblUsCheckSystemIntegrityForUser === | ||
Line 369: | Line 432: | ||
| 0.990-3.60 || 0xBED8DFC7 | | 0.990-3.60 || 0xBED8DFC7 | ||
|} | |} | ||
Do nothing | |||
<source lang="C"> | |||
int SceSblSsUpdateMgr_BED8DFC7(void) | |||
{ | |||
int state; | |||
if (ksceSblACIsSystemProgram(0) == 0) | |||
return 0x800F022C; | |||
ENTER_SYSCALL(state); | |||
EXIT_SYSCALL(state); | |||
return 0; | |||
} | |||
</source> | |||
<source lang="C">int sceSblUsCheckSystemIntegrityForUser(void);</source> | |||
=== sceSblUsGetApplicableVersionForUser === | === sceSblUsGetApplicableVersionForUser === | ||
Line 376: | Line 457: | ||
| 0.990-3.60 || 0x3ADD4B7A | | 0.990-3.60 || 0x3ADD4B7A | ||
|} | |} | ||
<source lang="C">int sceSblUsGetApplicableVersionForUser(int arg1, void *arg2);</source> | |||
=== SceSblSsUpdateMgr_9FC8E905 === | |||
{| class="wikitable" | |||
! Version !! NID | |||
|- | |||
| 0.990-3.60 || 0x9FC8E905 | |||
|} | |||
<source lang="C">int SceSblSsUpdateMgr_9FC8E905(int arg1, int arg2, const void *src, int len);</source> | |||
=== SceSblSsUpdateMgr_D0CB50AC === | |||
{| class="wikitable" | |||
! Version !! NID | |||
|- | |||
| 3.60 || 0xD0CB50AC | |||
|} | |||
<source lang="C">int SceSblSsUpdateMgr_D0CB50AC(int arg1, int arg2);</source> | |||
=== SceSblSsUpdateMgr_2A02DCFB === | |||
{| class="wikitable" | |||
! Version !! NID | |||
|- | |||
| 3.60 || 0x2A02DCFB | |||
|} | |||
<source lang="C">int SceSblSsUpdateMgr_2A02DCFB(int arg1, const void *src, int len);</source> | |||
=== SceSblSsUpdateMgr_157AD4AD === | |||
{| class="wikitable" | |||
! Version !! NID | |||
|- | |||
| 3.60 || 0x157AD4AD | |||
|} | |||
<source lang="C">int SceSblSsUpdateMgr_157AD4AD(const void *src, int len, int arg3);</source> | |||
=== SceSblSsUpdateMgr_FE930747 === | |||
{| class="wikitable" | |||
! Version !! NID | |||
|- | |||
| 3.60 || 0xFE930747 | |||
|} | |||
<source lang="C">int SceSblSsUpdateMgr_FE930747(const void *src1, int len1, const void *src2, int len2);</source> | |||
=== SceSblSsUpdateMgr_92A8002B === | |||
{| class="wikitable" | |||
! Version !! NID | |||
|- | |||
| 3.60 || 0x92A8002B | |||
|} | |||
<source lang="C">int SceSblSsUpdateMgr_92A8002B(const void *src1, int len1, const void *src2, int len2);</source> | |||
= Update Process = | = Update Process = |
Revision as of 02:49, 22 July 2019
Various components in user, kernel, and secure kernel work together to update the system. All the relevant libraries are documented in this one page because they work close together.
SceCuiSetUpper
Module
This is a user application that is found inside the update PUP. It has not been seen used outside of development units but is included in retail updates. It does not change often between firmware updater versions.
Known NIDs
Version | Name | World | Privilege | NID |
---|---|---|---|---|
2.12 | SceCuiSetUpper | Non-secure | User | 0x8802DAE9 |
Libraries
This module does not export any library.
ScePsp2Swu
Module
This is a user application that is found inside the update PUP, and extracted to ud0:UPDATE/.
Known NIDs
Version | Name | World | Privilege | NID |
---|---|---|---|---|
1.69 | ScePsp2Swu | Non-secure | User | 0xF8D9C101 |
Libraries
This module does not export any library.
SceSblUpdateMgr
Module
This module exists only in the non-secure kernel. The SELF can be found in bootfs:update_mgr.skprx
.
Known NIDs
Version | Name | World | Privilege | NID |
---|---|---|---|---|
1.69 | SceSblUpdateMgr | Non-secure | Kernel | 0xBA91FE90 |
3.60 | SceSblUpdateMgr | Non-secure | Kernel | 0x528F6BF5 |
Libraries
This module exports libraries to both kernel and user.
Known NIDs
Version | Name | World | Visibility | NID |
---|---|---|---|---|
1.69 | SceSblUpdateMgrForKernel | Non-secure | Kernel | 0xC4466E48 |
1.69 | SceSblUpdateMgrForDriver | Non-secure | Kernel | 0x0E04CD3D |
1.69-3.60 | SceSblSsUpdateMgr | Non-secure | User | 0x31406C49 |
0.990 | SceSblSsUpdateMgrAdditional | Non-secure | User | 0xBDD7A86F |
SceSblUpdateMgrForDriver
sceSblUsVerifyPupForDriver
Version | NID |
---|---|
0.940 | 0xD593D613 |
sceSblUsVerifyPupHeaderForDriver
Version | NID |
---|---|
0.940 | 0xBAFCA304 |
sceSblUsVerifyPupSegmentForDriver
Version | NID |
---|---|
0.940 | 0xF43372C4 |
sceSblUsVerifyPupSegmentByIdForDriver
Version | NID |
---|---|
0.940 | 0xB4AC7684 |
sceSblUsVerifyPupWatermarkForDriver
Version | NID |
---|---|
0.940 | 0xDD90C4B9 |
sceSblUsUpdateSpackageForDriver
Version | NID |
---|---|
0.990 | 0xF41138F1 |
sceSblUsInspectSpackageForDriver
Version | NID |
---|---|
0.990 | 0xE7F5A4C0 |
sceSblUsExtractSpackageForDriver
Version | NID |
---|---|
0.990 | 0x87AC6E73 |
sceSblUsAllocateBufferForDriver
Version | NID |
---|---|
0.990 | 0x2D69BFDC |
sceSblUsReleaseBufferForDriver
Version | NID |
---|---|
0.990 | 0x45B91736 |
sceSblUsGetStatusForDriver
Version | NID |
---|---|
0.990 | 0x99D57D18 |
sceSblUsGetSpkgInfoForDriver
Version | NID |
---|---|
0.990 | 0xAE7D3BF5 |
sceSblUsGetUpdateModeForDriver
Version | NID |
---|---|
0.990 | 0xEEC71CCC |
sceSblUsSetUpdateModeForDriver
Version | NID |
---|---|
0.990 | 0x266820E9 |
SceSblUpdateMgrForDriver_return_0
Version | NID |
---|---|
0.990 | 0x6ACEF44D |
sceSblUsPowerControlForDriver
Version | NID |
---|---|
0.990 | 0x64ECC81A |
sceSblUsGetApplicableVersionForDriver
Version | NID |
---|---|
0.990 | 0x7CC73839 |
SceSblSsUpdateMgrAdditional
sceSblUsInformUpdateStartedForUser
Version | NID |
---|---|
0.990 | 0x1E40A14E |
sceSblUsInformUpdateOngoingForUser
Version | NID |
---|---|
0.990 | 0x3A917CCE |
sceSblUsInformUpdateFinishedForUser
Version | NID |
---|---|
0.990 | 0x4734B987 |
sceSblUsSetSwInfoIntForUser
Version | NID |
---|---|
0.990 | 0xA870D285 |
sceSblUsSetSwInfoStrForUser
Version | NID |
---|---|
0.990 | 0x8C7255C8 |
sceSblUsSetSwInfoBinForUser
Version | NID |
---|---|
0.990 | 0xF157E34A |
SceSblSsUpdateMgr
Types
typedef char SceUpdateMode; typedef struct { int unk_0x00; int sysver; int unk_0x08; int unk_0x0C; } SceSblUsSpkgInfo;
sceSblUsGetUpdateModeForUser
Version | NID |
---|---|
0.990-3.60 | 0x8E834565 |
Temp name was sceSblSsUpdateMgrGetBootMode.
int sceSblUsGetUpdateModeForUser(SceUpdateMode *mode);
sceSblUsSetUpdateModeForUser
Version | NID |
---|---|
0.990-3.60 | 0xC725E3F0 |
Temp name was sceSblSsUpdateMgrSetBootMode.
int sceSblUsSetUpdateModeForUser(SceUpdateMode mode);
sceSblUsPowerControlForUser
Version | NID |
---|---|
0.990-3.60 | 0x1825D954 |
Temp name was sceSblSsUpdateMgrSendCommand.
int sceSblUsPowerControlForUser(int arg1, int arg2);
sceSblUsGetSpkgInfoForUser
Version | NID |
---|---|
0.990-3.60 | 0x8E3EC2E1 |
Temp name was sceSblSsUpdateMgrGetSpkgInfo.
int sceSblUsGetSpkgInfoForUser(int arg1, SceSblUsSpkgInfo *arg2);
sceSblUsVerifyPupForUser
Version | NID |
---|---|
0.940-3.60 | 0x6F5EDBF4 |
path max len : 0x3FF, path len >= 0x400 : error
int sceSblUsVerifyPupForUser(const char *path);
sceSblUsVerifyPupAdditionalSignForUser
Version | NID |
---|---|
3.60 | 0xB19366CB |
path max len : 0x3FF, path len >= 0x400 : error
int sceSblUsVerifyPupAdditionalSignForUser(const char *path);
sceSblUsVerifyPupHeaderForUser
Version | NID |
---|---|
0.940-3.60 | 0x9BE17A06 |
path max len : 0x3FF, path len >= 0x400 : error
int sceSblUsVerifyPupHeaderForUser(const char *path);
sceSblUsVerifyPupSegmentForUser
Version | NID |
---|---|
0.940-3.60 | 0xD47FD33E |
path max len : 0x3FF, path len >= 0x400 : error Since arg2 is internally rewritten to 0x4000001, it is set to 0.
int sceSblUsVerifyPupSegmentForUser(const char *path, void *arg2, int seg_id, int arg4);
sceSblUsVerifyPupSegmentByIdForUser
Version | NID |
---|---|
0.940-3.60 | 0x95FC1A0A |
path max len : 0x3FF, path len >= 0x400 : error Since arg2 is internally rewritten to 0x4000001, it is set to 0.
int sceSblUsVerifyPupSegmentByIdForUser(const char *path, void *arg2, int seg_id, int arg4);
sceSblUsVerifyPupWatermarkForUser
Version | NID |
---|---|
0.940-3.60 | 0xC6CDEB8D |
path max len : 0x3FF, path len >= 0x400 : error
int sceSblUsVerifyPupWatermarkForUser(const char *path);
sceSblUsUpdateSpackageForUser
Version | NID |
---|---|
0.990-3.60 | 0x6E8DDAC4 |
int sceSblUsUpdateSpackageForUser(int arg1, void *arg2, void *arg3);
sceSblUsInspectSpackageForUser
Version | NID |
---|---|
0.990-3.60 | 0x1A39F6EE |
int sceSblUsInspectSpackageForUser(int arg1, void *arg2, void *arg3);
sceSblUsExtractSpackageForUser
Version | NID |
---|---|
0.990-3.60 | 0xC1792A1C |
int sceSblUsExtractSpackageForUser(int arg1, void *arg2, void *arg3);
sceSblUsGetExtractSpackageForUser
Version | NID |
---|---|
0.990-3.60 | 0x4897AD56 |
int sceSblUsGetExtractSpackageForUser(int arg1, void *arg2, void *arg3);
sceSblUsAllocateBufferForUser
Version | NID |
---|---|
0.990-3.60 | 0x4C06F41C |
int sceSblUsAllocateBufferForUser(int arg1, void *arg2);
sceSblUsReleaseBufferForUser
Version | NID |
---|---|
0.990-3.60 | 0xBD677F5A |
int sceSblUsReleaseBufferForUser(int arg1);
sceSblUsGetStatusForUser
Version | NID |
---|---|
0.990-3.60 | 0xF403143E |
int sceSblUsGetStatusForUser(int arg1, int arg2, void *arg3);
sceSblUsCheckSystemIntegrityForUser
Version | NID |
---|---|
0.990-3.60 | 0xBED8DFC7 |
Do nothing
int SceSblSsUpdateMgr_BED8DFC7(void) { int state; if (ksceSblACIsSystemProgram(0) == 0) return 0x800F022C; ENTER_SYSCALL(state); EXIT_SYSCALL(state); return 0; }
int sceSblUsCheckSystemIntegrityForUser(void);
sceSblUsGetApplicableVersionForUser
Version | NID |
---|---|
0.990-3.60 | 0x3ADD4B7A |
int sceSblUsGetApplicableVersionForUser(int arg1, void *arg2);
SceSblSsUpdateMgr_9FC8E905
Version | NID |
---|---|
0.990-3.60 | 0x9FC8E905 |
int SceSblSsUpdateMgr_9FC8E905(int arg1, int arg2, const void *src, int len);
SceSblSsUpdateMgr_D0CB50AC
Version | NID |
---|---|
3.60 | 0xD0CB50AC |
int SceSblSsUpdateMgr_D0CB50AC(int arg1, int arg2);
SceSblSsUpdateMgr_2A02DCFB
Version | NID |
---|---|
3.60 | 0x2A02DCFB |
int SceSblSsUpdateMgr_2A02DCFB(int arg1, const void *src, int len);
SceSblSsUpdateMgr_157AD4AD
Version | NID |
---|---|
3.60 | 0x157AD4AD |
int SceSblSsUpdateMgr_157AD4AD(const void *src, int len, int arg3);
SceSblSsUpdateMgr_FE930747
Version | NID |
---|---|
3.60 | 0xFE930747 |
int SceSblSsUpdateMgr_FE930747(const void *src1, int len1, const void *src2, int len2);
SceSblSsUpdateMgr_92A8002B
Version | NID |
---|---|
3.60 | 0x92A8002B |
int SceSblSsUpdateMgr_92A8002B(const void *src1, int len1, const void *src2, int len2);
Update Process
The Vita updater is composed of various parts.
Initiator
The first part is the initiator of the update. The responsibility of the initiator is to copy the update file (PSP2UPDAT.PUP
) to the ud0
partition and extract psp2swu.self
from the update file to ud0:PSP2UPDATE/psp2swu.self
. Then it signals the syscon to start in update mode, where psp2swu.self
is loaded instead of the usual shell.
The initiator that most people use is likely the update option in SceSettings. Another is the update option in SceSafeMode. Another option is SceCuiSetUpper
, which is extracted from the update PUP. SceCuiSetUpper
is likely used in development units as it can load the update data from host0
, which only exists on development units. This file, however, can be found in retail update packages. SceCuiSetUpper
also sets a flag to start updater in CUI mode.
ScePsp2Swu
Once the system restarts into update mode, the updater runs. Normally, it runs in GUI mode which is the green screen with the progress bar. If a flag is set by the initiator, the updater will run in CUI mode, which is a text interface that provides more verbose information about the update process.
The updater first makes calls to SceSblSsUpdateMgr
to verify the PUP header. For more information, check out PUP. Next, the updater will spawn a thread that calls into the kernel to decrypt, verify, and flash each package file according to the information found in the package header. For more information, check out PUP#Packages.
SceSblSsUpdateMgr
This is a kernel module that actually does the work and performs the update. It verifies the PUP headers as well as the package headers and then flashes the decrypted images directly to the eMMC with block writes.
Update Package Decryption Code
The following code snippet will decrypt and update a directory of package files on 1.69 (the kernel functions called are specific to 1.69 NIDs). It is an attempted reproduction of the main code in ScePsp2Swu
. The requirements are that you patch the application to be running in Vsh context (or specifically patch the Authority ID to allow access to the kernel update functions). You also need an ability to read and write to the kernel from within your application. Finally, the updater will always attempt to flash the decrypted contents. If the flash failed because of model checks or whatever, it will return an error but the data will still be successfully decrypted and outputted. If it succeeds, note that you have now updated your PSVita.
int start_decryption1(int code1, unsigned char *buf, int buflen, int code2, int *phandle) { int argst[11]; int res; memset(argst, 0, 0x2C); argst[0]=0x2C; argst[1]=code1; argst[2]=(int)buf; argst[3]=buflen; argst[4]=code2; sceClibPrintf("Calling type 1 decryption with code1 = 0x%x buf = 0x%x buflen = 0x%x code2 = 0x%x \n", code1, (int)buf, buflen, code2); res=callKernelFunction(sceSblUsUpdateSpackageForUser, code1, argst, phandle, 0); return res; } int start_decryption2(int code1, unsigned char *buf, int buflen, int code2, int *phandle) { int argst[11]; int res; memset(argst, 0, 0x2C); argst[0]=0x2C; argst[1]=code1; argst[2]=(int)buf; argst[3]=buflen; argst[4]=code2; sceClibPrintf("Calling type 2 decryption with code1 = 0x%x buf = 0x%x buflen = 0x%x code2 = 0x%x\n", code1, (int)buf, buflen, code2); res=callKernelFunction(sceSblUsInspectSpackageForUser, code1, argst, phandle, 0); return res; } int start_decryption3(int code1, unsigned char *buf, int buflen, int code2, int *phandle) { int argst[11]; int res; memset(argst, 0, 0x2C); argst[0]=0x2C; argst[1]=code1; argst[2]=(int)buf; argst[3]=buflen; argst[4]=code2; sceClibPrintf("Calling type 3 decryption with code1 = 0x%x buf = 0x%x buflen = 0x%x code2 = 0x%x\n", code1, (int)buf, buflen, code2); res=callKernelFunction(sceSblUsExtractSpackageForUser, code1, argst, phandle, 0); return res; } int check_decryption_status(int code, int handle, int *out1, int *out2, int *out3, int *out4) { int argst[11]; int res; memset(argst, 0, 0x2C); argst[0]=0x2C; argst[7]=(int)out1; argst[8]=(int)out2; argst[9]=(int)out3; argst[10]=(int)out4; sceClibPrintf("Calling status with code = 0x%x handle = 0x%x\n", code, handle); res=callKernelFunction(sceSblUsGetStatusForUser, code, handle, argst, 0); return res; } int get_final_size(unsigned char *buf) { int *poffs; int *psize; poffs = (int *) (buf+0x10); psize = (int *) (buf+(*poffs)+0x20); return *psize; } int get_type(unsigned char *buf) { int *poffs; int *psize; if ( *(int *)buf == 0x00454353 ) // "SCE\0" { poffs = (int *) (buf+0x10); psize = (int *) (buf+(*poffs)+4); return *psize; } else { return -1; } } unsigned char *get_data_offset(unsigned char *buf) { int *poffs; poffs = (int *) (buf+0x10); return (buf+(*poffs)+0x80); } int complete_decryption(int code, int handle, unsigned char *buf, int maxlen) { int argst[11]; int res; unsigned char *payload; int size; memset(argst, 0, 0x2C); argst[0]=0x2C; argst[1]=code; argst[5]=(int)buf; argst[6]=maxlen; sceClibPrintf("Calling complete decryption with code = 0x%x handle = 0x%x buf = 0x%x maxlen = 0x%x\n", code, handle, (int)buf, maxlen); res=callKernelFunction(sceSblUsGetExtractSpackageForUser, code, handle, argst, 0); return res; } int do_decrypt_file(const char *inpath, const char *outpath, const char *errpath, unsigned int size) { int fd; int res; int memid; int read; int maxlen = 0x810000; int argst[0x2C/4]; int id; int type; int code; unsigned char *src, *outbuf; unsigned int handle, p1, p2, p3, p4; res=callKernelFunction(sceSblUsAllocateBufferForUser, size, &src, 0, 0); sceClibPrintf("Allocation returned 0x%x addr 0x%x\n", res, (int)src); if(res) { sceClibPrintf("Cannot allocate memory. (size 0x%x) fail.\n", size); return 0; } //sceClibPrintf("Loading Firmware pkg file from host0:"); fd= sceIoOpen(inpath, 1, 0); read = 0; while ((read = sceIoRead(fd, src, size - read)) > 0); sceIoClose(fd); code = get_type(src); switch (code) { case -1: sceClibPrintf("Not an encrypted file.\n"); goto ERROR; case 3: case 4: case 0x1B: type = 3; res=start_decryption3(code, src, size, 9, &handle); break; case 0: case 2: case 5: case 6: case 7: case 0xE: case 0x1A: sceClibPrintf("Warning, code %x is unsupported!\n", code); default: type = 2; res=start_decryption2(code, src, size, 9, &handle); break; } if(res) { sceClibPrintf("start_decryption failed. (0x%x)\n", res); goto ERROR; } for(;;) { res=check_decryption_status(type, handle, &p1, &p2, &p3, &p4); if(res) { sceClibPrintf("check_decryption_status failed. (0x%x)\n", res); goto ERROR; } if(p3 == 5) { break; } else { sceKernelDelayThread(0x7A120); } } sceClibPrintf("p1= 0x%x p2 = 0x%x p3 = 0x%x p4 = 0x%x\n", p1, p2, p3, p4); if(p2 == 0) { sceClibPrintf("Starting to write %s\n", outpath); fd = sceIoOpen(outpath, 0x603, 0x186); read = get_final_size(src); while ((read -= sceIoWrite(fd, get_data_offset(src), read)) > 0); sceIoClose(fd); } else { sceClibPrintf("Error decrypting. Writing results to %s\n", errpath); fd= sceIoOpen(errpath, 0x603, 0x186); read = get_final_size(src); while ((read -= sceIoWrite(fd, get_data_offset(src), read)) > 0); sceIoClose(fd); goto ERROR; } res=complete_decryption(type, handle, src, maxlen); if(res) { sceClibPrintf("complete_decryption failed. (0x%x)\n", res); goto ERROR; } res=callKernelFunction(sceSblUsReleaseBufferForUser, src, 0, 0, 0); return 1; ERROR: res=callKernelFunction(sceSblUsReleaseBufferForUser, src, 0, 0, 0); return 0; } void do_decrypt_dir(const char *path) { int fd; SceIoDirent dir; char input[256]; char output[256]; char errput[256]; if ((fd = sceIoDopen(path)) < 0) { sceClibPrintf("Error opening pkg dir.\n"); return; } while (sceIoDread(fd, &dir) > 0) { sprintf(input, "%s/%s", path, dir.d_name); sprintf(output, "%s/%s.dec", path, dir.d_name); sprintf(errput, "%s/%s.err", path, dir.d_name); sceClibPrintf("Decrypting %s (size 0x%x)\n", input, (unsigned int)dir.d_stat.st_size); if (do_decrypt_file(input, output, errput, (unsigned int)dir.d_stat.st_size)) sceClibPrintf("Decrypted to %s\n", output); else sceClibPrintf("Failed to decrypt %s\n", dir.d_name); } sceIoDclose(fd); }
Bootloader
There's evidence that the bootloaders are re-encrypted with probably per-console keys during the update process. second_loader.enp
and second_loader.enc
are transformed into second_loader.enp_
and second_loader.enp
respectively by F00D before flashing (and the same thing is done to secure_kernel
).
Some useful notes
sceSblUsUpdateSpackageForUser does the bulk of the work decrypting and flashing all the update parts. There appears to be two ways to skip the version checks (but not revokion checks).
First way is to patch the imported function
SceQafMgrForDriver_8C423C18(void);
to return 1. Alternatively, patch Sysroot offset 0x2C+3 and set bit 0x2. This will bypass ALL version checks, including the peripherals which might be dangerous.
Update: don't do this, it does brick as expected.
Second way is to patch
SceVshBridge
export of vshSblAimgrIsCEX
(takes no arguments) to return 0. Alternatively patch ScePsp2Swu
's import of that function.
Update: this doesn't work because the export is used by other functions and fails earlier checks. This flag is set by psp2swu.self to indicate bypassing of version checks on the bootloader and system partitions. All other components will be updated if at higher version. This is what devkits do by default. You can also patch the flags directly. In sceSblUsUpdateSpackageForUser
, sceSblUsInspectSpackageForUser
, and sceSblUsExtractSpackageForUser
(in order: flash, dry run, decrypt only) you can patch the flags argument directly and set 0x8
to indicate skipping version check on bootloader and system partitions. The flags argument found in R1 (second argument) as a user memory pointer offset 0x10.
Auth id for psp2swu.self is either 2800800000000002
or 2800800000000003
.