About Introducing Your Own
Code
Written by SiuL+Hacky
Introduction |
I must admit one of the funny ways to crack applications is using dlls from the program; it is what we've called Object Oriented Cracking. In my opinion that's one of the more powerful and witty approaches i've seen. Despite this fact, i faced in my last windows-cracking-times, the problem of calling routines that were not present in dlls, but executables.
The general problem is: imagine a program that validates some code. As a matter of fact, what the interesting routine does is not important, but think about you have to modify the execution flow in order to test different things. Sometimes you can just patch the code, but many times the amount of foreign code you must enter is larger that the code you can fit into "dead areas". You can always, of course, overwrite code, but i always thought that's not a quite elegant approach. One example is a validation routine that it's not easy to clone, because some kind of data is initialized, and you have to call just in the right moment, neither before nor after. Now i want to make a brute force attack and i need to give room for my code that generates new alternatives, test them, and show me somehow that i've been successful.
Tools required |
In this essay you'll need no particular tool that is not available in any distribution: gcc, ld-so, binutils ... You may need for aditional information the source code of some programs. If it does not come with your distribution, at least Debian and RedHat have source codes available in their respective ftp sites and mirrors.
Target's URL/FTP |
In this essay i'm gonna talk about general technics and ideas that are not applied to any particular target.
Essay |
Now we're gonna see different ways to do it. Some of them proved to be impossible, others were rather complicated and others were finally good. You'll see if some of them could deserve further development, and it would be happy if someone can do useful things with options i refused (or even better, new ones).
The first idea was to simply ADD the code. As i briefly explained in my very first linux essay, linux uses mainly ELF format executables, whose structure is really modular, so one could think about just appending your code to some part of the executable. There two documents about ELF format (that i know of), that will answer many of the question that can arise:
elf.hps -> Format
gory details
elf.ps.gz ->
Programmers guide
Firstly a small review about ELF format. Three elements are important:
Program Header: PHDR off 0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2 filesz 0x000000a0 memsz 0x000000a0 flags r-x INTERP off 0x000000d4 vaddr 0x080480d4 paddr 0x080480d4 align 2**0 filesz 0x00000013 memsz 0x00000013 flags r-- LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 filesz 0x0000055c memsz 0x0000055c flags r-x LOAD off 0x0000055c vaddr 0x0804955c paddr 0x0804955c align 2**12 filesz 0x000000d4 memsz 0x000000d8 flags rw- DYNAMIC off 0x00000598 vaddr 0x08049598 paddr 0x08049598 align 2**2 filesz 0x00000098 memsz 0x00000098 flags rw-
The code segment is present in the third element. Note that alignment is 4096, the size of each page of virtual memory.
This is just a reminding if someone have already read about elf structure, i'm not teaching elf structure. If you're lazy, as me, you will not want to read the docs i pointed before, but do not expect to understand the what i'm gonna discuss now.
Now let's suppose i have a piece of code i want to add to the program. I could think about creating a new code section and append it. Ok, that's not complicated, as you can do it with a simple program named objcopy. The program comes with the binutils package, that every distribution carries. One of the features of objcopy is to add a section given a file name.
That sounds good, let's suppose i program my new code in C, i compile it (i can link it statically to ease the task), and then objcopy glues it to the protected crap. Well it works, but ... objcopy does nothing to map the new section onto the executable segment, where all the code is loaded. In other words my new code is unreachable, because it is never loaded.
A pity, but now you'll begin to realize the difficulties of the job, you must edit by yourself the elf headers and try to make your new section reachable from the rest of the code. Our code is not located physically contiguous to the rest of the executable code:
------------ elf headers and so on ------------ |
------------ data from different kinds ------------ |
------------ native code ------------ |
------------ more data/code ------------ |
------------ our code ------------ |
I'm locating the new section as the last one, not only because it's the easiest solution, but it's the way objcopy does. The problem here is that we can't overlap segments (nor sections), so due to the fact you can't (AFAIK) define two code segments, you'll get nothing. The only thing you could do is expanding the current code section (.text section) and append at the end the new piece of code. Of course you'll have to expand the segment too, and other things i'll tell you soon (that makes the task a nightmare).
But before tackling the problems of expanding a .text section, let's face the problem of modifying elf files. Objcopy can handle section attributes and so on, but do not even think about modifying attributes from program headers:
Now if somebody's interested on writing X-Windows apps (with some of the new and attractive graphic libraries for instance), a VERY USEFUL tool could be to program a graphical ELF editor, that could have as a "maximum" challenge: insert data/code into sections. If anybody has the guts to try it i could help him with ELF details (if necessary, of course).
Ok, unless you could rebuild completely an executable with BFD, you'll need modifications in the elf header in order to expand .text section. I think there are two different groups of modifications you have to do, one more obvious, and the second more complicated:
Sections: Idx Name Size VMA LMA File off Algn 0 .interp 00000013 080480d4 080480d4 000000d4 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .hash 00000098 080480e8 080480e8 000000e8 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .dynsym 00000130 08048180 08048180 00000180 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .dynstr 000000c7 080482b0 080482b0 000002b0 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .rel.got 00000008 08048378 08048378 00000378 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .rel.bss 00000008 08048380 08048380 00000380 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 6 .rel.plt 00000030 08048388 08048388 00000388 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .init 0000002c 080483c0 080483c0 000003c0 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 8 .plt 00000070 080483ec 080483ec 000003ec 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 9 .text 000000c8 0804845c 0804845c 0000045c 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 10 .fini 0000001c 08048530 08048530 00000530 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 11 .rodata 00000010 0804854c 0804854c 0000054c 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 12 .data 00000004 0804955c 0804955c 0000055c 2**2 CONTENTS, ALLOC, LOAD, DATA 13 .ctors 00000008 08049560 08049560 00000560 2**2 CONTENTS, ALLOC, LOAD, DATA 14 .dtors 00000008 08049568 08049568 00000568 2**2 CONTENTS, ALLOC, LOAD, DATA 15 .got 00000028 08049570 08049570 00000570 2**2 CONTENTS, ALLOC, LOAD, DATA 16 .dynamic 00000098 08049598 08049598 00000598 2**2 CONTENTS, ALLOC, LOAD, DATA 17 .bss 00000004 08049630 08049630 00000630 2**2 ALLOC 18 .comment 00000064 00000000 00000000 00000630 2**0 CONTENTS, READONLY 19 .note 00000064 00000064 00000064 00000694 2**0 CONTENTS, READONLY
If you look at some function present in the symbol table that is dynamically loaded (printf for instance), you'll get an address:
080483fc DF *UND* 00000024 printf
so 80483fc is the supposed address for printf in our program. There you'll not find printf's code, but a jmp [index_table]. The contents of the table are initialized by dynamic loader. We see, we're lucky because that address (80483fc) is from .plt section, and that address is not modified by the insertion of the new code. But if we go on, we see:
080483fc jmp *0x804957c
so the data table that keeps the real address of dynamic function, located in section .got, is disturbed by our patch. If we add, say 10k of code, *0x804957c is not pointing .got section anymore. It is pointing some innocent instruction inside .text section.
You would need to patch .plt section, that could be big, and well, i gave up here. The problem is not unsolvable, may be patient programmer could do :-). Anyway you'll agree the procedure is getting more confused and less elegant.
2. TRACING A PROCESS
The idea of this approach is taken from ltrace written by Juan Céspedes. What he does is read symbol table and place breakpoints before calling dynamically linked functions. Read the stack, call the function and keep the returned value. That job is accomplished by ptrace, a system call that let you "debug" a process.
What i want to do here is to patch code and data on the fly in order to suit my needs: change the calling parameter, create calling loops to validating functions, ... The program will know nothing :). Ptrace provides elements to modify code/data, read code/data, insert breakpoints, resume execution, trap signals, trap system calls, etc ... almost all you want. I'd like to remark that, WITH PTRACE YOU HAVE GOT ALL THE POWER.
The main lacks for this approach are:
It would be nice to manipulate the kernel and make the trick, but that's far beyond my available time ... and you'll see there are other alternatives. To get this approach closer to you let's see a simple piece of code dealing with ptrace. It creates a child process that will be debugged by its parent, then the child process executes the victim program. I will not explain what is a child/parent process, or how a fork call works, but there are thousands of books that will inform you. On the other hand i would like to tell you about a good guide for ptrace's call, but sadly i did not find it, so consult man page.
#include#include #include #include #include #include #include
void main(int ARGC, char *ARGV[]){ int pid, status;
pid=fork(); if (pid==-1) perror("fork"); else if (pid==0){
/* this code will be executed ONLY by the child process */
signal(SIGTRAP, SIG_IGN); if ( ptrace(PTRACE_TRACEME, 0, 0, 0) == -1) perror("ptrace"); printf("\nProcess controlled\n"); if (execlp("./the_victim_program", "./the_victim_program", NULL)== -1) perror("execlp"); } else{
/* this code will be executed ONLY by the parent process */ /* it will wait until receives a signal from the child process */
wait(&status); if ( WIFSTOPPED(status) ) printf ("\nSignal: %i\n", WSTOPSIG(status) );
/* the debugged process is stopped (with sigtrap) and the parent */ /* receives the signal. The process is stopped before starting. Here */ /* you can change whatever you want. With "sigaction" you can handle */ /* signals (for instance sigtrap) with the function you fancy */
/* After changing whatever the execution is continued */
if (ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status))==-1) perror("ptrace"); wait(&status);
/* wait until child process exits */
} }
3. MANIPULATING DYNAMIC LINKER
What we are trying to do is to write our own code and make it visible from our victim's code. We are trying to share our code, if you want to put that way. But that is done everyday with no artificial method: dynamic linker. So we are going to try some trick or otherwise try-to-emulate what the linker does.
The most obvious and easy trick, but not less powerful is the well known LD_PRELOAD trick. You can find it documented (though the procedure has to be tuned :-) together with dynamic liker (ld-so) source code. It was mentioned in zlib package and other docs too. The trick was also explained by adq in a previous essay. Anyway, as far as i've read it is always used to fake some function dynamically loaded, but never to access victim's code from the faked function.
Example:
Suppose our evil program uses some common function as sin, you could preload it (via LD_PRELOAD env. variable) and load in memory your "holy" code. You could always resolve the problem of the actual function along with cos function, for example ;). Now pass (or hardwire) the address of a validating function to our preloaded library (or to our preloaded sin function if you feel like that), and patch the executable (physically or ptracing it) to call the faked sin function instead of the validating function. Then from your faked function you "see" the calling address space and you can call the validating function a zillion times until you get a good value, and you can then return to the caller code :-). You get ????
Before
LOCAL CODE call validating_function :validating_function .... ret check_it
After
LOCAL CODE LIBRARY CODE call sin --------------------> :my_preloaded_faked_sin <-- call validating_function --> ... call validating function ret check_it <--------------------
I like the above method especially because it's fairly easy and is the dynamic loader the one who makes the dirty job of loading pages into memory. Moreover the patching is minimum, but it is good to know other alternatives, that will do more or less what the dynamic linker does in background. Keep in mind this easy method can only be used in dynamic executables, that although they are the most usual, sometimes you find statically linked ones.
Firstly you can try to load a library in a way similar to the way you do in Windoze. The most important drawback is that you need not only to overwrite code from the executable, but you need that the functions involved were previously used by the program (as far that they have to be present in the dynamic table). The functions involved are:
void *dlopen (const char *filename, int flag)
void *dlsym (void *handle, char *symbol)
int dlclose (void *handle)
so you will load by yourself (from the victim's code) a library and get the address of a particular function or symbol. The you can jump to it.
Another alternative, more sophisticated but easier to implement is to introduce the system call mmap. It is a very interesting service that maps a file into memory with the corresponding attributes. If you wondered is the way dynamic loader "loads" libraries into memory:
void * mmap (void *start, size_t length, int prot , int flags, int fd, off_t offset);
mmap, remember is a system call, no library is necessary. It's a great gift from kernel guys. The system call returns a pointer to the loaded area. If you use in the "flag" parameter the value MAP_FIXED, the parameter start should indicate the address where YOU WANT the code/data to be loaded. I didn't try yet, but what about if you overwrite the code previously loaded ... it would not work as it is read-only data..
Final Notes |
Well, that's all. Lots of material to play with. I have not given ready-to-make-recipes because if you have the interest you will build by yourself the procedures you need with the clues given here. But you can always ask whatever you feel is not clear enough. Of course, if you've just installed linux for the first time, this will not be useful for you and you better read previous essays in order learn something
Ob Duh |
I WILL bother explaining you that you should TEST by yourself what is explained here and try to find new ways to make accesible your code to a non-colaborating process.
You are deep inside Fravia's page of reverse
engineering, choose your
way out:
homepage
links
+ORC
bots wars
students' essays
counter measures
bots wars
antismut CGI tricks
academy database
tools
javascript tricks
cocktails
search_forms
mail_Fravia
Is software reverse engineering illegal?