说明
根据这篇文章的内容结合glibc-2.27对tcache的分配和释放做了一次调试实验。
测试代码
$ cat t2.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
void *p = malloc(112);
memset(p, 'A', 112);
free(p);
void *p2 = malloc(112);
free(p2);
}
$ gcc t2.c -o t2 -g
$ ldd --version
ldd (Ubuntu GLIBC 2.27-3ubuntu1) 2.27
...
$ uname -a
Linux ubuntu 5.3.0-51-generic #44~18.04.2-Ubuntu SMP Thu Apr 23 14:27:18 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
实验
1. 获取tcache_perthread_struct 地址
gdb t2
b main
r
b *tcache_init+144
c
p victim
set $tcache_0 = victim
输出:
gdb-peda$ b *tcache_init+144
Breakpoint 2 at 0x7ffff7a7a4f0: file malloc.c, line 3005.
gdb-peda$ c
=> 0x7ffff7a7a4f0 <tcache_init+144>: mov rax,QWORD PTR [rip+0x354881] # 0x7ffff7dced78
...
Breakpoint 2, tcache_init () at malloc.c:3005
3005 tcache = (tcache_perthread_struct *) victim;
gdb-peda$ p victim
$1 = (void *) 0x555555756010
gdb-peda$ set $tcache_0 = victim
tcache分的地址为:0x555555756010
断点说明:
b *tcache_init+144 用于定位tcache指针
=> 0x7ffff7a7a4f0 <tcache_init+144>: mov rax,QWORD PTR [rip+0x354881] # 0x7ffff7dced78
# ...
Breakpoint 2, tcache_init () at malloc.c:3005
3005 tcache = (tcache_perthread_struct *) victim;
# ------------------------------------------------------------------------------------------------
2. 获取第一次分配的内存地址
b *_int_malloc+366
c
reg rax
b *main+26
c
p p
p $rax
输出:
gdb-peda$ reg rax
RAX: 0x555555756260 --> 0x0
gdb-peda$ b *main+26
Breakpoint 4 at 0x5555555546f4: file t2.c, line 8.
gdb-peda$ c
[-------------------------------------code-------------------------------------]
0x5555555546e7 <main+13>: call 0x5555555545b0 <malloc@plt>
0x5555555546ec <main+18>: mov QWORD PTR [rbp-0x10],rax
0x5555555546f0 <main+22>: mov rax,QWORD PTR [rbp-0x10]
=> 0x5555555546f4 <main+26>: mov edx,0x70
0x5555555546f9 <main+31>: mov esi,0x41
0x5555555546fe <main+36>: mov rdi,rax
0x555555554701 <main+39>: call 0x5555555545a0 <memset@plt>
0x555555554706 <main+44>: mov rax,QWORD PTR [rbp-0x10]
[------------------------------------stack-------------------------------------]
...
Breakpoint 4, 0x00005555555546f4 in main () at t2.c:8
8 memset(p, 'A', 112);
gdb-peda$ p p
$2 = (void *) 0x555555756260
gdb-peda$ p $rax
$3 = 0x555555756260
第一次malloc出的地址:0x555555756260
断点说明:
b *_int_malloc+366 定位到_int_malloc的return位置,从rax中获取malloc分配的内存地址
=> 0x7ffff7a7843e <_int_malloc+366>: ret
# static void *
# _int_malloc (mstate av, size_t bytes)
# {
# ...
# checked_request2size (bytes, nb);
# if (__glibc_unlikely (av == NULL))
# {
# void *p = sysmalloc (nb, av);
# if (p != NULL)
# alloc_perturb (p, bytes);
# return p;
# }
# ...
# }
b *main+26 回到main函数中查看malloc出的内存地址
# gdb-peda$ disassemble main
# Dump of assembler code for function main:
# ...
0x00005555555546e7 <+13>: call 0x5555555545b0 <malloc@plt>
0x00005555555546ec <+18>: mov QWORD PTR [rbp-0x10],rax
0x00005555555546f0 <+22>: mov rax,QWORD PTR [rbp-0x10]
=> 0x00005555555546f4 <+26>: mov edx,0x70
3. 查看释放tcache的位置
b * __libc_free+1273
c
p *(tcache_perthread_struct *)$tcache_0
n
p *(tcache_perthread_struct *)$tcache_0
n
p *(tcache_perthread_struct *)$tcache_0
输出:
gdb-peda$ b * __libc_free+1273
Breakpoint 5 at 0x7ffff7a7be49: file malloc.c, line 2931.
gdb-peda$ c
=> 0x7ffff7a7be49 <__GI___libc_free+1273>: mov QWORD PTR [rsi+0x40],r12
...
Breakpoint 5, tcache_put (tc_idx=0x6, chunk=0x555555756250) at malloc.c:2931
2931 tcache->entries[tc_idx] = e;
gdb-peda$ p *(tcache_perthread_struct *)$tcache_0
$4 = {
counts = '\000' <repeats 63 times>,
entries = {0x0 <repeats 64 times>}
}
gdb-peda$ n
...
2932 ++(tcache->counts[tc_idx]);
gdb-peda$ p *(tcache_perthread_struct *)$tcache_0
$5 = {
counts = '\000' <repeats 63 times>,
entries = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x555555756260, 0x0 <repeats 57 times>}
}
gdb-peda$ n
gdb-peda$ p *(tcache_perthread_struct *)$tcache_0
$6 = {
counts = "\000\000\000\000\000\000\001", '\000' <repeats 56 times>,
entries = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x555555756260, 0x0 <repeats 57 times>}
}
回收第一次malloc的内存到 tcache.entrise[6]
断点说明:
b * __libc_free+1273 定位到tcache_put函数(内联)
=> 0x7ffff7a7be49 <__GI___libc_free+1273>: mov QWORD PTR [rsi+0x40],r12
...
Breakpoint 5, tcache_put (tc_idx=0x6, chunk=0x555555756250) at malloc.c:2931
2931 tcache->entries[tc_idx] = e;
4. 查看tcache第二次被取出
b *main+61
c
delete 1-7
b *__libc_malloc+401
c
p *(tcache_perthread_struct *)$tcache_0
s
s
s
p *(tcache_perthread_struct *)$tcache_0
s
p *(tcache_perthread_struct *)$tcache_0
b *main+74
c
p p2
输出:
gdb-peda$ b *main+61
Breakpoint 6 at 0x555555554717: file t2.c, line 10.
gdb-peda$ c
...
gdb-peda$ b *__libc_malloc+401
Breakpoint 7 at 0x7ffff7a7b201: file malloc.c, line 2941.
gdb-peda$ c
...
3050 return tcache_get (tc_idx);
gdb-peda$ p *(tcache_perthread_struct *)$tcache_0
$7 = {
counts = "\000\000\000\000\000\000\001", '\000' <repeats 56 times>,
entries = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x555555756260, 0x0 <repeats 57 times>}
}
gdb-peda$ s
...
tcache_get (tc_idx=0x6) at malloc.c:2941
2941 assert (tc_idx < TCACHE_MAX_BINS);
gdb-peda$ s
...
2943 tcache->entries[tc_idx] = e->next;
gdb-peda$ s
...
2944 --(tcache->counts[tc_idx]);
gdb-peda$ p *(tcache_perthread_struct *)$tcache_0
$8 = {
counts = "\000\000\000\000\000\000\001", '\000' <repeats 56 times>,
entries = {0x0 <repeats 64 times>}
}
gdb-peda$ s
gdb-peda$ p *(tcache_perthread_struct *)$tcache_0
$9 = {
counts = '\000' <repeats 63 times>,
entries = {0x0 <repeats 64 times>}
}
gdb-peda$ b *main+74
Breakpoint 8 at 0x555555554724: file t2.c, line 11.
gdb-peda$ c
gdb-peda$ p p2
$10 = (void *) 0x555555756260
释放之前的tcache分配给新的指针p2
断点说明:
b *main+61 定位到main函数第二次调用malloc的位置
[-------------------------------------code-------------------------------------]
0x55555555470a <main+48>: mov rdi,rax
0x55555555470d <main+51>: call 0x555555554590 <free@plt>
0x555555554712 <main+56>: mov edi,0x70
=> 0x555555554717 <main+61>: call 0x5555555545b0 <malloc@plt>
0x55555555471c <main+66>: mov QWORD PTR [rbp-0x8],rax
0x555555554720 <main+70>: mov rax,QWORD PTR [rbp-0x8]
0x555555554724 <main+74>: mov rdi,rax
0x555555554727 <main+77>: call 0x555555554590 <free@plt>
[------------------------------------stack-------------------------------------]
b *__libc_malloc+401 定位到tcache_get的调用位置
=> 0x7ffff7a7b201 <__GI___libc_malloc+401>: cmp rax,0x3f
...
Breakpoint 7, __GI___libc_malloc (bytes=0x70) at malloc.c:3050
3050 return tcache_get (tc_idx);
b *main+61 定位到第二次malloc返回的位置
=> 0x555555554724 <main+74>: mov rdi,rax
0x555555554727 <main+77>: call 0x555555554590 <free@plt>
0x55555555472c <main+82>: mov eax,0x0
0x555555554731 <main+87>: leave
0x555555554732 <main+88>: ret
参考
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/implementation/tcache/