Writing a File Dropper

Solving Heavy Wizardry 101 Appendix A exercise
SYSTEM PROGRAMMING SECURITYDROPPERS HACKING

If you have read or are reading Heavy Wizardry 101, you surely went through the chapter about droppers, and perhaps you caught a glimpse of Appendix B. This appendix provides tips and tricks on how to use classical tools like objcopy. In fact, if you read that section, you may find an exercise suggesting the use of objcopy to update the droppers in Chapter 7 to drop a file packed together with the binary. If you are having trouble solving this exercise, you can find a potential solution here.

In case you haven’t read that great book ;) , let’s introduce some concepts so this post is self-contained. A dropper is a simple program whose purpose is to drop some other program, either on disk or in memory, and execute it. They are popular in malware deployment because droppers themselves don’t really perform any suspicious actions and they can easily bypass antivirus checks.

The file being dropped can come from two main sources: a network connection or data stored in the dropper itself. Chapter 7 of Heavy Wizardry 101 explores mainly how to drop programs out of a network connection. In this post, we’re going to see how we can easily pack a binary inside another binary and drop and run it.

The payload

I’m not going to use any malware here, and actually we don’t have to. For our educational purposes, any program will work, so let’s use a static “hello world!” program. Let’s make it static so the file has a size closer to a real-world example. We can produce this payload very easily using:

 $ gcc -static -xc - -o payload << EOM
 >#include 
 >int main() {puts("Hello, world!");}
 >EOM

Once we have our dropee, we can use objcopy to convert it into an object file, which we can use with the linker, with some extra advantages as we will see in a sec.

$ objcopy -I binary -O elf64-x86-64 payload payload.elf

You can obtain the same result using the linker with a command like this:

ld -r -b binary payload -o payload.elf

This may be confusing because you might think: Hey, pico!, “hello” is already an ELF file, why do you have to convert it again? Well, you can try it yourself. What will happen is that the linker will try to link our dropper and our dropee and will find out that there are two main functions. However, the big advantage of converting the file this way is something else. Let’s see.

$ readelf -a hello.elf
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          758656 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         5
  Section header string table index: 4

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .data             PROGBITS         0000000000000000  00000040
       00000000000b9280  0000000000000000  WA       0     0     1
  [ 2] .symtab           SYMTAB           0000000000000000  000b92c0
       0000000000000060  0000000000000018           3     1     8
  [ 3] .strtab           STRTAB           0000000000000000  000b9320
       000000000000003a  0000000000000000           0     0     1
  [ 4] .shstrtab         STRTAB           0000000000000000  000b935a
       0000000000000021  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

There are no section groups in this file.

There are no program headers in this file.

There is no dynamic section in this file.

There are no relocations in this file.
No processor specific unwind information to decode

Symbol table '.symtab' contains 4 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT    1 _binary_hello_start
     2: 00000000000b9280     0 NOTYPE  GLOBAL DEFAULT    1 _binary_hello_end
     3: 00000000000b9280     0 NOTYPE  GLOBAL DEFAULT  ABS _binary_hello_size

No version information found in this file.

There are three main things you have to pay attention to:

  • The file is now of type REL. In other words, it’s like any other object file we produce using our compiler or assembly.
  • Keeping aside the symbols (we’ll talk about this in a sec), it only contains a data segment and therefore it will be treated as raw data by the linker.
  • It automatically defines three symbols that we can use in our program. Those symbols will tell us where the data starts, ends, and its size in memory—which is very convenient.

The dropper

The dropper is pretty simple. It just has to copy a memory block into a file. Let’s take a quick look at the complete code, and then we can dive into the specifics.

#include <fcntl.h>
#include <unistd.h>

extern unsigned char _binary_payload_start[];
extern unsigned char _binary_payload_end[];
#define BLOCK_SIZE 1024
int main () {
  int       fd, n;
  size_t    size = _binary_payload_end - _binary_payload_start;

  if ((fd = open ("/tmp/a", O_CREAT | O_TRUNC| O_WRONLY, 0777)) > 0) {
    for (size_t i = 0; i < size; i += write (fd, _binary_payload_start + i, BLOCK_SIZE));
    close (fd);
  }
  execve("/tmp/a",NULL,NULL);
}

The dropper just accesses the _binary_payload_start and _binary_payload_end generated by the linker to get access to its payload. As the whole payload was in a .data section that ends up in a PT_LOAD segment, the content in the file is directly loaded into memory when the dropper is executed, so the dropper just needs to write that memory area into a file. In the general case, to reduce the detection chances, the payload may also be encrypted. In that case, the loop writing the file should decrypt the data before writing to the file.

The way to access the symbols shown in the code is the easiest way to get it right without compiler warnings. Note, however, that getting access to these symbols may be confusing if done directly. The gotcha behind this is that, for this kind of symbols, the symbol value in the ELF file is the actual value we want, while for regular symbols (like variables or functions), the symbol actually contains a pointer to the real entity it represents (a variable or a function). Overall, this means that in this case, in order to get the value we want, we have to get the address of the symbol with the & operator, which, in the general case, returns the value of the symbol (that is, the pointer to the variable, function), but in this case, we want the actual value, not the pointer.

What all this means is that, if you declare your external variables as the type they should have (a generic pointer), you need to use the & operator and a cast to obtain the value you really want.

extern void *_binary_payload_start;
(...)
unsigned char *buf = (unsigned char*)&_binary_payload_start;

That’s it. We are now ready to try our file dropper.

Testing our new dropper

To be able to try our dropper, we need to compile our code and include the payload in the resulting binary. We can get this using the following command:

$ gcc -o dropper-file dropper-file.c payload.elf
$ ./dropper-file
Hello, world!

Hope you found this interesting. Now you can extend this example following the different techniques in Chapter 7 of the book to drop the files in memory and make forensic analysis a bit more complicated.

Related Posts

How to unload a LD_PRELOAD library the hard way

It's easy to preload a library but how could you remove that library once the application has started?

Read

LINUX SYSTEM PROGRAMMING SECURITY HACKING

System Programming

The path to fully understand how your computer works under the hood

Read

SYSTEM PROGRAMMING GNU/LINUX WEB SECTION

Return to Home Page