【问题标题】:how LD_PRELOAD works in my code [closed]LD_PRELOAD 如何在我的代码中工作 [关闭]
【发布时间】: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,这会使您的测试变得非常复杂 :) 请重载一些罕见的函数,或者重载外部副作用(与可逆数据重整相反)

标签: c ld glibc


【解决方案1】:

这是因为出于某种原因,GCC 决定在第一次调用 memcpy 时使用 memcpy 的内联版本。为避免这种情况,您可以使用 -fno-builtin 选项。

另外请注意,如果由于某种原因memcpy 被静态链接到可执行文件,则可能导致memcpy 被静态解析。由于 memcpy 是一个低级函数,因此 CRT 启动代码(静态链接)提供了实现并非不可能。

【讨论】:

    【解决方案2】:

    只需在您的二进制文件上执行objdump -DS(正如qarma 已经建议的那样),您可以看到您的第一个memcpy 不会生成函数调用。这是它在我的机器上的样子:

    //print str2, address of memcpy, return value of memcpy                         
    ret = memcpy(str2, str, 6);                                                     
    40066e:       8b 85 70 ff ff ff       mov    -0x90(%rbp),%eax                     
    400674:       89 45 80                mov    %eax,-0x80(%rbp)                     
    400677:       0f b7 85 74 ff ff ff    movzwl -0x8c(%rbp),%eax                     
    40067e:       66 89 45 84             mov    %ax,-0x7c(%rbp)                      
    400682:       48 8d 45 80             lea    -0x80(%rbp),%rax                     
    400686:       48 89 85 68 ff ff ff    mov    %rax,-0x98(%rbp) 
    

    尝试使用 -fno-builtin-memcpy 进行编译 - 它应该可以解决这个问题:

    ret = memcpy(str2, str, 6);
    40066e:       48 8d 8d 70 ff ff ff    lea    -0x90(%rbp),%rcx
    400675:       48 8d 45 80             lea    -0x80(%rbp),%rax
    400679:       ba 06 00 00 00          mov    $0x6,%edx
    40067e:       48 89 ce                mov    %rcx,%rsi
    400681:       48 89 c7                mov    %rax,%rdi
    400684:       e8 87 fe ff ff          callq  400510 <memcpy@plt>
    400689:       48 89 85 68 ff ff ff    mov    %rax,-0x98(%rbp)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多