混淆了Linux中共享库的实现

时间:2014-12-01 12:38:40

标签: c linux shared-libraries

我在Linux上做了一些关于共享库的实验。通过阅读几篇论文,我想我知道在调用共享库函数时会发生什么 但是当我试图跟踪内存以获取共享库函数中的二进制代码时,我发现了一些奇怪的东西。在我看来,在调用共享库函数之后,.got.plt中的相应插槽应该包含实际的函数地址,但我的实验表明它仍然保持不变,即func @ plt节中第二条指令的地址。我对此很困惑,所以如果有人能帮助我吗? 这是我的代码和输出:

#include <stdio.h>
#include <string.h>

typedef unsigned long u_l;

int main()
{    
    char *p_ch = strstr("abc", "b");
    printf("result = %s\n", p_ch);

    long long *p = (long long *) &strstr;

    printf("data = %llx\n", *(p));

    long long k = *p >> 16; 
    u_l *entry_addr = (u_l *)(k & 0x00000000ffffffff);

    printf("entry_addr = %lx\n", entry_addr);

    u_l *func_addr = (u_l *)*entry_addr;
    printf("func_addr = %lx\n", func_addr);
    printf("code = %llx\n", *func_addr);
    return 0;
}

输出:

result = bc  
data = 680804a00c25ff  
entry_addr = 804a00c  
func_addr = 8048326  
code = 68080400000068  

先谢谢!
PS:请不要问我为什么需要获取共享库函数的代码。当然我知道源代码和二进制文件可以很容易地获得。这只是一个实验 我的GCC版本是4.7.3。内核版本是3.8.0-35

2 个答案:

答案 0 :(得分:2)

不确定您的程序的逻辑是什么,但我会尝试显示地址更改的位置。

$ gcc -Wall -g test.c
$ gdb a.out
(gdb) break main
Breakpoint 1 at 0x40054c: file test.c, line 8.
(gdb) run
(gdb) disassemble
Dump of assembler code for function main:
   0x0000000000400544 <+0>: push   %rbp
   0x0000000000400545 <+1>: mov    %rsp,%rbp
   0x0000000000400548 <+4>: sub    $0x30,%rsp
=> 0x000000000040054c <+8>: movq   $0x4006fd,-0x28(%rbp)
   0x0000000000400554 <+16>:    mov    $0x400700,%eax
   0x0000000000400559 <+21>:    mov    -0x28(%rbp),%rdx
   0x000000000040055d <+25>:    mov    %rdx,%rsi
   0x0000000000400560 <+28>:    mov    %rax,%rdi
   0x0000000000400563 <+31>:    mov    $0x0,%eax
   0x0000000000400568 <+36>:    callq  0x400430 <printf@plt>
   0x000000000040056d <+41>:    movq   $0x400450,-0x20(%rbp)
   0x0000000000400575 <+49>:    mov    -0x20(%rbp),%rax
   0x0000000000400579 <+53>:    mov    (%rax),%rdx
   0x000000000040057c <+56>:    mov    $0x40070d,%eax
   0x0000000000400581 <+61>:    mov    %rdx,%rsi
   0x0000000000400584 <+64>:    mov    %rax,%rdi
   0x0000000000400587 <+67>:    mov    $0x0,%eax
   0x000000000040058c <+72>:    callq  0x400430 <printf@plt>
   0x0000000000400591 <+77>:    mov    -0x20(%rbp),%rax
   0x0000000000400595 <+81>:    mov    (%rax),%rax
   0x0000000000400598 <+84>:    sar    $0x10,%rax
   0x000000000040059c <+88>:    mov    %rax,-0x18(%rbp)

让我们在printf条目(0x400430)的PLT表中创建断点并继续:

(gdb) break *0x400430
Breakpoint 2 at 0x400430
(gdb) continue 
Continuing.

Breakpoint 2, 0x0000000000400430 in printf@plt ()
(gdb) disassemble 
Dump of assembler code for function printf@plt:
=> 0x0000000000400430 <+0>: jmpq   *0x200bca(%rip)        # 0x601000 <printf@got.plt>
   0x0000000000400436 <+6>: pushq  $0x0
   0x000000000040043b <+11>:    jmpq   0x400420
End of assembler dump.
(gdb) x/x 0x601000
0x601000 <printf@got.plt>:  0x00400436

在PLT表中你可以看到存储在GOT中的地址间接跳转到0x601000(0x200bca + 0x400430 + 6),这在第一次函数调用时解析为PLT中的下一个地址( 0x00400436 :pushq和jump到动态链接器)。动态链接器找到真实的printf,更新它的GOT条目并跳转到它。

下次你调用相同的printf函数(并点击断点)时,它在GOT 0x601000的条目已经更新为 0xf7a6d840 ,所以直接跳转到printf,而不是动态链接器。

(gdb) c
Continuing.
result = bc

Breakpoint 2, 0x0000000000400430 in printf@plt ()
(gdb) disassemble 
Dump of assembler code for function printf@plt:
=> 0x0000000000400430 <+0>: jmpq   *0x200bca(%rip)        # 0x601000 <printf@got.plt>
   0x0000000000400436 <+6>: pushq  $0x0
   0x000000000040043b <+11>:    jmpq   0x400420
End of assembler dump.
(gdb) x/x 0x601000
0x601000 <printf@got.plt>:  0xf7a6d840

此示例来自64位Linux。在其他* NIX&#39; es组件或类似细节可能会有所不同,但想法保持不变。

答案 1 :(得分:0)

  

还有一件事,我在libc.so中找不到printf,...

该程序为每个作为参数给出的函数显示一个地址和包含的库(使用Glibc扩展名):

/* cc -ldl */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int argc, char *argv[])
{
  while (*++argv)
  {
    void *handle = dlopen(NULL, RTLD_NOW);
    if (!handle) puts(dlerror()), exit(1);
    void *p = dlsym(handle, *argv);
    char *s = dlerror();
    if (s) puts(s), exit(1);
    printf("%s = %p\n", *argv, p);
    Dl_info info;
    if (dladdr(p, &info))
        printf("%s contains %s\n", info.dli_fname, info.dli_sname);
  }
}