【发布时间】:2017-06-08 06:48:32
【问题描述】:
我试图了解 Linux 中动态库的加载时链接(使用 gcc -l)与运行时链接(使用 dlopen(), dlsym())的机制之间的区别,以及这些机制如何影响库及其符号的地址。
实验
我有三个简单的文件:
libhello.c:
int var;
int func() {
return 7;
}
libhello.h:
extern int var;
int func();
main.c:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>
#include "libhello.h"
int main() {
void* h = dlopen("libhello.so", RTLD_NOW);
printf("Address Load-time linking Run-time linking\n");
printf("------- ----------------- ----------------\n");
printf("&var 0x%016" PRIxPTR " 0x%016" PRIxPTR "\n", (uintptr_t)&var , (uintptr_t)dlsym(h, "var" ));
printf("&func 0x%016" PRIxPTR " 0x%016" PRIxPTR "\n", (uintptr_t)&func, (uintptr_t)dlsym(h, "func"));
}
我用命令gcc -shared -o libhello.so -fPIC libhello.c编译libhello.c
我用命令gcc main.c -L. -lhello -ldl编译main.c
观察
运行 main.c 可执行文件会打印如下内容:
Address Load-time linking Run-time linking
------- ----------------- ----------------
&var 0x0000000000601060 0x00007fdb4acb1034
&func 0x0000000000400700 0x00007fdb4aab0695
加载时链接地址保持不变,但运行时链接地址每次运行都会改变。
问题
- 为什么每次运行时运行时地址都会改变?他们会因为Address space layout randomization而改变吗?
- 如果是这种情况,为什么加载时链接不改变地址?加载时链接是否容易受到随机化旨在防止的相同攻击?
- 在上面的程序中,同一个库被加载了两次——一次在加载时,然后在运行时使用
dlopen()。第二次加载不会复制第一次加载的状态。 IE。如果var的值在dlopen()之前更改,则此值不会反映在通过dlsym()加载的var的版本中。有没有办法在第二次加载时保持这种状态?
【问题讨论】:
-
相关,请参阅Configuring ASLR with randomize_va_space 和Jump Over ASLR: Attacking Branch Predictors to Bypass ASLR。如果你想随机化数据段,那么我相信你需要设置
randomize_va_space = 2。 -
在linux/amd64中,我得到了类似的结果;注意:我使用此命令链接可执行文件:
gcc -o main main.c -L. -lhello -ldl -Wl,-rpath $(pwd -L) -
也在 AIX/PowerPC 中尝试过,两个地址对('func' 和 'var')是相等的。链接命令是:
gcc -o main main.c -L. -lhello -ldl -Wl,-brtl,-blibpath:$(pwd -L):/usr/lib
标签: c++ c linux gcc dynamic-linking