SceKernelModulemgr is in charge of loading both user modules and kernel modules. SceSblAuthMgr facilitates the SELF decryption process and this library loads the ELF programs into memory along with linking with NIDs and relocation of ELF in position independent executables.
Module
This module exists only in non-secure world. The SELF can be found in os0:kd/modulemgr.skprx
.
Known NIDs
Version |
Name |
World |
Privilege |
NID
|
1.69 |
SceKernelModulemgr |
Non-secure |
Kernel |
0xAFDA75C2
|
3.57 |
SceKernelModulemgr |
Non-secure |
Kernel |
0x8FDDA3C0
|
3.60 |
SceKernelModulemgr |
Non-secure |
Kernel |
0x726C6635
|
3.65 |
SceKernelModulemgr |
Non-secure |
Kernel |
0x781C6F50
|
Libraries
This module exports kernel and user libraries.
Known NIDs
Types
//these types are defined in elfutils
typedef Elf32_Ehdr Elf32_Ehdr;
typedef Elf32_Phdr Elf32_Phdr;
typedef char SceKernelModuleName[0x1C];
typedef struct SCE_header
{
uint32_t magic; /* 53434500 = SCE\0 */
uint32_t version; /* header version 3*/
uint16_t sdk_type; /* */
uint16_t header_type; /* 1 self, 2 unknown, 3 pkg */
uint32_t metadata_offset; /* metadata offset */
uint64_t header_len; /* self header length */
uint64_t elf_filesize; /* ELF file length */
uint64_t self_filesize; /* SELF file length */
uint64_t unknown; /* UNKNOWN */
uint64_t self_offset; /* SELF offset */
uint64_t appinfo_offset; /* app info offset */
uint64_t elf_offset; /* ELF #1 offset */
uint64_t phdr_offset; /* program header offset */
uint64_t shdr_offset; /* section header offset */
uint64_t section_info_offset; /* section info offset */
uint64_t sceversion_offset; /* version offset */
uint64_t controlinfo_offset; /* control info offset */
uint64_t controlinfo_size; /* control info size */
uint64_t padding;
} SCE_header;
typedef struct SCE_appinfo
{
uint64_t program_authority_id; /* program authority id */
uint32_t vendor_id; /* vendor id */
uint32_t self_type; /* app type */
uint64_t version; /* app version */
uint64_t padding; /* UNKNOWN */
} SCE_appinfo;
typedef struct segment_info
{
uint64_t offset;
uint64_t length;
uint64_t compression; // 1 = uncompressed, 2 = compressed
uint64_t encryption; // 1 = encrypted, 2 = plain
} segment_info;
typedef struct self_data_buffer
{
SCE_header sce_header;
SCE_appinfo sce_appinfo;
Elf32_Ehdr elf_hdr;
//... data goes
} self_data_buffer;
typedef struct SceDecryptCtx //size is 0x30
{
self_data_buffer* self_header; // aligned buffer - based on (buffer_unaligned).
// points at SCE_header followed by SCE_appinfo
// size is usually 0x1000
int self_header_length;
Elf32_Ehdr* elf_ptr; // pointer constructed with elf_offset
Elf32_Phdr* phdr_ptr; // pointer constructed with phdr_offset
uint8_t type; // ex: 2
uint8_t init_completed;
uint8_t unk_12;
uint8_t unk_13;
segment_info* section_info_ptr; // pointer constructed with section_info_offset
void* buffer_unaligned; // SELF header data - size 0x103F - raw data read from file
int sm_ctx; // obtained with sceSblAuthMgrSmStartForKernel
SceSblSmCommContext130* context_130;
SceUID fd; // file descriptor of SELF file - obtained with sceIoOpenForDriver
SceUID pid;
uint32_t max_size;
} SceDecryptCtx;
typedef struct SceDecryptCtxGlobal // size is 0x4C
{
uint32_t unk_0;
uint32_t unk_4; // ex:3
void *module_decrypt_buff_ptr1;
int decrypt_size; // max 0x10000
int unk_10; // 0 or 1 or 2
int unk_14; // ex:-1
void *module_decrypt_buff_ptr2;
int unk_1C; // some size
SceDecryptCtx *decrypt_ctx;
SceUID evid; // SceModuleMgrSelfDecryptComm event flag
SceUID tid; // SceModuleMgrSelfDecrypter thread uid
void *unk_2C; // ksceDeflateDecompressPartial out. memblock
int compressed_seg_size;
uint32_t unk_34; // unk_2C out size?
uint16_t segment_number;
uint16_t unk_3A; // ex:0xFFFF
SceDeflatePartialInputParam cbinfo;
} SceDecryptCtxGlobal;
typedef struct {
SceSize size;
char versionString[0x1C];
SceUInt version;
SceUInt unk_24;
} SceKernelFwInfo;
typedef struct SceKernelSegmentInfo {
SceUInt size; //!< this structure size (0x18)
SceUInt perms; //!< probably rwx in low bits
void *vaddr; //!< address in memory
SceUInt memsz; //!< size in memory
SceUInt flags; //!< meaning unknown
SceUInt res; //!< unused?
} SceKernelSegmentInfo;
typedef struct SceKernelModuleInfo { // size is 0x1B8
uint32_t size; //0
SceUID UID; //4
uint32_t attributes; //8
char name[0x1C]; //0xC
uint32_t unk28; //0x28
void *module_start; //0x2C
void *module_stop; //0x30
void *module_exit; //0x34
void *exidx_start; //0x38
void *exidx_end; //0x3C
void *unk40; //0x40
void *unk44; //0x44
void *tlsInit; //0x48
SceSize tlsInitSize; //0x4C
SceSize tlsAreaSize; //0x50
char path[256]; //0x54
SceKernelSegmentInfo segments[4]; //0x58
SceUInt type; //0x1B4
} SceKernelModuleInfo;
typedef struct {
SceSize size; //!< sizeof(SceKernelSegmentInfo2) (0x14)
int perm;
void *vaddr;
uint32_t memsz;
int unk_10;
} SceKernelSegmentInfo2;
typedef struct {
SceSize size;
SceUID modid;
uint32_t version;
uint32_t module_version;
uint32_t unk10;
void *unk14;
uint32_t unk18;
void *unk1C;
void *unk20;
char module_name[28];
uint32_t unk40;
uint32_t unk44;
uint32_t nid;
int segments_num;
union {
struct {
SceKernelSegmentInfo2 SegmentInfo[1];
uint32_t addr[4];
} seg1;
struct {
SceKernelSegmentInfo2 SegmentInfo[2];
uint32_t addr[4];
} seg2;
struct {
SceKernelSegmentInfo2 SegmentInfo[3];
uint32_t addr[4];
} seg3;
struct {
SceKernelSegmentInfo2 SegmentInfo[4];
uint32_t addr[4];
} seg4;
};
} SceKernelModuleListInfo; // is for SceCoredump?
typedef struct {
SceSize size; //!< sizeof(SceKernelModuleInfo2) : 0x120
SceUID modid1;
uint32_t unk_0x08;
uint16_t unk_0x0C;
uint16_t unk_0x0E;
uint16_t unk_0x10;
uint16_t unk_0x12;
uint16_t unk_0x14;
uint16_t unk_0x16;
char module_name[0x100]; // offset : 0x18
uint32_t unk_0x118;
SceUID modid2;
} SceKernelModuleInfo2;
/**
* option parameter for load module APIs
*/
typedef struct SceKernelLoadModuleOpt {
SceSize size; /**< Size of structure itself */
} SceKernelLoadModuleOpt;
/**
* option parameter for start module API
*/
typedef struct SceKernelStartModuleOpt {
SceSize size; /**< size of structure itself */
SceUInt32 flags; /**< should be 0 */
SceUInt32 prologue; /**< should be 0 */
SceUInt32 start; /**< should be 0 */
} SceKernelStartModuleOpt;
/**
* option parameter for stop module API
*/
typedef struct SceKernelStopModuleOpt {
SceSize size; /**< size of structure itself */
SceUInt32 flags; /**< should be 0 */
SceUInt32 epilogue; /**< should be 0 */
SceUInt32 stop; /**< should be 0 */
} SceKernelStopModuleOpt;
/**
* option parameter for unload module APIs
*/
typedef struct SceKernelUnloadModuleOpt {
SceSize size; /**< size of structure itself */
} SceKernelUnloadModuleOpt;
module decrypt threads
SceKernelModulemgr_func_8100910D
This thread keeps waiting at sceKernelWaitEventFlagForDriver until a module decrypt request comes.
bits of ksceKernelWaitEventFlag is 3.
common functions
int SceKernelModulemgr_func_81009309(SceDecryptCtx *ctx, int seg_idx, void *membase, int arg4);
Decrypt module to membase with current ctx.
Data segment layout
Offsets are for FW 3.60.
data section size is 0x203C0.
Offset |
Size |
Description
|
0x0000 |
0x34 |
unknown, all zero
|
0x0034 |
0x4 |
SceKernelFwInfo data Initialize flag
|
0x0038 |
0x4 |
pointer of SceClass. The first class obtained with sceKernelSysrootGetModulePrivateForKernel. used by only sceKernelFinalizeKblForKernel.
|
0x003C |
0x4 |
pointer of SceClass. The third class obtained with sceKernelSysrootGetModulePrivateForKernel. SceUIDLibStubClass
|
0x0040 |
0x4 |
pointer of SceClass. The second class obtained with sceKernelSysrootGetModulePrivateForKernel. SceUIDLibraryClass
|
0x0044 |
0x4 |
Return value of SceThreadmgrForDriver_B645C7EF
|
0x0048 |
0x4 |
pointer of SceClass. The first class obtained with sceKernelSysrootGetModulePrivateForKernel. SceUIDModuleClass
|
0x004C |
0x4 |
SceModuleMgr Mutex uid
|
0x0050 |
0x280 |
unknown
|
0x02D0 |
0x28 |
SceKernelFwInfo data
|
0x02F8 |
0x4 |
some thread id, check SceModulemgrForKernel_2A69385E
|
0x02FC |
0x4 |
some kernel module uid, check SceModulemgrForKernel_2A69385E
|
0x0300 |
0x4 |
unk, used by SceModulemgrForKernel_3AD26B43
|
0x0304 |
0x4 |
some storage ptr. used by sceKernelMountBootfsForKernel, sceKernelUmountBootfsForKernel
|
0x0308 |
0x4 |
unk, used by SceModulemgrForKernel_60E176C8, SceModulemgrForKernel_9D20C9BB
|
0x030C |
0x4 |
unk
|
0x0310 |
0x4 |
cpu_addr out (ksceKernelCpuSuspendIntr arg1)
|
0x0314 |
0x4 |
unk, some flag
|
0x0318 |
0x4 |
sceKernelGetMemBlockBaseForDriver membase out
|
0x031C |
0x4 |
sceKernelAllocMemBlockForDriver ret
|
0x0320 |
0xC |
unk
|
0x032C |
0x4 |
unk, used by SceModulemgrForKernel_F3CD647F
|
0x0330 |
0x4 |
unk, used by SceModulemgrForKernel_F3CD647F
|
0x0334 |
0x4 |
syscall table vaddr
|
0x0338 |
0x4 |
unk, related to syscall. used by SceKernelUtilsForDriver_875B2A1C
|
0x033C |
0x4 |
unk
|
0x0340 |
0x4C |
SceDecryptCtxGlobal data
|
0x038C |
0x34 |
unk, all zero
|
0x03C0 |
0x10000 |
module decrypt buff 1
|
0x103C0 |
0x10000 |
module decrypt buff 2
|
typedef struct SceKernelModulemgr_data_t // size is 0x203C0
{
char unk_00[0x34]; // unknown, all zero
int is_FwInfo_init;
SceClass *kbl_unload;
SceClass *pSceUIDLibStubClass;
SceClass *pSceUIDLibraryClass;
int some_thread_res;
SceClass *pSceUIDModuleClass;
SceUID mutex_id;
char unk_50[0x280]; // unknown
SceKernelFwInfo FwInfo;
SceUID some_threadid;
SceUID some_kernel_module_id;
int unk_0x0300;
void *bootfs_info;
int unk_0x0308;
int unk_0x030C;
int cpu_addr;
int some_flag;
void *membase;
SceUID memuid;
int unk_0x0320[3];
int unk_0x032C;
int unk_0x0330;
void *syscall_table;
int some_syscall_info;
int unk_0x033C;
SceDecryptCtxGlobal g_decrypt_ctx;
char unk_0x038C[0x34];
char module_decrypt_buff1[0x10000];
char module_decrypt_buff2[0x10000];
} SceKernelModulemgr_data_t;
Loading Sequence
When loading a module the sequence creates a SceModule structure to represent it.
typedef struct SceModule { // ?size is 0x3EC?
u8 unk0[0x64]; // 0x0
const char *filename; // 0x64
u8 unk1[0xC]; // 0x68
Elf32_Ehdr ehdr; // 0x74
Elf32_Phdr phdr; // 0xA8
void *text_addr; // 0x108
SceUID text_uid; // 0x10C
u32 text_size; // 0x110
void *kernel_addr; // 0x114
SceUID kernel_uid; // 0x118
u8 unk2[0x2C8]; // 0x11C
SceUID parent_pid; // 0x3E4
SceSblSmCommContext130* context_130; // 0x3E8
} SceModule;
SELF Decryption
The following code can decrypt a SELF located at path
. Set user
to 1 if decrypting a user module else 0 for kernel. Set pathid
to 0 if you're decrypting the SELF at the right location (for example decrypting sysmem.skprx
located in os0:
). If you have copied the SELF elsewhere, you need to set the pathid
to the right value for where the real path was. usecdram
is for modules that are too large and won't fit in contiguous regular memory.
int decrypt_self(const char *path, const char *outprefix, int pathid, int usecdram, int user)
{
char outpath[256];
int ctx;
int ret;
int pid;
int fd = 0, wfd = 0;
char *somebuf = NULL;
char *hdr_buf = NULL, *hdr_buf_aligned;
char *data_buf = NULL, *data_buf_aligned;
int phdr;
unsigned int hdr_size;
// set up SBL decrypt context
ret = SceSblAuthMgrForKernel_0xA9CD2A09(&ctx);
printf("SceSblAuthMgrForKernel_0xA9CD2A09: 0x%08X, CTX: 0x%08X\n", ret, ctx);
if (ret < 0)
return 1;
// set up this weird buffer
somebuf = sceKernelLoadcoreKallocForKernel(0x10005, 0x130);
printf("Weird buffer: 0x%08X\n", somebuf);
if (somebuf == NULL)
goto fail;
memset(somebuf, 0, 0x130);
if (ret < 0)
goto fail;
*(int *)(somebuf + 0x4) = user;
*(u64_t *)(somebuf + 0x8) = 0x2808000000000001LL;
*(u64_t *)(somebuf + 0x10) = 0xF000C000000080LL;
*(u64_t *)(somebuf + 0x18) = 0xFFFFFFFF00000000LL;
*(u64_t *)(somebuf + 0x30) = 0xC300003800980LL;
*(u64_t *)(somebuf + 0x38) = 0x8009800000LL;
*(u64_t *)(somebuf + 0x48) = 0xFFFFFFFF00000000LL;
if (pathid)
{
*(int *)(somebuf + 0x128) = pathid;
}
else
{
ret = SceIofilemgrForDriver_0x9C220246(0x10005, path, 1, somebuf + 0x128);
printf("SceIofilemgrForDriver_0x9C220246: 0x%08X\n", ret);
if (ret < 0)
goto fail;
}
// read header
fd = sceIoOpenForDriver(path, 1, 0);
printf("sceIoOpenForDriver: 0x%08X\n", fd);
if (fd < 0)
goto fail;
hdr_buf = sceKernelLoadcoreKallocForKernel(0x10005, 0x1000+63);
hdr_buf_aligned = (char *)(((int)hdr_buf + 63) & 0xFFFFFFC0);
printf("Header buffer: 0x%08X, aligned: 0x%08X\n", hdr_buf, hdr_buf_aligned);
if (hdr_buf == NULL)
goto fail;
ret = sceIoReadForDriver(fd, hdr_buf_aligned, 0x1000);
printf("Header read: 0x%08X\n", ret);
hdr_size = *(unsigned int *)(hdr_buf_aligned + 0x10);
if (hdr_size > 0x1000)
{
printf("Header too large: 0x%08X\n", hdr_size);
goto fail;
}
ret = sceIoLseekForDriver(fd, 0LL, 0);
printf("Header rewind: 0x%08X\n", ret);
// set up SBL decryption for this SELF
ret = SceSblAuthMgrForKernel_0xF3411881(ctx, hdr_buf_aligned, hdr_size, somebuf);
printf("SceSblAuthMgrForKernel_0xF3411881: 0x%08X\n", ret);
if (ret < 0)
{
goto fail;
}
// set up read buffer
data_buf = sceKernelLoadcoreKallocForKernel(0x10005, 0x10000+63);
data_buf_aligned = (char *)(((int)data_buf + 63) & 0xFFFFFFC0);
printf("Data buffer: 0x%08X, aligned: 0x%08X\n", data_buf, data_buf_aligned);
if (data_buf == NULL)
goto fail;
// get sections
int elf_offset = *(int*)(hdr_buf_aligned + 0x40);
int num_segs = *(short*)(hdr_buf_aligned + elf_offset + 0x2C);
printf("Number of segments to read: 0x%04X\n", num_segs);
int info_offset = *(int*)(hdr_buf_aligned + 0x58);
struct seg_info *segs = (struct seg_info *)(hdr_buf_aligned + info_offset);
int phdr_offset = *(int*)(hdr_buf_aligned + 0x48);
struct e_phdr *phdrs = (struct e_phdr *)(hdr_buf_aligned + phdr_offset);
// decrypt sections
int i;
int total, to_read, num_read, off;
int aligned_size;
int blkid = 0;
void *pgr_buf;
for (i = 0; i < num_segs; i++)
{
sprintf(outpath, "%s.seg%u", outprefix, i);
sceIoCloseForDriver(wfd);
wfd = sceIoOpenForDriver(outpath, 0x602, 6);
printf("sceIoOpenForDriver(%s): 0x%08X\n", outpath, wfd);
if (wfd < 0)
break;
if (blkid)
sceKernelFreeMemBlockForKernel(blkid);
aligned_size = (phdrs[i].p_filesz + 4095) & 0xFFFFF000;
if (usecdram)
blkid = sceKernelAllocMemBlockForKernel("self_decrypt_buffer", 0x40404006, 0x4000000, NULL);
else
blkid = sceKernelAllocMemBlockForKernel("self_decrypt_buffer", 0x1020D006, aligned_size, NULL);
printf("sceKernelAllocMemBlockForKernel: 0x%08X, size: 0x%08X\n", blkid, aligned_size);
ret = sceKernelGetMemBlockBaseForKernel(blkid, &pgr_buf);
printf("sceKernelGetMemBlockBaseForKernel: 0x%08X, base: 0x%08X\n", ret, pgr_buf);
if (ret < 0)
break;
// setup buffer for output
ret = SceSblAuthMgrForKernel_0x89CCDA2C(ctx, i, (u32_t)segs[i].length, pgr_buf, phdrs[i].p_filesz);
printf("SceSblAuthMgrForKernel_0x89CCDA2C: 0x%08X\n", ret);
if (ret < 0)
{
break;
}
ret = sceIoLseekForDriver(fd, segs[i].offset, 0);
printf("sceIoLseekForDriver(0x%08X): 0x%08X\n", (u32_t)segs[i].offset, ret);
if (ret < 0)
break;
total = (u32_t)segs[i].length;
to_read = total > 0x10000 ? 0x10000 : total;
off = 0;
while (total > 0 && (num_read = sceIoReadForDriver(fd, data_buf_aligned+off, to_read)) > 0)
{
off += num_read;
total -= num_read;
if (num_read < to_read)
{
to_read -= num_read;
continue;
}
ret = SceSblAuthMgrForKernel_0xBC422443(ctx, data_buf_aligned, off); // decrypt buffer
printf("SceSblAuthMgrForKernel_0xBC422443: 0x%08X\n", ret);
if (ret < 0)
printf("!!! ERROR !!!\n");
ret = SceSblAuthMgrForKernel_0x15248FB4(ctx, data_buf_aligned, off); // copy buffer to output
printf("SceSblAuthMgrForKernel_0x15248FB4: 0x%08X\n", ret);
if (ret < 0)
{
printf("!!! ERROR !!!\n");
}
off = 0;
to_read = total > 0x10000 ? 0x10000 : total;
}
// write buffer
off = 0;
while ((off += sceIoWriteForDriver(wfd, pgr_buf+off, phdrs[i].p_filesz-off)) < phdrs[i].p_filesz);
}
if (blkid)
sceKernelFreeMemBlockForKernel(blkid);
sceIoCloseForDriver(wfd);
fail:
SceSblAuthMgrForKernel_0x026ACBAD(ctx);
if (fd)
sceIoCloseForDriver(fd);
if (somebuf)
SceModulemgrForKernel_0xF4B2D8B8_free(somebuf);
if (hdr_buf)
SceModulemgrForKernel_0xF4B2D8B8_free(hdr_buf);
if (data_buf)
SceModulemgrForKernel_0xF4B2D8B8_free(data_buf);
return 1;
}
Module decryption and signature checks ("HENkaku patches" on 1.60)
See also SELF_Loading to see how these SceSblAuthMgr functions are used to decrypt SELFs.
The code below will patch signature checks and bypass module decryption and allow homebrews to run. The idea is to hook SceSblAuthMgr* calls that are imported to SceKernelModulemgr. The offsets are from 1.60, you will probably need to modify functions defines (set to addresses of functions) and INSTALL_HOOK second arguments (set to addresses of imports in SceKernelModulemgr).
For old FWs like 1.60, as there is no kASLR, you can set hardcoded addresses, else take HENkaku code. As a bonus there's also patch_npdrm functions that patches SceNpDrm to bypass some DRM checks and allow unsigned packages to be installed, which you also need to modify addresses. See SceNpDrm#Package_integrity_checks.
// hardcoded addresses for 1.60
#define G_OUR_EBOOT *(unsigned*)(0x01E60000 - 0x14)
#define G_BUF *(unsigned*)(0x01E60000 - 0xC)
#define G_WRITTEN *(unsigned*)(0x01E60000 - 0x10)
#define Func(addr) ((unsigned(*)())(addr))
// Hardcoded addresses for 1.60
#define sceSblAuthMgrAuthHeaderForKernel Func(0x4BC6C9)
#define sceSblAuthMgrLoadSegmentForKernel Func(0x4BC851)
#define sceSblAuthMgrLoadBlockForKernel Func(0x4BC909)
#define sceSblAuthMgrLoadSegmentInternalForKernel Func(0x4BCA89)
// setup file decryption
unsigned sceSblAuthMgrAuthHeaderForKernel_patched(unsigned a1, unsigned a2, unsigned a3, unsigned a4) {
unsigned res = sceSblAuthMgrAuthHeaderForKernel(a1, a2, a3, a4);
if (res == 0x800f0624 || res == 0x800f0616 || res == 0x800f0024) {
G_OUR_EBOOT = 1;
// patch somebuf so our module actually runs
unsigned *somebuf = (unsigned*)a4;
somebuf[42] = 0x40;
return 0;
} else {
G_OUR_EBOOT = 0;
}
return res;
}
// setup output buffer
unsigned sceSblAuthMgrLoadSegmentForKernel_patched(unsigned a1, unsigned a2, unsigned a3, unsigned a4, unsigned a5) {
G_BUF = a4;
G_WRITTEN = 0;
if (G_OUR_EBOOT == 1) {
return 0;
}
return sceSblAuthMgrLoadSegmentForKernel(a1, a2, a3, a4, a5);
}
// decrypt
unsigned sceSblAuthMgrLoadBlockForKernel_patched(unsigned a1, unsigned a2, unsigned a3) {
if (G_OUR_EBOOT == 1) {
return 0;
}
return sceSblAuthMgrLoadBlockForKernel(a1, a2, a3);
}
// copy to output - not present on 3.60
unsigned sceSblAuthMgrLoadSegmentInternalForKernel_patched(unsigned a1, unsigned a2, unsigned a3) {
if (G_OUR_EBOOT == 1) {
memcpy((void*)(G_BUF + G_WRITTEN), (void*)a2, a3);
G_WRITTEN += a3;
return 0;
}
return sceSblAuthMgrLoadSegmentInternalForKernel(a1, a2, a3);
}
#define INSTALL_HOOK(func, addr) \
{ unsigned *target; \
target = (unsigned*)addr; \
*target++ = 0xE59FF000; /* ldr pc, [pc, #0] */ \
*target++; /* doesn't matter */ \
*target = (unsigned)func; \
}
// hardcoded addresses for 1.60
void hook_install(void) {
INSTALL_HOOK(sceSblAuthMgrLoadBlockForKernel_patched, 0x5BAA0C);
INSTALL_HOOK(sceSblAuthMgrLoadSegmentInternalForKernel_patched, 0x5BA9CC);
INSTALL_HOOK(sceSblAuthMgrAuthHeaderForKernel_patched, 0x5BAA1C);
INSTALL_HOOK(sceSblAuthMgrLoadSegmentForKernel_patched, 0x5BA9DC);
}
unsigned get_module_base(const char *name) {
int * modlist[MOD_LIST_SIZE];
int modlist_records;
int res;
SceKernelModuleInfo modinfo;
memset(modlist, 0, sizeof(modlist));
modlist_records = MOD_LIST_SIZE;
sceKernelGetModuleListForKernel(0x10005, 0x7FFFFFFF, 1, modlist, &modlist_records);
for(int j = 0; j < modlist_records; j++) {
memset(&modinfo, 0, sizeof(modinfo));
res=sceKernelGetModuleInfoForKernel(modlist[j], &modinfo);
if (strcmp(modinfo.name, name) == 0)
return (unsigned)modinfo.module_top;
}
return 0;
}
// Hardcoded addresses for 1.60
void patch_npdrm(unsigned base) {
unsigned *patch;
// check where check_func[0] is called
patch = (unsigned*)(base + 0x310);
*patch = 0x47702001;
// check where check_func[1] is called
patch = (unsigned*)(base + 0xaa4);
*patch = 0x47702001;
// always return 1 in install_allowed
patch = (unsigned*)(base + 0x2d64);
*patch = 0x47702001;
// patch error code 0x80870003
patch = (unsigned*)(base + 0x4856);
*patch = 0x2500;
// second same error code
patch = (unsigned*)(base + 0x35fe);
*patch = 0x2600;
}
// call this from a thread
int hook(void) {
fprintf("Hook start\n");
unsigned prev_dacr;
__asm__ volatile("mrc p15, 0, %0, c3, c0, 0" : "=r" (prev_dacr));
__asm__ volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (-1));
unsigned base_npdrm = get_module_base("SceNpDrm");
fprintf("SceNpDrm base: 0x%08x\n", base_npdrm);
patch_npdrm(base_npdrm);
hook_install();
__asm__ volatile("MCR p15, 0, %0, c7, c5, 0" : : "r" (0)); // flush icache
__asm__ volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (prev_dacr));
sceKernelDelayThread(4*1000*1000);
return 0;
}
SceModulemgrForKernel
sceModulemgrLockLibDBForKernel
Version |
NID
|
0.990 |
0x37C2A1A5
|
sceModulemgrUnlockLibDBForKernel
Version |
NID
|
0.990 |
0x0751F162
|
SceModulemgrForKernel_2C2618D9
Version |
NID
|
0.990-3.60 |
0x2C2618D9
|
Used by sceKernelPrintBacktraceForDriver.
int SceModulemgrForKernel_2C2618D9(SceUID pid, void *a2, void *a3);
sceKernelGetModuleIdByAddrForKernel
Version |
NID
|
0.990-3.60 |
0x0053BA4A
|
SceUID sceKernelGetModuleIdByAddrForKernel(SceUID pid, const void *module_addr);
sceKernelGetProcessEntryPointForKernel
Version |
NID
|
0.990 |
0xC72CA412
|
3.60 |
not present
|
sceKernelLoadcoreKallocForKernel
Version |
NID
|
0.990 |
0xB4A1DE31
|
uint32_t sceKernelLoadcoreKallocForKernel(SceUID pid, uint32_t size);
sceKernelFinalizeKblForKernel
Version |
NID
|
0.990-3.60 |
0xFDD7F646
|
void *sysroot_buffer = sceKernelGetSysrootBuffer;
kbl_modid = *(_DWORD *)(SceSysrootForKernel_CD70C9D7(sysroot_buffer) + 0x38);
sceKernelStopUnloadModuleForDriver(kbl_modid);
unk = *(_DWORD *)(SceSysrootForKernel_CD70C9D7(sysroot_buffer) + 0x34);
// then does other things with other sysroot functions
0.990
void sceKernelFinalizeKblForKernel(void);
3.60
int sceKernelFinalizeKblForKernel(void);
sceKernelRegisterSyscallForKernel
Version |
NID
|
3.60 |
0xB427025E
|
3.65-3.68 |
0x2E4A10A0
|
void sceKernelRegisterSyscallForKernel(uint32_t num, void *function);
sceKernelLoadPtLoadSegForFwloaderForKernel
Version |
NID
|
0.990-3.60 |
0x448810D5
|
sceKernelDecryptSelfByPathForKernel
Version |
NID
|
0.990-3.60 |
0x448810D5
|
3.65 |
0xA07063EA
|
int sceKernelDecryptSelfByPathForKernel(const char *path, int e_phnum, void *buffer, uint32_t bufsize, int zero_unk, uint32_t *bytes_read);
This is an easy way of decrypting SELFs but you are limited to the kinds of SELFs you can load in the current context (for example, you can't load user modules from kernel context). It is also susceptible to limitations of where the SELF can be loaded from. For example, you are not allowed to load SELFs found in os0:
from ux0:
. This is because it checks the PathId.
On 3.60, statically compiled self give an error.
sceKernelGetModuleListForKernel
Version |
NID
|
1.60-3.60 |
0x97CF7B4E
|
int sceKernelGetModuleListForKernel(SceUID pid, int flags1, int flags2, SceUID *modids, size_t *num);
sceKernelGetModuleList2ForKernel
Version |
NID
|
3.60 |
0x410E1D2E
|
Found by Princess
sceKernelGetModuleUidForKernel
Version |
NID
|
3.60 |
0x3B93CF88
|
Found by Princess
sceKernelGetModuleUidListForKernel
Version |
NID
|
3.60 |
0x1FDEAE16
|
Found by Princess
sceKernelGetModuleInfoForKernel
Version |
NID
|
3.60 |
0xD269F915
|
int sceKernelGetModuleInfoForKernel(SceUID pid, SceUID modid, SceKernelModuleInfo *info);
sceKernelGetModuleInfo2ForKernel
Version |
NID
|
3.60 |
0x6A655255
|
int sceKernelGetModuleInfo2ForKernel(SceUID pid, SceUID modid, SceKernelModuleInfo2 *info);
sceKernelGetModuleCBForDebugger
Version |
NID
|
3.60 |
0xFE303863
|
Temp name was sceKernelGetModuleInternalForKernel.
int sceKernelGetModuleInternalForKernel(SceUID modid, void **module);
sceKernelGetModuleLibraryInfoForKernel
Version |
NID
|
3.60 |
0xD4BF409C
|
Found by Princess
sceKernelGetProcessMainModuleForKernel
Version |
NID
|
3.60 |
0x20A27FA9
|
/**
* @brief Get the main module for a given process.
* @param pid The process to query.
* @return the UID of the module else < 0 for an error.
*/
SceUID sceKernelGetProcessMainModuleForKernel(SceUID pid);
sceKernelGetProcessMainModulePathForKernel
Version |
NID
|
3.60 |
0x779A1025
|
int sceKernelGetProcessMainModulePathForKernel(SceUID pid, char *path, int pathlen);
sceKernelMountBootfsForKernel
Version |
NID
|
3.60 |
0x01360661
|
3.65 |
0x185FF1BC
|
int sceKernelMountBootfsForKernel(const char *bootImagePath);
sceKernelUmountBootfsForKernel
Version |
NID
|
3.60 |
0x9C838A6B
|
3.65 |
0xBD61AD4D
|
int sceKernelUmountBootfsForKernel(void);
sceKernelLoadModuleForPidForKernel
Version |
NID
|
3.60 |
0xFA21D8CB
|
SceUID sceKernelLoadModuleForPidForKernel(SceUID pid, const char *path, int flags, SceKernelLMOption *option);
sceKernelStartModuleForPidForKernel
Version |
NID
|
3.60 |
0x6DF745D5
|
// flags must be 0
// pOpt can be null
/**
* @brief start module for process
*
* Starts the module specified by uid. When calling the start entry function,
* the value specified by the args and argp arguments is passed as an argument.
*
* If the start process is successful, the library declared with AUTO_EXPORT will be registered.
* Public processing is performed and the return value of the start entry function is stored in the area indicated by pRes.
* If the start process fails, library registration and publishing will not be performed.
*
* SCE_KERNEL_START_NO_RESIDENT is returned as the return value of the start entry function
* only if the module is automatically unloaded after executing the start entry function.
* If SCE_KERNEL_START_FAILED is returned, the start process will fail.
* At this time, the module is not unloaded. Modules that failed to start
* It can be restarted with sceKernelStartModuleForPidForKernel().
*
* @param[in] pid process id
* @param[in] uid module id
* @param[in] args argument block size
* @param[in] argp argument block address
* @param[in] flags flags, should be 0
* @param[in] pOpt option parameter, should be SCE_NULL
* @param[out] pRes result of start entry
* @retval SCE_OK success
* @retval (<0) Error code
*/
int sceKernelStartModuleForPidForKernel(SceUID pid, SceUID uid, SceSize args, const void *argp, SceUInt32 flags, const SceKernelStartModuleOpt *pOpt, int *pRes);
sceKernelStopModuleForPidForKernel
Version |
NID
|
3.60 |
0x7BB4CE54
|
int sceKernelStopModuleForPidForKernel(SceUID pid, SceUID modid, SceSize args, void *argp, int flags, void *option, int *status);
sceKernelUnloadModuleForPidForKernel
Version |
NID
|
3.60 |
0x5972E2CC
|
int sceKernelUnloadModuleForPidForKernel(SceUID pid, SceUID modid, int flags, SceKernelULMOption *option);
sceKernelLoadProcessModulesForKernel
Temp name was sceKernelLoadPreloadingModulesForKernel. Was wrongly named sceKernelLoadStartDefaultSharedModulesForPidForKernel.
Version |
NID
|
1.69-3.60 |
0x3AD26B43
|
This loads the default shared modules for a process (only the ones that are actually imported). This includes, for example, SceLibKernel
. Modules are loaded with flags 0x10000000
meaning that text pages can be shared. If dipsw 210 is set, then flag 0x1000
is set, meaning that if the existing page is found, do not share it but instead make a copy.
int sceKernelLoadProcessModulesForKernel(int pid, void *unk_buf, int flags);
sceKernelLoadProcessImageForKernel
Version |
NID
|
0.990-3.60 |
0xAC4EABDB
|
sceKernelUnloadProcessModulesForKernel
Temp name was sceKernelStopUnloadPreloadingModulesForKernel.
Version |
NID
|
0.990-3.60 |
0x0E33258E
|
sceKernelLoadcoreKfreeForKernel
Version |
NID
|
0.990-1.60 |
0xF4B2D8B8
|
Calls sceKernelFreeHeapMemoryForDriver.
sceKernelCallModuleSuspendEntryForKernel
Version |
NID
|
0.990 |
0x829E1C94
|
sceKernelLoadcoreRegisterSyscallsAfterBootForKernel
Version |
NID
|
0.990 |
0x1100A1B8
|
SceModulemgrForDriver
sceKernelGetModuleInfoByAddrForDriver
Version |
NID
|
0.990-3.60 |
0x1D9E0F7E
|
note : kernel only.
int sceKernelGetModuleInfoByAddrForDriver(const void *module_addr, SceKernelModuleInfo *info);
sceKernelRegisterLibaryForDriver
Version |
NID
|
0.990-3.60 |
0x861638AD
|
note : kernel only.
int sceKernelRegisterLibaryForDriver(const void *module_addr);
sceKernelReleaseLibaryForDriver
Version |
NID
|
0.990-3.60 |
0x0975B104
|
note : kernel only.
int sceKernelReleaseLibaryForDriver(const void *module_addr);
sceKernelGetModuleInfoForDriver
sceKernelSearchModuleByNameForDriver
Version |
NID
|
3.60 |
0xBBE1771C
|
SceUID sceKernelSearchModuleByNameForDriver(const char *module_name);
sceKernelGetSystemSwVersionForDriver
Version |
NID
|
0.940-3.60 |
0x5182E212
|
int sceKernelGetSystemSwVersionForDriver(SceKernelFwInfo *data);
sceKernelSetSystemSwVersionForDriver
Version |
NID
|
1.69 |
0x912AEB73
|
3.60 |
non existent. Integrated with sceKernelGetSystemSwVersionForDriver
|
sceKernelLoadStartModuleForDriver
Version |
NID
|
1.69-3.60 |
0x189BFBBB
|
SceUID sceKernelLoadStartModuleForDriver(const char *path, SceSize args, void *argp, int flags, SceKernelLMOption *option, int *status);
sceKernelLoadStartModuleForPidForDriver
Version |
NID
|
3.60 |
0x9D953C22
|
SceUID sceKernelLoadStartModuleForPidForDriver(SceUID pid, const char *path, SceSize args, void *argp, int flags, SceKernelLMOption *option, int *status);
sceKernelLoadStartSharedModuleForPidForDriver
Version |
NID
|
3.60 |
0xE2ADEF8D
|
SceUID sceKernelLoadStartSharedModuleForPidForDriver(SceUID pid, const char *path, SceSize args, void *argp, int flags, SceKernelLMOption *option, int *status);
sceKernelLoadModuleWithoutStartForDriver / sceKernelLoadModuleForDriver
Version |
NID
|
1.69-3.60 |
0x86D8D634
|
int opt = 4; // must be set
SceUID sceKernelLoadModuleForDriver(const char *path, int flags, SceKernelLMOption *option);
Returns module uid (to use with sceKernelStartModuleForDriver).
sceKernelStartModuleForDriver
Version |
NID
|
1.69-3.60 |
0x0675B682
|
// flags must be 0
// pOpt can be null
/**
* @brief start module
*
* Starts the module specified by uid. When calling the start entry function,
* the value specified by the args and argp arguments is passed as an argument.
*
* If the start process is successful, the library declared with AUTO_EXPORT will be registered.
* Public processing is performed and the return value of the start entry function is stored in the area indicated by pRes.
* If the start process fails, library registration and publishing will not be performed.
*
* SCE_KERNEL_START_NO_RESIDENT is returned as the return value of the start entry function
* only if the module is automatically unloaded after executing the start entry function.
* If SCE_KERNEL_START_FAILED is returned, the start process will fail.
* At this time, the module is not unloaded. Modules that failed to start
* It can be restarted with sceKernelStartModuleForDriver().
*
* @param[in] uid module id
* @param[in] args argument block size
* @param[in] argp argument block address
* @param[in] flags flags, should be 0
* @param[in] pOpt option parameter, should be SCE_NULL
* @param[out] pRes result of start entry
* @retval SCE_OK success
* @retval (<0) Error code
*/
int sceKernelStartModuleForDriver(SceUID uid, SceSize args, const void *argp, SceUInt32 flags, const SceKernelStartModuleOpt *pOpt, int *pRes);
sceKernelStopUnloadModuleForDriver
Version |
NID
|
1.69-3.60 |
0x03B30B7E
|
// flags must be 0
// opt can be null
int sceKernelStopUnloadModuleForDriver(SceUID modid, SceSize args, void *argp, int flags, SceKernelULMOption *option, int *status);
sceKernelStopUnloadModuleForPidForDriver
Version |
NID
|
3.60 |
0x49A3EDC7
|
int sceKernelStopUnloadModuleForPidForDriver(SceUID pid, SceUID modid, SceSize args, void *argp, int flags, SceKernelULMOption *option, int *status);
sceKernelStopUnloadSharedModuleForPidForDriver
Version |
NID
|
3.60 |
0x02D3D0C1
|
int sceKernelStopUnloadSharedModuleForPidForDriver(SceUID pid, SceUID modid, SceSize args, void *argp, int flags, SceKernelULMOption *option, int *status);
sceKernelStopModuleForDriver
Version |
NID
|
1.69-3.60 |
0x100DAEB9
|
int sceKernelStopModuleForDriver(SceUID modid, SceSize args, void *argp, int flags, SceKernelULMOption *option, int *status);
sceKernelUnloadModuleForDriver
Version |
NID
|
1.69-3.60 |
0x728E72A6
|
// flags must be 0
int sceKernelUnloadModuleForDriver(SceUID modid, int flags, SceKernelULMOption *option);
SceModulemgr
__sceKernelLoadModuleWithoutStart
Version |
NID
|
1.69 |
0xA4E6DA4D
|
3.60 |
non existent
|
_sceKernelLoadModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0xB4C5EF9E
|
_sceKernelLoadStartModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x60647592
|
__sceKernelStartModule
Version |
NID
|
1.69 |
0x1FD99C9F
|
3.60 |
non existent
|
_sceKernelStartModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x72CD301F
|
__sceKernelStopModule
Version |
NID
|
1.69 |
0xBA49EA5C
|
3.60 |
non existent
|
_sceKernelStopModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x086867A8
|
_sceKernelStopUnloadModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x86EAEA0A
|
__sceKernelUnloadModuleWithoutStop
Version |
NID
|
1.69 |
0xE439E26B
|
3.60 |
non existent
|
_sceKernelUnloadModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x8E4A7716
|
__sceKernelOpenModule
Version |
NID
|
0.990-1.69 |
0x9C2A9A49
|
3.60 |
non existent
|
_sceKernelOpenModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x9D674F45
|
__sceKernelCloseModule
Version |
NID
|
1.69 |
0x5303C52F
|
3.60 |
non existent
|
_sceKernelCloseModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x849E78BE
|
sceKernelKttyWrite
Version |
NID
|
0.940-1.69 |
0x4D76CF9E
|
3.60 |
non existent
|
sceKernelPutc
Version |
NID
|
1.69 |
0x9D2FE122
|
3.60 |
non existent
|
sceKernelGetSystemSwVersion
Version |
NID
|
0.940-3.60 |
0x5182E212
|
sceKernelSetSystemSwVersion
Version |
NID
|
1.69 |
0x912AEB73
|
3.60 |
non existent
|
sceKernelGetAllowedSdkVersionOnSystem
Version |
NID
|
1.69-3.60 |
0x4397FC4E
|
sceKernelGetModuleList
Version |
NID
|
1.69-3.60 |
0x2EF2581F
|
sceKernelGetModuleIdByAddr
Version |
NID
|
1.69-3.60 |
0xF5798C7C
|
sceKernelGetModuleInfo
Version |
NID
|
1.69-3.60 |
0x36585DAF
|
sceKernelGetLibraryInfoByNID
Version |
NID
|
1.69-3.60 |
0xEAEB1312
|
sceKernelIsCalledFromSysModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x85E6D2BB
|
sceKernelInhibitLoadingModule
Version |
NID
|
1.69 |
non existent
|
3.60 |
0x6CED1F63
|
Added somewhere between 3.30 an 3.60 to prevent loading Sysmodules from webbrowser (see Vitasploit 2.00-3.36 and h-encore 3.65-3.68 writeup).
SceBacktraceForDriver
sceKernelBacktraceForDriver
Version |
NID
|
0.990-3.60 |
0x166B9C8C
|
// a4 size = 0x10
int sceKernelBacktraceForDriver(int a1, int a2, int a3, char* a4);
sceKernelPrintBacktraceForDriver
Version |
NID
|
0.990 |
0xC5608386
|
3.60 |
0x7C878F90
|
sceKernelBacktraceInternalForDriver
Version |
NID
|
0.990 |
0xCECD5584
|
3.60 |
0x888E99B8
|
SceBacktrace
_sceKernelBacktrace
Version |
NID
|
3.60 |
0xBF371A98
|
Calls sceKernelBacktraceForDriver.
// a4 size = 0x10
int _sceKernelBacktrace(int a1, int a2, int a3, char* a4);
_sceKernelPrintBacktrace
Version |
NID
|
0.990 |
0x21F00CF2
|
Calls sceKernelPrintBacktraceForDriver.