/* uncripple.c - section header table fixer by [ByteRage] (byterage@yahoo.com) * http://www.byterage.cjb.net * * This program appends a section header table to an ELF file that hasn't got * one, this makes it easier to reverse engineer certain 'crippled' ELF files. * (older versions of IDA can deal with the ELF file, objdump works again, * gdb works again, etc...) This source compiles under Linux. * * example usage (together with burndump) : * # gcc -c burndump.c * # gcc uncripple.c -o uncripple * # insmod burndump * # ./burneye * # rmmod burndump * # ./uncripple burnout * # gdb burnout * gdb> run */ #include <stdio.h> #include <elf.h> char * et(e_type) { switch(e_type) { case 0 : return "ET_NONE"; case 1 : return "ET_REL"; case 2 : return "ET_EXEC"; case 3 : return "ET_DYN"; case 4 : return "ET_CORE"; case 0xff00: return "ET_LOPROC"; case 0xffff: return "ET_HIPROC"; default : return "<unknown>"; } } char * em(e_machine) { switch(e_machine) { case 0 : return "EM_NONE"; case 1 : return "EM_32"; case 2 : return "EM_SPARC"; case 3 : return "EM_386"; case 4 : return "EM_68K"; case 5 : return "EM_88K"; case 6 : return "EM_486"; case 7 : return "EM_860"; case 8 : return "EM_MIPS"; case 10: return "EM_MIPS_RS4_BE"; case 15: return "EM_PARISC"; case 18: return "EM_SPARC32PLUS"; case 20: return "EM_PPC"; case 42: return "EM_SH"; case 43: return "EM_SPARCV9"; case 50: return "EM_IA_64"; case 62: return "EM_X8664"; case 76: return "EM_CRIS"; default : return "<unknown>"; } } char * pt(p_type) { switch(p_type) { case 0 : return "PT_NULL"; case 1 : return "PT_LOAD"; case 2 : return "PT_DYNAMIC"; case 3 : return "PT_INTERP"; case 4 : return "PT_NOTE"; case 5 : return "PT_SHLIB"; case 6 : return "PT_PHDR"; case 0x70000000: return "PT_LOPROC / PT_MIPS_REGINFO"; case 0x7fffffff: return "PT_HIPROC"; default : return "<unknown>"; } } char * sht(sh_type) { switch(sh_type) { case 0 : return "SHT_NULL"; case 1 : return "SHT_PROGBITS"; case 2 : return "SHT_SYMTAB"; case 3 : return "SHT_STRTAB"; case 4 : return "SHT_RELA"; case 5 : return "SHT_HASH"; case 6 : return "SHT_DYNAMIC"; case 7 : return "SHT_NOTE"; case 8 : return "SHT_NOBITS"; case 9 : return "SHT_REL"; case 10: return "SHT_SHLIB"; case 11: return "SHT_DYNSYM"; case 12: return "SHT_NUM"; case 0x70000000: return "SHT_LOPROC / SHT_MIPS_LIST"; case 0x7fffffff: return "SHT_HIPROC"; case 0x80000000: return "SHT_LOUSER"; case 0xffffffff: return "SHT_HIUSER"; case 0x70000002: return "SHT_MIPS_CONFLICT"; case 0x70000003: return "SHT_MIPS_GPTAB"; case 0x70000004: return "SHT_MIPS_UCODE"; default : return "<unknown>"; } } char *shl(sh_link) { switch(sh_link) { case 0: return "SHN_UNDEF"; case 0xff00: return "SHN_LORESERVE / SHN_LOPROC / SHN_MIPS_ACCOMON"; case 0xff1f: return "SHN_HIPROC"; case 0xfff1: return "SHN_ABS"; case 0xfff2: return "SHN_COMMON"; case 0xffff: return "SHN_HIRESERVE"; default : return "<unknown>"; } } void dumpelfhdr(Elf32_Ehdr ehdr) { int i; printf("e_ident : "); for(i = 0; i < 16; i++) if ((ehdr.e_ident[i] > 0x20) && (ehdr.e_ident[i] < 0x7F)) printf("%c", ehdr.e_ident[i]); else printf(" "); for(i = 0; i < 16; i++) printf(" %02x", ehdr.e_ident[i]); printf("\ne_type : 0x%04x (%s)" "\ne_machine : 0x%04x (%s)" "\ne_version : 0x%08x (%s)" "\ne_entry : 0x%08x" "\ne_phoff : 0x%08x" "\ne_shoff : 0x%08x" "\ne_flags : 0x%08x" "\ne_ehsize : 0x%04x" "\ne_phentsize : 0x%04x" "\ne_phnum : 0x%04x" "\ne_shentsize : 0x%04x" "\ne_shnum : 0x%04x" "\ne_shstrndx : 0x%04x\n", ehdr.e_type, et(ehdr.e_type), ehdr.e_machine, em(ehdr.e_machine), ehdr.e_version, (ehdr.e_version == 1) ? "EV_CURRENT" : "EV_NONE", ehdr.e_entry, ehdr.e_phoff, ehdr.e_shoff, ehdr.e_flags, ehdr.e_ehsize, ehdr.e_phentsize, ehdr.e_phnum, ehdr.e_shentsize, ehdr.e_shnum, ehdr.e_shstrndx); } void dumpprogramhdr(Elf32_Phdr phdr) { int i; printf("p_type : 0x%08x (%s)\n" "p_offset : 0x%08x\n" "p_vaddr : 0x%08x\n" "p_paddr : 0x%08x\n" "p_filesz : 0x%08x\n" "p_memsz : 0x%08x\n" "p_flags : 0x%08x (", phdr.p_type, pt(phdr.p_type), phdr.p_offset, phdr.p_vaddr, phdr.p_paddr, phdr.p_filesz, phdr.p_memsz, phdr.p_flags); i = 0; if (phdr.p_flags & PF_R) { printf("PF_R"); i = 1; } if (phdr.p_flags & PF_W) { if (i) printf("|"); printf("PF_W"); i = 1; } if (phdr.p_flags & PF_X) { if (i) printf("|"); printf("PF_X"); i = 1; } printf(")\np_align : 0x%08x\n", phdr.p_align); } void dumpsectionhdr(Elf32_Shdr shdr) { int i = 0; printf("sh_name : 0x%08x\n" "sh_type : 0x%08x (%s)\n", shdr.sh_name, shdr.sh_type, sht(shdr.sh_type)); printf("sh_flags : 0x%08x (", shdr.sh_flags); if (shdr.sh_flags & SHF_WRITE) { printf("SHF_WRITE"); i = 1; } if (shdr.sh_flags & SHF_ALLOC) { if (i) printf("|"); printf("SHF_ALLOC"); i = 1; } if (shdr.sh_flags & SHF_EXECINSTR) { if (i) printf("|"); printf("SHF_EXECINSTR"); i = 1; } if (shdr.sh_flags & SHF_MASKPROC) { if (i) printf("|"); printf("SHF_MASKPROC"); i = 1; } printf(")\nsh_addr : 0x%08x" "\nsh_offset : 0x%08x" "\nsh_size : %d bytes (0x%08x)" "\nsh_link : 0x%08x (%s)" "\nsh_info : 0x%08x" "\nsh_addralign : 0x%08x" "\nsh_entsize : 0x%08x\n", shdr.sh_addr, shdr.sh_offset, shdr.sh_size, shdr.sh_size, shdr.sh_link, shl(shdr.sh_link), shdr.sh_info, shdr.sh_addralign, shdr.sh_entsize); } int main(int argc, char ** argv) { int i; unsigned long origsize, savefpos; FILE *fh; Elf32_Ehdr elfhdr; Elf32_Phdr programhdr; Elf32_Shdr sectionhdr; if (argc < 2) { printf("usage: %s filename\n", argv[0]); return 1; } if ((fh = fopen(argv[1],"r+b")) != 0) { fread(&elfhdr, 1, sizeof(Elf32_Ehdr), fh); if (*(unsigned long *)&elfhdr.e_ident[0] != 0x464C457F) { printf("woops! ELF signature not found\n"); fclose(fh); return 1; } if (elfhdr.e_ident[EI_CLASS] != 1) { printf("woops! there is no support for non 32-bit ELF files\n"); fclose(fh); return 1; } printf("--- ELF header\n"); dumpelfhdr(elfhdr); printf("---\n"); if ((elfhdr.e_phoff == 0) || (elfhdr.e_phnum == 0) || (elfhdr.e_phentsize == 0)) { printf("no valid program headers found\nyou are on your own :)\n"); fclose(fh); return 1; } fseek(fh, elfhdr.e_phoff, SEEK_SET); for(i = 0; i < elfhdr.e_phnum; i++) { printf("--- program header %d\n", i, i); fread(&programhdr, 1, sizeof(Elf32_Phdr), fh); dumpprogramhdr(programhdr); } printf("---\n"); if ((elfhdr.e_shoff != 0) && (elfhdr.e_shnum != 0) && (elfhdr.e_shentsize != 0)) { printf("section header table present! (@0x%08x, shnum:%d)\n", elfhdr.e_shoff, elfhdr.e_shnum); fseek(fh, elfhdr.e_shoff, SEEK_SET); for(i = 0; i < elfhdr.e_shnum; i++) { printf("--- section header %d\n", i, i); fread(§ionhdr, 1, sizeof(Elf32_Shdr), fh); dumpsectionhdr(sectionhdr); } printf("---\n"); fclose(fh); return 0; } printf("section header table is crippled...\n"); fseek(fh, 0, SEEK_END); origsize = ftell(fh); printf("--- appending section header table entry 0 : empty\n"); memset(§ionhdr, 0, sizeof(Elf32_Shdr)); dumpsectionhdr(sectionhdr); fwrite(§ionhdr, sizeof(Elf32_Shdr), 1, fh); printf("--- appending section header table entry 1 : .text\n"); memset(§ionhdr, 0, sizeof(Elf32_Shdr)); sectionhdr.sh_name = 1; sectionhdr.sh_type = SHT_PROGBITS; sectionhdr.sh_flags = SHF_ALLOC|SHF_EXECINSTR; savefpos = ftell(fh); fseek(fh, elfhdr.e_phoff, SEEK_SET); for(i = 0; i < elfhdr.e_phnum; i++) { fread(&programhdr, 1, sizeof(Elf32_Phdr), fh); if ((programhdr.p_type == PT_LOAD) && (programhdr.p_flags & PF_R) && (programhdr.p_flags & PF_X)) { if ((elfhdr.e_entry >= programhdr.p_vaddr) && (elfhdr.e_entry <= programhdr.p_vaddr+programhdr.p_memsz)) { sectionhdr.sh_addr = programhdr.p_vaddr; sectionhdr.sh_offset = programhdr.p_offset; /* sectionhdr.sh_size = programhdr.p_filesz; */ sectionhdr.sh_size = origsize-programhdr.p_offset; break; } } } if (i == elfhdr.e_phnum) { printf("couldn't find the program header of a segment that " "contains the entry point code\n"); return 1; } fseek(fh, savefpos, SEEK_SET); sectionhdr.sh_addralign = 1; dumpsectionhdr(sectionhdr); fwrite(§ionhdr, sizeof(Elf32_Shdr), 1, fh); printf("--- appending section header table entry 2 : .shstrtab\n"); memset(§ionhdr, 0, sizeof(Elf32_Shdr)); sectionhdr.sh_name = 7; sectionhdr.sh_type = SHT_STRTAB; sectionhdr.sh_offset = origsize+(3*sizeof(Elf32_Shdr)); sectionhdr.sh_size = 17; dumpsectionhdr(sectionhdr); fwrite(§ionhdr, sizeof(Elf32_Shdr), 1, fh); printf("---\n"); printf("appending string table...\n"); fwrite("\x00.text\x00.shstrtab\x00", 17, 1, fh); printf("modifying ELF header...\n"); printf("---\n"); elfhdr.e_shoff = origsize; elfhdr.e_shentsize = 40; elfhdr.e_shnum = 3; elfhdr.e_shstrndx = 2; dumpelfhdr(elfhdr); fseek(fh, 0, SEEK_SET); fwrite(&elfhdr, sizeof(Elf32_Ehdr), 1, fh); printf("---\n"); fclose(fh); } else { printf("failed to open the file!\n"); } return 0; }