123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include "common.h"
- #include "lzma.h"
- #include "elf_abi.h"
- #define ALIGNOFFSET 32
- extern int stub_mini_elf_len;
- extern char stub_mini_elf[];
- extern int stub_mini_debug_elf_len;
- extern char stub_mini_debug_elf[];
- extern int stub_dkf_elf_len;
- extern char stub_dkf_elf[];
- extern int stub_dkf_debug_elf_len;
- extern char stub_dkf_debug_elf[];
- extern int stub_dkfc_elf_len;
- extern char stub_dkfc_elf[];
- extern int stub_dkfc_debug_elf_len;
- extern char stub_dkfc_debug_elf[];
- typedef struct {
- const char *name;
- const int *len;
- const u8 *data;
- } stub_t;
- static const stub_t stubs[] = {
- { "mini", &stub_mini_elf_len, (u8 *) stub_mini_elf },
- { "mini_debug", &stub_mini_debug_elf_len, (u8 *) stub_mini_debug_elf },
- { "devkitfail", &stub_dkf_elf_len, (u8 *) stub_dkf_elf },
- { "devkitfail_debug", &stub_dkf_debug_elf_len, (u8 *) stub_dkf_debug_elf },
- { "dkfailchannel", &stub_dkfc_elf_len, (u8 *) stub_dkfc_elf },
- { "dkfailchannel_debug", &stub_dkfc_debug_elf_len, (u8 *) stub_dkfc_debug_elf },
- { NULL, NULL, NULL }
- };
- typedef struct {
- u8 *data;
- u32 len;
- Elf32_Ehdr *ehdr;
- Elf32_Phdr *phdrs;
- Elf32_Shdr *shdrs;
- } elf_t;
- typedef struct {
- u32 dataptr;
- u32 len_in;
- u32 len_out;
- u8 props[LZMA_PROPS_SIZE];
- } __attribute__((packed)) payload_t;
- static inline u8 *phdr_data(const elf_t *elf, const u16 ndx, const u32 off) {
- return &elf->data[be32(elf->phdrs[ndx].p_offset) + off];
- }
- static elf_t *read_stub(const char *name) {
- elf_t *elf = (elf_t *) calloc(1, sizeof(elf_t));
- if (!elf)
- die("Error allocating %u bytes", (u32) sizeof(elf_t));
- int i = 0;
- while (stubs[i].name) {
- if (!strcmp(name, stubs[i].name)) {
- printf("Using stub '%s'\n", name);
- elf->len = *(stubs[i].len);
- elf->data = (u8 *) stubs[i].data;
- return elf;
- }
- ++i;
- }
- die("Unknown stub '%s'", name);
- return NULL;
- }
- static elf_t *read_elf(const char *filename) {
- int fd;
- struct stat st;
- elf_t *elf;
- printf("Reading %s\n", filename);
- fd = open(filename, O_RDONLY);
- if (fd < 0)
- perrordie("Could not open ELF file");
- if (fstat(fd, &st))
- perrordie("Could not stat ELF file");
- if ((u32) st.st_size < sizeof(Elf32_Ehdr))
- die("File too short for ELF");
- elf = (elf_t *) calloc(1, sizeof(elf_t));
- if (!elf)
- die("Error allocating %u bytes", (u32) sizeof(elf_t));
- elf->len = st.st_size;
- elf->data = (u8 *) malloc(elf->len);
- if (!elf->data)
- die("Error allocating %u bytes", elf->len);
- if (read(fd, elf->data, elf->len) != elf->len)
- perrordie("Could not read from file");
- close(fd);
- return elf;
- }
- static void write_elf(const char *filename, const elf_t *elf) {
- int fd;
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0755);
- if (fd < 0)
- perrordie("Could not open ELF file");
- if (write(fd, elf->data, elf->len) != elf->len)
- perrordie("Could not write ELF file");
- close(fd);
- }
- static void free_elf(elf_t *elf) {
- free(elf->data);
- free(elf);
- }
- static void check_elf(elf_t *elf) {
- if (elf->len < sizeof(Elf32_Phdr))
- die("Too short for an ELF");
- Elf32_Ehdr *ehdr = (Elf32_Ehdr *) elf->data;
- if (!IS_ELF(*ehdr))
- die("Not an ELF");
- if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
- die("Invalid ELF class");
- if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
- die("Invalid ELF byte order");
- if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)
- die("Invalid ELF ident version");
- if (be16(ehdr->e_type) != ET_EXEC)
- die("ELF is not an executable");
- if (be16(ehdr->e_machine) != EM_PPC)
- die("Machine is not PowerPC");
- if (be32(ehdr->e_version) != EV_CURRENT)
- die("Invalid ELF version");
- if (!be32(ehdr->e_entry))
- die("ELF has no entrypoint");
- }
- static void init_elf(elf_t *elf, int sections) {
- elf->ehdr = (Elf32_Ehdr *) elf->data;
- u16 num = be16(elf->ehdr->e_phnum);
- u32 off = be32(elf->ehdr->e_phoff);
- if (!num || !off)
- die("ELF has no program headers");
- if (be16(elf->ehdr->e_phentsize) != sizeof(Elf32_Phdr))
- die("Invalid program header entry size");
- if ((off + num * sizeof(Elf32_Phdr)) > elf->len)
- die("Program headers out of bounds");
- elf->phdrs = (Elf32_Phdr *) &elf->data[off];
- num = be16(elf->ehdr->e_shnum);
- off = be32(elf->ehdr->e_shoff);
- if (!num || !off) {
- if (!sections) {
- elf->shdrs = NULL;
- return;
- }
- die("ELF has no section headers");
- }
- if (be16(elf->ehdr->e_shentsize) != sizeof(Elf32_Shdr))
- die("Invalid section header entry size");
- if ((off + num * sizeof(Elf32_Shdr)) > elf->len)
- die("Section headers out of bounds");
- elf->shdrs = (Elf32_Shdr *) &elf->data[off];
- }
- static u32 find_payload_offset(const elf_t *elf) {
- u16 shnum = be16(elf->ehdr->e_shnum);
- u16 shstrndx = be16(elf->ehdr->e_shstrndx);
- if (!shstrndx || shstrndx > shnum)
- die("Invalid .shstrtab index");
- u32 off = be32(elf->shdrs[shstrndx].sh_offset);
- u32 size = be32(elf->shdrs[shstrndx].sh_size);
- if (off + size > elf->len - 1)
- die(".shstrtab section out of bounds");
- const char *shstr = (const char *) &elf->data[off];
- u16 i;
- for (i = 0; i < shnum; ++i) {
- off = be32(elf->shdrs[i].sh_name);
- if (off > size)
- die("Section #%u name out of .shstrtab bounds", i);
- if (!strcmp(&shstr[off], ".payload")) {
- printf(".payload section found: #%u\n", i);
- return be32(elf->shdrs[i].sh_offset);
- }
- }
- die(".payload section not present");
- }
- static void map_file_offset(const elf_t *elf, const u32 offset,
- u16 *phdrndx, u32 *phdroff) {
- u16 phnum = be16(elf->ehdr->e_phnum);
- u16 i;
- for (i = 0; i < phnum; ++i) {
- if (be32(elf->phdrs[i].p_type) != PT_LOAD)
- continue;
- if (be32(elf->phdrs[i].p_filesz) < 1)
- continue;
- u32 poff = be32(elf->phdrs[i].p_offset);
- u32 psize = be32(elf->phdrs[i].p_filesz);
- if (offset >= poff && offset <= poff + psize) {
- *phdrndx = i;
- *phdroff = offset - poff;
- printf("Mapped payload to program header [%u] 0x%06x\n",
- *phdrndx, *phdroff);
- return;
- }
- }
- die("File offset 0x%x is not part of any PT_LOAD program header", offset);
- }
- static elf_t *strip_elf(const elf_t *elf, u16 *phdrndx) {
- elf_t *out;
- u32 pos;
- u16 count;
- u16 phnum = be16(elf->ehdr->e_phnum);
- u16 i;
- count = 0;
- pos = round_up(sizeof(Elf32_Ehdr), ALIGNOFFSET);
- for (i = 0; i < phnum; ++i) {
- if (be32(elf->phdrs[i].p_type) != PT_LOAD)
- continue;
- if (be32(elf->phdrs[i].p_filesz) < 1)
- continue;
- if (be32(elf->phdrs[i].p_memsz) < 1)
- continue;
- pos += round_up(be32(elf->phdrs[i].p_filesz), ALIGNOFFSET);
- count++;
- }
- pos += round_up(count * sizeof(Elf32_Phdr), ALIGNOFFSET);
- if (pos > 20 * 1024 * 1024)
- die("ELF too big, even after stripping (0x%x)", pos);
- printf("Stripping ELF from 0x%x to 0x%x bytes\n", elf->len, pos);
- out = (elf_t *) calloc(1, sizeof(elf_t));
- if (!out)
- die("Error allocating %u bytes", (u32) sizeof(elf_t));
- out->len = pos;
- out->data = calloc(1, pos);
- if (!out->data)
- die("Error allocating %u bytes", pos);
- out->ehdr = (Elf32_Ehdr *) out->data;
- pos = round_up(sizeof(Elf32_Ehdr), ALIGNOFFSET);
- out->ehdr->e_ident[EI_MAG0] = ELFMAG0;
- out->ehdr->e_ident[EI_MAG1] = ELFMAG1;
- out->ehdr->e_ident[EI_MAG2] = ELFMAG2;
- out->ehdr->e_ident[EI_MAG3] = ELFMAG3;
- out->ehdr->e_ident[EI_CLASS] = ELFCLASS32;
- out->ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
- out->ehdr->e_ident[EI_VERSION] = EV_CURRENT;
- out->ehdr->e_type = be16(ET_EXEC);
- out->ehdr->e_machine = be16(EM_PPC);
- out->ehdr->e_version = be32(EV_CURRENT);
- out->ehdr->e_entry = elf->ehdr->e_entry;
- out->ehdr->e_phoff = be32(pos);
- out->ehdr->e_phentsize = be16(sizeof(Elf32_Phdr));
- out->ehdr->e_phnum = be16(count);
- out->ehdr->e_shentsize = be16(sizeof(Elf32_Shdr));
- out->phdrs = (Elf32_Phdr *) &out->data[pos];
- pos += round_up(count * sizeof(Elf32_Phdr), ALIGNOFFSET);
- count = 0;
- int found = 0;
- for (i = 0; i < phnum; ++i) {
- if (be32(elf->phdrs[i].p_type) != PT_LOAD)
- continue;
- if (be32(elf->phdrs[i].p_filesz) < 1)
- continue;
- if (be32(elf->phdrs[i].p_memsz) < 1)
- continue;
- if (phdrndx && i == *phdrndx) {
- *phdrndx = count;
- found = 1;
- }
- out->phdrs[count].p_type = elf->phdrs[i].p_type;
- out->phdrs[count].p_offset = be32(pos);
- out->phdrs[count].p_vaddr = elf->phdrs[i].p_vaddr;
- out->phdrs[count].p_paddr = elf->phdrs[i].p_paddr;
- out->phdrs[count].p_filesz = elf->phdrs[i].p_filesz;
- out->phdrs[count].p_memsz = elf->phdrs[i].p_memsz;
- out->phdrs[count].p_flags = elf->phdrs[i].p_flags;
- out->phdrs[count].p_align = elf->phdrs[i].p_align;
- u32 p_offset = be32(elf->phdrs[i].p_offset);
- u32 p_filesz = be32(elf->phdrs[i].p_filesz);
- printf(" PHDR[%u] 0x%08x 0x%06x -> [%u] 0x%06x\n",
- i, p_offset, p_filesz, count, pos);
- memcpy(&out->data[pos], &elf->data[p_offset], p_filesz);
- pos += round_up(p_filesz, ALIGNOFFSET);
- count++;
- }
- if (phdrndx && !found)
- die("PHDR #%u not part of the stripped ELF", *phdrndx);
- return out;
- }
- static elf_t *inject_elf(elf_t *dst, const u8 *src, const u32 len,
- u32 *dataaddr, u8 **dataptr) {
- u16 phdrndx = be16(dst->ehdr->e_phnum) - 1;
- Elf32_Phdr *phdr = &dst->phdrs[phdrndx];
- if (phdr->p_filesz != phdr->p_memsz)
- die("File size does not match the memory size for the last PHDR");
- u32 pos = be32(phdr->p_vaddr) + be32(phdr->p_filesz);
- u32 pos_a = round_up(pos, ALIGNOFFSET);
- u32 pos_d = pos_a - pos;
- u32 size_d = pos_d + round_up(len, ALIGNOFFSET);
- printf("Injecting payload in PHDR %u, size += 0x%x (0x%x/0x%x/0x%x)\n",
- phdrndx, size_d, pos_d, len, size_d - pos_d - len);
- elf_t *elf = (elf_t *) calloc(1, sizeof(elf_t));
- if (!elf)
- die("Error allocating %u bytes", (u32) sizeof(elf_t));
- elf->data = calloc(1, dst->len + size_d);
- elf->len = dst->len + size_d;
- if (!elf->data)
- die("Failed to alloc 0x%x bytes", dst->len + size_d);
- memcpy(elf->data, dst->data, dst->len);
- init_elf(elf, 0);
- phdr = &elf->phdrs[phdrndx];
- u8 *p = phdr_data(elf, phdrndx, be32(phdr->p_filesz));
- memcpy(&p[pos_d], src, len);
- *dataaddr = pos_a - be32(phdr->p_vaddr) + be32(phdr->p_paddr);
- *dataaddr |= 0x80000000;
- phdr->p_filesz = be32(be32(phdr->p_filesz) + size_d);
- phdr->p_memsz = be32(be32(phdr->p_memsz) + size_d);
- phdr->p_vaddr = phdr->p_paddr;
- printf("Payload blob @0x%x at runtime\n", pos_a);
- *dataptr = &p[pos_d];
- return elf;
- }
- #define CLOCKS_PER_BYTE 47
- #define BUF_SIZE 256
- #define ROUNDS 256
- static void usage(const char *name) {
- printf("usage: %s [-s stub] in.elf out.elf\n", name);
- printf("stubs:");
- int i = 0;
- while (stubs[i].name) {
- printf(" %s", stubs[i].name);
- ++i;
- }
- printf("\n");
- exit(1);
- }
- int main(int argc, char *argv[]) {
- elf_t *elf_tmp, *elf_pl, *elf_stub;
- u32 offset;
- u16 phdrndx;
- u32 phdroff;
- u32 dataaddr;
- u8 *dataptr;
- lzma_t *lzma;
- printf("wiipax v0.2 (c) 2009 Team Twiizers\n\n");
- if (argc < 3)
- usage(argv[0]);
- char *stubname = "mini";
- char **arg = &argv[1];
- argc--;
- while (argc && *arg[0] == '-') {
- if (!strcmp(*arg, "-h")) {
- usage(argv[0]);
- } else if (!strcmp(*arg, "-s")) {
- if (argc < 2)
- usage(argv[0]);
- arg++;
- argc--;
- stubname = *arg;
- } else if (!strcmp(*arg, "--")) {
- arg++;
- argc--;
- break;
- } else {
- die("Unrecognized option %s\n", *arg);
- usage(argv[0]);
- }
- arg++;
- argc--;
- }
- if (argc != 2)
- usage(argv[0]);
- elf_tmp = read_stub(stubname);
- check_elf(elf_tmp);
- init_elf(elf_tmp, 1);
- offset = find_payload_offset(elf_tmp);
- map_file_offset(elf_tmp, offset, &phdrndx, &phdroff);
- elf_stub = strip_elf(elf_tmp, &phdrndx);
- free(elf_tmp);
- elf_tmp = read_elf(arg[0]);
- check_elf(elf_tmp);
- init_elf(elf_tmp, 0);
- elf_pl = strip_elf(elf_tmp, NULL);
- free_elf(elf_tmp);
- lzma = lzma_compress(elf_pl->data, elf_pl->len);
- // test decoding
- lzma_decode(lzma, elf_pl->data);
- free_elf(elf_pl);
- #if 0
- lzma_write("x.lzma", lzma);
- #endif
- u32 aes_len = (lzma->len_out + 15) & (~15);
- u8 aiv[16];
- memset(aiv, 0, 16);
- lzma->data = realloc(lzma->data, aes_len);
- memset(lzma->data + lzma->len_out, 0, aes_len - lzma->len_out);
- elf_tmp = inject_elf(elf_stub, lzma->data, aes_len, &dataaddr, &dataptr);
- free_elf(elf_stub);
- payload_t *pl = (payload_t *) phdr_data(elf_tmp, phdrndx, phdroff);
- pl->dataptr = be32(dataaddr);
- pl->len_in = be32(lzma->len_out);
- pl->len_out = be32(lzma->len_in);
- memcpy(pl->props, lzma->props, LZMA_PROPS_SIZE);
- lzma_free(lzma);
- write_elf(arg[1], elf_tmp);
- free_elf(elf_tmp);
- printf("Done.\n");
- return 0;
- }
|