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.

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

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

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.

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.

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

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

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