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/i386-redhat7.3-linux/sections/objdump.sh
#!/bin/bash
/bin/ls -Ll tmp/i386-redhat7.3-linux/evil_magic/intel
/usr/bin/objdump -h tmp/i386-redhat7.3-linux/evil_magic/intel |
Output: out/i386-redhat7.3-linux/sections/objdump
-rwxrwxr-x 1 alba alba 416 Jan 8 23:08 tmp/i386-redhat7.3-linux/evil_magic/intel
tmp/i386-redhat7.3-linux/evil_magic/intel: file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 00000017 08048080 08048080 00000080 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .bss 00000001 08049097 08049097 00000097 2**0
CONTENTS
2 .comment 0000001f 00000000 00000000 00000098 2**0
CONTENTS, READONLY |
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/i386-redhat7.3-linux/sections/readelf.sh
#!/bin/bash
/bin/ls -Ll tmp/i386-redhat7.3-linux/evil_magic/intel
/usr/bin/readelf -S tmp/i386-redhat7.3-linux/evil_magic/intel |
Output: out/i386-redhat7.3-linux/sections/readelf
-rwxrwxr-x 1 alba alba 416 Jan 8 23:08 tmp/i386-redhat7.3-linux/evil_magic/intel
There are 5 section headers, starting at offset 0xd8:
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 08048080 000080 000017 00 AX 0 0 16
[ 2] .bss PROGBITS 08049097 000097 000001 00 W 0 0 1
[ 3] .comment PROGBITS 00000000 000098 00001f 00 0 0 1
[ 4] .shstrtab STRTAB 00000000 0000b7 00001f 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 5 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 =
0xd8 + 0x5 * 0x28 =
216 + 5 * 40 = 0x1a0 = 416
ls reported a file size of 416 bytes.
The start of section .text, 0x8048080, equals the entry point (compare with objdump -fp). This is nowhere specified in the standard. But further down it is demonstrated on /bin/bash. 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/i386-redhat7.3-linux/sections/sh/readelf.sh
#!/bin/bash
/bin/ls -Ll /bin/bash
/usr/bin/readelf -S /bin/bash |
Output: out/i386-redhat7.3-linux/sections/sh/readelf
-rwxr-xr-x 1 root root 541096 Apr 12 2002 /bin/bash
There are 23 section headers, starting at offset 0x83e10:
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 080480f4 0000f4 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048108 000108 000020 00 A 0 0 4
[ 3] .hash HASH 08048128 000128 002a20 04 A 4 0 4
[ 4] .dynsym DYNSYM 0804ab48 002b48 0067f0 10 A 5 1 4
[ 5] .dynstr STRTAB 08051338 009338 006538 00 A 0 0 1
[ 6] .gnu.version VERSYM 08057870 00f870 000cfe 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 08058570 010570 000070 00 A 5 2 4
[ 8] .rel.dyn REL 080585e0 0105e0 000058 08 A 4 0 4
[ 9] .rel.plt REL 08058638 010638 0004a0 08 A 4 b 4
[10] .init PROGBITS 08058ad8 010ad8 000018 00 AX 0 0 4
[11] .plt PROGBITS 08058af0 010af0 000950 04 AX 0 0 4
[12] .text PROGBITS 08059440 011440 058680 00 AX 0 0 16
[13] .fini PROGBITS 080b1ac0 069ac0 00001e 00 AX 0 0 4
[14] .rodata PROGBITS 080b1ae0 069ae0 014934 00 A 0 0 32
[15] .data PROGBITS 080c7420 07e420 0055e8 00 WA 0 0 32
[16] .eh_frame PROGBITS 080cca08 083a08 000004 00 WA 0 0 4
[17] .dynamic DYNAMIC 080cca0c 083a0c 0000d8 08 WA 5 0 4
[18] .ctors PROGBITS 080ccae4 083ae4 000008 00 WA 0 0 4
[19] .dtors PROGBITS 080ccaec 083aec 000008 00 WA 0 0 4
[20] .got PROGBITS 080ccaf4 083af4 000260 04 WA 0 0 4
[21] .bss NOBITS 080ccd60 083d60 004190 00 WA 0 0 32
[22] .shstrtab STRTAB 00000000 083d60 0000b0 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 =
0x83e10 + 0x23 * 0x28 =
540176 + 35 * 40 = 0x84388 = 541576
ls reported a file size of 541096 bytes.
LSB [1] has a good overview of section names. [2] Anyway, a detailed look on section .text shows that its start address (0x8059440) equals the entry point (compare with Segments of /bin/sh).
[1] | |
[2] | http://www.linuxbase.org/spec/gLSB/gLSB/specialsections.html |