从递归学习 function call
- infinite.c
int func() {
static int count = 0;
return ++count && func();
}
int main() {
return func();
}
用 GDB 执行和测试,记得加上 -g:
$ gcc -o infinite infinite.c -g
$ gdb -q infinite
Reading symbols from infinite...done.
(gdb) r
Starting program: /tmp/infinite
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004f8 in func () at infinite.c:3
3 return ++count && func();
(gdb) p count
$1 = 524032
如果将infinite.c 改为以下,重复上述动作:
int func(int x) {
static int count = 0;
return ++count && func(x++);
}
int main() {
return func(0);
}
将得到:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400505 in func (x=1) at infinite.c:3
3 return ++count && func(x++);
(gdb) p count
$1 = 262016
继续修改 infinite.c 為以下,重复上述动作:
int func(int x) {
static int count = 0;
int y = x; // local var
return ++count && func(x++);
}
int main() {
return func(0);
}
将得到以下:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004de in func (x=<error reading variable: Cannot access memory at address 0x7fffff7fefec>) at infinite.c:1
1 int func(int x) {
(gdb) p count
$1 = 174677
stack 里面有 x (parameter), y (local variable), return address
- stack frame
观察UNIX Process 中的 stack 空间:
$ sudo cat /proc/1/maps | grep stack
7fff7e13f000-7fff7e160000 rw-p 00000000 00:00 0 [stack]
60000Hex - 3f000Hex = 21000Hex = 135168Dec
135168 * 4 = 540672
这跟前面的数字很接近!
- return address 很重要,不管有没有选上,都要有 退路
sp = stack pointer; stack register
(AMD x86_64) A stack frame’s best friends are the two registers rsp and rbp, called the “stack pointer” and the “frame pointer”.
function prologue
function epilogue
(gdb) x /16gx $rsp
5.10. Borrow an
stack-based buffer overflow
- CVE-2015-7547
vulnerability in glibc’s DNS client-side resolver that is used to translate human-readable domain names, like google.com, into a network IP address. [读者可以网上自行搜索了解]
- Buffer Overflow : Example of Using GDB to Check Stack Memory(非常好的PPT文档)
准备 gdb-example.c,其內容为
#include <stdio.h>
void foo(char *input) {
int a1 = 11;
int a2 = 22;
char buf[7];
strcpy(buf, input);
}
void main(int argc, char **argv) {
foo(argv[1]);
}
编译,记得加上 -g 和 -m32
用 i686 架构执行 GDB:
$ setarch i686 -R gdb -q ./gdb-example
(gdb) break 6
Breakpoint 1 at 0x804847a: file gdb-example.c, line 6.
(gdb) run “whatever”
Starting program: /tmp/gdb-example "whatever"
Breakpoint 1, foo (input=0xffffd406 "whatever") at gdb-example.c:6
6 strcpy(buf, input);
观察 stack 內容:
(gdb) info frame
Stack level 0, frame at 0xffffd180:
eip = 0x8048490 in foo (gdb-example.c:6); saved eip = 0x80484da
called by frame at 0xffffd1b0
source language c.
Arglist at 0xffffd178, args: input=0xffffd40c "whatever"
Locals at 0xffffd178, Previous frame’s sp is 0xffffd180
Saved registers:
ebp at 0xffffd178, eip at 0xffffd17c
(gdb) x &a1
0xffffd15c: 0x0000000b
(gdb) x &a2
0xffffd160: 0x00000016
(gdb) x buf
0xffffd165: 0x44f7f9c0
(gdb) x 0xffffd160
0xffffd160: 0x00000016
藏在 Heap 里细节
free() 释放的是 pointer 指向位于 heap 的连续内存,而非 pointer 本身占有的内存(*ptr)。
举例來说:
#include <stdlib.h>
int main() {
int *p = (int *) malloc(1024);
free(p);
free(p);
return 0;
}
编译不會有错误,但运行时会失败:
*** Error in './free': double free or corruption (top):
0x000000000067a010 ***
倘若改为以下:
#include <stdlib.h>
int main() {
int *p = (int *) malloc(1024);
free(p);
p = NULL;
free(p);
return 0;
}
则会编译和执行都成功。
因此,为了防止对同一个 pointer 作 free() 两次的操作,而导致程序失败,free() 后应该设定为 NULL。
[ 思考] 为什么 glibc 可以侦测出上述程序的 “double free or corruption” 呢?
malloc / free
在 GNU/Linux 里观察 malloc
事先安装 gdb套件
$ sudo apt install gdb gdb-dbg
GDB 操作:
$ gdb -q `which gdb`
Reading symbols from /usr/bin/gdb...
(gdb) start
...
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe4c8) at ./gdb/gdb.c:25
...
(gdb) p ((double(*)())pow)(2.,3.)
$1 = 8
(gdb) call malloc_stats()
Arena 0:
system bytes = 135168
in use bytes = 28000
Total (incl. mmap):
system bytes = 135168
in use bytes = 28000
max mmap regions = 0
max mmap bytes = 0
$2 = -168929728
(gdb) call malloc_info(0, stdout)
<malloc version="1">
<heap nr="0">
glibc 提供了 malloc_stats() 和 malloc_info() 这两个函数,可显示 process 的 heap 信息
延伸阅读
- 如何实现一个 malloc(https://kb.cnblogs.com/page/512454/)
- c malloc/free 初探 (https://descent-incoming.blogspot.com/2015/06/c-mallocfree.html)
- 用 C 语言编写一个简单的垃圾回收器(https://blog.csdn.net/lxw907304340/article/details/44420119)
原文: Writing a Simple Garbage Collector in C
https://blog.csdn.net/lxw907304340/article/details/44420119
https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html
malloc: first-fit => https://github.com/jserv/mini-arm-os/blob/master/07-Threads/malloc.c
本文暂时没有评论,来添加一个吧(●'◡'●)