Sections

The ELF Virus Writing HOWTO: i386-redhat8.0-linux
Prev |  | Next

# 6. Sections

| 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.

## 6.1. objdump -h

Command: pre/i386-redhat8.0-linux/sections/objdump.sh

    #!/bin/bash
    cd tmp/i386-redhat8.0-linux/evil_magic
    /bin/ls -Ll intel
    /usr/bin/objdump -h intel

Output: out/i386-redhat8.0-linux/sections/objdump

    -rwxrwxr-x    1 alba     alba          416 Feb 15 23:48 intel

    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          00000000  08049098  08049098  00000097  2**0
                      CONTENTS
      2 .comment      0000001f  00000000  00000000  00000097  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`. And it does not help at all that the section type itself is not included in the output.

## 6.2. readelf

Command: pre/i386-redhat8.0-linux/sections/readelf.sh

    #!/bin/bash
    cd tmp/i386-redhat8.0-linux/evil_magic
    /bin/ls -Ll intel
    /usr/bin/readelf -S intel

Output: out/i386-redhat8.0-linux/sections/readelf

    -rwxrwxr-x    1 alba     alba          416 Feb 15 23:48 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        08049098 000097 000000 00   W  0   0  1
      [ 3] .comment          PROGBITS        00000000 000097 00001f 00      0   0  1
      [ 4] .shstrtab         STRTAB          00000000 0000b6 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.

## 6.3. Observations

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.

## 6.4. Sections of /bin/tcsh

Let's zoom in on our target. [1].

Command: pre/i386-redhat8.0-linux/sections/sh/readelf.sh

    #!/bin/bash
    shell=$( /bin/sed 1q \
    	out/i386-redhat8.0-linux/scanner/segment_padding/infect )
    /bin/ls -Ll ${shell}
    /usr/bin/readelf -S ${shell}

Output: out/i386-redhat8.0-linux/sections/sh/readelf

    -rwxr-xr-x    1 root     root       365432 Aug  8  2002 /bin/tcsh
    There are 28 section headers, starting at offset 0x4dcfc:

    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        08048114 000114 000013 00   A  0   0  1
      [ 2] .note.ABI-tag     NOTE            08048128 000128 000020 00   A  0   0  4
      [ 3] .hash             HASH            08048148 000148 000458 04   A  4   0  4
      [ 4] .dynsym           DYNSYM          080485a0 0005a0 000910 10   A  5   1  4
      [ 5] .dynstr           STRTAB          08048eb0 000eb0 000536 00   A  0   0  1
      [ 6] .gnu.version      VERSYM          080493e6 0013e6 000122 02   A  4   0  2
      [ 7] .gnu.version_r    VERNEED         08049508 001508 000060 00   A  5   2  4
      [ 8] .rel.dyn          REL             08049568 001568 000028 08   A  4   0  4
      [ 9] .rel.plt          REL             08049590 001590 0003d0 08   A  4   b  4
      [10] .init             PROGBITS        08049960 001960 000018 00  AX  0   0  4
      [11] .plt              PROGBITS        08049978 001978 0007b0 04  AX  0   0  4
      [12] .text             PROGBITS        0804a130 002130 0405ec 00  AX  0   0 16
      [13] .fini             PROGBITS        0808a71c 04271c 00001c 00  AX  0   0  4
      [14] .rodata           PROGBITS        0808a740 042740 006bcc 00   A  0   0 32
      [15] .eh_frame_hdr     PROGBITS        0809130c 04930c 00004c 00   A  0   0  4
      [16] .data             PROGBITS        08092360 049360 0034a0 00  WA  0   0 32
      [17] .eh_frame         PROGBITS        08095800 04c800 0002ac 00  WA  0   0  4
      [18] .dynamic          DYNAMIC         08095aac 04caac 0000d8 08  WA  5   0  4
      [19] .ctors            PROGBITS        08095b84 04cb84 000008 00  WA  0   0  4
      [20] .dtors            PROGBITS        08095b8c 04cb8c 000008 00  WA  0   0  4
      [21] .jcr              PROGBITS        08095b94 04cb94 000004 00  WA  0   0  4
      [22] .got              PROGBITS        08095b98 04cb98 0001f8 04  WA  0   0  4
      [23] .bss              NOBITS          08095da0 04cda0 030100 00  WA  0   0 32
      [24] .comment          PROGBITS        00000000 04cda0 000e7f 00      0   0  1
      [25] .shstrtab         STRTAB          00000000 04dc1f 0000dc 00      0   0  1
      [26] .symtab           SYMTAB          00000000 04e15c 006eb0 10     27 270  4
      [27] .strtab           STRTAB          00000000 05500c 00436c 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 =`

> `0x4dcfc + 0x28 * 0x28 =`

> `318716 + 40 * 40 = 0x4e33c = 320316`

`ls` reported a file size of 365432 bytes.

LSB [1] has a good overview of section names. [2] Anyway, a detailed look on section `.text` shows that its start address (0x804a130) equals the entry point (compare with Segments of /bin/tcsh).

### Notes

[1] | http://www.linuxbase.org/
[2] | http://www.linuxbase.org/spec/gLSB/gLSB/specialsections.html

Prev | Home | Next
Segments |  | Scanners