盘古开天

导航

strace 解决库依赖问题

解决库依赖问题

starce 的另一个用处是解决和动态库相关的问题。当对一个可执行文件运行ldd时,它会告诉你程序使用的动态库和找到动态库的位置。但是如果你正在使用一个比较老 的glibc版本(2.2或更早),你可能会有一个有bug的ldd程序,它可能会报告在一个目录下发现一个动态库,但是真正运行程序时动态连接程序 (/lib/ld-linux.so.2)却可能到另外一个目录去找动态连接库。这通常因为/etc/ld.so.conf和 /etc/ld.so.cache文件不一致,或者/etc/ld.so.cache被破坏。在glibc 2.3.2版本上这个错误不会出现,可能ld-linux的这个bug已经被解决了。

尽管这样,ldd并不能把所有程序依赖的动态库列出 来,系统调用dlopen可以在需要的时候自动调入需要的动态库,而这些库可能不会被ldd列出来。作为glibc的一部分的NSS(Name Server Switch)库就是一个典型的例子,NSS的一个作用就是告诉应用程序到哪里去寻找系统帐号数据库。应用程序不会直接连接到NSS库,glibc则会通 过dlopen自动调入NSS库。如果这样的库偶然丢失,你不会被告知存在库依赖问题,但这样的程序就无法通过用户名解析得到用户ID了。让我们看一个例子:
whoami程序会给出你自己的用户名,这个程序在一些需要知道运行程序的真正用户的脚本程序里面非常有用,whoami的一个示例 输出如下:

# whoami
root

假设因为某种原因在升 级glibc的过程中负责用户名和用户ID转换的库NSS丢失,我们可以通过把nss库改名来模拟这个环境:

# mv /lib/libnss_files.so.2 /lib/libnss_files.so.2.backup 
# whoami
whoami: cannot find username for UID 0

这里你可以看到,运行whoami时出现了错误,ldd程序的输出不会提供有用的帮助:

# ldd /usr/bin/whoami
libc.so.6 => /lib/libc.so.6 (0x4001f000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

你只会看到whoami依赖Libc.so.6和ld-linux.so.2,它没有给出运行whoami所必须的其他库。这里时用strace跟踪 whoami时的输出:

复制代码
strace -o whoami-strace.txt whoami

open("/lib/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/lib/i686/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/lib/i686/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
open("/lib/i686/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/lib/i686", 0xbffff190) = -1 ENOENT (No such file or directory)
open("/lib/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/lib/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
open("/lib/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/lib", {st_mode=S_IFDIR|0755, st_size=2352, ...}) = 0
open("/usr/lib/i686/mmx/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat64("/usr/lib/i686/mmx", 0xbffff190) = -1 ENOENT (No such file or directory)
open("/usr/lib/i686/libnss_files.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
复制代码

你可以发现在不同目录下面查找libnss.so.2的尝试,但是都失败了。如果没有strace这样的工具,很难发现这个错误是由于缺少动态库造成的。现 在只需要找到libnss.so.2并把它放回到正确的位置就可以了。 

 

正常的输出情况:

execve("/usr/bin/whoami",["/usr/bin/whoami"],[/* 24 vars */]) = 0  //execve为strace输出系统调用中的第一个,调用execve加载需要执行的程序

brk(0)                                                 =0x229a000     //调用brk,参数为零,返回内存管理的其实地址(如果子进程中调用malloc,从0x9ac4000地址开始分配空间)

mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0) = 0x7f909809c000 //使用mmap函数进行匿名内存映射,长度为4096bytes内存空间,起始地址0x7f909809c000,主要起到申请内存的作用

access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)  //调用access函数判断当前用户对/etc/ld.so.preload 是否可读[R_OK,W_OK,X_OK,F_OK,读取,写入,执行,是否存在],check real user's permissions for a file

open("/lib64/libc.so.6", O_RDONLY) = 3  //打开文件,只读模式[O_RDONLY,O_WRONLY,O_RDWR,只读,只写,读写]

fstat(3,{st_mode=S_IFREG|0644,st_size=36400, ...}) = 0 //根据文件描述符 3,获取文件信息;S_IFREG 文件是一个普通文件

mmap(NULL,36400,PROT_READ,MAP_PRIVATE,3,0) = 0x7f9098090000 //把文件描述符3映射到内存,私有模式

close(3) = 0 //关闭文件描述符3

open("/lib64/libc.so.6", O_RDONLY) = 3

read(3,"/177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360\355\1\0\0\0\0\0"...,832) = 832 //读取文件描述符3中832bytes的内容,

fstat(3,{st_mode=S_IFREG|0755,st_size=1916568,...}) = 0 

mmap(NULL,3745960,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_DENYWRITE,3,0) = 0x7f9097ae7000

mprotect(0x7f9097c71000,2093056,PROT_NONE) = 0 

...

arch_prctl(ARCH_SET_FS, 0x7f909808f700) = 0  // set architecture-specific thread state,set the 64-bit base for the FS register to addr

....(未完)

 

 

 

 

转载自:http://www.cnblogs.com/ggjucheng/archive/2012/01/08/2316692.html

posted on 2013-08-10 12:25  盘古开天  阅读(519)  评论(0编辑  收藏  举报