I am studying how to hook a self-defined function through dynamical linking using LD_PRELOAD.
However, most of the tutorials try to hook a libc function, e.g. puts().
Is it possible to hook a self-defined function, too?
I am trying the following code
//test.c
#include <stdio.h>
int ptest(){
printf("test!\n");
return 0;
}
int main(void){
printf("%d\n", ptest());
return 0;
}
//hook.c
//compile: "gcc hook.c -shared -fPIC -Wall -o hook.so"
#include <stdio.h>
int ptest(){
printf("fake!\n");
return 1;
}
run
LD_PRELOAD=./hook.so ./test
Result (It means nothing changed by hook.so)
test!
0
What I expect
fake!
1
Related
I am trying to wrap the GLIBC math functions including summation, division, multiplication, Cosine, log, and etc. I found a similar post here.
I have created a wrapper script for the log function in which prints something before calculation. Something like this for log function:
#include <dlfcn.h>
#include <stdio.h>
#include <math.h>
static double (*real_log)(double dbl);
double log(double dbl)
{
printf("value is %0.16f\n" , dbl);
real_log = dlsym(RTLD_NEXT, "log");
real_log(dbl);
}
And the test file is something like this:
#include <stdio.h>
#include <math.h>
int main () {
double var;
var = log(2.7);
printf("log is equal to %0.16f\n" , var);
return 0;
}
I have re-compiled the wrapper to create the shared library by this command: gcc -fPIC -shared -o libpreload.so wrapper.c -ldl.
I compiled test file: gcc -fno-builtin-log test.c -o test -lm.
Then I run my test script using: LD_PRELOAD=/path/to/libpreload.so ./test
The output now prints
value is 2.7000000000000002
log is equal to 0.0000000000000000
The log returns zero value while I expect to get the real calculation like this:
value is 2.7000000000000002
log is equal to 0.9932517730102834
I'm so beginner on C programming and also Glibc functionality.
I would appreciate any ideas.
I am trying to wrap existing function.
below code is perfectly worked.
#include<stdio.h>
int __real_main();
int __wrap_main()
{
printf("Wrapped main\n");
return __real_main();
}
int main()
{
printf("main\n");
return 0;
}
command:
gcc main.c -Wl,-wrap,main
output:
Wrapped main
main
So i have changed main function with temp. my goal is to wrap temp() function.
Below is the code
temp.c
#include<stdio.h>
int temp();
int __real_temp();
int __wrap_temp()
{
printf("Wrapped temp\n");
return __real_temp();
}
int temp()
{
printf("temp\n");
return 0;
}
int main()
{
temp();
return 0;
}
command:
gcc temp.c -Wl,-wrap,temp
output:
temp
Wrapped temp is not printing. please guide me to wrap funciton temp.
The manpage for ld says:
--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to "__wrap_symbol". Any
undefined reference to "__real_symbol" will be resolved to symbol.
The keyword here is undefined.
If you put the definition temp in the same translation unit as the code that uses it, it will not be undefined in the code that uses it.
You need to split the code definition and the code that uses it:
#!/bin/sh
cat > user.c <<'EOF'
#include<stdio.h>
int temp(void);
int __real_temp(void);
int __wrap_temp()
{
printf("Wrapped temp\n");
return __real_temp();
}
int main()
{
temp();
return 0;
}
EOF
cat > temp.c <<'EOF'
#include<stdio.h>
int temp()
{
printf("temp\n");
return 0;
}
EOF
gcc user.c -Wl,-wrap,temp temp.c # OK
./a.out
Splitting the build into two separate compiles perhaps makes it clearer:
$ gcc -c user.c
$ gcc -c temp.c
$ nm user.o temp.o
temp.o:
U puts
0000000000000000 T temp
user.o:
0000000000000015 T main
U puts
U __real_temp
U temp
0000000000000000 T __wrap_temp
Now since temp is undefined in user.c, the linker can do its __real_/__wrap_magic on it.
$ gcc user.o temp.o -Wl,-wrap=temp
$ ./a.out
Wrapped temp
temp
The answer proposed by PSCocik works great if you can split the function you want to override from the function that will call it. However if you want to keep the callee and the caller in the same source file the --wrap option will not work.
Instead you can use __attribute__((weak)) before the implementation of the callee in order to let someone reimplement it without GCC yelling about multiple definitons.
For example suppose you want to mock the world function in the following hello.c code unit. You can prepend the attribute in order to be able to override it.
#include "hello.h"
#include <stdio.h>
__attribute__((weak))
void world(void)
{
printf("world from lib\n");
}
void hello(void)
{
printf("hello\n");
world();
}
And you can then override it in another unit file. Very useful for unit testing/mocking:
#include <stdio.h>
#include "hello.h"
/* overrides */
void world(void)
{
printf("world from main.c\n");
}
int main(void)
{
hello();
return 0;
}
When I use a shared library via dlopen, can the library code "see" memory of my process that calls dlopen? For example, I would like to pass a pointer to memory allocated by my application to the library API.
I'm on Linux/x86 if it is important.
The answer is yes, it can. Here is a simple quick example for illustration purposes.
The library code (in file myso.c):
void setInt( int * i )
{
*i = 12345;
}
The library can be built as follows:
gcc -c -fPIC myso.c
gcc -shared -Wl,-soname,libmy.so -o libmy.so myso.o -lc
Here is the client code (main.c):
#include <stdio.h>
#include <dlfcn.h>
typedef void (*setint_t)( int * );
int main()
{
void * h = dlopen("./libmy.so", RTLD_NOW);
if (h)
{
puts("Loaded library.");
setint_t setInt = dlsym( h, "setInt" );
if (setInt) {
puts("Symbol found");
int k;
setInt(&k);
printf("The int is %d\n", k);
}
}
return 0;
}
Now build and run the code. Make sure main.c and the library are in the same directory, in which we execute the following:
user#fedora-21 ~]$ gcc main.c -ldl
[user#fedora-21 ~]$ ./a.out
Loaded library.
Symbol found
The int is 12345
As one can see, the library was able to write to the memory of the integer k.
I was wondering how this works, creating a library and preloading it so a program can use it instead of the one in the include statement.
here is what I am doing and is not working so far .
//shared.cpp
int rand(){
return 33;
}
//prograndom.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
srand(time(NULL));
int i = 10;
while(i--) printf("%d\n", rand()%100);
return 0;
}
Then in the terminal:
$ gcc -shared -fPIC shared.cpp -o libshared.so
$ gcc prograndom.cpp -o prograndom
$ export LD_PRELOAD=/home/bob/desarrollo/libshared.so
and finally
$ LD_PRELOAD=/home/bob/desarrollo/libshared.so ./prograndom
which doesnt print 33, just random numbers...
Your programs are C programs, but the cpp file extension implies C++, and GCC will interpret it that way.
That's an issue because it means that your function rand (in shared.cpp) will be compiled as a C++ function, with its name mangled to include its type-signature. However, in main you #include <stdlib.h>, which has the effect of declaring:
extern "C" int rand();
and that is the rand that the linker will look for. So your PRELOAD will have no effect.
If you change the name of the file from shared.cpp to shared.c, then it will work as expected.
Other alternatives, of dubious value, are:
Declare rand to be extern "C" in your shared.cpp file. You can then compile it as C++.
Force compilation as C by using the GCC option -x c.
I'm try to override some libc function using LD_PRELOAD technique, but cannot make it work.
this is the strlib.c
#include <stdio.h>
size_t strlen(const char *s){
printf("take strlen for %s\n",s);
return 0;
}
gcc -shared -fPIC -o strlib.so strlib.c (.c file, no name mangle here)
and the main app
#include <string.h>
int main(){
const char* s = "hello";
printf("length=%d\n",strlen(s));
}
gcc -o main main.c
then start to run it
LD_PRELOAD=./strlib.so ./main
it run but seem that it did not call my override function
$ LD_PRELOAD=./strlib.so ./main
length=5
Did I do anything wrong here?
#edit: as Emest mention, a changed the main.c to avoid compiler optimize, but it still did not work.
#include <string.h>
int main(int argc,char** argv){
const char* s = "hello";
printf("length=%d\n",strlen(argv[1]));
}
$ LD_PRELOAD=./strlib.so ./main hehe
length=4
Check the assembly code ( use the -s argument to gcc.) The compiler will optimize out the strlen() call on the compile-time constant string "hello", computing the length at compile time instead. Try calling your function on a string whose length isn't known until runtime, like one of the arguments to main(), and this should work as you expect.