0

我现在正在研究在 Ubuntu 18.04 中使用 C 进行库插入,并且我正在测试两个简单的代码来包装strlen:“mystrlen.c”、“mystrlenTest.c”。

这是我写的代码:mystrlen.c

#ifdef RUNTIME
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>

/* strlen wrapper function */
size_t strlen(const char *str) {
    size_t (*strlenp)(const char *) = NULL;
    printf("%s\n", *str);

    strlenp = dlsym(RTLD_NEXT, "strlen");   // Get address of libc strlen
    printf("length: %ld\n", strlenp(str));

    return strlenp(str);
}
#endif

和 mystrlenTest.c:

#include <stdio.h>
#include <string.h>

int main(void) {
    char testString[] = "Hello World!";
    printf("length of the testString: %ld\n", strlen(testString));

    return 0;
}

我尝试在运行时使用以下命令注入:

$ gcc -DRUNTIME -shared -fpic -g -o mystrlen.so mystrlen.c -ldl
$ gcc -g -o mystrlenTest mystrlenTest.c
$ LD_PRELOAD=./mystrlen.so ./mystrlenTest

这就是我得到的全部:Segmentation fault (core dumped) 所以我尝试dmesg使用命令找出发生了什么,结果如下:

[842291.658267] mystrlenTest[51446]: segfault at 48 ip 00007f7b918e35a1 sp 00007ffdd7158c88 error 4 in libc-2.27.so[7f7b91755000+1e7000]
[842291.658272] Code: 2e 0f 1f 84 00 00 00 00 00 31 c0 c5 f8 77 c3 66 2e 0f 1f 84 00 00 00 00 00 89 f9 48 89 fa c5 f9 ef c0 83 e1 3f 83 f9 20 77 1f <c5> fd 74 0f c5 fd d7 c1 85 c0 0f 85 df 00 00 00 48 83 c7 20 83 e1

我想问的是,我怎样才能用gdb调试这个?或者有没有其他方法可以调试它?我知道如何使用 gdb 调试单个程序,但我在调试运行时库 interpositioned process 时遇到了困难。如果我能找出其中的内容00007f7b918e35a1,那将是一个很大的帮助。

4

2 回答 2

1

调用 gdb 时,可以传递要设置的环境变量,比如:

gdb --args env LD_PRELOAD=./mystrlen.so ./mystrlenTest

现在您可以像往常一样在 gdb 中使用获取回溯。

您还可以使用系统调用来打印调试消息,例如:

write(2, "message", sizeof "message" - 1);

它根本不调用任何库函数。(虽然,大多数系统调用在 glibc 中都有瘦包装器,这与其用户在很大程度上无关)。在您的具体情况下,可能的问题是Andrew Henle 指出的printf本身调用strlen,从而导致无限递归。

插入时,您需要注意从插入函数中调用的内容,并始终问自己,来自插入函数内部的任何调用是否可能导致回调同一个插入函数或任何其他插入函数,并采取必要措施处理此类案件。例如,许多标准函数可能会通过malloc家庭函数在内部分配内存,如果您是中间人malloc和朋友,这可能会导致意想不到的问题。

于 2019-11-30T13:26:38.217 回答
1

鉴于此代码:

size_t strlen(const char *str) {
    size_t (*strlenp)(const char *) = NULL;
    printf("%s\n", *str);

    strlenp = dlsym(RTLD_NEXT, "strlen");   // Get address of libc strlen
    printf("length: %ld\n", strlenp(str));

    return strlenp(str);
}

如果在内部printf()使用strlen(),您将获得无限递归,并且几乎可以肯定会违反分段。

请注意,在libc.soLinux 上使用的 GLIBCprintf()是通过 实现vfprintf(),它确实使用了strlen().

于 2019-11-29T01:54:33.510 回答