The ELF Virus Writing HOWTO: sparc-debian-linux
Prev |  |

# 2. The language of evil

| "Evil does seek to maintain power by suppressing the truth." "Or by misleading the innocent."
| Spock and McCoy, "And The Children Shall Lead", star date 5029.5.

The fancy output format of The address of main was chosen for a reason. It is valid input for `/bin/sh`. Let's see whether In the language of mortals has `main` at the same offset.

While the simplicity of `ndisasm` is charming, the glitches in `objdump`'s output require heavy machinery. Note that character "`;`" starts a comment on `i386`. On `sparc` a "`!`" is used instead.

Command: src/magic_elf/objdump.sh

    #!/bin/sh
    . ${OUT}/magic_elf/addr_of_main
    ${OBJDUMP} --start-address=${main} -d ${TMP}/magic_elf/magic_elf \
    | src/magic_elf/objdump_format.sh

Command: src/magic_elf/objdump_format.sh

    #!/bin/sh
    # white space is tab-stop, not just spaces
    tab='[^	]\{1,\}	'
    space='[[:space:]]\{1,\}'
    nospace='[^[:space:]]\{1,\}'

    sed -n -e 's/ *	/	/g' \
    	-e "s/${space}\([;!]\)/	\1/" \
    	-e "s/^\(${tab}${tab}${nospace}\)${space}/\1	/" \
    	-e '/^ *[[:xdigit:]]*:/,$ p' \
    	-e '/ret/q' \
    | expand -t 12,32,40,60

Output: out/sparc-debian-linux/magic_elf/objdump

       106a8:   9d e3 bf 98         save    %sp, -104, %sp
       106ac:   13 00 00 40         sethi   %hi(0x10000), %o1
       106b0:   92 12 60 01         or      %o1, 1, %o1         ! 10001 <*ABS*+0x10001>
       106b4:   90 10 20 01         mov     1, %o0
       106b8:   40 00 44 a1         call    2193c <_PROCEDURE_LINKAGE_TABLE_+0x30>
       106bc:   94 10 20 03         mov     3, %o2
       106c0:   81 c7 e0 08         ret

Both programs have `main` at the same file offset. Unfortunately a brief look through `/bin` proves this to be pure chance. And instead of a real system call for `write` we see a call to strange negative address (check the opcode). It resolves to a location in a shared library. But what function in what library?

Command: src/magic_elf/gdb-core.sh

    #!/bin/sh
    gdb ${1} -q <<EOF
    	set disassembly-flavor ${ASM_STYLE}
    	disassemble ${2}
    EOF

Command: src/magic_elf/gdb.sh

    #!/bin/sh
    file=${1:-${TMP}/magic_elf/magic_elf}
    func=${2:-main}
    src/magic_elf/gdb-core.sh ${file} ${func} \
    | src/magic_elf/gdb-format.sh

Output: out/sparc-debian-linux/magic_elf/gdb

    No symbol table is loaded.  Use the "file" command.
    0x106a8 <main>:         save    %sp, -104, %sp
    0x106ac <main+4>:       sethi   %hi(0x10000), %o1
    0x106b0 <main+8>:       or      %o1, 1, %o1                 ! 0x10001
    0x106b4 <main+12>:      mov     1, %o0
    0x106b8 <main+16>:      call    0x2193c <write>
    0x106bc <main+20>:      mov     3, %o2
    0x106c0 <main+24>:      ret

Not shown is a pathetic attempt to single-step to the actual code of `write`.

## 2.1. In doubt use force

We can now search for a fine manual explaining how to debug shared libraries. Or just compile the bugger static.

Command: src/magic_elf/cc_static.sh

    #!/bin/sh
    gcc ${CFLAGS} -static ${OUT}/${arch}/magic_elf/magic_elf.c \
    	-o ${TMP}/magic_elf/magic_elf_static \
    && ls -l ${TMP}/magic_elf \
    && ${TMP}/magic_elf/magic_elf_static

Output: out/sparc-debian-linux/magic_elf/magic_elf_static

    total 496
    -rwxrwxr-x    1 alba     alba        11104 Aug 16 00:19 magic_elf
    -rwxrwxr-x    1 alba     alba       490676 Aug 16 00:19 magic_elf_static
    ELF

Seems we found an easy way to fill up the hard disk. Anyway, what has gdb(1) to say about it?

Output: out/sparc-debian-linux/evil_magic/static_main.gdb

    No symbol table is loaded.  Use the "file" command.
    0x1022c <main>:         save    %sp, -104, %sp
    0x10230 <main+4>:       sethi   %hi(0x10000), %o1
    0x10234 <main+8>:       or      %o1, 1, %o1                 ! 0x10001
    0x10238 <main+12>:      mov     1, %o0
    0x1023c <main+16>:      call    0x19644 <write>
    0x10240 <main+20>:      mov     3, %o2
    0x10244 <main+24>:      ret

The function was called `write` before, it is called `write` now. Let's look what is behind the name.

Output: out/sparc-debian-linux/evil_magic/static_write.gdb

    No symbol table is loaded.  Use the "file" command.
    0x19644 <write>:        mov     4, %g1                      ! 0x4
    0x19648 <write+4>:      ta      0x10
    0x1964c <write+8>:      bcc,a   0x1966c <write+40>
    0x19650 <write+12>:     nop
    0x19654 <write+16>:     save    %sp, -96, %sp
    0x19658 <write+20>:     call    0x11508 <__errno_location>
    0x1965c <write+24>:     nop
    0x19660 <write+28>:     st      %i0, [ %o0 ]
    0x19664 <write+32>:     ret

There are two man pages giving some overview of system calls, intro(2) and syscalls(2). The statement `mov 4,%g1` corresponds to the value of `__NR_write` in `/usr/include/asm/unistd.h`.

## 2.2. In the language of evil

The code generated by gcc(1) is not suitable for a virus. So here comes hand crafted code.

Source: src/evil_magic/sparc-Linux.asm

    		.section .text
    		.globl _start
    _start:		mov	4, %g1			! write
    		mov	1, %o0			! fd=1
    		sethi	%hi(0x10001), %o1
    		or	%o1, %lo(0x10001), %o1	! buf=0x10001
    		mov	3, %o2			! count=3
    		ta	0x10

    		mov	1, %g1			! exit
    		mov	%g0, %o0		! status=0
    		ta	0x10

Command: src/evil_magic/att.sh

    #!/bin/sh
    as -o ${TMP}/evil_magic/${ASM_STYLE}.o \
    	src/evil_magic/${ARCH}-${UNAME}.asm \
    && ld -o ${TMP}/evil_magic/${ASM_STYLE} ${TMP}/evil_magic/${ASM_STYLE}.o \
    && ${TMP}/evil_magic/${ASM_STYLE}

Output: out/sparc-debian-linux/evil_magic/att

    ELF

Output is good. But how do we get the resulting machine code? We can't just add a call to printf(3) to the assembly code. Above example is not linked with glibc; it does not even have a function called `main`.

## 2.3. Enter evil

On the other hand things became a lot easier. There is no initialization code that gets executed before `_start`, so the address of `_start` is really the ELF entry point of the executable.

Source: src/evil_magic/ofs_entry.c

    #include <stddef.h>
    #include <stdio.h>
    #include <elf.h>

    int main()
    {
      printf("sizeof_Elf32_Ehdr=%u\n", sizeof(Elf32_Ehdr));
      printf("offset_e_entry=%u\n", offsetof(Elf32_Ehdr, e_entry));
      printf("sizeof_e_entry=%u\n", sizeof(((Elf32_Ehdr*)0)->e_entry));
      return 0;
    }

Output: out/sparc-debian-linux/evil_magic/ofs_entry

    sizeof_Elf32_Ehdr=52
    offset_e_entry=24
    sizeof_e_entry=4

A look into `/usr/include/elf.h` shows that `Elf32_Ehdr::e_entry` is really at file offset 24.

Command: src/evil_magic/od/Linux.sh

    #!/bin/sh
    od -j24 -An -tx4 -N4 ${TMP}/evil_magic/${ASM_STYLE} \
    | sed 's/^[[:space:]]/0x/'

Output: out/sparc-debian-linux/evil_magic/od

    0x00010074

The entry point is specified as a virtual address in memory. By subtracting the base address we get the file offset:

> 0x10074 - 0x10000 = 0x74 = 116

## 2.4. Evil magic revealed

Command: out/sparc-debian-linux/evil_magic/dis-att.sh

    #!/bin/sh
    ${OBJDUMP} --start-address=0x00010074 -d \
    	-b elf32-sparc tmp/sparc-debian-linux/evil_magic/att \
    | src/magic_elf/objdump_format.sh

Output: out/sparc-debian-linux/evil_magic/evil_magic.asm

       10074:   82 10 20 04         mov     4, %g1
       10078:   90 10 20 01         mov     1, %o0
       1007c:   13 00 00 40         sethi   %hi(0x10000), %o1
       10080:   92 12 60 01         or      %o1, 1, %o1         ! 10001 <*ABS*+0x10001>
       10084:   94 10 20 03         mov     3, %o2
       10088:   91 d0 20 10         ta      0x10
       1008c:   82 10 20 01         mov     1, %g1
       10090:   90 10 00 00         mov     %g0, %o0
       10094:   91 d0 20 10         ta      0x10

## 2.5. Dressing up binary code

There is still one thing left: Dressing up the hex dump as C source. We use the script from Dressing up binary code.

Output: out/sparc-debian-linux/evil_magic/evil_magic.c

    const unsigned char main[]
    __attribute__ (( aligned(8), section(".text") )) =
    {
      0x82,0x10,0x20,0x04,           /* 10074: mov 4, %g1                */
      0x90,0x10,0x20,0x01,           /* 10078: mov 1, %o0                */
      0x13,0x00,0x00,0x40,           /* 1007c: sethi %hi(0x10000), %o1   */
      0x92,0x12,0x60,0x01,           /* 10080: or %o1, 1, %o1            */
      0x94,0x10,0x20,0x03,           /* 10084: mov 3, %o2                */
      0x91,0xd0,0x20,0x10,           /* 10088: ta 0x10                   */
      0x82,0x10,0x20,0x01,           /* 1008c: mov 1, %g1                */
      0x90,0x10,0x00,0x00,           /* 10090: mov %g0, %o0              */
      0x91,0xd0,0x20,0x10            /* 10094: ta 0x10                   */
    };

Calling the string constant `main` is not a mistake. Above output is a complete and valid C program.

Command: src/evil_magic/cc.sh

    #!/bin/sh
    gcc -Wall -O2 ${OUT}/evil_magic/evil_magic.c \
    	-o ${TMP}/evil_magic/cc \
    && ${TMP}/evil_magic/cc

Output: out/sparc-debian-linux/evil_magic/cc

    out/sparc-debian-linux/evil_magic/evil_magic.c:2: warning: `main' is usually a function
    ELF

Prev | Home |
The magic of the Elf |  |