vita-toolchain

git clone https://git.neptards.moe/neptards/vita-toolchain.git
Log | Files | Refs | README | LICENSE

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 }