11. Suspicious code

 

Attorney General Edwin Meese III explained why the Supreme Court's Miranda decision (holding that subjects have a right to remain silent and have a lawyer present during questioning) is unnecessary: "You don't have many suspects who are innocent of a crime. That's contradictory. If a person is innocent of a crime, then he is not a suspect."

 U.S. News and World Report, 10/14/85

The tricks shown in Doing it in C raise a question. Is it possible to distinguish virus code from regular code by a static scan of the disassembly?

The first problem is how to get at "the code". Everything from the start of the file to the last byte of code is mapped into the code segment. This is described in How it works and illustrated in Bashful glance. A virus could hide in a region declared as ELF header.

A possible approach is to follow the flow of control starting with the entry point. Either compare it directly with expected code (see The entry point). Or verify addresses with the ELF header. This requires a certain homogeneity of executables. But it would be an easy way to detect all infective code shown so far. The entry code of both One step closer to the edge and Doing it in C differs from a regular function decoration.

It's more fun to have a look at the sections of an executable file, however.

11.1. Extracting sections

Here comes a script that extracts a single section from an executable as raw data. readelf(1) provides a related (but useless) option.

-x <number>

--hex-dump=<number>

Displays the contents of the indicated section as a hexadecimal dump.

Source - dumpsection.pl.
#!/usr/bin/perl -sw
use strict;

$::file = '/bin/sh' if (!defined($::file));
$::section = '.text' if (!defined($::section));

open(READELF, '-|', "readelf -S $::file") || die "readelf: $! ";
while(<READELF>)
{
  if (m/^  \[[ 0-9]+\] $::section /)
  {
    my @word = split;
    my $off = hex($word[4]);
    my $size = hex($word[5]);

    open(FILE, '<', $::file) || die "open: $!";
    sysseek(FILE, $off, 0) || die "seek: $!";
    my $dump;
    sysread(FILE, $dump, $size) || die "read: $!";
    close FILE;
    syswrite STDOUT, $dump;
  }
}
close READELF;

And the first test is simple. Compare the following output with gdb(1)'s dump in The entry point.

Command.
#!/bin/sh
src/suspicious_code/dumpsection.pl -file=/bin/bash -section=.text \
| ndisasm -u - \
| sed -e '/hlt/q'

Output.
00000000  31ED              xor ebp,ebp
00000002  5E                pop esi
00000003  89E1              mov ecx,esp
00000005  83E4F0            and esp,byte -0x10
00000008  50                push eax
00000009  54                push esp
0000000A  52                push edx
0000000B  6830D00A08        push dword 0x80ad030
00000010  68608A0508        push dword 0x8058a60
00000015  51                push ecx
00000016  56                push esi
00000017  6880940508        push dword 0x8059480
0000001C  E827FCFFFF        call 0xfffffc48
00000021  F4                hlt