The entry point

 

The longest part of the journey is said to be the passing of the gate.

 Marcus Terentius Varro

After emotions cooled down a bit we can examine the infected executable and compare it with the original.

Command.

#!/bin/sh
cd tmp/one_step_closer
ls -l sh_infected
readelf -l sh_infected

Output.

-rwxrwxr-x    1 alba     alba       524060 Mar 14 19:19 sh_infected

Elf file type is EXEC (Executable file)
Entry point 0x80c1273
There are 6 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x000c0 0x000c0 R E 0x4
  INTERP         0x0000f4 0x080480f4 0x080480f4 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x7a273 0x7a273 R E 0x1000
  LOAD           0x07a280 0x080c2280 0x080c2280 0x057e0 0x09bd0 RW  0x1000
  DYNAMIC        0x07f980 0x080c7980 0x080c7980 0x000e0 0x000e0 RW  0x4
  NOTE           0x000108 0x08048108 0x08048108 0x00020 0x00020 R   0x4

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.got .rel.bss .rel.plt .init .plt .text .fini .rodata 
   03     .data .eh_frame .ctors .dtors .got .dynamic .bss 
   04     .dynamic 
   05     .note.ABI-tag 

File size and code segment have grown as expected. Data segment and DYNAMIC segment moved accordingly:

infected.file_size - sh.file_size = 524060 - 519964 = 4096 = 0x1000

infected.LOAD[1].Filesiz - sh.LOAD[1].Filesiz = 0x7a273 - 0x79273 = 0x1000

infected.LOAD[2].Offset - sh.LOAD[2].Offset = 0x7a280 - 0x79280 = 0x1000

infected.DYNAMIC.Offset - sh.DYNAMIC.Offset = 0x7f980 - 0x7e980 = 0x1000

First scan

Let's give the heuristic scanner a try.

Command.

#!/bin/sh
echo	'/bin/bash
	tmp/one_step_closer/sh_infected' \
| src/check_dist/check_dist.pl

Output.

	tmp/one_step_closer/sh_infected virtaddr=0x80c2280 dist=0x00000d

2 files; min_distance=0x00000d max_distance=0x00100d

As predicted. This is like playing chess against oneself, and losing. Can't do much about it, though. I'll fix something else in revenge.

Second scan

The value of Entry point changed dramatically. In the original it is in the first part of the file:

entry_point_ofs = 0x8059380 - 0x8048000 = 0x11380 = 70528 bytes.

The infected copy moved that to exactly 4096 bytes from the end of the code segment.

entry_point_ofs = 0x80c1273 - 0x8048000 = 0x79273 = 496243 bytes.

end_of_LOAD1 = 0x8048000 + 0x7a273 = 0x80c2273

entry_point_distance_to_end = 0x80c2273 - 0x80c1273 = 0x1000 = 4096

This is another easy vulnerability to scanners. By restructuring our code we can make that number even smaller. But for a real cure we need stronger voodoo.

Patch me if you can

If we chose to leave entry_point as it is, we have to patch something else. One approach is to disassemble the code, starting at entry_point, find the first call (or jmp) and abuse it. This requires way too much intelligence for a virus, though.

But then we are operating in a homogeneous environment, having one compiler and one C run-time library for all. The startup code should be the same for every executable.

Command.

#!/bin/sh
entry_point=$( readelf -l /bin/bash | sed -ne 's/^Entry point //p' )
gdb /bin/bash -q <<EOT | sed -ne '/:$/,/hlt *$/p'
	break *$entry_point
	run
	disassemble
EOT

Output.

(gdb) Dump of assembler code for function _start:
0x8059380 <_start>:	xor    %ebp,%ebp
0x8059382 <_start+2>:	pop    %esi
0x8059383 <_start+3>:	mov    %esp,%ecx
0x8059385 <_start+5>:	and    $0xfffffff0,%esp
0x8059388 <_start+8>:	push   %eax
0x8059389 <_start+9>:	push   %esp
0x805938a <_start+10>:	push   %edx
0x805938b <_start+11>:	push   $0x80ad030
0x8059390 <_start+16>:	push   $0x8058a60
0x8059395 <_start+21>:	push   %ecx
0x8059396 <_start+22>:	push   %esi
0x8059397 <_start+23>:	push   $0x8059480
0x805939c <_start+28>:	call   0x8058fc8 <__libc_start_main>
0x80593a1 <_start+33>:	hlt