-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy patharbextract.c
More file actions
122 lines (98 loc) · 3.11 KB
/
arbextract.c
File metadata and controls
122 lines (98 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define ELF_MAGIC "\x7f""ELF"
#define EI_CLASS 4
#define ELFCLASS64 2
typedef struct {
uint32_t p_type;
uint32_t p_flags;
uint64_t p_offset;
uint64_t p_vaddr;
uint64_t p_paddr;
uint64_t p_filesz;
uint64_t p_memsz;
uint64_t p_align;
} Elf64_Phdr;
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "usage: arbextract <xbl_config.img>\n");
return 1;
}
FILE *f = fopen(argv[1], "rb");
if (!f) {
perror("fopen");
return 1;
}
/* Read ELF header */
unsigned char ehdr[64];
if (fread(ehdr, 1, sizeof(ehdr), f) != sizeof(ehdr)) {
fprintf(stderr, "Failed to read ELF header\n");
return 1;
}
if (memcmp(ehdr, ELF_MAGIC, 4) != 0 || ehdr[EI_CLASS] != ELFCLASS64) {
fprintf(stderr, "Not a valid ELF64 file\n");
return 1;
}
uint64_t e_phoff = *(uint64_t *)(ehdr + 0x20);
uint16_t e_phentsz = *(uint16_t *)(ehdr + 0x36);
uint16_t e_phnum = *(uint16_t *)(ehdr + 0x38);
/* Locate candidate HASH segment (last non-empty PT_NULL) */
uint64_t hash_off = 0, hash_size = 0;
for (int i = e_phnum - 1; i >= 0; i--) {
Elf64_Phdr ph;
fseek(f, e_phoff + (uint64_t)i * e_phentsz, SEEK_SET);
fread(&ph, 1, sizeof(ph), f);
if (ph.p_type == 0 && ph.p_filesz > 0) {
hash_off = ph.p_offset;
hash_size = ph.p_filesz;
break;
}
}
if (!hash_size) {
fprintf(stderr, "HASH segment not found\n");
return 1;
}
/* Read HASH segment */
uint8_t *seg = malloc(hash_size);
fseek(f, hash_off, SEEK_SET);
fread(seg, 1, hash_size, f);
fclose(f);
/* Scan for Hash Table Segment Header */
uint32_t version, common_sz, qti_sz, oem_sz, hash_tbl_sz;
size_t header_off = 0;
int found = 0;
for (size_t off = 0; off + 36 <= hash_size && off < 0x1000; off += 4) {
memcpy(&version, seg + off + 0, 4);
memcpy(&common_sz, seg + off + 4, 4);
memcpy(&qti_sz, seg + off + 8, 4);
memcpy(&oem_sz, seg + off + 12, 4);
memcpy(&hash_tbl_sz, seg + off + 16, 4);
if (version < 1 || version > 10)
continue;
if (common_sz > 0x1000 || oem_sz > 0x4000 || hash_tbl_sz > 0x4000)
continue;
if (off + 36 + common_sz + qti_sz + oem_sz > hash_size)
continue;
header_off = off;
found = 1;
break;
}
if (!found) {
fprintf(stderr, "Hash table header not found\n");
free(seg);
return 1;
}
/* Locate OEM Metadata */
uint64_t oem_md_off = header_off + 36 + common_sz + qti_sz;
uint32_t major, minor, arb;
memcpy(&major, seg + oem_md_off + 0, 4);
memcpy(&minor, seg + oem_md_off + 4, 4);
memcpy(&arb, seg + oem_md_off + 8, 4);
printf("OEM Metadata Major Version : %u\n", major);
printf("OEM Metadata Minor Version : %u\n", minor);
printf("ARB (Anti-Rollback) : %u\n", arb);
free(seg);
return 0;
}