Poking the X-Lehigh virus

| | Comments ()

While doing some tests with the X-Lehigh virus, I needed to process some binaries with the intention of knowing if they were infected and, if so, proceed to disinfect them with some kind of tool.

The above context provided a good scenario for implementing detection and sanitization logic through a domain-specific language (DSL) rather than using a general-purpose language.

The chosen DSL was Poke, with upper case P, which is the name of the domain-specific programming language implemented by GNU poke

Poking with GNU poke

GNU poke is an extensible editor for structured binary data providing a full-fledged procedural, interactive programming language designed to describe data structures and to operate on them.

The choice to experiment with Poke and the X-Lehigh viral signature is related to the advantages of obtaining a more encapsulated and declarative way to implement those signatures as I mentioned some time ago in this post.

The Poke script

The complete code of the Poke script can be seen here, although the most interesting part of the script is the declaration of the type that allows us to capture the infection of the binary and translate it into a flexible and dynamic structure that we can easily interrogate.

01   type Lehigh_Virus =
02     struct {
03       byte host_jump_op = 0xe9;
04       uint<16> host_jump_offset;
05       var host_size = iosize/#B;
06       uint<16> old_entry_point @ (host_size-10)#B;
07       uint<16> signature = 0x65a9 @ (host_size-2)#B;
08       method old_entry_point_fixed = uint:
09         {
10           return old_entry_point - 0x100 - 3;
11         }
12       method start_addr = uint:
13         {
14           var aux = host_jump_offset;
15           var vir_head = [0x50UB, 0x53UB, 0x3dUB, 0xa9UB, 0x65UB, 0x75UB];
16           while (aux--)
17             {
18               if ((uint<8>[vir_head'size] @ aux#B) == vir_head) break;
19             }
20           return aux;
21         }
22       method size = uint:
23         {
24           return host_size - start_addr;
25         }
26       method name = string:
27         {
28           return "DOS.X-Lehigh.v0.1." + ltos(size-1);
29         }
30     };

In the type declaration, it is observed that the structure is flexible in that it allows the use of pattern matching, constraints, units, etc.

The structure is also dynamic in that it not only allows capturing static elements but also generating them at runtime through the methods embedded in the structure itself ('name', 'size', etc).

This type of facility allows us to mediate between the program views on disk and instance in memory very easily.

An example of the latter is the 'old_entry_point_fixed' method in which the original entry point of the program is recalculated in order to subtract the length of the PSP (0x100) and the length of the initial jump instruction (3 bytes).

Another interesting aspect of using Poke is observed in line 18 where the expressiveness of the language allows comparing a sequence of bytes in the condition itself without the need to make a loop explicit.

Running x-lehigh.pk

$ ls -l command.p*
-rw-r--r-- 1 test test 47845 mar 27 08:05 command.pos
-rw-r--r-- 1 test test 47845 mar 27 08:00 command.pre

$ strings command.pre | grep "Microsoft(R)"
Microsoft(R) MS-DOS(R) Version 5.00

$ md5sum command.p*
d20b43615194808edc6fbb3e49416856  command.pos
c2ea62ca46cea5463cf1dda84a239cc1  command.pre

$ x-lehigh.pk
usage: x-lehigh.pk file [remove]

$ x-lehigh.pk command.pre 
Virus not detected

$ x-lehigh.pk command.pos
Virus detected : DOS.X-Lehigh.v0.1.762

$ x-lehigh.pk command.pos remove
Virus detected : DOS.X-Lehigh.v0.1.762
Virus deleted successfully

$ x-lehigh.pk command.pos
Virus not detected

$ md5sum command.p*
c2ea62ca46cea5463cf1dda84a239cc1  command.pos
c2ea62ca46cea5463cf1dda84a239cc1  command.pre


comments powered by Disqus

Recent Entries