dlopen 和 dlsym 动态调用函数
iOS/MacOSX/移动安全 exchen 2年前 (2018-08-20) 2997浏览 0评论
Linux/unix 提供了使用 dlopen 和 dlsym 方法动态加载库和调用函数,这套方法在 macOS 和 iOS 上也支持。
dlopen 打开一个库,获取句柄。
dlsym 在打开的库中查找符号的值。
dlclose 关闭句柄。
dlerror 返回一个描述最后一次调用dlopen、dlsym,或 dlclose 的错误信息的字符串。
动态调用 printf 函数,编写测试代码如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #import <dlfcn.h>
typedef int (*printf_func_pointer) (const char * __restrict, ...);
void dynamic_call_function(){
//动态库路径 char *dylib_path = "/usr/lib/libSystem.dylib";
//打开动态库 void *handle = dlopen(dylib_path, RTLD_GLOBAL | RTLD_NOW); if (handle == NULL) { //打开动态库出错 fprintf(stderr, "%s\n", dlerror()); } else {
//获取 printf 地址 printf_func_pointer printf_func = dlsym(handle, "printf");
//地址获取成功则调用 if (printf_func) { int num = 100; printf_func("Hello exchen.net %d\n", num); printf_func("printf function address 0x%lx\n", printf_func); }
dlclose(handle); //关闭句柄 } }
int main(int argc, char * argv[]) { @autoreleasepool {
dynamic_call_function(); return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } |
在手机上运行的输出结果如下:
| 1 2 | Hello exchen.net 100 printf function address 0x189f0da78 |
转载请注明:exchen's blog » [iOS Hacker] dlopen 和 dlsym 动态调用函数
补充dlsym():
获取新符号
进程可以使用 dlsym(3C) 获取特定符号的地址。此函数采用句柄和符号名称,并将符号地址返回给调用方。该句柄通过以下方式指示符号搜索:
-
可通过指定目标文件的 dlopen(3C) 返回句柄。该句柄允许从指定目标文件及定义其依赖项树的目标文件获取符号。使用模式 RTLD_FIRST 返回的句柄仅允许从指定目标文件获取符号。
-
可通过其值为 0 的路径名的 dlopen(3C) 返回句柄。该句柄允许从关联链接映射的启动目标文件及定义其依赖项树的目标文件获取符号。通常,启动目标文件为动态可执行文件。对于关联链接映射,该句柄还允许从通过 dlopen(3C) 获取且模式为 RTLD_GLOBAL 的任何目标文件获取符号。使用模式 RTLD_FIRST 返回的句柄仅允许从关联链接映射的启动目标文件获取符号。
-
特殊句柄 RTLD_DEFAULT 和 RTLD_PROBE 允许从关联链接映射的启动目标文件及定义其依赖项树的目标文件获取符号。此句柄还允许从通过 dlopen(3C) 获取且与调用方同属一组的任何目标文件获取符号。 使用 RTLD_DEFAULT 或 RTLD_PROBE 时采用在解析调用目标文件中的符号重定位时所用的同一模型。
在以下可能很常见的示例中,应用程序首先会将其他目标文件添加到其地址空间。然后,应用程序会使用 dlsym(3C) 来查找函数或数据符号。接下来,应用程序将使用这些符号来调用这些新目标文件中提供的服务。文件 main.c 包含以下代码:
#include <stdio.h>
#include <dlfcn.h>
main()
{
void * handle;
int * dptr, (* fptr)();
if ((handle = dlopen("foo.so.1", RTLD_LAZY)) == NULL) {
(void) printf("dlopen: %s\n", dlerror());
exit (1);
}
if (((fptr = (int (*)())dlsym(handle, "foo")) == NULL) ||
((dptr = (int *)dlsym(handle, "bar")) == NULL)) {
(void) printf("dlsym: %s\n", dlerror());
exit (1);
}
return ((*fptr)(*dptr));
} |
首先会在文件 foo.so.1 中搜索符号 foo 和 bar,然后在与此文件关联的所有依赖项中搜索。接下来,在 return() 语句中使用单个参数 bar 调用函数 foo。
使用前面的文件 main.c 生成的应用程序 prog 包含下列依赖项。

1717

被折叠的 条评论
为什么被折叠?



