Sections

The ELF Virus Writing HOWTO: sparc-sunos5.9
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/sparc-sunos5.9/sections/objdump.sh

    #!/usr/xpg4/bin/sh
    cd tmp/sparc-sunos5.9/evil_magic
    /usr/xpg4/bin/ls -Ll att
    /opt/sfw/bin/gobjdump -h att

Output: out/sparc-sunos5.9/sections/objdump

    -rwxr-xr-x   1 alba     alba        1416 Feb 15  2003 att

    att:     file format elf32-sparc

    Sections:
    Idx Name          Size      VMA               LMA               File off  Algn
      0 .interp       00000011  00000000000100d4  00000000000100d4  000000d4  2**0
                      CONTENTS, ALLOC, LOAD, READONLY, DATA
      1 .hash         00000044  00000000000100e8  00000000000100e8  000000e8  2**2
                      CONTENTS, ALLOC, LOAD, READONLY, DATA
      2 .dynsym       00000080  000000000001012c  000000000001012c  0000012c  2**2
                      CONTENTS, ALLOC, LOAD, READONLY, DATA
      3 .dynstr       000000a2  00000000000101ac  00000000000101ac  000001ac  2**0
                      CONTENTS, ALLOC, LOAD, READONLY, DATA
      4 .text         00000024  0000000000010250  0000000000010250  00000250  2**2
                      CONTENTS, ALLOC, LOAD, READONLY, CODE
      5 .got          00000004  0000000000020274  0000000000020274  00000274  2**2
                      CONTENTS, ALLOC, LOAD, DATA
      6 .dynamic      00000090  0000000000020278  0000000000020278  00000278  2**2
                      CONTENTS, ALLOC, LOAD, DATA
      7 .bss          00000000  0000000000020308  0000000000020308  00000308  2**0
                      ALLOC
      8 .comment      0000006b  0000000000000000  0000000000000000  00000308  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/sparc-sunos5.9/sections/readelf.sh

    #!/usr/xpg4/bin/sh
    cd tmp/sparc-sunos5.9/evil_magic
    /usr/xpg4/bin/ls -Ll att
    /opt/sfw/bin/greadelf -S att

Output: out/sparc-sunos5.9/sections/readelf

    -rwxr-xr-x   1 alba     alba        1416 Feb 15  2003 att
    There are 11 section headers, starting at offset 0x3d0:

    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 000044 04   A  3   0  4
      [ 3] .dynsym           DYNSYM          0001012c 00012c 000080 10   A  4   1  4
      [ 4] .dynstr           STRTAB          000101ac 0001ac 0000a2 00  AS  0   0  1
      [ 5] .text             PROGBITS        00010250 000250 000024 00  AX  0   0  4
      [ 6] .got              PROGBITS        00020274 000274 000004 04  WA  0   0  4
      [ 7] .dynamic          DYNAMIC         00020278 000278 000090 08  WA  4   0  4
      [ 8] .bss              NOBITS          00020308 000308 000000 00  WA  0   0  1
      [ 9] .comment          PROGBITS        00000000 000308 00006b 00      0   0  1
      [10] .shstrtab         STRTAB          00000000 000373 00005b 00   S  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 17 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 =`

> `0x3d0 + 0x11 * 0x28 =`

> `976 + 17 * 40 = 0x678 = 1656`

`ls` reported a file size of 1416 bytes.

## 6.3. elfdump

`elfdump` also omits section `SHT_NULL` but at least gets the numbering right.

Command: pre/sparc-sunos5.9/sections/elfdump.sh

    #!/usr/xpg4/bin/sh
    cd tmp/sparc-sunos5.9/evil_magic
    /usr/xpg4/bin/ls -Ll att
    /usr/ccs/bin/elfdump -c att

Output: out/sparc-sunos5.9/sections/elfdump

    -rwxr-xr-x   1 alba     alba        1416 Feb 15  2003 att

    Section Header[1]:  sh_name: .interp
        sh_addr:      0x100d4         sh_flags:   [ SHF_ALLOC ]
        sh_size:      0x11            sh_type:    [ SHT_PROGBITS ]
        sh_offset:    0xd4            sh_entsize: 0
        sh_link:      0               sh_info:    0
        sh_addralign: 0x1

    Section Header[2]:  sh_name: .hash
        sh_addr:      0x100e8         sh_flags:   [ SHF_ALLOC ]
        sh_size:      0x44            sh_type:    [ SHT_HASH ]
        sh_offset:    0xe8            sh_entsize: 0x4
        sh_link:      3               sh_info:    0
        sh_addralign: 0x4

    Section Header[3]:  sh_name: .dynsym
        sh_addr:      0x1012c         sh_flags:   [ SHF_ALLOC ]
        sh_size:      0x80            sh_type:    [ SHT_DYNSYM ]
        sh_offset:    0x12c           sh_entsize: 0x10
        sh_link:      4               sh_info:    1
        sh_addralign: 0x4

    Section Header[4]:  sh_name: .dynstr
        sh_addr:      0x101ac         sh_flags:   [ SHF_ALLOC  SHF_STRINGS ]
        sh_size:      0xa2            sh_type:    [ SHT_STRTAB ]
        sh_offset:    0x1ac           sh_entsize: 0
        sh_link:      0               sh_info:    0
        sh_addralign: 0x1

    Section Header[5]:  sh_name: .text
        sh_addr:      0x10250         sh_flags:   [ SHF_ALLOC  SHF_EXECINSTR ]
        sh_size:      0x24            sh_type:    [ SHT_PROGBITS ]
        sh_offset:    0x250           sh_entsize: 0
        sh_link:      0               sh_info:    0
        sh_addralign: 0x4

    Section Header[6]:  sh_name: .got
        sh_addr:      0x20274         sh_flags:   [ SHF_WRITE  SHF_ALLOC ]
        sh_size:      0x4             sh_type:    [ SHT_PROGBITS ]
        sh_offset:    0x274           sh_entsize: 0x4
        sh_link:      0               sh_info:    0
        sh_addralign: 0x4

    Section Header[7]:  sh_name: .dynamic
        sh_addr:      0x20278         sh_flags:   [ SHF_WRITE  SHF_ALLOC ]
        sh_size:      0x90            sh_type:    [ SHT_DYNAMIC ]
        sh_offset:    0x278           sh_entsize: 0x8
        sh_link:      4               sh_info:    0
        sh_addralign: 0x4

    Section Header[8]:  sh_name: .bss
        sh_addr:      0x20308         sh_flags:   [ SHF_WRITE  SHF_ALLOC ]
        sh_size:      0               sh_type:    [ SHT_NOBITS ]
        sh_offset:    0x308           sh_entsize: 0
        sh_link:      0               sh_info:    0
        sh_addralign: 0x1

    Section Header[9]:  sh_name: .comment
        sh_addr:      0               sh_flags:   0
        sh_size:      0x6b            sh_type:    [ SHT_PROGBITS ]
        sh_offset:    0x308           sh_entsize: 0
        sh_link:      0               sh_info:    0
        sh_addralign: 0x1

    Section Header[10]:  sh_name: .shstrtab
        sh_addr:      0               sh_flags:   [ SHF_STRINGS ]
        sh_size:      0x5b            sh_type:    [ SHT_STRTAB ]
        sh_offset:    0x373           sh_entsize: 0
        sh_link:      0               sh_info:    0
        sh_addralign: 0x1

## 6.4. Observations

The start of section `.text`, `0x10250`, 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.

## 6.5. Sections of /usr/bin/csh

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

Command: pre/sparc-sunos5.9/sections/sh/readelf.sh

    #!/usr/xpg4/bin/sh
    shell=$( /usr/xpg4/bin/sed 1q \
    	out/sparc-sunos5.9/scanner/segment_padding/infect )
    /usr/xpg4/bin/ls -Ll ${shell}
    /opt/sfw/bin/greadelf -S ${shell}

Output: out/sparc-sunos5.9/sections/sh/readelf

    -r-xr-xr-x   2 root     bin       159332 Apr  7  2002 /usr/bin/csh
    There are 28 section headers, starting at offset 0x26a04:

    Section Headers:
      [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
      [ 0]                   NULL            00000000 000000 000000 00      0   0  0
      [ 1] .SUNW_syminfo     VERDEF          000100f4 0000f4 000d44 04  AI  4  14  4
      [ 2] .interp           PROGBITS        00010e38 000e38 000011 00   A  0   0  1
      [ 3] .hash             HASH            00010e4c 000e4c 001a98 04   A  4   0  4
      [ 4] .dynsym           DYNSYM          000128e4 0028e4 003510 10   A  5   1  4
      [ 5] .dynstr           STRTAB          00015df4 005df4 001ac9 00  AS  0   0  1
      [ 6] .SUNW_version     VERNEED         000178c0 0078c0 000070 00   A  5   3  4
      [ 7] .rela.ex_shared   RELA            00017930 007930 000030 0c  AI  4  15  4
      [ 8] .rela.cpp_finidat RELA            00017960 007960 00000c 0c  AI  4  16  4
      [ 9] .rela.data        RELA            0001796c 00796c 00000c 0c  AI  4  17  4
      [10] .rela.bss         RELA            00017978 007978 000018 0c  AI  4  19  4
      [11] .rela.plt         RELA            00017990 007990 00057c 0c  AI  4  13  4
      [12] .text             PROGBITS        00017f0c 007f0c 01af8c 00  AX  0   0  4
      [13] .init             PROGBITS        00032e98 022e98 000050 00  AX  0   0  4
      [14] .fini             PROGBITS        00032ee8 022ee8 000080 00  AX  0   0  4
      [15] .exception_ranges PROGBITS        00032f68 022f68 000004 00   A  0   0  4
      [16] .rodata           PROGBITS        00032f6c 022f6c 00003c 00   A  0   0  4
      [17] .rodata1          PROGBITS        00032fa8 022fa8 0004fc 00   A  0   0  4
      [18] .got              PROGBITS        00044000 024000 000004 04  WA  0   0 8192
      [19] .plt              PROGBITS        00044004 024004 0005b0 0c WAX  0   0  4
      [20] .dynamic          DYNAMIC         000445b4 0245b4 000100 08  WA  5   0  4
      [21] .ex_shared        PROGBITS        000446b4 0246b4 000028 00  WA  0   0  4
      [22] .cpp_finidata     PROGBITS        000446dc 0246dc 00000c 00  WA  0   0  4
      [23] .data             PROGBITS        000446e8 0246e8 001600 00  WA  0   0  8
      [24] .data1            PROGBITS        00045ce8 025ce8 000bf8 00  WA  0   0  4
      [25] .bss              NOBITS          000468e0 0268e0 003958 00  WA  0   0  8
      [26] .comment          PROGBITS        00000000 0268e0 000020 00      0   0  1
      [27] .shstrtab         STRTAB          00000000 026900 000103 00   S  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 =`

> `0x26a04 + 0x28 * 0x28 =`

> `158212 + 40 * 40 = 0x27044 = 159812`

`ls` reported a file size of 159332 bytes.

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

### Notes

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

Prev | Home | Next
Segments |  | Scanners