1 // Copyright 2010 Sven Peter <svenpeter@gmail.com>
2 // Licensed under the terms of the GNU GPL, version 2
3 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
15 #define ALIGNMENT 0x20
18 static u8
*elf
= NULL
;
19 static u8
*self
= NULL
;
21 static enum sce_key type
;
24 struct elf_phdr phdr
[MAX_PHDR
];
27 static u8 sce_header
[0x70];
28 static u8 info_header
[0x20];
29 static u8 ctrl_header
[0x70];
30 static u8 version_header
[0x10];
32 static u8
*sec_header
;
33 static u32 sec_header_size
;
35 static u8
*meta_header
;
36 static u32 meta_header_size
;
38 static u64 header_size
;
39 static u32 meta_offset
;
41 static u64 compressed_size
;
42 static u64 info_offset
;
43 static u64 version_offset
;
44 static u64 elf_offset
;
45 static u64 phdr_offset
;
46 static u64 shdr_offset
;
47 static u64 sec_offset
;
48 static u64 ctrl_offset
;
56 static const char *elf_name
= NULL
;
57 static const char *self_name
= NULL
;
58 static int compression
= 0;
67 static void get_type(const char *p
)
69 if (strncmp(p
, "lv0", 4) == 0)
71 else if (strncmp(p
, "lv1", 4) == 0)
73 else if (strncmp(p
, "lv2", 4) == 0)
75 else if (strncmp(p
, "iso", 4) == 0)
77 else if (strncmp(p
, "app", 4) == 0)
79 else if (strncmp(p
, "ldr", 4) == 0)
82 fail("invalid type: %s", p
);
85 static void get_keys(const char *suffix
)
87 if (key_get(type
, suffix
, &ks
) < 0)
88 fail("key_get failed");
91 fail("no public key available");
93 if (ks
.priv_avail
< 0)
94 fail("no private key available");
96 if (ecdsa_set_curve(ks
.ctype
) < 0)
97 fail("ecdsa_set_curve failed");
99 ecdsa_set_pub(ks
.pub
);
100 ecdsa_set_priv(ks
.priv
);
103 static void parse_elf(void)
107 arch64
= elf_read_hdr(elf
, &ehdr
);
109 for (i
= 0; i
< ehdr
.e_phnum
; i
++)
110 elf_read_phdr(arch64
, elf
+ ehdr
.e_phoff
+ i
* ehdr
.e_phentsize
, &phdr
[i
]);
113 static void build_sce_hdr(void)
115 memset(sce_header
, 0, sizeof sce_header
);
117 wbe32(sce_header
+ 0x00, 0x53434500); // magic
118 wbe32(sce_header
+ 0x04, 2); // version
119 wbe16(sce_header
+ 0x08, sdk_type
); // dunno, sdk type?
120 wbe16(sce_header
+ 0x0a, 1); // SCE header type; self
121 wbe32(sce_header
+ 0x0c, meta_offset
);
122 wbe64(sce_header
+ 0x10, header_size
);
123 wbe64(sce_header
+ 0x18, round_up(elf_size
, ALIGNMENT
));
124 wbe64(sce_header
+ 0x20, 3); // dunno, has to be 3
125 wbe64(sce_header
+ 0x28, info_offset
);
126 wbe64(sce_header
+ 0x30, elf_offset
);
127 wbe64(sce_header
+ 0x38, phdr_offset
);
128 wbe64(sce_header
+ 0x40, shdr_offset
);
129 wbe64(sce_header
+ 0x48, sec_offset
);
130 wbe64(sce_header
+ 0x50, version_offset
);
131 wbe64(sce_header
+ 0x58, ctrl_offset
);
132 wbe64(sce_header
+ 0x60, 0x70); // ctrl size
135 static void build_version_hdr(void)
137 memset(version_header
, 0, sizeof version_header
);
138 wbe32(version_header
, 1);
139 wbe32(version_header
+ 0x08, 0x10);
142 static void build_info_hdr(void)
146 memset(info_header
, 0, sizeof info_header
);
168 fail("something that should never fail failed.");
171 wbe64(info_header
+ 0x00, auth_id
);
172 wbe32(info_header
+ 0x08, vendor_id
);
173 wbe32(info_header
+ 0x0c, app_type
);
174 wbe64(info_header
+ 0x10, version
); // version 1.0.0
177 static void build_ctrl_hdr(void)
179 memset(ctrl_header
, 0, sizeof ctrl_header
);
181 wbe32(ctrl_header
+ 0x00, 1); // type: control flags
182 wbe32(ctrl_header
+ 0x04, 0x30); // length
183 // flags are all zero here
185 wbe32(ctrl_header
+ 0x30, 2); // type: digest
186 wbe32(ctrl_header
+ 0x34, 0x40); // length
189 static void build_sec_hdr(void)
194 sec_header_size
= ehdr
.e_phnum
* 0x20;
195 sec_header
= malloc(sec_header_size
);
197 memset(sec_header
, 0, sec_header_size
);
199 for (i
= 0; i
< ehdr
.e_phnum
; i
++) {
200 ptr
= sec_header
+ i
* 0x20;
202 wbe64(ptr
+ 0x00, phdr_map
[i
].offset
);
203 wbe64(ptr
+ 0x08, phdr_map
[i
].size
);
205 if (phdr_map
[i
].compressed
== 1)
206 wbe32(ptr
+ 0x10, 2);
208 wbe32(ptr
+ 0x10, 1);
210 wbe32(ptr
+ 0x14, 0); // unknown
211 wbe32(ptr
+ 0x18, 0); // unknown
213 if (phdr
[i
].p_type
== 1)
214 wbe32(ptr
+ 0x1c, 1); // encrypted LOAD phdr
216 wbe32(ptr
+ 0x1c, 0); // no loadable phdr
220 static void meta_add_phdr(u8
*ptr
, u32 i
)
222 wbe64(ptr
+ 0x00, phdr_map
[i
].offset
);
223 wbe64(ptr
+ 0x08, phdr_map
[i
].size
);
226 wbe32(ptr
+ 0x10, 2);
227 wbe32(ptr
+ 0x14, i
); // phdr index maybe?
228 wbe32(ptr
+ 0x18, 2);
230 wbe32(ptr
+ 0x1c, i
*8); // sha index
231 wbe32(ptr
+ 0x20, 1); // not encpryted
232 wbe32(ptr
+ 0x24, 0xffffffff); // no key
233 wbe32(ptr
+ 0x28, 0xffffffff); // no iv
234 wbe32(ptr
+ 0x2c, 1); // not compressed
237 static void meta_add_load(u8
*ptr
, u32 i
)
239 wbe64(ptr
+ 0x00, phdr_map
[i
].offset
);
240 wbe64(ptr
+ 0x08, phdr_map
[i
].size
);
243 wbe32(ptr
+ 0x10, 2);
244 wbe32(ptr
+ 0x14, i
); // phdr index maybe?
245 wbe32(ptr
+ 0x18, 2);
247 wbe32(ptr
+ 0x1c, i
*8); // sha index
248 wbe32(ptr
+ 0x20, 3); // phdr is encrypted
249 wbe32(ptr
+ 0x24, (i
*8) + 6); // key index
250 wbe32(ptr
+ 0x28, (i
*8) + 7); // iv index
252 if (phdr_map
[i
].compressed
== 1)
253 wbe32(ptr
+ 0x2c, 2);
255 wbe32(ptr
+ 0x2c, 1);
258 static void build_meta_hdr(void)
263 meta_header_size
= 0x80 + ehdr
.e_phnum
* (0x30 + 0x20 + 0x60) + 0x30;
264 meta_header
= malloc(meta_header_size
);
265 memset(meta_header
, 0, meta_header_size
);
267 ptr
= meta_header
+ 0x20;
269 // aes keys for meta encryption
271 get_rand(ptr
+ 0x20, 0x10);
274 // area covered by the signature
275 wbe64(ptr
+ 0x00, meta_offset
+ meta_header_size
- 0x30);
277 wbe32(ptr
+ 0x08, 1);
278 wbe32(ptr
+ 0x0c, ehdr
.e_phnum
); // number of encrypted headers
279 wbe32(ptr
+ 0x10, ehdr
.e_phnum
* 8); // number of keys/hashes required
280 wbe32(ptr
+ 0x14, meta_header_size
/ 0x10);
283 // add encrypted phdr information
284 for (i
= 0; i
< ehdr
.e_phnum
; i
++) {
285 if (phdr
[i
].p_type
== 1)
286 meta_add_load(ptr
, i
);
288 meta_add_phdr(ptr
, i
);
293 // add keys/ivs and hmac keys
294 get_rand(ptr
, ehdr
.e_phnum
* 8 * 0x10);
297 static void calculate_hashes(void)
302 keys
= self
+ meta_offset
+ 0x80 + (0x30 * ehdr
.e_phnum
);
304 for (i
= 0; i
< ehdr
.e_phnum
; i
++) {
305 memset(keys
+ (i
* 8 * 0x10), 0, 0x20);
306 sha1_hmac(keys
+ ((i
* 8) + 2) * 0x10,
307 self
+ phdr_map
[i
].offset
,
309 keys
+ (i
* 8) * 0x10
314 static void build_hdr(void)
316 memcpy(self
, sce_header
, sizeof sce_header
);
317 memcpy(self
+ info_offset
, info_header
, sizeof info_header
);
318 memcpy(self
+ version_offset
, version_header
, sizeof version_header
);
319 memcpy(self
+ ctrl_offset
, ctrl_header
, sizeof ctrl_header
);
320 memcpy(self
+ sec_offset
, sec_header
, sec_header_size
);
321 memcpy(self
+ phdr_offset
, elf
+ ehdr
.e_phoff
, ehdr
.e_phnum
* ehdr
.e_phentsize
);
322 // memcpy(self + shdr_offset, elf + ehdr.e_shoff, ehdr.e_shnum * ehdr.e_shentsize);
323 memcpy(self
+ meta_offset
, meta_header
, meta_header_size
);
324 memcpy(self
+ elf_offset
, elf
, ehdr
.e_ehsize
);
327 static void write_elf(void)
332 for (i
= 0; i
< ehdr
.e_phnum
; i
++) {
333 memcpy(self
+ phdr_map
[i
].offset
,
337 memcpy(self
+ shdr_offset
, elf
+ ehdr
.e_shoff
, ehdr
.e_shnum
* ehdr
.e_shentsize
);
339 memcpy(self
+ header_size
, elf
, elf_size
);
343 static void compress_elf(void)
351 offset
= header_size
;
353 for (i
= 0; i
< ehdr
.e_phnum
; i
++) {
354 phdr_map
[i
].offset
= offset
;
356 if (phdr
[i
].p_type
!= 1) {
357 phdr_map
[i
].ptr
= elf
+ phdr
[i
].p_off
;
358 phdr_map
[i
].size
= phdr
[i
].p_filesz
;
359 phdr_map
[i
].compressed
= 0;
360 offset
= round_up(offset
+ phdr
[i
].p_filesz
, 0x20);
364 size_compressed
= compressBound(phdr
[i
].p_filesz
);
365 size_zlib
= size_compressed
;
367 phdr_map
[i
].ptr
= malloc(size_compressed
);
368 if (!phdr_map
[i
].ptr
)
369 fail("out of memory");
371 res
= compress(phdr_map
[i
].ptr
, &size_zlib
,
372 elf
+ phdr
[i
].p_off
, phdr
[i
].p_filesz
);
374 if (size_zlib
>= phdr
[i
].p_filesz
) {
375 free(phdr_map
[i
].ptr
);
376 phdr_map
[i
].ptr
= elf
+ phdr
[i
].p_off
;
377 phdr_map
[i
].size
= phdr
[i
].p_filesz
;
378 phdr_map
[i
].compressed
= 0;
379 offset
= round_up(offset
+ phdr
[i
].p_filesz
, ALIGNMENT
);
381 phdr_map
[i
].ptr
= realloc(phdr_map
[i
].ptr
, size_zlib
);
382 if (phdr_map
[i
].ptr
== NULL
)
383 fail("out of memory");
385 phdr_map
[i
].size
= size_zlib
;
386 phdr_map
[i
].compressed
= 1;
387 offset
= round_up(offset
+ phdr_map
[i
].size
, ALIGNMENT
);
391 compressed_size
= phdr_map
[i
- 1].offset
+ phdr_map
[i
- 1].size
;
392 shdr_offset
= compressed_size
;
393 compressed_size
+= ehdr
.e_shentsize
* ehdr
.e_shnum
;
396 static void fill_phdr_map(void)
400 memset(phdr_map
, 0, sizeof phdr_map
);
402 for (i
= 0; i
< ehdr
.e_phnum
; i
++) {
403 phdr_map
[i
].offset
= phdr
[i
].p_off
+ header_size
;
404 phdr_map
[i
].size
= phdr
[i
].p_filesz
;
405 phdr_map
[i
].compressed
= 0;
409 compressed_size
= elf_size
;
410 shdr_offset
= ehdr
.e_shoff
+ header_size
;
413 static void sign_hdr(void)
419 sig_len
= be64(self
+ meta_offset
+ 0x60);
423 sha1(self
, sig_len
, hash
);
425 ecdsa_sign(hash
, r
, s
);
428 static u64
get_filesize(const char *path
)
437 static void get_version(const char *v
)
445 maj
= min
= rev
= tmp
= 0;
449 fprintf(stderr
, "WARNING: invalid sdk_version, using 1.0.0\n");
450 version
= 1ULL << 48;
467 if (*ptr
>= '0' && *ptr
<= '9') {
474 fprintf(stderr
, "WARNING: invalid sdk_version, using 1.0.0\n");
475 version
= 1ULL << 48;
482 version
= ((u64
)maj
& 0xffff) << 48;
483 version
|= ((u64
)min
& 0xffff) << 32;
487 static void get_vendor(char *v
)
489 vendor_id
= strtoull(v
, NULL
, 16);
492 static void get_auth(char *a
)
494 auth_id
= strtoull(a
, NULL
, 16);
497 static void get_sdktype(char * t
)
499 sdk_type
= strtoul(t
, NULL
, 10);
502 static void get_args(int argc
, char *argv
[])
506 if (argc
!= 9 && argc
!= 10)
507 fail("usage: makeself [-c] [type] [version suffix] [version] [vendor id] [auth id] [sdk type] [elf] [self]");
512 if (strcmp(argv
[1], "-c") != 0)
513 fail("invalid option: %s", argv
[1]);
520 get_version(argv
[i
++]);
521 get_vendor(argv
[i
++]);
523 get_sdktype(argv
[i
++]);
525 elf_name
= argv
[i
++];
526 self_name
= argv
[i
++];
530 fail("no compression support for isolated modules");
532 fail("no compression support for secure loaders");
537 int main(int argc
, char *argv
[])
542 get_args(argc
, argv
);
544 elf_size
= get_filesize(elf_name
);
545 elf
= mmap_file(elf_name
);
549 meta_header_size
= 0x80 + ehdr
.e_phnum
* (0x30 + 0x20 + 0x60) + 0x30;
552 phdr_offset
= elf_offset
+ ehdr
.e_ehsize
;
553 sec_offset
= round_up(phdr_offset
+ ehdr
.e_phentsize
* ehdr
.e_phnum
, ALIGNMENT
);
554 version_offset
= round_up(sec_offset
+ ehdr
.e_phnum
* 0x20, ALIGNMENT
);
555 ctrl_offset
= round_up(version_offset
+ 0x10, ALIGNMENT
);
556 meta_offset
= round_up(ctrl_offset
+ 0x70, ALIGNMENT
);
557 header_size
= round_up(meta_offset
+ meta_header_size
, 0x80);
571 self
= malloc(header_size
+ elf_size
);
572 memset(self
, 0, header_size
+ elf_size
);
579 sce_encrypt_data(self
);
580 sce_encrypt_header(self
, &ks
);
582 fp
= fopen(self_name
, "wb");
584 fail("fopen(%s) failed", self_name
);
586 if (fwrite(self
, header_size
+ compressed_size
, 1, fp
) != 1)
587 fail("unable to write self");
589 memset(bfr
, 0, sizeof bfr
);
590 fwrite(bfr
, round_up(compressed_size
, ALIGNMENT
) - compressed_size
, 1, fp
);