├── .github └── FUNDING.yml ├── .gitignore ├── Makefile ├── elfboot.h └── elftool.cpp /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: osm0sis # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: https://www.paypal.me/osm0sis # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.exe 3 | elftool -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(CC),cc) 2 | CC = g++ 3 | endif 4 | AR = ar rc 5 | ifeq ($(windir),) 6 | EXT = 7 | RM = rm -f 8 | CP = cp 9 | else 10 | EXT = .exe 11 | RM = del 12 | CP = copy /y 13 | endif 14 | 15 | CFLAGS += -ffunction-sections -O3 16 | 17 | INC = -I. 18 | 19 | ifneq (,$(findstring darwin,$(CROSS_COMPILE))) 20 | UNAME_S := Darwin 21 | else 22 | UNAME_S := $(shell uname -s) 23 | endif 24 | ifeq ($(UNAME_S),Darwin) 25 | LDFLAGS += -Wl,-dead_strip 26 | else 27 | LDFLAGS += -Wl,--gc-sections -s 28 | endif 29 | 30 | all:elftool$(EXT) 31 | 32 | static: 33 | $(MAKE) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS) -static" 34 | 35 | elftool$(EXT):elftool.o 36 | $(CROSS_COMPILE)$(CC) -o $@ $^ $(LDFLAGS) 37 | 38 | %.o:%.cpp 39 | $(CROSS_COMPILE)$(CC) -o $@ $(CFLAGS) -c $< $(INC) -Werror 40 | 41 | install: 42 | install -m 755 elftool$(EXT) $(PREFIX)/bin 43 | 44 | clean: 45 | $(RM) elftool 46 | $(RM) *.a *.~ *.exe *.o 47 | 48 | -------------------------------------------------------------------------------- /elfboot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: elfboot.h 3 | * Author: srl3gx@gmail.com 4 | * 5 | * 6 | */ 7 | 8 | #ifndef ELFBOOT_H 9 | #define ELFBOOT_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | struct elf_header { 16 | char e_ident[8]; 17 | char padding[8]; 18 | unsigned short int e_type; 19 | unsigned short int e_machine; 20 | unsigned int e_version; 21 | unsigned int e_entry; 22 | unsigned int e_phoff; 23 | unsigned int e_shoff; 24 | unsigned int e_flags; 25 | unsigned short int e_ehsize; 26 | unsigned short int e_phnetsize; 27 | unsigned short int e_phnum; 28 | unsigned short int e_shentsize; 29 | unsigned short int e_shnum; 30 | unsigned short int e_shstrndx; 31 | }; 32 | 33 | struct elfphdr { 34 | unsigned int p_type; 35 | unsigned int p_offset; 36 | unsigned int p_vaddr; 37 | unsigned int p_paddr; 38 | unsigned int p_filesz; 39 | unsigned int p_memsz; 40 | unsigned int p_flags; 41 | unsigned int p_align; 42 | }; 43 | 44 | const char elf_magic[8] = {0x7F, 0x45, 0x4C, 0x46, 0x01, 0x01, 0x01, 0x61}; 45 | const int elf_header_size = 52; 46 | const int elf_p_header_size = 32; 47 | const int elf_magic_size = 8; 48 | 49 | const unsigned int p_flags_ramdisk = 0x80000000; 50 | const unsigned int p_flags_ipl = 0x40000000; 51 | const unsigned int p_flags_cmdline = 0x20000000; 52 | const unsigned int p_flags_rpm = 0x01000000; 53 | const unsigned int p_flags_kernel = 0; 54 | 55 | 56 | #ifdef __cplusplus 57 | } 58 | #endif 59 | 60 | #endif /* ELFBOOT_H */ 61 | 62 | -------------------------------------------------------------------------------- /elftool.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: packelf.cpp 3 | * Author: srl3gx@gmail.com 4 | * 5 | * Packing and unpacking boot image of sony mobile devices 6 | * https://forum.xda-developers.com/xperia-j-e/development/arm-elftool-pack-unpack-boot-image-sony-t2146022 7 | * 8 | * Thanks to sony for providing boot image format in packelf.py 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "elfboot.h" 18 | 19 | using namespace std; 20 | 21 | void handlePackElf(int, char**); 22 | void handleUnpackElf(int, char**); 23 | void usage(); 24 | unsigned int getAddressFromHeader(string); 25 | 26 | long getFileSize(FILE*); 27 | void writeElfHeader(FILE*, unsigned int, int); 28 | 29 | struct elfphdr part_headers[5]; 30 | 31 | struct file { 32 | string file_path; 33 | unsigned int address; 34 | unsigned int size; 35 | string flag; 36 | unsigned int offset; 37 | }; 38 | 39 | void writeElfPHeader(FILE*, struct file); 40 | 41 | int main(int argc, char** argv) { 42 | if (argc <= 1) { 43 | printf("Invalid format...EXIT\n"); 44 | usage(); 45 | } 46 | char* arg = argv[1]; 47 | if (strcmp(arg, "pack") == 0) { 48 | printf("Packing elf file.....\n"); 49 | handlePackElf(argc, argv); 50 | } else if (strcmp(arg, "unpack") == 0) { 51 | printf("Unpacking elf file.....\n"); 52 | handleUnpackElf(argc, argv); 53 | } else { 54 | printf("Invalid format....EXIT"); 55 | usage(); 56 | } 57 | return 0; 58 | } 59 | 60 | void handlePackElf(int argc, char** argv) { 61 | struct file files[argc - 1]; 62 | string output_path; 63 | FILE *header; 64 | FILE *temp_file; 65 | int parts = 0; 66 | int offset = 4096; 67 | for (int i = 2; i < argc; i++) { 68 | char* arg = argv[i]; 69 | string arguments[3]; 70 | if (strcmp(arg, "-o") == 0 || strcmp(arg, "--output") == 0) { 71 | i++; 72 | output_path = argv[i]; 73 | continue; 74 | } 75 | arg = strtok(arg, "@,="); 76 | int k = 0; 77 | while (arg != NULL) { 78 | arguments[k] = arg; 79 | arg = strtok(NULL, "@,"); 80 | k++; 81 | } 82 | long address; 83 | if (arguments[1].compare("cmdline") == 0) { 84 | address = 0L; 85 | arguments[2] = "cmdline"; 86 | } else if (arguments[0].compare("header") == 0) { 87 | header = fopen(arguments[1].c_str(), "rb"); 88 | struct elf_header boot_header; 89 | fseek(header, 0, SEEK_SET); 90 | if (fread(&boot_header, elf_header_size, 1, header)) {}; 91 | if (memcmp(boot_header.e_ident, elf_magic, 8) != 0) { 92 | printf("Header file is not a valid elf image header...Exit"); 93 | exit(EXIT_FAILURE); 94 | } 95 | int offset = 52; 96 | for (int i = 0; i < boot_header.e_phnum; i++) { 97 | struct elfphdr part_header; 98 | fseek(header, offset, SEEK_SET); 99 | if (fread(&part_header, elf_p_header_size, 1, header)) {}; 100 | part_headers[i] = part_header; 101 | offset += 32; 102 | } 103 | fclose(header); 104 | continue; 105 | } else { 106 | address = strtol(arguments[1].c_str(), NULL, 16); 107 | if (address == 0) { 108 | if (arguments[1].empty()){ 109 | arguments[1] = "kernel"; 110 | } 111 | arguments[2] = arguments[1]; 112 | address = getAddressFromHeader(arguments[1]); 113 | } 114 | } 115 | printf("Reading file %s\n", arguments[0].c_str()); 116 | temp_file = fopen(arguments[0].c_str(), "r"); 117 | if (temp_file == NULL) { 118 | printf("Failed to open %s\n", arguments[0].c_str()); 119 | exit(EXIT_FAILURE); 120 | } 121 | long size = getFileSize(temp_file); 122 | struct file f = { 123 | arguments[0], 124 | static_cast(address), 125 | static_cast(size), 126 | arguments[2], 127 | static_cast(offset) 128 | }; 129 | offset += size; 130 | fclose(temp_file); 131 | files[parts] = f; 132 | parts++; 133 | } 134 | 135 | if (parts < 2) { 136 | printf("Kernel and ramdisk must be specified....Error\n"); 137 | usage(); 138 | } 139 | 140 | if (output_path.empty()) { 141 | printf("Output path must be specified....Error\n"); 142 | usage(); 143 | } 144 | 145 | FILE* output_file = fopen(output_path.c_str(), "wb"); 146 | 147 | if (output_file == NULL) { 148 | printf("Invalid path %s\n", output_path.c_str()); 149 | } 150 | 151 | writeElfHeader(output_file, files[0].address, parts); 152 | 153 | for (int i = 0; i < parts; i++) { 154 | writeElfPHeader(output_file, files[i]); 155 | } 156 | for (int i = 0; i < parts; i++) { 157 | struct file current_file = files[i]; 158 | fseek(output_file, current_file.offset, SEEK_SET); 159 | printf("Writing file : %s to elf image\n", current_file.file_path.c_str()); 160 | temp_file = fopen(current_file.file_path.c_str(), "r"); 161 | if (temp_file == NULL) { 162 | printf("Cannot read file %s\n", current_file.file_path.c_str()); 163 | exit(EXIT_FAILURE); 164 | } 165 | int size = getFileSize(temp_file); 166 | unsigned char* data = new unsigned char [size]; 167 | fseek(temp_file, 0, SEEK_SET); 168 | if (fread(data, size, 1, temp_file)) {}; 169 | fclose(temp_file); 170 | fwrite(data, size, 1, output_file); 171 | } 172 | fclose(output_file); 173 | } 174 | 175 | void writeElfHeader(FILE* file, unsigned int address, int number) { 176 | printf("Writing elf header\t address : %x \t number : %i\n", address, number); 177 | struct elf_header header = { 178 | {0x7F, 0x45, 0x4C, 0x46, 0x01, 0x01, 0x01, 0x61}, 179 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 180 | 2, 181 | 40, 182 | 1, 183 | address, 184 | 52, 185 | 0, 186 | 0, 187 | 52, 188 | 32, 189 | static_cast(number), 190 | 0, 191 | 0, 192 | 0 193 | }; 194 | fwrite((char *) &header, sizeof (header), 1, file); 195 | } 196 | 197 | void writeElfPHeader(FILE* file, struct file f) { 198 | printf("Writing part header for %s\t", f.file_path.c_str()); 199 | long flags; 200 | long type = 1; 201 | if (f.flag.compare("ramdisk") == 0) { 202 | printf("Found ramdisk\n"); 203 | flags = 0x80000000; 204 | } else if (f.flag.compare("ipl") == 0) { 205 | printf("Found ipl\n"); 206 | flags = 0x40000000; 207 | } else if (f.flag.compare("cmdline") == 0) { 208 | printf("Found cmdline\n"); 209 | flags = 0x20000000; 210 | type = 4; 211 | } else if (f.flag.compare("rpm") == 0) { 212 | printf("Found rpm\n"); 213 | flags = 0x01000000; 214 | } else { 215 | printf("Using zero flag\n"); 216 | flags = 0; 217 | } 218 | printf("Write part header part:%s offset:%i address:%x, size:%i\n", f.flag.c_str(), f.offset, f.address, f.size); 219 | struct elfphdr phdr = { 220 | static_cast(type), 221 | f.offset, 222 | f.address, 223 | f.address, 224 | f.size, 225 | f.size, 226 | static_cast(flags), 227 | 0 228 | }; 229 | fwrite((char *) &phdr, sizeof (phdr), 1, file); 230 | } 231 | 232 | long getFileSize(FILE* file) { 233 | fseek(file, 0, SEEK_END); 234 | return ftell(file); 235 | } 236 | 237 | void handleUnpackElf(int argc, char** argv) { 238 | 239 | string input_path; 240 | string output_path; 241 | 242 | for (int i = 2; i < argc; i += 2) { 243 | char* arg = argv[i]; 244 | if (strcmp(arg, "-i") == 0 || strcmp(arg, "--input") == 0) { 245 | input_path = argv[i + 1]; 246 | } else if (strcmp(arg, "-o") == 0 || strcmp(arg, "--output") == 0) { 247 | output_path = argv[i + 1]; 248 | } 249 | } 250 | 251 | if (input_path.empty()) { 252 | printf("Input path not provided...Exit\n"); 253 | usage(); 254 | } 255 | if (output_path.empty()) { 256 | printf("Output path must be specified....Exit\n"); 257 | usage(); 258 | } 259 | 260 | int offset = 0; 261 | FILE* temp; 262 | string tempstr; 263 | 264 | FILE* input_file = fopen(input_path.c_str(), "rb"); 265 | 266 | if (input_file == NULL) { 267 | printf("Cannot read input boot image %s....Exit", input_path.c_str()); 268 | } 269 | 270 | fseek(input_file, offset, SEEK_SET); 271 | struct elf_header header; 272 | if (fread(&header, elf_header_size, 1, input_file)) {}; 273 | offset += elf_header_size; 274 | 275 | if (memcmp(elf_magic, header.e_ident, elf_magic_size) != 0) { 276 | printf("ELF magic not found....EXIT"); 277 | exit(EXIT_FAILURE); 278 | } 279 | 280 | int number_of_parts = header.e_phnum; 281 | printf("Found %i parts in elf image\n", number_of_parts); 282 | 283 | struct elfphdr pheaders[number_of_parts]; 284 | 285 | for (int i = 0; i < number_of_parts; i++) { 286 | fseek(input_file, offset, SEEK_SET); 287 | if (fread(&pheaders[i], elf_p_header_size, 1, input_file)) {}; 288 | offset += elf_p_header_size; 289 | } 290 | 291 | //dump header 292 | printf("Writing header....\n"); 293 | unsigned char* fileBuffer = (unsigned char*) malloc(4096); 294 | fseek(input_file, 0, SEEK_SET); 295 | if (fread(fileBuffer, 4096, 1, input_file)) {}; 296 | tempstr = output_path + "/header"; 297 | temp = fopen(tempstr.c_str(), "w+"); 298 | fwrite(fileBuffer, 4096, 1, temp); 299 | fclose(temp); 300 | free(fileBuffer); 301 | printf("Done...\n"); 302 | 303 | for (int i = 0; i < number_of_parts; i++) { 304 | struct elfphdr pheader = pheaders[i]; 305 | printf("flag : %u\n", pheader.p_flags); 306 | printf("offset : %i\n", pheader.p_offset); 307 | printf("size : %i\n", pheader.p_memsz); 308 | string name; 309 | switch (pheader.p_flags) { 310 | case p_flags_cmdline: 311 | name = "cmdline"; 312 | break; 313 | case p_flags_kernel: 314 | name = "kernel"; 315 | break; 316 | case p_flags_ipl: 317 | name = "ipl"; 318 | break; 319 | case p_flags_rpm: 320 | name = "rpm"; 321 | default: 322 | name = "ramdisk"; 323 | } 324 | tempstr = output_path + "/" + name; 325 | printf("%s found at offset %i with size %i\n", name.c_str(), pheader.p_offset, pheader.p_memsz); 326 | temp = fopen(tempstr.c_str(), "w+"); 327 | unsigned char* buffer = (unsigned char*) malloc(pheader.p_memsz); 328 | fseek(input_file, pheader.p_offset, SEEK_SET); 329 | if (fread(buffer, pheader.p_memsz, 1, input_file)) {}; 330 | fwrite(buffer, pheader.p_memsz, 1, temp); 331 | fclose(temp); 332 | free(buffer); 333 | } 334 | fclose(input_file); 335 | } 336 | 337 | unsigned int getAddressFromHeader(string flag) { 338 | unsigned int part_flag; 339 | if (flag.compare("cmdline") == 0) { 340 | part_flag = p_flags_cmdline; 341 | } else if (flag.compare("kernel") == 0) { 342 | part_flag = p_flags_kernel; 343 | } else if (flag.compare("ramdisk") == 0) { 344 | part_flag = p_flags_ramdisk; 345 | } else if (flag.compare("rpm") == 0) { 346 | part_flag = p_flags_rpm; 347 | } else if (flag.compare("ipl") == 0) { 348 | part_flag = p_flags_ipl; 349 | } else { 350 | printf("Unknown flag : %s\n", flag.c_str()); 351 | exit(EXIT_FAILURE); 352 | } 353 | for (int i = 0; i < 5; i++) { 354 | struct elfphdr part_header; 355 | part_header = part_headers[i]; 356 | if (part_header.p_flags == part_flag) { 357 | return part_header.p_paddr; 358 | } 359 | } 360 | printf("Address of %x cannot found from header file", part_flag); 361 | exit(EXIT_FAILURE); 362 | } 363 | 364 | void usage() { 365 | printf("Usage:\n\n"); 366 | printf("For packing\n"); 367 | printf("If you have header file containing address of kernel, ramdisk etc..\n"); 368 | printf("elftool pack -o output-path header=path/to/header kernel-path " 369 | "ramdisk-path,ramdisk ipl-path,ipl " 370 | "rpm-path,rpm cmdline-path@cmdline\n\n"); 371 | printf("elftool pack -o output-path kernel-path@address " 372 | "ramdisk-path@address,ramdisk ipl-path@address,ipl " 373 | "rpm-path@address,rpm cmdline-path@cmdline\n\n"); 374 | printf("For unpacking\n"); 375 | printf("elftool unpack -i input-path -o output-path\n"); 376 | exit(EXIT_FAILURE); 377 | } 378 | 379 | --------------------------------------------------------------------------------