首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Linux中加载时链接与运行时链接期间的符号地址

在Linux中加载时链接与运行时链接期间的符号地址
EN

Stack Overflow用户
提问于 2017-06-08 06:48:32
回答 4查看 2.2K关注 0票数 14

我试图了解Linux中动态库的加载时链接(使用gcc -l)和运行时链接(使用dlopen(), dlsym())的机制的不同,以及这些机制如何影响库的状态及其符号的地址。

实验

我有三个简单的文件:

libhello.c:

代码语言:javascript
复制
int var;
int func() {
    return 7;
}

libhello.h:

代码语言:javascript
复制
extern int var;
int func();

C.主要:

代码语言:javascript
复制
#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可执行文件会打印如下所示:

代码语言:javascript
复制
Address  Load-time linking    Run-time linking
-------  -----------------    ----------------
&var     0x0000000000601060   0x00007fdb4acb1034
&func    0x0000000000400700   0x00007fdb4aab0695

加载时链接地址保持不变,但运行时链接地址每次运行都会更改.

问题

  1. 为什么运行时地址每次运行都会改变?它们会因为地址空间布局随机化而改变吗
  2. 如果是这样的话,为什么不解决加载时链接的更改呢?加载时间链接是否容易受到针对随机化攻击的攻击?
  3. 在上面的程序中,同一个库被加载两次--一次在加载时,然后在运行时使用dlopen()。第二个加载不复制第一个加载的状态。也就是说,如果var的值在dlopen()之前被更改,则此值不会反映在通过dlsym()加载的var版本中。在第二个负载期间是否有任何方法来保持这种状态?
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-06-08 07:38:12

  1. 是的,是ASLR。
  2. 因为PIE (位置独立可执行文件)非常昂贵(在性能上)。许多系统在随机化库时做了权衡,因为它们无论如何都必须是独立于位置的,但不要将可执行文件随机化,因为这需要花费太多的性能。是的,这种方式更容易受到攻击,但大多数安全都是一种权衡。
  3. 是的,不要通过句柄搜索符号,而是使用RTLD_DEFAULT。像这样加载同一个动态库的两个实例通常是个坏主意。一些系统可以跳过在dlopen中加载库,如果它们知道同一个库已经加载,而动态链接器认为“相同的库”可能会根据您的库路径而改变。在这里,您处于定义非常差/定义很弱的领域,多年来,这些行为更多地是为了处理bug和问题,而不是通过深思熟虑的设计。

请注意,RTLD_DEFAULT将返回主可执行文件中符号的地址或加载的第一个动态库,而动态加载的库将被忽略。

另外,需要记住的另一件事是,如果在libhello中引用var,它将始终解析库加载时版本中的符号,即使在dlopen:ed版本中也是如此。我修改了func以返回var,并将此代码添加到示例代码中:

代码语言:javascript
复制
int (*fn)(void) = dlsym(h, "func");
int *vp;

var = 17;
printf("%d %d %d %p\n", var, func(), fn(), vp);

vp = dlsym(h, "var");
*vp = 4711;
printf("%d %d %d %p\n", var, func(), fn(), vp);

vp = dlsym(RTLD_DEFAULT, "var");
*vp = 42;
printf("%d %d %d %p\n", var, func(), fn(), vp);

得到这个输出:

代码语言:javascript
复制
$ gcc main.c -L. -lhello -ldl && LD_LIBRARY_PATH=. ./a.out
17 17 17 0x7f2e11bec02c
17 17 17 0x7f2e11bec02c
42 42 42 0x601054
Address  Load-time linking    Run-time linking
-------  -----------------    ----------------
&var     0x0000000000601054   0x0000000000601054
&func    0x0000000000400700   0x0000000000400700
票数 14
EN

Stack Overflow用户

发布于 2017-06-08 07:15:21

你所看到的取决于许多变量。这是我第一次尝试的Debian 64位

代码语言:javascript
复制
Address  Load-time linking    Run-time linking
-------  -----------------    ----------------
&var     0x0000000000600d58   0x0000000000600d58
&func    0x00000000004006d0   0x00000000004006d0

这意味着,dlopen使用了已经链接的库,而您的系统似乎没有这样做。要获得ASLR的优势,您需要使用独立于位置的代码:gcc -fPIC main.c ./libhello.so -ldl编译gcc -fPIC main.c ./libhello.so -ldl

代码语言:javascript
复制
Address  Load-time linking    Run-time linking
-------  -----------------    ----------------
&var     0x00007f4e6cec6944   0x00007f4e6cec6944
&func    0x00007f4e6ccc6670   0x00007f4e6ccc6670
票数 4
EN

Stack Overflow用户

发布于 2017-06-08 07:37:48

我希望这个提示能帮到你。

  1. 主程序是ELF文件,需要重新定位。重新定位发生在加载时间。因此,在调用dlsym之前,主程序中的var和func地址已经重新定位。
  2. dlsym func返回OS ad运行时中的符号地址,而不进行重新定位,该地址位于SO映射区域。

您可以使用映射信息找到不同的:

代码语言:javascript
复制
wutiejun@linux-00343520:~/Temp/sotest> LD_LIBRARY_PATH=./ ./test
Address  Load-time linking    Run-time linking
-------  -----------------    ----------------
&var     0x000000000804a028   0x00000000f77a9014
&func    0x0000000008048568   0x00000000f77a744c


wutiejun@linux-00343520:~> cat /proc/7137/maps
08048000-08049000 r-xp 00000000 08:02 46924194                           /home/wutiejun/Temp/sotest/test
08049000-0804a000 r--p 00000000 08:02 46924194                           /home/wutiejun/Temp/sotest/test
0804a000-0804b000 rw-p 00001000 08:02 46924194                           /home/wutiejun/Temp/sotest/test
0804b000-0806c000 rw-p 00000000 00:00 0                                  [heap]
f75d3000-f7736000 r-xp 00000000 08:02 68395411                           /lib/libc-2.11.3.so
f7736000-f7738000 r--p 00162000 08:02 68395411                           /lib/libc-2.11.3.so
f7738000-f7739000 rw-p 00164000 08:02 68395411                           /lib/libc-2.11.3.so
f7739000-f773c000 rw-p 00000000 00:00 0
f773c000-f7740000 r-xp 00000000 08:02 68395554                           /lib/libachk.so
f7740000-f7741000 r--p 00003000 08:02 68395554                           /lib/libachk.so
f7741000-f7742000 rw-p 00004000 08:02 68395554                           /lib/libachk.so
f777a000-f777c000 rw-p 00000000 00:00 0
f777c000-f7784000 r-xp 00000000 08:02 68395441                           /lib/librt-2.11.3.so
f7784000-f7785000 r--p 00007000 08:02 68395441                           /lib/librt-2.11.3.so
f7785000-f7786000 rw-p 00008000 08:02 68395441                           /lib/librt-2.11.3.so
f7786000-f779d000 r-xp 00000000 08:02 68395437                           /lib/libpthread-2.11.3.so
f779d000-f779e000 r--p 00016000 08:02 68395437                           /lib/libpthread-2.11.3.so
f779e000-f779f000 rw-p 00017000 08:02 68395437                           /lib/libpthread-2.11.3.so
f779f000-f77a2000 rw-p 00000000 00:00 0
f77a2000-f77a5000 r-xp 00000000 08:02 68395417                           /lib/libdl-2.11.3.so
f77a5000-f77a6000 r--p 00002000 08:02 68395417                           /lib/libdl-2.11.3.so
f77a6000-f77a7000 rw-p 00003000 08:02 68395417                           /lib/libdl-2.11.3.so
f77a7000-f77a8000 r-xp 00000000 08:02 46924193                           /home/wutiejun/Temp/sotest/libhello.so
f77a8000-f77a9000 r--p 00000000 08:02 46924193                           /home/wutiejun/Temp/sotest/libhello.so
f77a9000-f77aa000 rw-p 00001000 08:02 46924193                           /home/wutiejun/Temp/sotest/libhello.so
f77aa000-f77ab000 rw-p 00000000 00:00 0
f77ab000-f77ca000 r-xp 00000000 08:02 68395404                           /lib/ld-2.11.3.so
f77ca000-f77cb000 r--p 0001e000 08:02 68395404                           /lib/ld-2.11.3.so
f77cb000-f77cc000 rw-p 0001f000 08:02 68395404                           /lib/ld-2.11.3.so
ffd99000-ffdba000 rw-p 00000000 00:00 0                                  [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0                                  [vdso]
wutiejun@linux-00343520:~>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44428552

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档