Intercept dynamic library methods with LD PRELOAD: Difference between revisions
(Created page with "=Introduction= Let's say you have a binary called 'main' which was compiled against a shared memory 'libprint1.so', which has a method called print_msg() which prints 'hello f...") |
mNo edit summary |
||
(2 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
=Introduction= | ==Introduction== | ||
Let's say you have a binary called 'main' which was compiled against a shared memory 'libprint1.so', which has a method called print_msg() which prints 'hello from print1'. This looks like this | Let's say you have a binary called 'main' which was compiled against a shared memory 'libprint1.so', which has a method called print_msg() which prints 'hello from print1'. This looks like this | ||
main.c | ===main.c=== | ||
< | <syntaxhighlight lang="C" > | ||
#include "print.h" | #include "print.h" | ||
Line 11: | Line 11: | ||
return 0; | return 0; | ||
} | } | ||
</ | </syntaxhighlight> | ||
print.h | ===print.h=== | ||
< | <syntaxhighlight lang="C" > | ||
#ifndef RR_PRINT_H | #ifndef RR_PRINT_H | ||
#define RR_PRINT_H | #define RR_PRINT_H | ||
Line 24: | Line 24: | ||
#endif | #endif | ||
</ | </syntaxhighlight> | ||
print1.c | ===print1.c=== | ||
< | <syntaxhighlight lang="C" > | ||
#include "print.h" | #include "print.h" | ||
Line 33: | Line 33: | ||
printf("hello from print1\n"); | printf("hello from print1\n"); | ||
} | } | ||
</ | </syntaxhighlight> | ||
This library can be compiled as dynamic and linked to the main program with | This library can be compiled as dynamic and linked to the main program with | ||
< | <syntaxhighlight lang="bash"> | ||
gcc -shared -o libprint1.so print1.c | gcc -shared -o libprint1.so print1.c | ||
gcc -o main main.c -L. -lprint1 | gcc -o main main.c -L. -lprint1 | ||
</ | </syntaxhighlight> | ||
As expected when executed the program will output | As expected when executed the program will output | ||
< | <syntaxhighlight lang="bash"> | ||
hello from print1 | hello from print1 | ||
</ | </syntaxhighlight> | ||
Lets say you don't want to recompile main, or you simply do not have that source code, but you want to replace print_msg with another functionality. Here is where the concept of LD_PRELOAD comes in handy. This is an environment variable that will instruct the dynamic linker the priority of the dynamic libraries when executing a binary. | Lets say you don't want to recompile main, or you simply do not have that source code, but you want to replace print_msg with another functionality. Here is where the concept of LD_PRELOAD comes in handy. This is an environment variable that will instruct the dynamic linker the priority of the dynamic libraries when executing a binary. | ||
Line 51: | Line 51: | ||
Let's change the message of print_msg() | Let's change the message of print_msg() | ||
print2.c | ===print2.c=== | ||
< | <syntaxhighlight lang="C" > | ||
#include "print.h" | #include "print.h" | ||
Line 58: | Line 58: | ||
printf("hello from print2\n"); | printf("hello from print2\n"); | ||
} | } | ||
</ | </syntaxhighlight> | ||
Again, compile with | Again, compile with | ||
< | <syntaxhighlight lang="bash"> | ||
gcc -shared -o libprint2.so print2.c | gcc -shared -o libprint2.so print2.c | ||
</ | </syntaxhighlight> | ||
But now, execute main like this | But now, execute main like this | ||
< | <syntaxhighlight lang="bash"> | ||
LD_PRELOAD=libprint2.so ./main | LD_PRELOAD=libprint2.so ./main | ||
</ | </syntaxhighlight> | ||
The output will be | The output will be | ||
< | <syntaxhighlight lang="bash"> | ||
hello from print2 | hello from print2 | ||
</ | </syntaxhighlight> | ||
You can even replace calls to stdlib like malloc and free, to help you keep track of memory allocation. | You can even replace calls to stdlib like malloc and free, to help you keep track of memory allocation. |
Latest revision as of 12:32, 16 May 2024
Introduction
Let's say you have a binary called 'main' which was compiled against a shared memory 'libprint1.so', which has a method called print_msg() which prints 'hello from print1'. This looks like this
main.c
#include "print.h" int main(int argc, char *argv[]) { print_msg(); return 0; }
print.h
#ifndef RR_PRINT_H #define RR_PRINT_H #include <stdio.h> void print_msg(); #endif
print1.c
#include "print.h" void print_msg(){ printf("hello from print1\n"); }
This library can be compiled as dynamic and linked to the main program with
gcc -shared -o libprint1.so print1.c gcc -o main main.c -L. -lprint1
As expected when executed the program will output
hello from print1
Lets say you don't want to recompile main, or you simply do not have that source code, but you want to replace print_msg with another functionality. Here is where the concept of LD_PRELOAD comes in handy. This is an environment variable that will instruct the dynamic linker the priority of the dynamic libraries when executing a binary.
Let's change the message of print_msg()
print2.c
#include "print.h" void print_msg(){ printf("hello from print2\n"); }
Again, compile with
gcc -shared -o libprint2.so print2.c
But now, execute main like this
LD_PRELOAD=libprint2.so ./main
The output will be
hello from print2
You can even replace calls to stdlib like malloc and free, to help you keep track of memory allocation.