点击蓝字,关注我们
日期:2024-05-16 作者:H4y0 介绍: Linux_io_FILE
基础知识。
0x00 前言
_IO_FILE
利用已成为CTF
中PWN
题的常规利用思路,逐渐成为基础知识,本文将介绍_IO_FILE
的结构及标准I/O
流相关内容。
0x01 IO_FILE结构
在libio.h
文件中有如下定义:
struct _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;
_IO_off64_t _offset;
/* Wide character stream stuff. */
struct _IO_codecvt *_codecvt;
struct _IO_wide_data *_wide_data;
struct _IO_FILE *_freeres_list;
void *_freeres_buf;
void *__pad1;
void *__pad2;
void *__pad3;
void *__pad4;
size_t __pad5;
int _mode;
/* Make sure we don't get into trouble again. */
char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
};
int _flags; :流的状态标志,例如是否到达文件末尾(EOF),是否出现错误等。
char* _IO_xxxx_xxx; :当前的指针位置,包括读、写、缓冲区。
struct _IO_marker *_markers; :标记链表,用于记录文件位置等信息。
struct _IO_FILE *_chain; :指向下一个文件流结构体的指针,用于维护所有打开文件流的链表。
_IO_FILE
结构体是用于表示一个文件流的基本结构。各种文件结构采用单链表的形式连接起来,通过_IO_list_all
访问。_IO_list_all
是_IO_FILE_plus
类型的一个指针。
extern struct _IO_FILE_plus *_IO_list_all;
在glibc
中_IO_list_all
指向程序中所有打开的文件流的链表的头部。每个节点都是一个_IO_FILE_plus
结构,这个结构扩展了 _IO_FILE
结构,并可能包含一些额外的信息,如虚函数表(vtable
)的指针。同时这个链表用于库函数间的通信和管理文件流,例如在程序结束时关闭所有打开的文件流。
struct _IO_FILE_plus
{
FILE file;
const struct _IO_jump_t *vtable;
};
其中vtable
为虚表函数指针,它指向_IO_jump_t
,_IO_jump_t
是一个包含多种IO
相关的函数指针的虚函数表。许多函数在调用过程中会调用虚表中的子函数,这也是某些利用方式中用到的点。
借用一张图片:
可以更直观地了解其结构。
0x02 标准I/O
_IO_FILE
是用于文件操作的核心数据结构,进行文件流的管理并进行文件的I/O
操作。在初始情况下存在stdin、stdout、stderr
即标准输入流、标准输出流、标准错误流。实际上,在libc
中存在3
个全局指针stdin
、stdout
、stderr
分别指向_IO_2_1_stdin_
,_IO_2_1_stdout_
,_IO_2_1_stderr_
。
FILE *stdin = (FILE *) &_IO_2_1_stdin_;
FILE *stdout = (FILE *) &_IO_2_1_stdout_;
FILE *stderr = (FILE *) &_IO_2_1_stderr_;
也就是说初始情况下存在_IO_2_1_stderr_
,_IO_2_1_stdout_
,_IO_2_1_stdin_
这三个IO_FILE
。
static _IO_lock_t _IO_stdfile_
static struct _IO_wide_data _IO_wide_data_
= { ._wide_vtable = &_IO_wfile_jumps }; _IO_wfile_jumps 是一个函数指针表,用于宽字符操作的函数集合。
struct _IO_FILE_plus NAME
= {FILEBUF_LITERAL(CHAIN, FLAGS, FD, &_IO_wide_data_
&_IO_file_jumps}
DEF_STDFILE(_IO_2_1_stdin_, 0, 0, _IO_NO_WRITES);
DEF_STDFILE(_IO_2_1_stdout_, 1, &_IO_2_1_stdin_, _IO_NO_READS);
DEF_STDFILE(_IO_2_1_stderr_, 2, &_IO_2_1_stdout_, _IO_NO_READS+_IO_UNBUFFERED);
struct _IO_FILE_plus *_IO_list_all = &_IO_2_1_stderr_;
libc_hidden_data_def (_IO_list_all)
重点介绍一下struct _IO_FILE_plus NAME = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, &_IO_wide_data_##FD), &_IO_file_jumps}
:这行代码定义了一个 struct _IO_FILE_plus
类型的变量。这个结构体可能包含 _IO_FILE
结构体和一些附加的数据。FILEBUF_LITERAL
是一个宏,用于初始化 _IO_FILE
结构体。_IO_file_jumps
是另一个函数指针表,用于标准字符操作的函数集合。
const struct _IO_jump_t _IO_file_jumps libio_vtable =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_file_finish),
JUMP_INIT(overflow, _IO_file_overflow),
JUMP_INIT(underflow, _IO_file_underflow),
JUMP_INIT(uflow, _IO_default_uflow),
JUMP_INIT(pbackfail, _IO_default_pbackfail),
JUMP_INIT(xsputn, _IO_file_xsputn),
JUMP_INIT(xsgetn, _IO_file_xsgetn),
JUMP_INIT(seekoff, _IO_new_file_seekoff),
JUMP_INIT(seekpos, _IO_default_seekpos),
JUMP_INIT(setbuf, _IO_new_file_setbuf),
JUMP_INIT(sync, _IO_new_file_sync),
JUMP_INIT(doallocate, _IO_file_doallocate),
JUMP_INIT(read, _IO_file_read),
JUMP_INIT(write, _IO_new_file_write),
JUMP_INIT(seek, _IO_file_seek),
JUMP_INIT(close, _IO_file_close),
JUMP_INIT(stat, _IO_file_stat),
JUMP_INIT(showmanyc, _IO_default_showmanyc),
JUMP_INIT(imbue, _IO_default_imbue)
};
libc_hidden_data_def (_IO_file_jumps)
_IO_file_jumps
是_IO_jump_t
结构体的具体实例,每个 JUMP_INIT
宏调用都对应_IO_jump_t
中的一个字段,每个字段都代表一个特定的文件操作函数。利用方法中有很多都用到_IO_file_jumps
中的函数,实际利用还需要进一步了解函数的具体内容。
如图,stderr
、stdout
、stdin
分别指向_IO_2_1_stderr_
,_IO_2_1_stdout_
,_IO_2_1_stdin_
三个结构体。各结构之间通过_chain
连接为链表,并通过_IO_list_all
访问,若有通过fread
等方式创建新的结构体,也会链接到_IO_list_all
链表上。
0x03 总结
_IO_FILE
的利用方法相对模板化,学会利用方法背后的原理及结构可以事半功倍。
希望这篇文章可以帮助大家看懂IO_FILE
结构及原理。
免责声明:本文仅供安全研究与讨论之用,严禁用于非法用途,违者后果自负。
点此亲启
原文始发于微信公众号(宸极实验室):『CTF』IO_FILE 利用入门
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论