Ansi C patch using dlsym compiles OK under linux but fails on Mac Os X

我只是一个虾纸丫 提交于 2019-12-06 06:28:58

问题


I have build a little patch to append to a certain application and trace the invocations of some functions. Among them, malloc() and open(). I am using dlsym to store the pointer to the original symbol and replace the function name with my own. It compiles -and works- perfectly under linux. Here's the code:

#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;
}

Then, I compile it with the following instruction, creating a pi.so.

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

And then, I use the LD_PRELOAD directive to inject it into any app.

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

And it worjks marvellous under Linux! But when I get back home and try to compile it using GCC under Mac, it fails to compile and the LD_PRELOAd directive does not work. What should I change? Thank you very much.


回答1:


On mach, you have to use DYLD_INSERT_LIBRARIES macro instead of LD_PRELOAD to specify a list of shared libraries to pre-load (1...*).

By default, standard functions are not getting replaced with functions from the shared objects just because they have the same names. You have to explicitly state what function overrides what using DYLD_INTERPOSE macro. It allows you to declare a replacement function with any name (for example, override open with my_open) and be able to call original function you are overriding. In addition to that, you don't have to resolve addresses of real functions manually.

Alternatively, to achieve Linux-like behavior you have to define DYLD_FORCE_FLAT_NAMESPACE macro.

There is a lot more going on, see dyld manual for details.

So your code should look something like this:

#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)



回答2:


The Mac OS X (10.6.4) does not contain any references to LD_PRELOAD - so it is ignored, and hence your attempt to interpose your code fails. All the world is not the same as Linux.

Looking through the man pages, I found:

$ man dyld

...

DYLD_INSERT_LIBRARIES This is a colon separated list of dynamic libraries to load before the ones specified in the program. This lets you test new modules of existing dynamic shared libraries that are used in flat-namespace images by loading a temporary dynamic shared library with just the new modules. Note that this has no effect on images built a two-level namespace images using a dynamic shared library unless DYLD_FORCE_FLAT_NAMESPACE is also used.




回答3:


For OSX you'd have to use the DYLD_INSERT_LIBRARIES env. variable instead of LD_PRELOAD.

However I'm fairly certain you won't get the overriding to work. The closest thing I can find is you'll have to do some magic assembly tricks, which someone has neatly packaged up in the code under mach_override here: http://extendamac.svn.sourceforge.net/viewvc/extendamac/trunk/code/



来源:https://stackoverflow.com/questions/3810326/ansi-c-patch-using-dlsym-compiles-ok-under-linux-but-fails-on-mac-os-x

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!