pwn | IO_FILE_ 学习

Author Avatar
Aryb1n 4月 07, 2018

setbuf && setvbuf

在学习之前先整理一下最近注意到的setvbuf

int setvbuf(FILE *stream,char *buf,int mode,size_t size)

buf : 如果不指定(null), 那么函数就在堆上给你自动分配一个
type: 缓冲区类型,
    _IOFBF Full(block) buffering, 输出时, 缓冲区满了或者flushed的时时候进行写, 输入时清空缓冲区
    _IOLBF Line buffering, 每次从流中读入一行数据或向流中写入一行数据, 也就是说有换行符才进行读写, 当然缓冲区满了也会写
    _IONBF   No buffering, 不使用缓冲区, 读写操作直接进行, 如果type设置成这个值, 那size和buf参数都会被忽略

还有一个函数setbuf

void setbuf(FILE *stream, char *buf);

当`buf = NULL`的时候, 不使用缓冲区, 相当于 _IONBF
所以这个函数相当于 setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZE)

我们打开的文件一般是Block buffering, 第一次I/O操作的时候会自动分配个适当大小的堆块作为它的缓冲区
stdin 是Line buffing
stdout是Line buffing
stderr是No buffering

一般的ctf题目里都会进行一个操作就是

setvbuf(stdin, 0, 2, 0); // 2就是 _IONBF
setvbuf(stdout, 0, 2, 0);

这样子就不给他们在堆上分配缓冲区了, 所以这样子是为了不干扰做题吗

卧槽…我是在哪看见篇文章说是在IO操作前, 分配个堆, 再free, 就能把free掉的空间给了FILE, 嗷, 找到了是这篇

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

void pwn(void)
{
    printf("Dave, my mind is going.\n");
    fflush(stdout);
}


void * funcs[] = {
    NULL, // "extra word"
    NULL, // DUMMY
    exit, // finish
    NULL, // overflow
    NULL, // underflow
    NULL, // uflow
    NULL, // pbackfail
    NULL, // xsputn
    NULL, // xsgetn
    NULL, // seekoff
    NULL, // seekpos
    NULL, // setbuf
    NULL, // sync
    NULL, // doallocate
    NULL, // read
    NULL, // write
    NULL, // seek
    pwn,  // close
    NULL, // stat
    NULL, // showmanyc
    NULL, // imbue
};

int main(int argc, char * argv[])
{  
    FILE *fp;
    unsigned char *str;

    printf("sizeof(FILE): 0x%x\n", sizeof(FILE));

    /* Allocate and free enough for a FILE plus a pointer. */
    str = malloc(sizeof(FILE) + sizeof(void *));
    printf("freeing %p\n", str);
    free(str);

    /* Open a file, observe it ended up at previous location. */
    if (!(fp = fopen("/dev/null", "r"))) {
        perror("fopen");
        return 1;
    }
    printf("FILE got %p\n", fp);
    printf("_IO_jump_t @ %p is 0x%08lx\n", str + sizeof(FILE), *(unsigned long*)(str + sizeof(FILE)));
    /* Overwrite vtable pointer. */
    *(unsigned long*)(str + sizeof(FILE)) = (unsigned long)funcs;
    printf("_IO_jump_t @ %p now 0x%08lx\n",
    str + sizeof(FILE), *(unsigned long*)(str + sizeof(FILE)));
    /* Trigger call to pwn(). */
    fclose(fp);
    return 0;
}