PWN系列-初探IO

PWN系列-初探IO

记录一下自己理解的IO,文章的代码均是glibc-2.23版本下的代码。

由于笔者才疏学浅,学识有限,文章中难免会有疏漏和错误之处,恳请各位师傅批评指正,多多包涵。

什么是IO

IO中的I其实就是in,O其实就是out,一个输入,一个输出。

IO长什么样子

_IO_FILE_plus

首先先来认识一下_IO_FILE_plus结构体

struct _IO_FILE_plus
{
  _IO_FILE file;  /* 基础的文件结构体 */
  const struct _IO_jump_t *vtable;  /* 虚表指针 */
};

总结起来,_IO_FILE_plus 结构体通过包含 _IO_FILE 结构体和一个虚表指针。

_IO_FILE

_IO_FILE结构体定义:

struct _IO_FILE {
  int _flags;           /* 文件状态标志 */
  char* _IO_read_ptr;   /* 读取缓冲区的当前位置 */
  char* _IO_read_end;   /* 读取缓冲区的结束位置 */
  char* _IO_read_base;  /* 读取缓冲区的起始位置 */
  char* _IO_write_base; /* 写入缓冲区的起始位置 */
  char* _IO_write_ptr;  /* 写入缓冲区的当前位置 */
  char* _IO_write_end;  /* 写入缓冲区的结束位置 */
  char* _IO_buf_base;   /* 缓冲区的起始位置 */
  char* _IO_buf_end;    /* 缓冲区的结束位置 */
  char *_IO_save_base;  /* 保存位置指针 */
  char *_IO_backup_base;/* 备份缓冲区指针 */
  char *_IO_save_end;   /* 保存结束指针 */
  struct _IO_marker *_markers; /* 标记 */
  struct _IO_FILE *_chain;     /* 文件链表 */
  int _fileno;                 /* 文件描述符 */
#if 0
  int _blksize;                /* 块大小 */
#else
  int _flags2;                 /* 额外标志 */
#endif
  _IO_off_t _old_offset;       /* 旧的偏移量 */
#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001
  unsigned short _cur_column;  /* 当前列号 */
  signed char _vtable_offset;  /* 虚表偏移量 */
  char _shortbuf[1];           /* 短缓冲区 */
#endif
  _IO_lock_t *_lock;           /* 锁 */
#if defined _LIBC_REENTRANT
  _IO_lock_t *_lock_owner;     /* 锁的拥有者 */
  unsigned int _lock_count;    /* 锁计数 */
#endif
  _IO_off64_t _offset;         /* 偏移量 */
  void *__pad1;                /* 填充1 */
  void *__pad2;                /* 填充2 */
  void *__pad3;                /* 填充3 */
  void *__pad4;                /* 填充4 */
  size_t __pad5;               /* 填充5 */
  int _mode;                   /* 模式 */
  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
                               /* 未使用的填充空间 */
};

此结构体定义了标准C库中用于文件操作的内部数据结构。以下是每个成员变量的简要说明:

  • _flags: 文件状态标志,表示文件的各种状态和属性。
  • _IO_read_ptr, _IO_read_end, _IO_read_base: 分别指向读取缓冲区的当前位置、结束位置和起始位置。
  • _IO_write_base, _IO_write_ptr, _IO_write_end: 分别指向写入缓冲区的起始位置、当前位置和结束位置。
  • _IO_buf_base, _IO_buf_end: 分别指向缓冲区的起始位置和结束位置。
  • _IO_save_base, _IO_backup_base, _IO_save_end: 分别用于保存和备份缓冲区的位置指针。
  • _markers: 指向文件流标记的指针。
  • _chain: 指向链表中下一个文件流的指针。
  • _fileno: 文件描述符。
  • _flags2: 额外的文件状态标志。
  • _old_offset: 旧的偏移量。
  • _cur_column, _vtable_offset, _shortbuf: 用于输入输出流的辅助变量。
  • _lock: 指向文件流锁的指针,用于线程安全。
  • _offset: 当前的文件偏移量。
  • __pad1, __pad2, __pad3, __pad4: 用于填充的指针,确保结构体对齐。
  • __pad5: 用于填充的大小。
  • _mode: 文件模式。
  • _unused2: 未使用的填充空间,用于确保结构体的大小和对齐。

_IO_jump_t

struct _IO_jump_t 定义如下:

struct _IO_jump_t
{
  size_t __dummy; 
  size_t __dummy2;
  _IO_finish_t __finish;
  _IO_overflow_t __overflow;
  _IO_underflow_t __underflow;
  _IO_underflow_t __uflow;
  _IO_pbackfail_t __pbackfail;
  _IO_xsputn_t __xsputn;
  _IO_xsgetn_t __xsgetn;
  _IO_seekoff_t __seekoff;
  _IO_seekpos_t __seekpos;
  _IO_setbuf_t __setbuf;
  _IO_sync_t __sync;
  _IO_doallocate_t __doallocate;
  _IO_read_t __read;
  _IO_write_t __write;
  _IO_seek_t __seek;
  _IO_close_t __close;
  _IO_stat_t __stat;
  _IO_showmanyc_t __showmanyc;
  _IO_imbue_t __imbue;
};

这些字段是指向不同函数类型的指针,用于实现多态性和灵活的文件操作。以下是这些函数指针的大致功能说明:

  • __finish: 完成流的操作。
  • __overflow: 处理输出缓冲区溢出的操作。
  • __underflow: 处理输入缓冲区空的操作。
  • __uflow: 处理输入缓冲区下溢的操作。
  • __pbackfail: 处理向输入缓冲区放回字符失败的操作。
  • __xsputn: 写入多个字符的操作。
  • __xsgetn: 读取多个字符的操作。
  • __seekoff: 相对偏移位置的文件定位操作。
  • __seekpos: 绝对位置的文件定位操作。
  • __setbuf: 设置缓冲区的操作。
  • __sync: 同步文件缓冲区的操作。
  • __doallocate: 分配缓冲区的操作。
  • __read: 读取数据的操作。
  • __write: 写入数据的操作。
  • __seek: 文件定位的操作。
  • __close: 关闭文件的操作。
  • __stat: 获取文件状态的操作。
  • __showmanyc: 显示字符数的操作。
  • __imbue: 设置区域设置信息的操作。

_IO_list_all

_IO_list_all 是一个全局变量,在 GNU C 库(glibc)中用于管理所有打开的文件流。它是一个指向 _IO_FILE 结构体链表的指针。通过这个链表,glibc 可以跟踪和操作所有当前打开的文件流。

链表结构

_IO_list_all 是一个指向 _IO_FILE 结构体的指针,而 _IO_FILE 结构体本身包含一个 _chain 指针,指向下一个文件流。因此,所有打开的文件流形成了一个链表。这个链表的头部是 _IO_list_all

作用

  • 管理文件流: 通过维护这个链表,glibc 能够方便地管理所有打开的文件流。每当有新的文件流创建时,会将其添加到链表中;当文件流关闭时,会将其从链表中移除。
  • 文件操作: 许多内部文件操作函数,例如刷新所有文件流、关闭所有文件流等,都需要遍历这个链表,以对每个文件流执行相应的操作。

IO的利用思路

IO利用的大致思路都是构造fake_io结构体,布置一些数据和函数,通过程序正常的执行流程走到IO操作来劫持程序流来getshell。

image-20240523122431321

这就是我目前所认识的IO,IO涉及到很多攻击手法,我应该会另写一篇文章来进行记录各种板子。

这篇文章中的图片来源两位师傅的博客,但是我一下子找不到这两位师傅的博客地址了,故没有在文章末尾添加参考文章,先冒昧的直接拿来了,望见谅。

posted @   山西小嫦娥  阅读(103)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示