Add COPYING file
[ps3tools.git] / pupunpack.c
blob2aee52afb99f944d82268cec338131436a7fcd13
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
4 #include <stdio.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 #include <string.h>
8 #include <inttypes.h>
10 #include "tools.h"
12 #ifdef WIN32
13 #define MKDIR(x,y) mkdir(x)
14 #else
15 #define MKDIR(x,y) mkdir(x,y)
16 #endif
18 static u8 *pup = NULL;
19 static u8 pup_hmac[0x40];
20 static int got_hmac = -1;
21 static u64 n_sections;
22 static u64 hdr_size;
24 static struct id2name_tbl t_names[] = {
25 {0x100, "version.txt"},
26 {0x101, "license.xml"},
27 {0x102, "promo_flags.txt"},
28 {0x103, "update_flags.txt"},
29 {0x104, "patch_build.txt"},
30 {0x200, "ps3swu.self"},
31 {0x201, "vsh.tar"},
32 {0x202, "dots.txt"},
33 {0x203, "patch_data.pkg"},
34 {0x300, "update_files.tar"},
35 {0x501, "spkg_hdr.tar"},
36 {0x601, "ps3swu2.self"},
37 {0, NULL}
40 static int check_hmac(u8 *hmac, u8 *bfr, u64 len)
42 u8 calc[0x14];
44 if (hmac == NULL)
45 return 1;
47 if (got_hmac < 0)
48 return 1;
50 sha1_hmac(pup_hmac, bfr, len, calc);
52 if (memcmp(calc, hmac, sizeof calc) == 0)
53 return 0;
54 else
55 return -1;
58 static u8 *find_hmac(u32 entry)
60 u8 *ptr;
61 u32 i;
63 ptr = pup + 0x30 + 0x20 * n_sections;
65 for(i = 0; i < n_sections; i++) {
66 if (be64(ptr) == entry)
67 return ptr + 8;
68 ptr += 0x20;
71 fail("not found: %d", entry);
72 return NULL;
75 static void do_section(u64 i)
77 u8 *ptr;
78 u64 entry;
79 u64 offset;
80 u64 size;
81 int hmac_res;
82 const char *fname;
83 const char *hmac_status;
85 ptr = pup + 0x30 + 0x20 * i;
86 entry = be64(ptr);
87 offset = be64(ptr + 0x08);
88 size = be64(ptr + 0x10);
90 fname = id2name(entry, t_names, NULL);
91 if (fname == NULL)
92 fail("unknown entry id: %08x_%08x", (u32)(entry >> 32), (u32)entry);
94 hmac_res = check_hmac(find_hmac(i), pup + offset, size);
95 if (hmac_res < 0)
96 hmac_status = "FAIL";
97 else if (hmac_res == 0)
98 hmac_status = "OK";
99 else
100 hmac_status = "???";
102 printf("unpacking %s (%08x_%08x bytes; hmac: %s)...\n", fname, (u32)(size >> 32), (u32)size, hmac_status);
103 memcpy_to_file(fname, pup + offset, size);
106 static void do_pup(void)
108 u64 data_size;
109 u64 i;
110 int res;
112 n_sections = be64(pup + 0x18);
113 hdr_size = be64(pup + 0x20);
114 data_size = be64(pup + 0x28);
116 printf("sections: %" PRIu64 "\n", n_sections);
117 printf("hdr size: %08x_%08x\n", (u32)(hdr_size >> 32), (u32)hdr_size);
118 printf("data size: %08x_%08x\n", (u32)(data_size >> 32), (u32)data_size);
119 printf("header hmac: ");
121 res = check_hmac(pup + 0x30 + 0x40 * n_sections, pup, 0x30 + 0x40 * n_sections);
123 if (res < 0)
124 printf("FAIL\n");
125 else if (res == 0)
126 printf("OK\n");
127 else
128 printf("???\n");
130 for (i = 0; i < n_sections; i++)
131 do_section(i);
134 int main(int argc, char *argv[])
136 (void)argc;
138 if (argc < 3)
139 fail("usage: pupunpack filename.pup directory");
141 got_hmac = key_get_simple("pup-hmac", pup_hmac, sizeof pup_hmac);
142 pup = mmap_file(argv[1]);
144 if(pup != NULL)
146 if (MKDIR(argv[2], 0777) < 0)
147 fail("mkdir(%s)", argv[2]);
148 if (chdir(argv[2]) < 0)
149 fail("chdir(%s)", argv[2]);
150 do_pup();
153 return 0;