Hook malloc和free 段错误调试

Hook malloc 和 free 段错误调试

1、自定义的 mallocfree

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// my_malloc.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

void* malloc(size_t size) {
static void* (*real_malloc)(size_t) = NULL;
if (!real_malloc) {
real_malloc = dlsym(RTLD_NEXT, "malloc");
if (!real_malloc) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
exit(1);
}
}
void* ptr = real_malloc(size);
printf("malloc(%zu) = %p\n", size, ptr);
return ptr;
}

void free(void* ptr) {
static void (*real_free)(void*) = NULL;
if (!real_free) {
real_free = dlsym(RTLD_NEXT, "free");
if (!real_free) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
exit(1);
}
}
printf("free(%p)\n", ptr);
real_free(ptr);
}

编译命令:

1
gcc -shared -fPIC -o libmymalloc.so my_malloc.c -ldl

2、测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// main.c

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

int main()
{
printf("enter main...\n");

int *p = (int *)malloc(10 * sizeof(int)); // 分配足够的内存
if (!p) {
printf("allocation error...\n");
exit(1);
}

printf("returning to main...\n");

free(p);

if (strcmp("aa", "bb") == 0)
{
printf("hook strcmp\n");
}
else
{
printf("not match\n");
}

return 0;
}

编译命令:

1
gcc main.c libmymalloc.so -o main -g

3、运行结果(段错误)

1
2
linhanmic@MOSS:~/study$ ./main
Segmentation fault

4、gdb 调试

1
2
3
4
5
6
7
8
Temporary breakpoint 1, main () at main.c:7
7 printf("enter main...\n");
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7e01097 in __printf_buffer (buf=buf@entry=0x7fffff7ff370,
format=format@entry=0x7ffff7fba01d "malloc(%zu) = %p\n", ap=ap@entry=0x7fffff7ff470, mode_flags=mode_flags@entry=0)
at ./stdio-common/vfprintf-internal.c:600

5、错误分析

根据调试信息发现,段错误发生在 printf 函数中,由于 printf 函数内部调用了 malloc ,而 hook 后的 malloc 内部又调用了 printf 函数,导致函数 递归调用 造成 栈溢出,出现 Segmentation fault

6、解决方案

避免在mallocfree中调用printf:可以使用write函数代替printf,因为write是一个系统调用,不会调用malloc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <unistd.h>
#include <string.h>

void* malloc(size_t size) {
static void* (*real_malloc)(size_t) = NULL;
if (!real_malloc) {
real_malloc = dlsym(RTLD_NEXT, "malloc");
if (!real_malloc) {
const char *error = "Error in `dlsym` for `malloc`\n";
write(STDERR_FILENO, error, strlen(error));
_exit(1);
}
}
void* ptr = real_malloc(size);
char buffer[256];
int len = snprintf(buffer, sizeof(buffer), "malloc(%zu) = %p\n", size, ptr);
write(STDOUT_FILENO, buffer, len);
return ptr;
}

void free(void* ptr) {
static void (*real_free)(void*) = NULL;
if (!real_free) {
real_free = dlsym(RTLD_NEXT, "free");
if (!real_free) {
const char *error = "Error in `dlsym` for `free`\n";
write(STDERR_FILENO, error, strlen(error));
_exit(1);
}
}
char buffer[256];
int len = snprintf(buffer, sizeof(buffer), "free(%p)\n", ptr);
write(STDOUT_FILENO, buffer, len);
real_free(ptr);
}

修改后的运行结果:

1
2
3
4
5
6
7
linhanmic@MOSS:~/study$ ./main
malloc(1024) = 0x558cae5fa2a0
enter main...
malloc(40) = 0x558cae5fa6b0
returning to main...
free(0x558cae5fa6b0)
not match

7、总结

1、在 hook 时调用其他函数,由于不知道函数内部实现容易出现递归调用导致栈溢出

2、善用 gdb 调试程序能够快速地定位错误,达到事半功倍的效果


Hook malloc和free 段错误调试
https://linhanmic.github.io/2023/10/12/Hook-malloc和free-段错误调试/
作者
Linhanmic
发布于
2023年10月12日
更新于
2024年9月5日
许可协议