LD_PRELOAD

http://www.catonmat.net/blog/simple-ld-preload-tutorial/

 

http://www.catonmat.net/blog/simple-ld-preload-tutorial-part-2/



This is going to be a super short and super simple tutorial for beginners about LD_PRELOAD. If you're familiar with LD_PRELOAD, you'll learn nothing new. Otherwise keep reading!

Did you know you could override the C standard library's functions (such as printf, fopen, etc) with your own version of these functions in any program? In this article I'll teach you how this can be done through the LD_PRELOAD environment variable.

Let's start with a simple C program (prog.c):

#include <stdio.h>

int main(void) {
    printf("Calling the fopen() function...\n");

    FILE *fd = fopen("test.txt","r");
    if (!fd) {
        printf("fopen() returned NULL\n");
        return 1;
    }

    printf("fopen() succeeded\n");

    return 0;
}

The code above simply makes a call to the standard fopen function and then checks its return value. Now, let's compile and execute it:

$ ls
prog.c  test.txt

$ gcc prog.c -o prog

$ ls
prog  prog.c  test.txt

$ ./prog
Calling the fopen() function...
fopen() succeeded

Now let's write our own version of fopen and compile it as a shared library:

#include <stdio.h>

FILE *fopen(const char *path, const char *mode) {
    printf("Always failing fopen\n");
    return NULL;
}

Let's call this file myfopen.c, and let's compile it as a shared library:

gcc -Wall -fPIC -shared -o myfopen.so myfopen.c

Now we can simply modify LD_PRELOAD:

$ export LD_PRELOAD=./myfopen.so 
./prog

Calling the fopen() function...
Always failing fopen
fopen() returned NULL
or 
$LD_PRELAOD=./myfopen.so ./prog

As you can see the fopen got replaced with our own version that is always failing. This is really handy if you've to debug or replace certain parts of libc or any other shared library.

Next time I'll write about how the LD_PRELOAD works internally.


Comments

Bradley Meck  Permalink
April 02, 2013, 17:22

Example with all the pragmas for Mac OS X, Solaris, and Linux C code we are using:

https://github.com/bmeck/interposed/blob/master/fixtures/nix.c

Example simple build script for the file:

https://github.com/bmeck/interposed/blob/master/fixtures/build.sh

April 02, 2013, 18:10

That is awesome!

Grzeg Permalink
July 29, 2013, 20:12

now continuing with our example, is it possible to still call the standard libc function fopen from your own version?

Albob Permalink
September 05, 2013, 13:45

Very cool :)
Any idea on how to make it work with Objective c++? My program is writing file on the disk and I can't find what line of code is doing it... Overriding fopen() would really solve my problem.

abel Permalink
March 29, 2015, 02:39

open, write or append to a file in obj-c. Which API do you use? those functions are overridable by a pre-loaded shared-object, even in obj-c. Just use the command-line tool of Linux, which is called: readelf -s. another tool is: readelf -h. another one objdump -D

<binary>

. Another one tool can be: ldd

<binary>

. That one, would give you the .so binaries which are loaded by that program which usually are libc-dev or libc.so ok? Just another way is to re-create the shared-object, even replacing, just you can load the other shared-object, but that's unproductable. So, just compile: -fPIC -nostartfiles -shared -ldl. Try to override that function which is using, ofcourse it will be fopen, fwrite, or just open, and write. But even in both cases, those API are inside libc-dev. So, just create a binary, library, and shared (.so file), with the correct functions to override, and ofc pre-load it. The file-name of the binary, would be mylibc.so for eample. Then there's a way to call the real fwrite, I would want to know, but I can remember: dylib_?????next(flags???); So good luck guy, nice. bye. -abel.

sharath Permalink
March 26, 2014, 18:08

I have overridden open() which is provided by glibc in my library & I have set LD_PRELOAD with my library first, so when the process calls open(), the open which is defined in my library gets called.

THE PROBLEM:- There are several other functions within glibc which calls open() once such example is getpt(), when getpt() calls open(), the open() which is defined in glibc gets called, how would I make getpt() to invoke the open() which is defined in my library().

markys Permalink
November 11, 2014, 05:58

I followed your example but something going wrong. Here is the output. Please explain me this.
"ERROR: ld.so: object 'myfopen.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored."

markys Permalink
November 11, 2014, 06:16

found my mistake. thank you for clear explain.

Jalal Permalink
May 27, 2015, 14:42

Hi,
Very useful article
thanks...


Last time I stopped at showing how to override functions in shared libraries by compiling your own shared library and preloading it via the LD_PRELOAD environment variable. Today I'll show you how to call the original function from the overridden function.

First let's review the code example that we used in the previous article. We had a program called prog.cthat simply used fopen:

#include <stdio.h>

int main(void) {
    printf("Calling the fopen() function...\n");

    FILE *fd = fopen("test.txt", "r");
    if (!fd) {
        printf("fopen() returned NULL\n");
        return 1;
    }

    printf("fopen() succeeded\n");

    return 0;
}

Today let's write a shared library called myfopen.c that overrides fopen in prog.c and calls the originalfopen from the c standard library:

#define _GNU_SOURCE

#include <stdio.h>
#include <dlfcn.h>

FILE *fopen(const char *path, const char *mode) {
    printf("In our own fopen, opening %s\n", path);

    FILE *(*original_fopen)(const char*, const char*);
    original_fopen = dlsym(RTLD_NEXT, "fopen");
    return (*original_fopen)(path, mode);
}

This shared library exports the fopen function that prints the path and then uses dlsym with theRTLD_NEXT pseudohandle to find the original fopen function. We must define the _GNU_SOURCE feature test macro in order to get the RTLD_NEXT definition from <dlfcn.h>RTLD_NEXT finds the next occurrence of a function in the search order after the current library.

We can compile this shared library this way:

gcc -Wall -fPIC -shared -o myfopen.so myfopen.c -ldl

Now when we preload it and run prog we get the following output that shows that test.txt was successfully opened:

$ LD_PRELOAD=./myfopen.so ./prog
Calling the fopen() function...
In our own fopen, opening test.txt
fopen() succeeded

This is really useful if you need to change how a part of a program works or do some advanced debugging. Next time we'll look at how LD_PRELOAD is implemented.

Comments

Jalal Hajigholamali Permalink
June 05, 2013, 14:37

Hi,

Very nice and useful article

Thanks a lot

kartikeyan Permalink
December 03, 2013, 05:05

Awesome. Its the helloworld of LD_PRELOAD.


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值