初识IO-FILE
IO_FILE结构
IO_FILE在Linux系统的标准IO库中是用于描述文件的结构,称为文件流。FILE结构在程序执行fopen等函数时会进行创建,并分配在堆中,进程中的FILE结构通过_chain域彼此连接形成一个链表。在标准I/O库中,每个程序启动时有三个文件流是自动打开的:stdin、stdout、stderr,在libc.so的数据段上。
在libc-2.23版本中,有个局部变量_IO_list_all,该变量指向了FILE链表的头部。_IO_FILE外包裹着另一种结构体_IO_FILE_plus,其中重要指针vtable指向一系列函数指针。libc2.23下,32位的vtable偏移0x94,64位偏移0xd8。_IO_FILE_plus结构体如下代码所示,其中有包括了两个重要的结构体_IO_FILE和IO_jump_t
1 | struct _IO_FILE_plus |
其中_IO_FILE结构体如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42struct _IO_FILE {
int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
/* The following pointers correspond to the C++ streambuf protocol. */
/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
char* _IO_read_ptr; /* Current read pointer */
char* _IO_read_end; /* End of get area. */
char* _IO_read_base; /* Start of putback+get area. */
char* _IO_write_base; /* Start of put area. */
char* _IO_write_ptr; /* Current put pointer. */
char* _IO_write_end; /* End of put area. */
char* _IO_buf_base; /* Start of reserve area. */
char* _IO_buf_end; /* End of reserve area. */
/* The following fields are used to support backing up and undo. */
char *_IO_save_base; /* Pointer to start of non-current get area. */
char *_IO_backup_base; /* Pointer to first valid character of backup area */
char *_IO_save_end; /* Pointer to end of non-current get area. */
struct _IO_marker *_markers;
struct _IO_FILE *_chain;
int _fileno;
int _blksize;
int _flags2;
_IO_off_t _old_offset; /* This used to be _offset but it's too small. */
/* 1+column number of pbase(); 0 is unknown. */
unsigned short _cur_column;
signed char _vtable_offset;
char _shortbuf[1];
/* char* _save_gptr; char* _save_egptr; */
_IO_lock_t *_lock;
};
vtable是IO_jump_t类型的指针1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24void * funcs[] = {
1 NULL, // "extra word"
2 NULL, // DUMMY
3 exit, // finish
4 NULL, // overflow
5 NULL, // underflow
6 NULL, // uflow
7 NULL, // pbackfail
8 NULL, // xsputn #printf
9 NULL, // xsgetn
10 NULL, // seekoff
11 NULL, // seekpos
12 NULL, // setbuf
13 NULL, // sync
14 NULL, // doallocate
15 NULL, // read
16 NULL, // write
17 NULL, // seek
18 pwn, // close
19 NULL, // stat
20 NULL, // showmanyc
21 NULL, // imbue
};
下图展示_IO_list_all变量指向的链表头部,在没有创建其他文件结构,它指向stderr,然后依次是stdout->stdin,通过在前面加上结构体可以打印详细的打印内存数据信息1
_IO_list_all->_IO_2_1_stderr_->_IO_2_1_stdout_->_IO_2_1_stdout

进一步看一下vtable
在_IO_FILE结构中,_chain字段指向下一个链表节点,因此我们可以通过这个字段打印下一个_IO_FILE_plus的结构体信息,如下所示








