|
2 | 2 | #define TYPES_H |
3 | 3 |
|
4 | 4 | #include <stdarg.h> |
| 5 | +#include <stddef.h> |
5 | 6 | #include <stdint.h> |
6 | 7 | #include <sys/types.h> |
7 | 8 |
|
@@ -47,14 +48,76 @@ typedef struct { |
47 | 48 | char unk[0x400]; |
48 | 49 | } NotificationRequest; |
49 | 50 |
|
| 51 | +/* --------------------------------------------------------------------------- |
| 52 | + * Optional pre-resolved API table (v2 args extension). |
| 53 | + * |
| 54 | + * Some launchers cannot let the payload resolve its own imports: syscall 0x24f |
| 55 | + * (dlsym) is refused for a WebProcess, so a kexp spawned from the PS5 browser |
| 56 | + * would hit __builtin_trap() in resolve_symbol(). Such launchers instead fill |
| 57 | + * api_entries[] with the runtime addresses of every imported function and set |
| 58 | + * api_magic/api_count; kexp then performs zero dlsym calls. Launchers that do |
| 59 | + * not know these addresses simply leave the extension zeroed (legacy 0x28 |
| 60 | + * block) and kexp falls back to its internal resolver as before. |
| 61 | + * |
| 62 | + * Table layout is a fixed contract (index -> function), matching the order of |
| 63 | + * libkernel-imports.h + libc-imports.h below: |
| 64 | + * [0] sceKernelSendNotificationRequest (libkernel) |
| 65 | + * [1] sysctlbyname (libkernel) |
| 66 | + * [2] pthread_create (libkernel) |
| 67 | + * [3] pthread_join (libkernel) |
| 68 | + * [4] getpid (libkernel) |
| 69 | + * [5] malloc (libSceLibcInternal) |
| 70 | + * [6] free (libSceLibcInternal) |
| 71 | + * [7] memcpy (libSceLibcInternal) |
| 72 | + * [8] memset (libSceLibcInternal) |
| 73 | + * [9] strcmp (libSceLibcInternal) |
| 74 | + * [10] memcmp (libSceLibcInternal) |
| 75 | + * [11] vsnprintf (libSceLibcInternal) |
| 76 | + * ------------------------------------------------------------------------- */ |
| 77 | +#define KEXP_API_MAGIC 0x4B585032U /* 'KXP2' */ |
| 78 | +#define KEXP_API_COUNT 12 |
| 79 | + |
| 80 | +enum { |
| 81 | + KEXP_API_NOTIFY = 0, |
| 82 | + KEXP_API_SYSCTLBYNAME, |
| 83 | + KEXP_API_PTHREAD_CREATE, |
| 84 | + KEXP_API_PTHREAD_JOIN, |
| 85 | + KEXP_API_GETPID, |
| 86 | + KEXP_API_MALLOC, |
| 87 | + KEXP_API_FREE, |
| 88 | + KEXP_API_MEMCPY, |
| 89 | + KEXP_API_MEMSET, |
| 90 | + KEXP_API_STRCMP, |
| 91 | + KEXP_API_MEMCMP, |
| 92 | + KEXP_API_VSNPRINTF, |
| 93 | +}; |
| 94 | + |
50 | 95 | typedef struct { |
51 | 96 | int master_pipe[2]; |
52 | 97 | int victim_pipe[2]; |
53 | 98 | uintptr_t allproc; |
54 | 99 | char *elfldr_ptr; |
55 | 100 | size_t elfldr_size; |
| 101 | + /* v2 extension: optional pre-resolved API table (see above). Legacy |
| 102 | + * launchers pass only the 0x28-byte prefix; reading past it is safe on the |
| 103 | + * heap and misinterpretation is ruled out by validating magic, count and |
| 104 | + * pointer before use. */ |
| 105 | + uint32_t api_magic; |
| 106 | + uint32_t api_count; |
| 107 | + void **api_entries; |
56 | 108 | } payload_args_t; |
57 | 109 |
|
| 110 | +_Static_assert(offsetof(payload_args_t, elfldr_size) == 0x20, |
| 111 | + "legacy prefix must stay 0x28 bytes"); |
| 112 | +_Static_assert(offsetof(payload_args_t, api_magic) == 0x28, |
| 113 | + "api_magic offset broke the v2 args contract"); |
| 114 | +_Static_assert(offsetof(payload_args_t, api_count) == 0x2C, |
| 115 | + "api_count offset broke the v2 args contract"); |
| 116 | +_Static_assert(offsetof(payload_args_t, api_entries) == 0x30, |
| 117 | + "api_entries offset broke the v2 args contract"); |
| 118 | +_Static_assert(sizeof(payload_args_t) == 0x38, |
| 119 | + "payload_args_t size broke the v2 args contract"); |
| 120 | + |
58 | 121 | typedef struct { |
59 | 122 | uint32_t cnt; |
60 | 123 | uint32_t in; |
|
0 commit comments