How to use LD_PRELOAD and dlsym hook

LD_PRELOAD

透過在執行檔案之前加上 LD_PRELOAD=xxx.so 可以將後面執行程式所呼叫的function取代成xxx.so內的function 也就是我們可以做到替換libc內的函式 改成我們自己的 當程式執行時

github 上面也有人寫相關資料

測試

目標是將malloc and free 替換成自己的library 當執行測試檔時,code 的內容如下

  • malloc_count.c
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>
#include <dlfcn.h>

void* malloc(size_t size)
{
    char buf[32];
    static void* (*real_malloc)(size_t) = NULL;
    // printf("ggggggggggg");

    if (real_malloc == NULL) {
        *(void**)(&real_malloc) = dlsym(RTLD_NEXT, "malloc");
    }

    sprintf(buf, "malloc called, size = %zu\n", size);
    write(2, buf, strlen(buf));
    return real_malloc(size);
}

void free(void* ptr)
{
    char buf[32];
    static void* (*real_free)(void* ptr) = NULL;

    if (real_free == NULL) {
        *(void**)(&real_free) = dlsym(RTLD_NEXT, "free");
    }

    sprintf(buf, "free called, ptr address = %p\n", ptr);
    write(2, buf, strlen(buf));
    real_free(ptr);
}
gcc -D_GNU_SOURCE -shared -fPIC -o libmcount.so malloc_count.c -ldl
LD_PRELOAD=./libmcount.so ls
memory_test$ LD_PRELOAD=./libmcount.so ls
malloc called, size = 568
malloc called, size = 120
free called, ptr address = 136a250
free called, ptr address = 136a010
free called, ptr address = 0
malloc called, size = 5
free called, ptr address = 136a010
malloc called, size = 120
malloc called, size = 12
malloc called, size = 784
malloc called, size = 112
malloc called, size = 952
malloc called, size = 216
  • test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char* buffer;
    buffer = malloc(sizeof(char) * 10);
    memset(buffer, 0x41, 10);
    puts(buffer);
    free(buffer);
    buffer = NULL;
    free(buffer);

	return 0;
}

但是跑test 測試程式會出現library 找不到的問題

gcc -D_GNU_SOURCE -shared -fPIC -ldl -o libmcount.so malloc_count.c 
gcc -o test test.c
memory_test$ LD_PRELOAD=libmcount.so ./test
./test: symbol lookup error: libmcount.so: undefined symbol: dlsym

檢查ls and test 執行檔 可以發現ls有linker ld library但是test沒有, 這也是為何ls可以跑

猜測因該是compiler最佳化之後將librar去除掉了 查看網路上有人說-ldl拉到最後面就可以 修改後做測試確定test可以跑了


// -ldl拉到最後面

gcc -D_GNU_SOURCE -shared -fPIC  -o libmcount.so malloc_count.c -ldl

or 加上  -Wl,--no-as-needed 

gcc -D_GNU_SOURCE -shared -fPIC -ldl  -Wl,--no-as-needed -o libmcount.so malloc_count.c 

LD_PRELOAD=./libmcount.so ./test

  • lbrary compiler時需要加上-D_GNU_SOURCE 是因為library有用到RTLD_NEXT
  • free pointer 之後需要將pointer 設為null 這樣在後面如果不小心再free 到時才不會有double free message double free or corruption C手冊上面有這一段


malloc 不能使用 printf , 因為 printf 又呼叫malloc 造成無限循環

  • coredump
#28848 0x00007fd3c8b45899 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#28849 0x00007fd3c90dc89d in malloc () from ./libmcount.so
#28850 0x00007fd3c8b5d1d5 in _IO_file_doallocate () from /lib/x86_64-linux-gnu/libc.so.6
#28851 0x00007fd3c8b6b594 in _IO_doallocbuf () from /lib/x86_64-linux-gnu/libc.so.6
#28852 0x00007fd3c8b6a8f8 in _IO_file_overflow () from /lib/x86_64-linux-gnu/libc.so.6
#28853 0x00007fd3c8b6928d in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
#28854 0x00007fd3c8b3d241 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6
#28855 0x00007fd3c8b45899 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#28856 0x00007fd3c90dc89d in malloc () from ./libmcount.so
#28857 0x00007fd3c8b5d1d5 in _IO_file_doallocate () from /lib/x86_64-linux-gnu/libc.so.6
#28858 0x00007fd3c8b6b594 in _IO_doallocbuf () from /lib/x86_64-linux-gnu/libc.so.6
#28859 0x00007fd3c8b6a8f8 in _IO_file_overflow () from /lib/x86_64-linux-gnu/libc.so.6
#28860 0x00007fd3c8b6928d in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
#28861 0x00007fd3c8b3d241 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6
#28862 0x00007fd3c8b45899 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#28863 0x00007fd3c90dc89d in malloc () from ./libmcount.so
#28864 0x00007fd3c8b5d1d5 in _IO_file_doallocate () from /lib/x86_64-linux-gnu/libc.so.6
#28865 0x00007fd3c8b6b594 in _IO_doallocbuf () from /lib/x86_64-linux-gnu/libc.so.6
#28866 0x00007fd3c8b6a8f8 in _IO_file_overflow () from /lib/x86_64-linux-gnu/libc.so.6
#28867 0x00007fd3c8b6928d in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
#28868 0x00007fd3c8b3d241 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6
#28869 0x00007fd3c8b45899 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#28870 0x00007fd3c90dc89d in malloc () from ./libmcount.so
#28871 0x00007fd3c8b5d1d5 in _IO_file_doallocate () from /lib/x86_64-linux-gnu/libc.so.6
#28872 0x00007fd3c8b6b594 in _IO_doallocbuf () from /lib/x86_64-linux-gnu/libc.so.6
#28873 0x00007fd3c8b6a8f8 in _IO_file_overflow () from /lib/x86_64-linux-gnu/libc.so.6
#28874 0x00007fd3c8b6928d in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
#28875 0x00007fd3c8b3d241 in vfprintf () from /lib/x86_64-linux-gnu/libc.so.6
#28876 0x00007fd3c8b45899 in printf () from /lib/x86_64-linux-gnu/libc.so.6
#28877 0x00007fd3c90dc89d in malloc () from ./libmcount.so</font>
#28878 0x00007fd3c8b5dcdd in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#28879 0x00007fd3c8ec49b6 in selinuxfs_exists () from /lib/x86_64-linux-gnu/libselinux.so.1
#28880 0x00007fd3c8ebfcdc in ?? () from /lib/x86_64-linux-gnu/libselinux.so.1
#28881 0x00007fd3c92ee6ba in ?? () from /lib64/ld-linux-x86-64.so.2
#28882 0x00007fd3c92ee7cb in ?? () from /lib64/ld-linux-x86-64.so.2
#28883 0x00007fd3c92dec6a in ?? () from /lib64/ld-linux-x86-64.so.2
#28884 0x0000000000000002 in ?? ()
#28885 0x00007ffc1b6f537a in ?? ()
#28886 0x00007ffc1b6f537d in ?? ()
#28887 0x0000000000000000 in ?? ()

书籍推荐