龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

覆盖GNU C库

时间:2009-12-22 15:42来源:未知 作者:admin 点击:
分享到:
2002 年 4 月 一种调试 glibc 函数的好方法是用您自己的版本覆盖所关注的函数。在没有 root 许可权和不必重新编译 libc 源代码的情况下就可以完成这个任务。想象一下编写您自己的 open

  2002 年 4 月

  

一种调试 glibc 函数的好方法是用您自己的版本覆盖所关注的函数。在没有 root 许可权和不必重新编译 libc 源代码的情况下就可以完成这个任务。想象一下编写您自己的 open() 版本该有多激动啊!

  

  

假如您没有应用程序的源代码并且由于 C 的 GNU 库(glibc)函数正将某些错误信息返回给该应用程序而使它失败,那么您该怎么办? 因为 glibc 是开放源码,所以您当然可以获得其源代码、对它进行更改、重新构建和安装。 然而,这不适合那些胆怯的人,因为虽然 API 有很好的文档说明,但 GNU C 库的内部组织却没有。 查找正确的函数原型只是众多挑战中的第一个。 它还是一个很大的包,所以第一次编译时,它将花一些时间(glibc 2.2.2 有 8552 个文件和 1775440 行代码,包括注释)。

  

  

更好的方法

  

比重新构建 glibc 更好的方法是选择性地覆盖一个函数。许多现代的 Unix 都支持预装入用户定义库这一概念。 这些库可以是完整的替代(即,glibc 的专用版本)也可以是子集 ― 甚至是一个函数。 首先,通过设置 LD_LIBRARY_PATH 来包含库的专用版本,您可以使用 glibc 的专用 版本。可通过使用 LD_PRELOAD 环境值来使用您编写的库例程的子集。LD_LIBRARY_PATH 和 LD_PRELOAD 都是由动态 ELF 链接器/装入器控制的。 它使用第一个匹配来满足任何符号名。通过预装入您自己的库或函数版本,您“短路”了正常路径,这样就答应您覆盖它。

  

  

这里是一个示例 makefile,它覆盖 glibc 函数 setresgid():

  

覆盖 setresgid() 的 Makefile

  

  

  

#

  

# Makefile

  

#

  

  

all: libs setresgid-tester

  

  

#

  

# Make a shared Library

  

#

  

libs: libfuncs.c

  

gcc -shared -Wl,-soname,libfuncs.so.1 -o libfuncs.so.1.0 libfuncs.c

  

ln -s libfuncs.so.1.0 libfuncs.so.1

  

ln -s libfuncs.so.1 libfuncs.so

  

  

#

  

# Here is a program that calls setresgid() for testing

  

#

  

setresgid-tester: setresgid-tester.c

  

gcc -o setresgid-tester setresgid-tester.c

  

  

文件 libfuncs.c 包含我的 setresgid() 专用版本。 实现它以支持与原始 setresgid() 相同的参数数目时要小心,并在其它方面完成与原始 setresgid() 相同的操作,尽管我的版本欺骗该应用程序并始终返回 0。

  

  

关注的第二个文件是 setresgid-tester.c。它通过调用 setresgid() 试验新函数。

  

  

这是动态库的源代码:

  

替换库

  

  

  

/*

  

Put all the functions you want to override here

  

*/

  

#include

  

#include

  

#include

  

  

int errno;

  

  

int

  

setresgid(rgid, egid, sgid)

  

gid_t rgid,egid,sgid;

  

{

  

errno=1;

  

printf("It me the shim, Hi there!

  

");

  

return(0);

  

  

}

  

  

您还需要一个简单方法来测试您的 setresgid() 专用版本。可以使用 strace 或 ltrace 来监视进程运行。这是普通测试示例的源代码:

  

普通测试示例

  

  

  

/*

  

setresgid() system/library call tester

  

*/

  

#include

  

#include

  

main(){

  

setresgid(0,0,0);

  

}

  

  

现在,编译该库,设置 LD_PRELOAD shell 变量,然后运行测试应用程序。您可能还需要设置 LD_LIBRARY_PATH。

  

运行测试应用程序

  

  

  

eXPort LD_PRELOAD=libfuncs.so

  

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

  

./setresgid-tester

  

It's me the shim, Hi there!

  

  

还可以通过使用 ldd 列出动态链接库来确认是否正在使用专用库:

  

确认专用库的使用

  

  

  

[jay@prion ld_preload]$ ldd setresgid-tester

  

libfuncs.so => libfuncs.so (0x40018000)

  

libc.so.6 => /lib/libc.so.6 (0x40022000)

  

/lib/ld-Linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

  

  

  

结束语

  

编写 GNU C 库函数的专用版本是调试系统问题或进行快速修正的好方法。 使用 LD_PRELOAD shell 变量,可以选择性地用您自己的专用版本来覆盖系 统 C 库函数。这种技术可用于 linux 和 Solaris 环境。

  

关于作者

  

Jay Allen 是 IBM linux for Service Providers Lab(LSPL)的程序员。可以通过 jaydallen@us.ibm.com 与 Jay 联系。

  

  

  

到页首

  

您对这篇文章的看法如何?

  

真棒!(5) 好文章 (4) 一般;尚可 (3) 需提高 (2) 太差! (1)

  

  

意见?

  

  

  

(c) Copyright IBM Corp. 2001, (c) Copyright IBM China 2001, All Right Reserved

  

关于 IBM 隐私条约 法律条款 联系 IBM

  

精彩图集

赞助商链接