All trails have more uphill sections than they have downhill sections. | |
Shedenhelm's Law |
The standard describes section headers as optional for programs, but you can't build dynamically linked executables without them. Still worse, strip(1) performs a destructive operation on the section headers that will break infected executables if we don't maintain the section headers as well. Let's have another look at The language of evil.
Command: pre/sparc-sunos5.7/sections/objdump.sh
#!/usr/xpg4/bin/sh
/usr/xpg4/bin/ls -Ll tmp/sparc-sunos5.7/evil_magic/att
/usr/local/bin/objdump -h tmp/sparc-sunos5.7/evil_magic/att |
Output: out/sparc-sunos5.7/sections/objdump
-rwxr-xr-x 1 alba alba 444 Jan 8 23:11 tmp/sparc-sunos5.7/evil_magic/att
tmp/sparc-sunos5.7/evil_magic/att: file format elf32-sparc
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000024 0000000000010074 0000000000010074 00000074 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000000 0000000000020098 0000000000020098 00000098 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .sbss 00000000 0000000000020098 0000000000020098 00000098 2**0
CONTENTS
3 .bss 00000000 0000000000020098 0000000000020098 00000098 2**0
ALLOC |
objdump's output for sections is outright disgusting. A real problem is the broken numbering due to ignored entries in the section table. The item on index 0 is actually of type SHT_NULL. Its index (SHN_UNDEF = 0) serves to mark an unused value of sh_link. Less troublesome is the ignored string table, a section of type STRTAB.
Command: pre/sparc-sunos5.7/sections/readelf.sh
#!/usr/xpg4/bin/sh
/usr/xpg4/bin/ls -Ll tmp/sparc-sunos5.7/evil_magic/att
/usr/local/bin/readelf -S tmp/sparc-sunos5.7/evil_magic/att |
Output: out/sparc-sunos5.7/sections/readelf
-rwxr-xr-x 1 alba alba 444 Jan 8 23:11 tmp/sparc-sunos5.7/evil_magic/att
There are 6 section headers, starting at offset 0xcc:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00010074 000074 000024 00 AX 0 0 1
[ 2] .data PROGBITS 00020098 000098 000000 00 WA 0 0 1
[ 3] .sbss PROGBITS 00020098 000098 000000 00 W 0 0 1
[ 4] .bss NOBITS 00020098 000098 000000 00 WA 0 0 1
[ 5] .shstrtab STRTAB 00000000 000098 000032 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific) |
The line starting with "There are 6 section headers" shows the value of e_shnum and e_shoff. Since Offset of e_entry we know that sizeof(Elf32_Shdr) is 40.
First byte beyond the section header table:
e_shoff + e_shnum * sizeof_Shdr =
0xcc + 0x6 * 0x28 =
204 + 6 * 40 = 0x1bc = 444
ls reported a file size of 444 bytes.
elfdump also ommits section SHT_NULL but at least gets the numbering right.
Command: pre/sparc-sunos5.7/sections/elfdump.sh
#!/usr/xpg4/bin/sh
/usr/ccs/bin/elfdump -c tmp/sparc-sunos5.7/evil_magic/att |
Output: out/sparc-sunos5.7/sections/elfdump
Section Header[1]: sh_name: .text
sh_addr: 0x10074 sh_flags: [ SHF_ALLOC SHF_EXECINSTR ]
sh_size: 0x24 sh_type: [ SHT_PROGBITS ]
sh_offset: 0x74 sh_entsize: 0
sh_link: 0 sh_info: 0
sh_addralign: 0x1
Section Header[2]: sh_name: .data
sh_addr: 0x20098 sh_flags: [ SHF_WRITE SHF_ALLOC ]
sh_size: 0 sh_type: [ SHT_PROGBITS ]
sh_offset: 0x98 sh_entsize: 0
sh_link: 0 sh_info: 0
sh_addralign: 0x1
Section Header[3]: sh_name: .sbss
sh_addr: 0x20098 sh_flags: [ SHF_WRITE ]
sh_size: 0 sh_type: [ SHT_PROGBITS ]
sh_offset: 0x98 sh_entsize: 0
sh_link: 0 sh_info: 0
sh_addralign: 0x1
Section Header[4]: sh_name: .bss
sh_addr: 0x20098 sh_flags: [ SHF_WRITE SHF_ALLOC ]
sh_size: 0 sh_type: [ SHT_NOBITS ]
sh_offset: 0x98 sh_entsize: 0
sh_link: 0 sh_info: 0
sh_addralign: 0x1
Section Header[5]: sh_name: .shstrtab
sh_addr: 0 sh_flags: 0
sh_size: 0x32 sh_type: [ SHT_STRTAB ]
sh_offset: 0x98 sh_entsize: 0
sh_link: 0 sh_info: 0
sh_addralign: 0x1 |
The start of section .text, 0x10074, equals the entry point (compare with objdump -fp). This is nowhere specified in the standard. But further down it is demonstrated on /usr/xpg4/bin/sh. See Scan entry point for empirical prove.
The relation between file size and ELF header is more complicated. In most executables the section header table itself is the last region of the file. But there is a second kind where the section described by the last item of the section header table is the last region of the file. With gcc the type of this last section is always SHT_STRTAB. Some of Sun's native sparc executables have a section called .comment (type SHT_PROGBITS) there instead. See Scan file size for empirical prove.
Anyway, we see that even for trivial examples the code is surrounded by lots of other stuff. Let's zoom in on our target.
Command: pre/sparc-sunos5.7/sections/sh/readelf.sh
#!/usr/xpg4/bin/sh
/usr/xpg4/bin/ls -Ll /usr/xpg4/bin/sh
/usr/local/bin/readelf -S /usr/xpg4/bin/sh |
Output: out/sparc-sunos5.7/sections/sh/readelf
-r-xr-xr-x 2 bin bin 193804 Nov 28 00:03 /usr/xpg4/bin/sh
There are 25 section headers, starting at offset 0x2f124:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 000100d4 0000d4 000011 00 A 0 0 1
[ 2] .hash HASH 000100e8 0000e8 0014c0 04 A 3 0 4
[ 3] .dynsym DYNSYM 000115a8 0015a8 002a10 10 A 4 19 4
[ 4] .dynstr STRTAB 00013fb8 003fb8 002fc8 00 A 0 0 1
[ 5] .SUNW_version VERNEED 00016f80 006f80 000050 00 A 4 2 4
[ 6] .rela.ex_shared RELA 00016fd0 006fd0 000018 0c A 3 13 4
[ 7] .rela.data RELA 00016fe8 006fe8 000024 0c A 3 14 4
[ 8] .rela.bss RELA 0001700c 00700c 00000c 0c A 3 16 4
[ 9] .rela.plt RELA 00017018 007018 0005ac 0c A 3 11 4
[10] .text PROGBITS 000175c4 0075c4 02504c 00 AX 0 0 4
[11] .init PROGBITS 0003c610 02c610 000038 00 AX 0 0 4
[12] .fini PROGBITS 0003c648 02c648 000038 00 AX 0 0 4
[13] .exception_ranges PROGBITS 0003c680 02c680 000004 00 A 0 0 4
[14] .rodata PROGBITS 0003c684 02c684 00157b 00 A 0 0 4
[15] .rodata1 PROGBITS 0003dc00 02dc00 000906 00 A 0 0 4
[16] .got PROGBITS 0004e508 02e508 000004 04 WA 0 0 4
[17] .plt PROGBITS 0004e50c 02e50c 0005e0 0c WAX 0 0 4
[18] .dynamic DYNAMIC 0004eaec 02eaec 0000b8 08 WA 4 0 4
[19] .ex_shared PROGBITS 0004eba4 02eba4 000020 00 WA 0 0 4
[20] .data PROGBITS 0004ebc8 02ebc8 000310 00 WA 0 0 8
[21] .data1 PROGBITS 0004eed8 02eed8 000148 00 WA 0 0 4
[22] .bss NOBITS 0004f020 02f020 001513 00 WA 0 0 8
[23] .comment PROGBITS 00000000 02f020 000030 00 0 0 1
[24] .shstrtab STRTAB 00000000 02f050 0000d4 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific) |
First byte beyond the section header table:
e_shoff + e_shnum * sizeof_Shdr =
0x2f124 + 0x25 * 0x28 =
192804 + 37 * 40 = 0x2f6ec = 194284
ls reported a file size of 193804 bytes.
LSB [1] has a good overview of section names. [2] Anyway, a detailed look on section .text shows that its start address (0x175c4) equals the entry point (compare with Segments of /bin/sh).
[1] | |
[2] | http://www.linuxbase.org/spec/gLSB/gLSB/specialsections.html |