DYLD_LIBRARY_PATH & DYLD_INSERT_LIBRARIES 不工作
DYLD_LIBRARY_PATH & DYLD_INSERT_LIBRARIES not working
我创建一个 .dylib 文件并编译它:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
static void* (*real_malloc)(size_t);
void *malloc(size_t size)
{
void *p = NULL;
fprintf(stderr, "malloc(%zd) = ", size);
p = real_malloc(size);
fprintf(stderr, "%p\n", p);
return p;
}
void __attribute((constructor))init()
{
real_malloc = (decltype(real_malloc))dlsym(RTLD_NEXT, "malloc");
if (NULL == real_malloc) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
return;
}
}
然后我创建了一个调用 malloc
的测试程序。我确保未优化对 malloc 的调用。
接下来我运行如下:
DYLD_PRINT_LIBRARIES=1 X=1 DYLD_INSERT_LIBRARIES=./libTestHook.dylib ./malloctest
它加载它但它根本不挂钩该功能..有什么想法吗?我在 El Capitan 升级之前尝试了这段代码,它曾经工作过。我还让 malloc 抛出一个异常,只是为了看看它是否被调用。不是。
我错过了什么?
结果是:
sh-3.2# DYLD_PRINT_LIBRARIES=1 X=1 DYLD_INSERT_LIBRARIES=./libTestHook.dylib ./malloctest clear
dyld: loaded: /Users/Brandon/Desktop/./malloctest
dyld: loaded: ./libTestHook.dylib
dyld: loaded: /usr/lib/libc++.1.dylib
dyld: loaded: /usr/lib/libSystem.B.dylib
dyld: loaded: /usr/lib/libc++abi.dylib
dyld: loaded: /usr/lib/system/libcache.dylib
dyld: loaded: /usr/lib/system/libcommonCrypto.dylib
dyld: loaded: /usr/lib/system/libcompiler_rt.dylib
dyld: loaded: /usr/lib/system/libcopyfile.dylib
dyld: loaded: /usr/lib/system/libcorecrypto.dylib
dyld: loaded: /usr/lib/system/libdispatch.dylib
dyld: loaded: /usr/lib/system/libdyld.dylib
dyld: loaded: /usr/lib/system/libkeymgr.dylib
dyld: loaded: /usr/lib/system/liblaunch.dylib
dyld: loaded: /usr/lib/system/libmacho.dylib
dyld: loaded: /usr/lib/system/libquarantine.dylib
dyld: loaded: /usr/lib/system/libremovefile.dylib
dyld: loaded: /usr/lib/system/libsystem_asl.dylib
dyld: loaded: /usr/lib/system/libsystem_blocks.dylib
dyld: loaded: /usr/lib/system/libsystem_c.dylib
dyld: loaded: /usr/lib/system/libsystem_configuration.dylib
dyld: loaded: /usr/lib/system/libsystem_coreservices.dylib
dyld: loaded: /usr/lib/system/libsystem_coretls.dylib
dyld: loaded: /usr/lib/system/libsystem_dnssd.dylib
dyld: loaded: /usr/lib/system/libsystem_info.dylib
dyld: loaded: /usr/lib/system/libsystem_kernel.dylib
dyld: loaded: /usr/lib/system/libsystem_m.dylib
dyld: loaded: /usr/lib/system/libsystem_malloc.dylib
dyld: loaded: /usr/lib/system/libsystem_network.dylib
dyld: loaded: /usr/lib/system/libsystem_networkextension.dylib
dyld: loaded: /usr/lib/system/libsystem_notify.dylib
dyld: loaded: /usr/lib/system/libsystem_platform.dylib
dyld: loaded: /usr/lib/system/libsystem_pthread.dylib
dyld: loaded: /usr/lib/system/libsystem_sandbox.dylib
dyld: loaded: /usr/lib/system/libsystem_secinit.dylib
dyld: loaded: /usr/lib/system/libsystem_trace.dylib
dyld: loaded: /usr/lib/system/libunc.dylib
dyld: loaded: /usr/lib/system/libunwind.dylib
dyld: loaded: /usr/lib/system/libxpc.dylib
dyld: loaded: /usr/lib/libobjc.A.dylib
dyld: loaded: /usr/lib/libauto.dylib
dyld: loaded: /usr/lib/libDiagnosticMessagesClient.dylib
A
B
C
D
我原来 post 中的代码曾用于 Yosemite。在 El Capitan 上,它不起作用。我最终采用了以下方法 (DYLD_INTERPOSE
+ DYLD_INSERT_LIBRARIES
):
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \
__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };
void* pMalloc(size_t size) //would be nice if I didn't have to rename my function..
{
printf("Allocated: %zu\n", size);
return malloc(size);
}
DYLD_INTERPOSE(pMalloc, malloc);
来自 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.
DYLD_FORCE_FLAT_NAMESPACE
Force all images in the program to be linked as flat-namespace images and ignore any two-level namespace bindings. This may cause programs to fail
to execute with a multiply defined symbol error if two-level namespace images are used to allow the images to have multiply defined symbols.
因此您的代码需要 DYLD_FORCE_FLAT_NAMESPACE=1。无论如何,my implementation 仅在启用此选项的情况下适用于 /usr/local/bin/git
。
如果您可以重新编译被挂钩的可执行文件,那么我认为更简单的解决方案是使用 -force_flat_namespace
:
重新编译可执行文件
➜ clang slow_leak.c -force_flat_namespace -o slow_leak
➜ DYLD_INSERT_LIBRARIES=malloc_hook.dylib ./slow_leak
leaking
in hooked malloc
More info。这是在 OSX 10.12.2 MacOS Sierra 上。
A comment on HN(2 年后)提到 DYLD_FORCE_FLAT_NAMESPACE=1
可以在重新编译不可行的情况下提供帮助。我还没试过,所以YMMV。
请尝试导出任何 DYLD 环境变量,f.e.:
export DYLD_LIBRARY_PATH=.
检查环境:
env
如果未导出变量,尝试 disable system integrity protection (also this link 如果您在 MacOS 虚拟机上 运行 可能会有用)
我创建一个 .dylib 文件并编译它:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
static void* (*real_malloc)(size_t);
void *malloc(size_t size)
{
void *p = NULL;
fprintf(stderr, "malloc(%zd) = ", size);
p = real_malloc(size);
fprintf(stderr, "%p\n", p);
return p;
}
void __attribute((constructor))init()
{
real_malloc = (decltype(real_malloc))dlsym(RTLD_NEXT, "malloc");
if (NULL == real_malloc) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
return;
}
}
然后我创建了一个调用 malloc
的测试程序。我确保未优化对 malloc 的调用。
接下来我运行如下:
DYLD_PRINT_LIBRARIES=1 X=1 DYLD_INSERT_LIBRARIES=./libTestHook.dylib ./malloctest
它加载它但它根本不挂钩该功能..有什么想法吗?我在 El Capitan 升级之前尝试了这段代码,它曾经工作过。我还让 malloc 抛出一个异常,只是为了看看它是否被调用。不是。
我错过了什么?
结果是:
sh-3.2# DYLD_PRINT_LIBRARIES=1 X=1 DYLD_INSERT_LIBRARIES=./libTestHook.dylib ./malloctest clear
dyld: loaded: /Users/Brandon/Desktop/./malloctest
dyld: loaded: ./libTestHook.dylib
dyld: loaded: /usr/lib/libc++.1.dylib
dyld: loaded: /usr/lib/libSystem.B.dylib
dyld: loaded: /usr/lib/libc++abi.dylib
dyld: loaded: /usr/lib/system/libcache.dylib
dyld: loaded: /usr/lib/system/libcommonCrypto.dylib
dyld: loaded: /usr/lib/system/libcompiler_rt.dylib
dyld: loaded: /usr/lib/system/libcopyfile.dylib
dyld: loaded: /usr/lib/system/libcorecrypto.dylib
dyld: loaded: /usr/lib/system/libdispatch.dylib
dyld: loaded: /usr/lib/system/libdyld.dylib
dyld: loaded: /usr/lib/system/libkeymgr.dylib
dyld: loaded: /usr/lib/system/liblaunch.dylib
dyld: loaded: /usr/lib/system/libmacho.dylib
dyld: loaded: /usr/lib/system/libquarantine.dylib
dyld: loaded: /usr/lib/system/libremovefile.dylib
dyld: loaded: /usr/lib/system/libsystem_asl.dylib
dyld: loaded: /usr/lib/system/libsystem_blocks.dylib
dyld: loaded: /usr/lib/system/libsystem_c.dylib
dyld: loaded: /usr/lib/system/libsystem_configuration.dylib
dyld: loaded: /usr/lib/system/libsystem_coreservices.dylib
dyld: loaded: /usr/lib/system/libsystem_coretls.dylib
dyld: loaded: /usr/lib/system/libsystem_dnssd.dylib
dyld: loaded: /usr/lib/system/libsystem_info.dylib
dyld: loaded: /usr/lib/system/libsystem_kernel.dylib
dyld: loaded: /usr/lib/system/libsystem_m.dylib
dyld: loaded: /usr/lib/system/libsystem_malloc.dylib
dyld: loaded: /usr/lib/system/libsystem_network.dylib
dyld: loaded: /usr/lib/system/libsystem_networkextension.dylib
dyld: loaded: /usr/lib/system/libsystem_notify.dylib
dyld: loaded: /usr/lib/system/libsystem_platform.dylib
dyld: loaded: /usr/lib/system/libsystem_pthread.dylib
dyld: loaded: /usr/lib/system/libsystem_sandbox.dylib
dyld: loaded: /usr/lib/system/libsystem_secinit.dylib
dyld: loaded: /usr/lib/system/libsystem_trace.dylib
dyld: loaded: /usr/lib/system/libunc.dylib
dyld: loaded: /usr/lib/system/libunwind.dylib
dyld: loaded: /usr/lib/system/libxpc.dylib
dyld: loaded: /usr/lib/libobjc.A.dylib
dyld: loaded: /usr/lib/libauto.dylib
dyld: loaded: /usr/lib/libDiagnosticMessagesClient.dylib
A
B
C
D
我原来 post 中的代码曾用于 Yosemite。在 El Capitan 上,它不起作用。我最终采用了以下方法 (DYLD_INTERPOSE
+ DYLD_INSERT_LIBRARIES
):
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#define DYLD_INTERPOSE(_replacment,_replacee) \
__attribute__((used)) static struct{ const void* replacment; const void* replacee; } _interpose_##_replacee \
__attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacment, (const void*)(unsigned long)&_replacee };
void* pMalloc(size_t size) //would be nice if I didn't have to rename my function..
{
printf("Allocated: %zu\n", size);
return malloc(size);
}
DYLD_INTERPOSE(pMalloc, malloc);
来自 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.
DYLD_FORCE_FLAT_NAMESPACE Force all images in the program to be linked as flat-namespace images and ignore any two-level namespace bindings. This may cause programs to fail to execute with a multiply defined symbol error if two-level namespace images are used to allow the images to have multiply defined symbols.
因此您的代码需要 DYLD_FORCE_FLAT_NAMESPACE=1。无论如何,my implementation 仅在启用此选项的情况下适用于 /usr/local/bin/git
。
如果您可以重新编译被挂钩的可执行文件,那么我认为更简单的解决方案是使用 -force_flat_namespace
:
➜ clang slow_leak.c -force_flat_namespace -o slow_leak
➜ DYLD_INSERT_LIBRARIES=malloc_hook.dylib ./slow_leak
leaking
in hooked malloc
More info。这是在 OSX 10.12.2 MacOS Sierra 上。
A comment on HN(2 年后)提到 DYLD_FORCE_FLAT_NAMESPACE=1
可以在重新编译不可行的情况下提供帮助。我还没试过,所以YMMV。
请尝试导出任何 DYLD 环境变量,f.e.:
export DYLD_LIBRARY_PATH=.
检查环境:
env
如果未导出变量,尝试 disable system integrity protection (also this link 如果您在 MacOS 虚拟机上 运行 可能会有用)