3

我已经构建了一个小补丁来附加到某个应用程序并跟踪某些函数的调用。其中,malloc() 和 open()。我正在使用 dlsym 来存储指向原始符号的指针并用我自己的替换函数名。它可以在 linux 下完美地编译和工作。这是代码:

#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <dlfcn.h>

/**
 * Interponemos nuestra funcion open
 * 
 * @param   char*    filename
 * @param   int      flags
 **/

int open(char * filename, int flags)
{
    static int (*real_open)(char*, int) = NULL;
    if (!real_open)
        real_open = dlsym(RTLD_NEXT, "open");

    // Entero
    int p = real_open(filename, flags);
    fprintf(stderr, "Abrimos %s) = %i\n", filename, flags);

    // Devolvemos
    return p;
}

//--------------------------------------------------------

/**
 * Interponemos nuestra funcion malloc
 * 
 * @param   size_t    size
 */

void* malloc(size_t size)
{
    static void* (*real_malloc)(size_t) = NULL;
    if (!real_malloc)
        real_malloc = dlsym(RTLD_NEXT, "malloc");

    void *p = real_malloc(size);

    // Memoria reservada
    fprintf(stderr, "Reserva de memoria (%d) = %p\n", size, p);

    // Devolvemos
    return p;
}

然后,我使用以下指令编译它,创建一个 pi.so。

gcc -Wall -O2 -fPIC -shared -ldl -o pi.so pi.c 

然后,我使用 LD_PRELOAD 指令将其注入任何应用程序。

LD_PRELOAD=/home/.../injection/pi.so <binary>

它在 Linux 下运行得非常好!但是当我回到家并尝试在 Mac 下使用 GCC 编译它时,它无法编译并且 LD_PRELOAd 指令不起作用。我应该改变什么?非常感谢。

4

3 回答 3

4

在 mach 上,您必须使用DYLD_INSERT_LIBRARIES宏而不是LD_PRELOAD指定要预加载的共享库列表 (1...*)。

默认情况下,标准函数不会仅仅因为它们具有相同的名称而被共享对象中的函数替换。您必须明确声明使用DYLD_INTERPOSE宏的函数覆盖了什么。它允许您使用任何名称声明替换函数(例如,用 覆盖openmy_open并能够调用您要覆盖的原始函数。除此之外,您不必手动解析实际函数的地址。

或者,要实现类似 Linux 的行为,您必须定义DYLD_FORCE_FLAT_NAMESPACE宏。

还有很多事情要做,有关详细信息,请参阅dyld手册。

所以你的代码应该是这样的:

#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <dlfcn.h>
#include <mach-o/dyld-interposing.h>

/**
 * Interponemos nuestra funcion open
 * 
 * @param   char*    filename
 * @param   int      flags
 **/

int my_open(char * filename, int flags)
{
    // Entero
    int p = open(filename, flags);
    fprintf(stderr, "Abrimos %s) = %i\n", filename, flags);

    // Devolvemos
    return p;
}
DYLD_INTERPOSE(my_open, open)

//--------------------------------------------------------

/**
 * Interponemos nuestra funcion malloc
 * 
 * @param   size_t    size
 */

void* my_malloc(size_t size)
{
    void *p = malloc(size);

    // Memoria reservada
    fprintf(stderr, "Reserva de memoria (%d) = %p\n", size, p);

    // Devolvemos
    return p;
}
DYLD_INTERPOSE(my_malloc, malloc)
于 2010-09-28T20:31:29.030 回答
1

对于 OSX,您必须使用 DYLD_INSERT_LIBRARIES 环境。变量而不是 LD_PRELOAD。

但是我相当肯定你不会让压倒一切的工作。我能找到的最接近的事情是你必须做一些神奇的组装技巧,有人在 mach_override 下的代码中巧妙地打包了这些技巧:http: //extendamac.svn.sourceforge.net/viewvc/extendamac/trunk/code /

于 2010-09-28T07:24:38.913 回答
1

Mac OS X (10.6.4) 不包含对 LD_PRELOAD 的任何引用 - 因此它被忽略,因此您插入代码的尝试失败。整个世界都与 Linux 不一样。

浏览手册页,我发现:

$ man dyld

...

DYLD_INSERT_LIBRARIES 这是一个以冒号分隔的动态库列表,在程序中指定的库之前加载。这使您可以通过仅加载新模块的临时动态共享库来测试平面命名空间图像中使用的现有动态共享库的新模块。请注意,这对使用动态共享库构建的两级命名空间图像没有影响,除非还使用了 DYLD_FORCE_FLAT_NAMESPACE。

于 2010-09-28T07:12:10.373 回答