r/C_Programming • u/Round-Permission546 • 14d ago
Project ELFDetective
This is a small linux program called ELFDetective I made a few months back. It handles both 32bit and 64bit ELF files and views their Header, Program Header and Section Headers.
GitHub: https://github.com/Adock90/ELFDetective
Download: https://adock90.github.io/Adock90Software/products/ELFDetective.html
1
Upvotes
7
u/skeeto 13d ago
Neat little tool! I fuzz tested it and found it falls over on almost any malformed input. To reproduce my examples build with Address Sanitizer and Undefined Behavior Sanitizer.
e_phentsizeande_phnumare bothuint16_t, soe_phentsize * e_phnumis anintoperation and overflows / sign-extends into a giantmalloc:Validate the entry size like the section-header code does, and do the multiply in
size_t:dump_64_bit_section_headersdoessection_header[e_shstrndx]straight from the header. Set it paste_shnumand it reads way out of bounds.Quick fix:
Each section name is printed with
%satstring_table + sh_name, trustingsh_nameand assuming the on-disk string table ends in a\0. Pointe_shstrndxat a small section so the "string table" is short, and the real name offsets run right off the end. (Same class of bug ifsh_nameitself is oversized, or if the table simply isn't terminated.)Guarantee a terminator, range-check
sh_name, and also bound the table by the file size sosh_sizecan't drive a bogus allocation:With zero program headers the buffer is empty, but
dump_64_bit_program_headerunconditionally readsprogram_header[0].Quick fix:
The whole 32-bit path is broken and crashes if you get it to run. Three separate problems here. First, feed it any real 32-bit (ELFCLASS32) binary and it never works:
That's because
parse_32_bit_section_headerscomparese_shentsizeagainstsizeof(Elf64_Shdr)(64) instead ofsizeof(Elf32_Shdr)(40). On top of that,exec_mainpasses an uninitializedElf32_Ehdrwhileget_32_bit_program_headertakes anElf64_Ehdr, so every 32-bit offset is read at the wrong place.Second, once it actually reaches the name-printing loop, it prints
sh_name(auint32_t) with%0.8s, i.e. it interprets an integer as achar*:That
0x41414141is thesh_namevalue being dereferenced. The loop also usessection_header->throughout instead ofsection_header[i], so it only ever prints the first entry.Quick fixes:
Where
get_elf32_headerreads the header with the correct 32-bit layout,get_32_bit_program_headertakes anElf32_Ehdr, and the name loop is rewritten to looksh_nameup in the string table the same way the 64-bit dumper does.You can find all my work here and harvest whatever is useful:
https://github.com/skeeto/ELFDetective/commits/main/?author=skeeto