【发布时间】:2016-04-08 04:09:05
【问题描述】:
LD_PRELOAD 可用于在另一个之前链接共享对象。所以我尝试覆盖 glibc 中的 memcpy。
我定义了我的memcpy,它将反转src的字节顺序并返回NULL以与glibc的memcpy区分开来
mymem.c
#include <string.h>
void *memcpy(void *dest, const void *src, size_t n) {
char *dest_c = dest;
const char *src_c = src;
size_t i = 0;
//reverse the byte order in src
for(i = 0; i < n; i++)
dest_c[i] = src_c[n-i-1];
return NULL;
}
test.c
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "hello";
char str2[100] = {};
char *ret;
//print the address of str2
printf("str2: %p\n", str2);
//print str2, address of memcpy, return value of memcpy
ret = memcpy(str2, str, 6);
printf("%s %p %p\n", str2, memcpy, ret);
//the same
ret = memcpy(str2, str, 3);
printf("%s %p %p\n", str2, memcpy, ret);
//the same
ret = memcpy(str2, str, 8);
printf("%s %p %p\n", str2, memcpy, ret);
return 0;
}
编译并运行:
$gcc -shared -o libmem.so mymem.c
$gcc test.c -o test
$export LD_PRELOAD="./libmem.so"
$./test
结果:
str2: 0x7fff0297e710
hello 0x400470 0x7fff0297e710
lehlo 0x400470 (nil)
0x400470 (nil)
当第三个参数等于 char 数组的大小(在这种情况下,sizeof str 为 6)时,输出与我预期的不一样。
在第一个 memcpy 之后,我认为 str2[0] 应该是 '\0',所以 str2 是一个空字符串,但输出是“hello”。并且memcpy的返回值应该是NULL,但是输出的是str2的地址。看起来 glic 的 memcpy 有效(我不确定)。
其他两个 memcpy 工作正常。
我已经在 debian 8 和 ubuntu 14.04 中对其进行了测试。
谁能解释一下?
【问题讨论】:
-
memcpy可以内联或通过“intrinsic”实现——请运行nm -D your_binary进行验证。 -
另外,
printf可能会在内部使用memcpy,这会使您的测试变得非常复杂 :) 请重载一些罕见的函数,或者重载外部副作用(与可逆数据重整相反)