main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <unistd.h>
  8. #include <fcntl.h>
  9. #include "common.h"
  10. #include "lzma.h"
  11. #include "elf_abi.h"
  12. #define ALIGNOFFSET 32
  13. extern int stub_mini_elf_len;
  14. extern char stub_mini_elf[];
  15. extern int stub_mini_debug_elf_len;
  16. extern char stub_mini_debug_elf[];
  17. extern int stub_dkf_elf_len;
  18. extern char stub_dkf_elf[];
  19. extern int stub_dkf_debug_elf_len;
  20. extern char stub_dkf_debug_elf[];
  21. extern int stub_dkfc_elf_len;
  22. extern char stub_dkfc_elf[];
  23. extern int stub_dkfc_debug_elf_len;
  24. extern char stub_dkfc_debug_elf[];
  25. typedef struct {
  26. const char *name;
  27. const int *len;
  28. const u8 *data;
  29. } stub_t;
  30. static const stub_t stubs[] = {
  31. { "mini", &stub_mini_elf_len, (u8 *) stub_mini_elf },
  32. { "mini_debug", &stub_mini_debug_elf_len, (u8 *) stub_mini_debug_elf },
  33. { "devkitfail", &stub_dkf_elf_len, (u8 *) stub_dkf_elf },
  34. { "devkitfail_debug", &stub_dkf_debug_elf_len, (u8 *) stub_dkf_debug_elf },
  35. { "dkfailchannel", &stub_dkfc_elf_len, (u8 *) stub_dkfc_elf },
  36. { "dkfailchannel_debug", &stub_dkfc_debug_elf_len, (u8 *) stub_dkfc_debug_elf },
  37. { NULL, NULL, NULL }
  38. };
  39. typedef struct {
  40. u8 *data;
  41. u32 len;
  42. Elf32_Ehdr *ehdr;
  43. Elf32_Phdr *phdrs;
  44. Elf32_Shdr *shdrs;
  45. } elf_t;
  46. typedef struct {
  47. u32 dataptr;
  48. u32 len_in;
  49. u32 len_out;
  50. u8 props[LZMA_PROPS_SIZE];
  51. } __attribute__((packed)) payload_t;
  52. static inline u8 *phdr_data(const elf_t *elf, const u16 ndx, const u32 off) {
  53. return &elf->data[be32(elf->phdrs[ndx].p_offset) + off];
  54. }
  55. static elf_t *read_stub(const char *name) {
  56. elf_t *elf = (elf_t *) calloc(1, sizeof(elf_t));
  57. if (!elf)
  58. die("Error allocating %u bytes", (u32) sizeof(elf_t));
  59. int i = 0;
  60. while (stubs[i].name) {
  61. if (!strcmp(name, stubs[i].name)) {
  62. printf("Using stub '%s'\n", name);
  63. elf->len = *(stubs[i].len);
  64. elf->data = (u8 *) stubs[i].data;
  65. return elf;
  66. }
  67. ++i;
  68. }
  69. die("Unknown stub '%s'", name);
  70. return NULL;
  71. }
  72. static elf_t *read_elf(const char *filename) {
  73. int fd;
  74. struct stat st;
  75. elf_t *elf;
  76. printf("Reading %s\n", filename);
  77. fd = open(filename, O_RDONLY);
  78. if (fd < 0)
  79. perrordie("Could not open ELF file");
  80. if (fstat(fd, &st))
  81. perrordie("Could not stat ELF file");
  82. if ((u32) st.st_size < sizeof(Elf32_Ehdr))
  83. die("File too short for ELF");
  84. elf = (elf_t *) calloc(1, sizeof(elf_t));
  85. if (!elf)
  86. die("Error allocating %u bytes", (u32) sizeof(elf_t));
  87. elf->len = st.st_size;
  88. elf->data = (u8 *) malloc(elf->len);
  89. if (!elf->data)
  90. die("Error allocating %u bytes", elf->len);
  91. if (read(fd, elf->data, elf->len) != elf->len)
  92. perrordie("Could not read from file");
  93. close(fd);
  94. return elf;
  95. }
  96. static void write_elf(const char *filename, const elf_t *elf) {
  97. int fd;
  98. fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0755);
  99. if (fd < 0)
  100. perrordie("Could not open ELF file");
  101. if (write(fd, elf->data, elf->len) != elf->len)
  102. perrordie("Could not write ELF file");
  103. close(fd);
  104. }
  105. static void free_elf(elf_t *elf) {
  106. free(elf->data);
  107. free(elf);
  108. }
  109. static void check_elf(elf_t *elf) {
  110. if (elf->len < sizeof(Elf32_Phdr))
  111. die("Too short for an ELF");
  112. Elf32_Ehdr *ehdr = (Elf32_Ehdr *) elf->data;
  113. if (!IS_ELF(*ehdr))
  114. die("Not an ELF");
  115. if (ehdr->e_ident[EI_CLASS] != ELFCLASS32)
  116. die("Invalid ELF class");
  117. if (ehdr->e_ident[EI_DATA] != ELFDATA2MSB)
  118. die("Invalid ELF byte order");
  119. if (ehdr->e_ident[EI_VERSION] != EV_CURRENT)
  120. die("Invalid ELF ident version");
  121. if (be16(ehdr->e_type) != ET_EXEC)
  122. die("ELF is not an executable");
  123. if (be16(ehdr->e_machine) != EM_PPC)
  124. die("Machine is not PowerPC");
  125. if (be32(ehdr->e_version) != EV_CURRENT)
  126. die("Invalid ELF version");
  127. if (!be32(ehdr->e_entry))
  128. die("ELF has no entrypoint");
  129. }
  130. static void init_elf(elf_t *elf, int sections) {
  131. elf->ehdr = (Elf32_Ehdr *) elf->data;
  132. u16 num = be16(elf->ehdr->e_phnum);
  133. u32 off = be32(elf->ehdr->e_phoff);
  134. if (!num || !off)
  135. die("ELF has no program headers");
  136. if (be16(elf->ehdr->e_phentsize) != sizeof(Elf32_Phdr))
  137. die("Invalid program header entry size");
  138. if ((off + num * sizeof(Elf32_Phdr)) > elf->len)
  139. die("Program headers out of bounds");
  140. elf->phdrs = (Elf32_Phdr *) &elf->data[off];
  141. num = be16(elf->ehdr->e_shnum);
  142. off = be32(elf->ehdr->e_shoff);
  143. if (!num || !off) {
  144. if (!sections) {
  145. elf->shdrs = NULL;
  146. return;
  147. }
  148. die("ELF has no section headers");
  149. }
  150. if (be16(elf->ehdr->e_shentsize) != sizeof(Elf32_Shdr))
  151. die("Invalid section header entry size");
  152. if ((off + num * sizeof(Elf32_Shdr)) > elf->len)
  153. die("Section headers out of bounds");
  154. elf->shdrs = (Elf32_Shdr *) &elf->data[off];
  155. }
  156. static u32 find_payload_offset(const elf_t *elf) {
  157. u16 shnum = be16(elf->ehdr->e_shnum);
  158. u16 shstrndx = be16(elf->ehdr->e_shstrndx);
  159. if (!shstrndx || shstrndx > shnum)
  160. die("Invalid .shstrtab index");
  161. u32 off = be32(elf->shdrs[shstrndx].sh_offset);
  162. u32 size = be32(elf->shdrs[shstrndx].sh_size);
  163. if (off + size > elf->len - 1)
  164. die(".shstrtab section out of bounds");
  165. const char *shstr = (const char *) &elf->data[off];
  166. u16 i;
  167. for (i = 0; i < shnum; ++i) {
  168. off = be32(elf->shdrs[i].sh_name);
  169. if (off > size)
  170. die("Section #%u name out of .shstrtab bounds", i);
  171. if (!strcmp(&shstr[off], ".payload")) {
  172. printf(".payload section found: #%u\n", i);
  173. return be32(elf->shdrs[i].sh_offset);
  174. }
  175. }
  176. die(".payload section not present");
  177. }
  178. static void map_file_offset(const elf_t *elf, const u32 offset,
  179. u16 *phdrndx, u32 *phdroff) {
  180. u16 phnum = be16(elf->ehdr->e_phnum);
  181. u16 i;
  182. for (i = 0; i < phnum; ++i) {
  183. if (be32(elf->phdrs[i].p_type) != PT_LOAD)
  184. continue;
  185. if (be32(elf->phdrs[i].p_filesz) < 1)
  186. continue;
  187. u32 poff = be32(elf->phdrs[i].p_offset);
  188. u32 psize = be32(elf->phdrs[i].p_filesz);
  189. if (offset >= poff && offset <= poff + psize) {
  190. *phdrndx = i;
  191. *phdroff = offset - poff;
  192. printf("Mapped payload to program header [%u] 0x%06x\n",
  193. *phdrndx, *phdroff);
  194. return;
  195. }
  196. }
  197. die("File offset 0x%x is not part of any PT_LOAD program header", offset);
  198. }
  199. static elf_t *strip_elf(const elf_t *elf, u16 *phdrndx) {
  200. elf_t *out;
  201. u32 pos;
  202. u16 count;
  203. u16 phnum = be16(elf->ehdr->e_phnum);
  204. u16 i;
  205. count = 0;
  206. pos = round_up(sizeof(Elf32_Ehdr), ALIGNOFFSET);
  207. for (i = 0; i < phnum; ++i) {
  208. if (be32(elf->phdrs[i].p_type) != PT_LOAD)
  209. continue;
  210. if (be32(elf->phdrs[i].p_filesz) < 1)
  211. continue;
  212. if (be32(elf->phdrs[i].p_memsz) < 1)
  213. continue;
  214. pos += round_up(be32(elf->phdrs[i].p_filesz), ALIGNOFFSET);
  215. count++;
  216. }
  217. pos += round_up(count * sizeof(Elf32_Phdr), ALIGNOFFSET);
  218. if (pos > 20 * 1024 * 1024)
  219. die("ELF too big, even after stripping (0x%x)", pos);
  220. printf("Stripping ELF from 0x%x to 0x%x bytes\n", elf->len, pos);
  221. out = (elf_t *) calloc(1, sizeof(elf_t));
  222. if (!out)
  223. die("Error allocating %u bytes", (u32) sizeof(elf_t));
  224. out->len = pos;
  225. out->data = calloc(1, pos);
  226. if (!out->data)
  227. die("Error allocating %u bytes", pos);
  228. out->ehdr = (Elf32_Ehdr *) out->data;
  229. pos = round_up(sizeof(Elf32_Ehdr), ALIGNOFFSET);
  230. out->ehdr->e_ident[EI_MAG0] = ELFMAG0;
  231. out->ehdr->e_ident[EI_MAG1] = ELFMAG1;
  232. out->ehdr->e_ident[EI_MAG2] = ELFMAG2;
  233. out->ehdr->e_ident[EI_MAG3] = ELFMAG3;
  234. out->ehdr->e_ident[EI_CLASS] = ELFCLASS32;
  235. out->ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
  236. out->ehdr->e_ident[EI_VERSION] = EV_CURRENT;
  237. out->ehdr->e_type = be16(ET_EXEC);
  238. out->ehdr->e_machine = be16(EM_PPC);
  239. out->ehdr->e_version = be32(EV_CURRENT);
  240. out->ehdr->e_entry = elf->ehdr->e_entry;
  241. out->ehdr->e_phoff = be32(pos);
  242. out->ehdr->e_phentsize = be16(sizeof(Elf32_Phdr));
  243. out->ehdr->e_phnum = be16(count);
  244. out->ehdr->e_shentsize = be16(sizeof(Elf32_Shdr));
  245. out->phdrs = (Elf32_Phdr *) &out->data[pos];
  246. pos += round_up(count * sizeof(Elf32_Phdr), ALIGNOFFSET);
  247. count = 0;
  248. int found = 0;
  249. for (i = 0; i < phnum; ++i) {
  250. if (be32(elf->phdrs[i].p_type) != PT_LOAD)
  251. continue;
  252. if (be32(elf->phdrs[i].p_filesz) < 1)
  253. continue;
  254. if (be32(elf->phdrs[i].p_memsz) < 1)
  255. continue;
  256. if (phdrndx && i == *phdrndx) {
  257. *phdrndx = count;
  258. found = 1;
  259. }
  260. out->phdrs[count].p_type = elf->phdrs[i].p_type;
  261. out->phdrs[count].p_offset = be32(pos);
  262. out->phdrs[count].p_vaddr = elf->phdrs[i].p_vaddr;
  263. out->phdrs[count].p_paddr = elf->phdrs[i].p_paddr;
  264. out->phdrs[count].p_filesz = elf->phdrs[i].p_filesz;
  265. out->phdrs[count].p_memsz = elf->phdrs[i].p_memsz;
  266. out->phdrs[count].p_flags = elf->phdrs[i].p_flags;
  267. out->phdrs[count].p_align = elf->phdrs[i].p_align;
  268. u32 p_offset = be32(elf->phdrs[i].p_offset);
  269. u32 p_filesz = be32(elf->phdrs[i].p_filesz);
  270. printf(" PHDR[%u] 0x%08x 0x%06x -> [%u] 0x%06x\n",
  271. i, p_offset, p_filesz, count, pos);
  272. memcpy(&out->data[pos], &elf->data[p_offset], p_filesz);
  273. pos += round_up(p_filesz, ALIGNOFFSET);
  274. count++;
  275. }
  276. if (phdrndx && !found)
  277. die("PHDR #%u not part of the stripped ELF", *phdrndx);
  278. return out;
  279. }
  280. static elf_t *inject_elf(elf_t *dst, const u8 *src, const u32 len,
  281. u32 *dataaddr, u8 **dataptr) {
  282. u16 phdrndx = be16(dst->ehdr->e_phnum) - 1;
  283. Elf32_Phdr *phdr = &dst->phdrs[phdrndx];
  284. if (phdr->p_filesz != phdr->p_memsz)
  285. die("File size does not match the memory size for the last PHDR");
  286. u32 pos = be32(phdr->p_vaddr) + be32(phdr->p_filesz);
  287. u32 pos_a = round_up(pos, ALIGNOFFSET);
  288. u32 pos_d = pos_a - pos;
  289. u32 size_d = pos_d + round_up(len, ALIGNOFFSET);
  290. printf("Injecting payload in PHDR %u, size += 0x%x (0x%x/0x%x/0x%x)\n",
  291. phdrndx, size_d, pos_d, len, size_d - pos_d - len);
  292. elf_t *elf = (elf_t *) calloc(1, sizeof(elf_t));
  293. if (!elf)
  294. die("Error allocating %u bytes", (u32) sizeof(elf_t));
  295. elf->data = calloc(1, dst->len + size_d);
  296. elf->len = dst->len + size_d;
  297. if (!elf->data)
  298. die("Failed to alloc 0x%x bytes", dst->len + size_d);
  299. memcpy(elf->data, dst->data, dst->len);
  300. init_elf(elf, 0);
  301. phdr = &elf->phdrs[phdrndx];
  302. u8 *p = phdr_data(elf, phdrndx, be32(phdr->p_filesz));
  303. memcpy(&p[pos_d], src, len);
  304. *dataaddr = pos_a - be32(phdr->p_vaddr) + be32(phdr->p_paddr);
  305. *dataaddr |= 0x80000000;
  306. phdr->p_filesz = be32(be32(phdr->p_filesz) + size_d);
  307. phdr->p_memsz = be32(be32(phdr->p_memsz) + size_d);
  308. phdr->p_vaddr = phdr->p_paddr;
  309. printf("Payload blob @0x%x at runtime\n", pos_a);
  310. *dataptr = &p[pos_d];
  311. return elf;
  312. }
  313. #define CLOCKS_PER_BYTE 47
  314. #define BUF_SIZE 256
  315. #define ROUNDS 256
  316. static void usage(const char *name) {
  317. printf("usage: %s [-s stub] in.elf out.elf\n", name);
  318. printf("stubs:");
  319. int i = 0;
  320. while (stubs[i].name) {
  321. printf(" %s", stubs[i].name);
  322. ++i;
  323. }
  324. printf("\n");
  325. exit(1);
  326. }
  327. int main(int argc, char *argv[]) {
  328. elf_t *elf_tmp, *elf_pl, *elf_stub;
  329. u32 offset;
  330. u16 phdrndx;
  331. u32 phdroff;
  332. u32 dataaddr;
  333. u8 *dataptr;
  334. lzma_t *lzma;
  335. printf("wiipax v0.2 (c) 2009 Team Twiizers\n\n");
  336. if (argc < 3)
  337. usage(argv[0]);
  338. char *stubname = "mini";
  339. char **arg = &argv[1];
  340. argc--;
  341. while (argc && *arg[0] == '-') {
  342. if (!strcmp(*arg, "-h")) {
  343. usage(argv[0]);
  344. } else if (!strcmp(*arg, "-s")) {
  345. if (argc < 2)
  346. usage(argv[0]);
  347. arg++;
  348. argc--;
  349. stubname = *arg;
  350. } else if (!strcmp(*arg, "--")) {
  351. arg++;
  352. argc--;
  353. break;
  354. } else {
  355. die("Unrecognized option %s\n", *arg);
  356. usage(argv[0]);
  357. }
  358. arg++;
  359. argc--;
  360. }
  361. if (argc != 2)
  362. usage(argv[0]);
  363. elf_tmp = read_stub(stubname);
  364. check_elf(elf_tmp);
  365. init_elf(elf_tmp, 1);
  366. offset = find_payload_offset(elf_tmp);
  367. map_file_offset(elf_tmp, offset, &phdrndx, &phdroff);
  368. elf_stub = strip_elf(elf_tmp, &phdrndx);
  369. free(elf_tmp);
  370. elf_tmp = read_elf(arg[0]);
  371. check_elf(elf_tmp);
  372. init_elf(elf_tmp, 0);
  373. elf_pl = strip_elf(elf_tmp, NULL);
  374. free_elf(elf_tmp);
  375. lzma = lzma_compress(elf_pl->data, elf_pl->len);
  376. // test decoding
  377. lzma_decode(lzma, elf_pl->data);
  378. free_elf(elf_pl);
  379. #if 0
  380. lzma_write("x.lzma", lzma);
  381. #endif
  382. u32 aes_len = (lzma->len_out + 15) & (~15);
  383. u8 aiv[16];
  384. memset(aiv, 0, 16);
  385. lzma->data = realloc(lzma->data, aes_len);
  386. memset(lzma->data + lzma->len_out, 0, aes_len - lzma->len_out);
  387. elf_tmp = inject_elf(elf_stub, lzma->data, aes_len, &dataaddr, &dataptr);
  388. free_elf(elf_stub);
  389. payload_t *pl = (payload_t *) phdr_data(elf_tmp, phdrndx, phdroff);
  390. pl->dataptr = be32(dataaddr);
  391. pl->len_in = be32(lzma->len_out);
  392. pl->len_out = be32(lzma->len_in);
  393. memcpy(pl->props, lzma->props, LZMA_PROPS_SIZE);
  394. lzma_free(lzma);
  395. write_elf(arg[1], elf_tmp);
  396. free_elf(elf_tmp);
  397. printf("Done.\n");
  398. return 0;
  399. }