vita-make-fself.c (8030B)
1 #include <string.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <inttypes.h> 5 #include <zlib.h> 6 7 #include "vita-export.h" 8 #include "sce-elf.h" 9 #include "endian-utils.h" 10 #include "self.h" 11 #include "sha256.h" 12 13 void usage(const char **argv) { 14 fprintf(stderr, "usage: %s [-s|-ss|-a 0x2XXXXXXXXXXXXXXX] [-c] input.velf output-eboot.bin\n", argv[0] ? argv[0] : "vita-make-fself"); 15 fprintf(stderr, "\t-s : Generate a safe eboot.bin. A safe eboot.bin does not have access\n\tto restricted APIs and important parts of the filesystem.\n"); 16 fprintf(stderr, "\t-ss: Generate a secret-safe eboot.bin. Do not use this option if you don't know what it does.\n"); 17 fprintf(stderr, "\t-a : Authid for more permissions (SceShell: 0x2800000000000001).\n"); 18 fprintf(stderr, "\t-c : Enable compression.\n"); 19 exit(1); 20 } 21 22 int main(int argc, const char **argv) { 23 const char *input_path, *output_path; 24 FILE *fin = NULL; 25 FILE *fout = NULL; 26 uint32_t mod_nid; 27 28 argc--; 29 argv++; // strip first argument 30 if (argc < 2) 31 usage(argv); 32 33 int safe = 0; 34 int compressed = 0; 35 uint64_t authid = 0; 36 while (argc > 2) { 37 if (strcmp(*argv, "-s") == 0) { 38 safe = 2; 39 } else if (strcmp(*argv, "-ss") == 0) { 40 safe = 3; 41 } else if (strcmp(*argv, "-c") == 0) { 42 compressed = 1; 43 } else if (strcmp(*argv, "-a") == 0) { 44 argc--; 45 argv++; 46 47 if (argc > 2) 48 authid = strtoull(*argv, NULL, 0); 49 } 50 argc--; 51 argv++; 52 } 53 input_path = argv[0]; 54 output_path = argv[1]; 55 56 if (sha256_32_file(input_path, &mod_nid) != 0) { 57 perror("Cannot generate module NID"); 58 goto error; 59 } 60 61 fin = fopen(input_path, "rb"); 62 if (!fin) { 63 perror("Failed to open input file"); 64 goto error; 65 } 66 fseek(fin, 0, SEEK_END); 67 size_t sz = ftell(fin); 68 fseek(fin, 0, SEEK_SET); 69 70 char *input = calloc(1, sz); 71 if (!input) { 72 perror("Failed to allocate buffer for input file"); 73 goto error; 74 } 75 if (fread(input, sz, 1, fin) != 1) { 76 static const char s[] = "Failed to read input file"; 77 if (feof(fin)) 78 fprintf(stderr, "%s: unexpected end of file\n", s); 79 else 80 perror(s); 81 goto error; 82 } 83 fclose(fin); 84 fin = NULL; 85 86 Elf32_Ehdr *ehdr = (Elf32_Ehdr*)input; 87 88 // write module nid 89 if (ehdr->e_type == ET_SCE_EXEC) { 90 Elf32_Phdr *phdr = (Elf32_Phdr*)(input + ehdr->e_phoff); 91 sce_module_info_raw *info = (sce_module_info_raw *)(input + phdr->p_offset + phdr->p_paddr); 92 info->library_nid = htole32(mod_nid); 93 } else if (ehdr->e_type == ET_SCE_RELEXEC) { 94 int seg = ehdr->e_entry >> 30; 95 int off = ehdr->e_entry & 0x3fffffff; 96 Elf32_Phdr *phdr = (Elf32_Phdr*)(input + ehdr->e_phoff + seg * ehdr->e_phentsize); 97 sce_module_info_raw *info = (sce_module_info_raw *)(input + phdr->p_offset + off); 98 info->library_nid = htole32(mod_nid); 99 } 100 101 SCE_header hdr = { 0 }; 102 hdr.magic = 0x454353; // "SCE\0" 103 hdr.version = 3; 104 hdr.sdk_type = 0xC0; 105 hdr.header_type = 1; 106 hdr.metadata_offset = 0x600; // ??? 107 hdr.header_len = HEADER_LEN; 108 hdr.elf_filesize = sz; 109 // self_filesize 110 hdr.self_offset = 4; 111 hdr.appinfo_offset = 0x80; 112 hdr.elf_offset = sizeof(SCE_header) + sizeof(SCE_appinfo); 113 hdr.phdr_offset = hdr.elf_offset + sizeof(Elf32_Ehdr); 114 hdr.phdr_offset = (hdr.phdr_offset + 0xf) & ~0xf; // align 115 // hdr.shdr_offset = ; 116 hdr.section_info_offset = hdr.phdr_offset + sizeof(Elf32_Phdr) * ehdr->e_phnum; 117 hdr.sceversion_offset = hdr.section_info_offset + sizeof(segment_info) * ehdr->e_phnum; 118 hdr.controlinfo_offset = hdr.sceversion_offset + sizeof(SCE_version); 119 hdr.controlinfo_size = sizeof(SCE_controlinfo_5) + sizeof(SCE_controlinfo_6) + sizeof(SCE_controlinfo_7); 120 hdr.self_filesize = 0; 121 122 uint32_t offset_to_real_elf = HEADER_LEN; 123 124 // SCE_header should be ok 125 126 SCE_appinfo appinfo = { 0 }; 127 if (authid) { 128 appinfo.authid = authid; 129 } else { 130 if (safe) 131 appinfo.authid = 0x2F00000000000000ULL | safe; 132 else 133 appinfo.authid = 0x2F00000000000001ULL; 134 } 135 appinfo.vendor_id = 0; 136 appinfo.self_type = 8; 137 appinfo.version = 0x1000000000000; 138 appinfo.padding = 0; 139 140 SCE_version ver = { 0 }; 141 ver.unk1 = 1; 142 ver.unk2 = 0; 143 ver.unk3 = 16; 144 ver.unk4 = 0; 145 146 SCE_controlinfo_5 control_5 = { 0 }; 147 control_5.common.type = 5; 148 control_5.common.size = sizeof(control_5); 149 control_5.common.unk = 1; 150 SCE_controlinfo_6 control_6 = { 0 }; 151 control_6.common.type = 6; 152 control_6.common.size = sizeof(control_6); 153 control_6.common.unk = 1; 154 control_6.unk1 = 1; 155 SCE_controlinfo_7 control_7 = { 0 }; 156 control_7.common.type = 7; 157 control_7.common.size = sizeof(control_7); 158 159 Elf32_Ehdr myhdr = { 0 }; 160 memcpy(myhdr.e_ident, "\177ELF\1\1\1", 8); 161 myhdr.e_type = ehdr->e_type; 162 myhdr.e_machine = 0x28; 163 myhdr.e_version = 1; 164 myhdr.e_entry = ehdr->e_entry; 165 myhdr.e_phoff = 0x34; 166 myhdr.e_flags = 0x05000000U; 167 myhdr.e_ehsize = 0x34; 168 myhdr.e_phentsize = 0x20; 169 myhdr.e_phnum = ehdr->e_phnum; 170 171 fout = fopen(output_path, "wb"); 172 if (!fout) { 173 perror("Failed to open output file"); 174 goto error; 175 } 176 177 fseek(fout, hdr.appinfo_offset, SEEK_SET); 178 if (fwrite(&appinfo, sizeof(appinfo), 1, fout) != 1) { 179 perror("Failed to write appinfo"); 180 goto error; 181 } 182 183 fseek(fout, hdr.elf_offset, SEEK_SET); 184 fwrite(&myhdr, sizeof(myhdr), 1, fout); 185 186 // copy elf phdr in same format 187 fseek(fout, hdr.phdr_offset, SEEK_SET); 188 for (int i = 0; i < ehdr->e_phnum; ++i) { 189 Elf32_Phdr *phdr = (Elf32_Phdr*)(input + ehdr->e_phoff + ehdr->e_phentsize * i); 190 // but fixup alignment, TODO: fix in toolchain 191 if (phdr->p_align > 0x1000) 192 phdr->p_align = 0x1000; 193 if (fwrite(phdr, sizeof(*phdr), 1, fout) != 1) { 194 perror("Failed to write phdr"); 195 goto error; 196 } 197 } 198 199 // convert elf phdr info to segment info that sony loader expects 200 // first round we assume no compression 201 fseek(fout, hdr.section_info_offset, SEEK_SET); 202 for (int i = 0; i < ehdr->e_phnum; ++i) { 203 Elf32_Phdr *phdr = (Elf32_Phdr*)(input + ehdr->e_phoff + ehdr->e_phentsize * i); // TODO: sanity checks 204 segment_info sinfo = { 0 }; 205 sinfo.offset = offset_to_real_elf + phdr->p_offset; 206 sinfo.length = phdr->p_filesz; 207 sinfo.compression = 1; 208 sinfo.encryption = 2; 209 if (fwrite(&sinfo, sizeof(sinfo), 1, fout) != 1) { 210 perror("Failed to write segment info"); 211 goto error; 212 } 213 } 214 215 fseek(fout, hdr.sceversion_offset, SEEK_SET); 216 if (fwrite(&ver, sizeof(ver), 1, fout) != 1) { 217 perror("Failed to write SCE_version"); 218 goto error; 219 } 220 221 fseek(fout, hdr.controlinfo_offset, SEEK_SET); 222 fwrite(&control_5, sizeof(control_5), 1, fout); 223 fwrite(&control_6, sizeof(control_6), 1, fout); 224 fwrite(&control_7, sizeof(control_7), 1, fout); 225 226 if (!compressed) { 227 fseek(fout, HEADER_LEN, SEEK_SET); 228 if (fwrite(input, sz, 1, fout) != 1) { 229 perror("Failed to write a copy of input ELF"); 230 goto error; 231 } 232 } else { 233 for (int i = 0; i < ehdr->e_phnum; ++i) { 234 Elf32_Phdr *phdr = (Elf32_Phdr*)(input + ehdr->e_phoff + ehdr->e_phentsize * i); // TODO: sanity checks 235 segment_info sinfo = { 0 }; 236 unsigned char *buf = malloc(2 * phdr->p_filesz + 12); 237 sinfo.length = 2 * phdr->p_filesz + 12; 238 if (compress2(buf, (uLongf *)&sinfo.length, (unsigned char *)input + phdr->p_offset, phdr->p_filesz, Z_BEST_COMPRESSION) != Z_OK) { 239 free(buf); 240 perror("compress failed"); 241 goto error; 242 } 243 // padding 244 uint64_t pad = ((sinfo.length + 3) & ~3) - sinfo.length; 245 for (int i = 0; i < pad; i++) { 246 buf[pad+sinfo.length] = 0; 247 } 248 sinfo.offset = ftell(fout); 249 sinfo.compression = 2; 250 sinfo.encryption = 2; 251 fseek(fout, hdr.section_info_offset + i * sizeof(segment_info), SEEK_SET); 252 if (fwrite(&sinfo, sizeof(sinfo), 1, fout) != 1) { 253 perror("Failed to write segment info"); 254 free(buf); 255 goto error; 256 } 257 fseek(fout, sinfo.offset, SEEK_SET); 258 if (fwrite(buf, sinfo.length, 1, fout) != 1) { 259 perror("Failed to write segment to fself"); 260 goto error; 261 } 262 free(buf); 263 } 264 } 265 266 fseek(fout, 0, SEEK_END); 267 hdr.self_filesize = ftell(fout); 268 fseek(fout, 0, SEEK_SET); 269 if (fwrite(&hdr, sizeof(hdr), 1, fout) != 1) { 270 perror("Failed to write SCE header"); 271 goto error; 272 } 273 274 275 fclose(fout); 276 277 return 0; 278 error: 279 if (fin) 280 fclose(fin); 281 if (fout) 282 fclose(fout); 283 return 1; 284 }