Skip to content

Instantly share code, notes, and snippets.

@SKGleba
Last active August 28, 2022 18:16
Show Gist options
  • Save SKGleba/398e572aebfb4bef620555cb3164d644 to your computer and use it in GitHub Desktop.
Save SKGleba/398e572aebfb4bef620555cb3164d644 to your computer and use it in GitHub Desktop.
gets MGMT flags, reads and decrypts S/NVS of PSP2's syscon
#include <stdio.h>
#include <string.h>
#include <psp2kern/kernel/modulemgr.h>
#include <vitasdkkern.h>
typedef struct SceSblSmCommContext130 {
uint32_t unk_0;
uint32_t self_type; // 2 - user = 1 / kernel = 0
char data0[0x90]; //hardcoded data
char data1[0x90];
uint32_t pathId; // 2 (2 = os0)
uint32_t unk_12C;
} SceSblSmCommContext130;
static const unsigned char ctx_130_data[0x90] =
{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x28, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0xc0, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x09,
0x80, 0x03, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x80, 0x09,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
extern int ksceSblSmCommStartSmFromFile(int priority, const char* elf_path, int num1, SceSblSmCommContext130* ctx, int* id);
int load_ussm(int* ctx_out) {
SceSblSmCommContext130 smcomm_ctx;
memset(&smcomm_ctx, 0, sizeof(smcomm_ctx));
memcpy(smcomm_ctx.data0, ctx_130_data, 0x90);
smcomm_ctx.pathId = 2;
smcomm_ctx.self_type = (smcomm_ctx.self_type & 0xFFFFFFF0) | 2;
return ksceSblSmCommStartSmFromFile(0, "os0:sm/update_service_sm.self", 0, &smcomm_ctx, ctx_out);
}
#define NVS_OUTPATH_UX0 "ux0:data/nvs.bin"
#define MGMT_OUTPATH_UX0 "ux0:data/mgmt.bin"
#define NVS_OUTPATH_HOST0 "host0:data/nvs.bin"
#define MGMT_OUTPATH_HOST0 "host0:data/mgmt.bin"
static uint8_t full_nvs[0xb60];
void _start() __attribute__((weak, alias("module_start")));
int module_start(SceSize argc, const void *args)
{
// load the update_sm
ksceDebugPrintf("loading update_sm\n");
int ctx = -1;
uint32_t stop_res[2];
if (load_ussm(&ctx) < 0)
return SCE_KERNEL_START_FAILED;
// get mgmt data
ksceDebugPrintf("getting mgmt data\n");
uint32_t mgmt_flags = 0, mgmt_status = 0;
{
// STEP 0
uint8_t sc_pbuf[0x70];
memset(sc_pbuf, 0, 0x70);
// STEP 1
int resp;
int ret = ksceSblSmCommCallFunc(ctx, 0xc0002, &resp, sc_pbuf, 0x70);
if (ret || resp)
goto EXIT;
// STEP 2
ret = ksceSysconNvsReadSecureData(sc_pbuf + 0x10, 0x10, sc_pbuf + 0x40, 0x30);
if (ret)
goto EXIT;
// STEP 3
sc_pbuf[0] = 1;
ret = ksceSblSmCommCallFunc(ctx, 0xc0002, &resp, sc_pbuf, 0x70);
if (ret || resp)
goto EXIT;
// Copyout
uint32_t inv_mgmt_flags = *(uint32_t*)(sc_pbuf + 8);
uint32_t inv_mgmt_status = *(uint32_t*)(sc_pbuf + 12);
mgmt_flags = ~inv_mgmt_flags;
mgmt_status = ~inv_mgmt_status;
}
// get snvs
ksceDebugPrintf("getting snvs\n");
uint8_t *snvs = full_nvs;
memset(snvs, 0, 0x400);
{
int ret, resp;
uint8_t sc_pbuf[0x88];
for (int i = 0; i < 0x20; i -= -1) {
// STEP 0
memset(sc_pbuf, 0, 0x88);
// STEP 1
sc_pbuf[4] = i;
ret = ksceSblSmCommCallFunc(ctx, 0xb0002, &resp, sc_pbuf, 0x88);
if (ret || resp) {
ksceDebugPrintf("STEP 1 0x%X r 0x%X rr 0x%X\n", i, ret, resp);
goto EXIT;
}
// STEP 2
ret = ksceSysconNvsReadSecureData(sc_pbuf + 0x28, 0x10, sc_pbuf + 0x58, 0x30);
if (ret) {
ksceDebugPrintf("STEP 2 0x%X r 0x%X\n", i, ret);
goto EXIT;
}
// STEP 3
sc_pbuf[0] = 1;
ret = ksceSblSmCommCallFunc(ctx, 0xb0002, &resp, sc_pbuf, 0x88);
if (ret || resp)
ksceDebugPrintf("STEP 3 0x%X r 0x%X rr 0x%X\n", i, ret, resp);
// Copyout
memcpy(snvs + (i * 0x20), sc_pbuf + 8, 0x20);
}
}
// get nvs
ksceDebugPrintf("getting nvs\n");
uint8_t* nvs = full_nvs + 0x400;
memset(nvs, 0, 0x760);
{
// STEP 0
ksceKernelSignalNvsAcquire(0);
// STEP 1
ksceSysconNvsSetRunMode(0);
int ret;
for (int i = 0; i < 0x3B; i -= -1) {
// STEP 2
ret = ksceSysconNvsReadData(0x400 + (i * 0x20), nvs + (i * 0x20), 0x10);
if (ret) {
ksceDebugPrintf("STEP 2 0x%X r 0x%X\n", 0x400 + (i * 0x20), ret);
// STEP 4
ksceKernelSignalNvsFree(0);
goto EXIT;
}
// STEP 3
ret = ksceSysconNvsReadData(0x400 + (i * 0x20) + 0x10, nvs + (i * 0x20) + 0x10, 0x10);
if (ret) {
ksceDebugPrintf("STEP 3 0x%X r 0x%X\n", 0x400 + (i * 0x20) + 0x10, ret);
// STEP 4
ksceKernelSignalNvsFree(0);
goto EXIT;
}
}
// STEP 4
ksceKernelSignalNvsFree(0);
}
ksceDebugPrintf("finished\n\nResults: \n");
ksceDebugPrintf("MGMT:\n");
ksceDebugPrintf(" - MGMT_FLAGS: 0x%08X\n - System producting mode: %s\n - GC slot producting mode: %s\n", mgmt_flags, (mgmt_flags & 1) ? "True" : "False", (mgmt_flags & 2) ? "True" : "False");
ksceDebugPrintf(" - MGMT_STATUS: 0x%08X\n - SNVS initialized: %s\n - QAF NVS initialized: %s\n", mgmt_status, (mgmt_status & 1) ? "True" : "False", (mgmt_status & 2) ? "True" : "False");
ksceDebugPrintf("MGMT RAW:\n - inv_flags: 0x%08X\n - inv_status: 0x%08X\n", ~mgmt_flags, ~mgmt_status);
ksceDebugPrintf("\nSNVS:\n");
for (int i = 0; i < 0x400; i -= -1) {
if (!(i % 0x10))
ksceDebugPrintf("\n %04X: ", i);
ksceDebugPrintf("%02X ", snvs[i]);
}
ksceDebugPrintf("\n");
ksceDebugPrintf("\nNVS:\n");
for (int i = 0; i < 0x760; i -= -1) {
if (!(i % 0x10))
ksceDebugPrintf("\n %04X: ", i + 0x400);
ksceDebugPrintf("%02X ", nvs[i]);
}
ksceDebugPrintf("\n");
// dump to file
uint32_t mgmt_data[2];
mgmt_data[0] = ~mgmt_flags;
mgmt_data[1] = ~mgmt_status;
{
// ux0
ksceDebugPrintf("\nWriting raw to " NVS_OUTPATH_UX0 " and " MGMT_OUTPATH_UX0 "\n");
// STEP 0
int fd = ksceIoOpen(NVS_OUTPATH_UX0, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
if (fd >= 0) {
ksceIoWrite(fd, full_nvs, 0xB60);
ksceIoClose(fd);
} else
ksceDebugPrintf("STEP 0 r 0x%X\n", fd);
// STEP 1
fd = ksceIoOpen(MGMT_OUTPATH_UX0, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
if (fd >= 0) {
ksceIoWrite(fd, mgmt_data, 8);
ksceIoClose(fd);
} else
ksceDebugPrintf("STEP 1 r 0x%X\n", fd);
// host0
ksceDebugPrintf("\nWriting raw to " NVS_OUTPATH_HOST0 " and " MGMT_OUTPATH_HOST0 "\n");
// STEP 2
fd = ksceIoOpen(NVS_OUTPATH_HOST0, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
if (fd >= 0) {
ksceIoWrite(fd, full_nvs, 0xB60);
ksceIoClose(fd);
} else
ksceDebugPrintf("STEP 2 r 0x%X\n", fd);
// STEP 3
fd = ksceIoOpen(MGMT_OUTPATH_HOST0, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
if (fd >= 0) {
ksceIoWrite(fd, mgmt_data, 8);
ksceIoClose(fd);
} else
ksceDebugPrintf("STEP 3 r 0x%X\n", fd);
}
EXIT:
ksceDebugPrintf("\nExiting\n");
ksceSblSmCommStopSm(ctx, stop_res);
return SCE_KERNEL_START_SUCCESS;
}
int module_stop(SceSize argc, const void *args)
{
return SCE_KERNEL_STOP_SUCCESS;
}
@SKGleba
Copy link
Author

SKGleba commented Aug 28, 2022

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8)

set(CMAKE_SYSTEM_NAME "Generic")
set(CMAKE_C_COMPILER "arm-vita-eabi-gcc")
set(CMAKE_CXX_COMPILER "arm-vita-eabi-g++")

project(nvs_read)

set(CMAKE_C_FLAGS "-Wl,-q -Wall -O3 -std=gnu99")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11 -fno-rtti -fno-exceptions")

add_executable(nvs_read.elf
	main.c
)

target_link_libraries(nvs_read.elf
	SceKernelSuspendForDriver_stub
	SceSysclibForDriver_stub
	SceSysmemForDriver_stub
	SceDebugForDriver_stub
	SceSysconForDriver_stub
	SceSblSmCommForKernel_stub
	SceIofilemgrForDriver_stub
)

set_target_properties(nvs_read.elf
	PROPERTIES LINK_FLAGS "-nostdlib"
	COMPILE_FLAGS "-D__VITA_KERNEL__"
)

add_custom_target(nvs_read.skprx ALL
	COMMAND vita-elf-create -e ${CMAKE_SOURCE_DIR}/nvs_read.yml nvs_read.elf nvs_read.velf
	COMMAND vita-make-fself -c nvs_read.velf nvs_read.skprx
)
add_dependencies(nvs_read.skprx nvs_read.elf)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment