我试图用我自己对该符号的定义来包装一个glibc符号。对于 glibc 公开的函数,到目前为止,这就像在我的源代码中定义一个__wrap_function_name
,然后将Wl,--wrap=external_function_name
添加到我的构建系统链接步骤的链接器标志中一样简单。在实践中,这看起来像这样:
extern "C" void __wrap_external_function_name(void) {
my_internal function();
}
但是,我最近在 glibc 暴露的变量上尝试了相同的操作,在这种情况下__signgam。我再次为其包装器定义了链接器标志,但我不确定如何以及是否可以为变量定义包装器。我尝试__wrap__signgam = signgam
,但没有效果。事实上,当使用objdump -T binary | grep signgam
公开时,符号表具有以下内容,表明即使定义了包装函数,原始符号仍然保持不变:
0000000000000000 DO *UND* 0000000000000000 GLIBC_2.23 __signgam
0000000000000000 DO *UND* 0000000000000000 GLIBC_2.2.5 signgam
0000000001509d24 g DO .bss 0000000000000004 Base __wrap___signgam
有没有一种规范的方式来包装这些动态对象?
您可以使用动态荷载库(例如-ldl
(并使用其某些功能,特别是dlsym
。
有三个步骤:
- 首先创建源文件。
- 从该源文件创建共享库(
.so
文件( - 调用目标程序(设置环境变量
LD_PRELOAD
以指向.so
文件
请注意,要截获给定的函数,必须使用相同的名称定义函数。
您可以在源文件中拥有任意数量的拦截函数。
以下是一些用于拦截(例如(read
的示例源代码...
// NOTE: need _GNU_SOURCE above for RTLD_NEXT in dlfcn.h
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>
static void
msg(const char *buf)
{
int len;
len = strlen(buf);
write(1,buf,len);
}
// read -- read a file
ssize_t
read(int unit,void *buf,size_t buflen)
{
static ssize_t (*proc)(int,void *,size_t) = NULL;
ssize_t rlen;
// get pointer to real function (only needs to be done once)
if (proc == NULL)
proc = dlsym(RTLD_NEXT,"read");
// do [whatever] stuff before real read ...
msg("PHONY: beforen");
// invoke the real function
rlen = proc(unit,buf,buflen);
// do [whatever] stuff after real read ...
msg("PHONY: aftern");
return rlen;
}
下面是一个示例目标程序:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int
main(void)
{
int fd;
int rlen;
char buf[100];
fd = open("/etc/passwd",O_RDONLY);
rlen = read(fd,buf,sizeof(buf));
close(fd);
printf("main: read %d bytesn",rlen);
return 0;
}
现在创建一个共享库(.so
(。
请注意,下面只有一个源文件。但是,您可以根据需要从任意数量的单独源文件创建库(例如,您可以为每个源文件放置一个截距函数,也可以根据需要将所有内容放在一个源文件中(。
下面是一个 [粗略]Makefile
(创建共享库和示例目标程序(:
all: mylib.so target
read.o: read.c
cc -c -fPIC read.c
mylib.so: read.o
cc -shared -o mylib.so read.o -ldl
target: target.c
cc -o target target.c
test:
env LD_PRELOAD=./mylib.so ./target
clean:
rm -f mylib.so *.o target
现在,要调用目标程序(例如(:
make test
下面是测试的生成输出:
env LD_PRELOAD=./mylib.so ./target
PHONY: before
PHONY: after
main: read 100 bytes