吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2731|回复: 4
上一主题 下一主题
收起左侧

[系统底层] IOFile学习及其作用和应用

  [复制链接]
跳转到指定楼层
楼主
helloxyj 发表于 2024-1-8 14:33 回帖奖励
本帖最后由 helloxyj 于 2024-1-8 14:34 编辑

IO_FILE学习及其作用和应用

1、结构

struct _IO_FILE {
  int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _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;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 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;
#ifdef _IO_USE_OLD_IO_FILE
};
struct _IO_FILE_complete
{
  struct _IO_FILE _file;
#endif
#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001
  _IO_off64_t _offset;
# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
  /* Wide character stream stuff.  */
  struct _IO_codecvt *_codecvt;
  struct _IO_wide_data *_wide_data;
  struct _IO_FILE *_freeres_list;
  void *_freeres_buf;
# else
  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)];
#endif
};

初始状态下,_IO_list_all 指向了一个有这些文件流构成的链表,IO_FILE有三个文件流是自动打开的,分别是stdin、stdout、stderr,这三个文件流在libc.so的data段,并且有符号表,这些符号都指向FILE结构的指针,分别是:

_IO_2_1_stderr_
_IO_2_1_stdout_
_IO_2_1_stdin_

_IO_FILE 结构外包裹着另一种结构_IO_FILE_plus,其中包含了一个重要的指针 vtable 指向了一系列函数指针,在 libc2.23 版本下,32 位的 vtable 偏移为 0x94,64 位偏移为 0xd8。

fread 是标准 IO 库函数,作用是从文件流中读数据,fread 的代码位于 / libio/iofread.c 中,函数名为_IO_fread,函数原型如下

size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;
buffer 存放读取数据的缓冲区。
size:指定每个记录的长度。
count: 指定记录的个数。
stream:目标文件流。
返回值:返回读取到数据缓冲区中的记录个数

fwrite 同样是标准 IO 库函数,作用是向文件流写入数据,fwrite 的代码位于 / libio/iofwrite.c 中,函数名为_IO_fwrite,函数原型如下,

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
buffer: 是一个指针,对 fwrite 来说,是要写入数据的地址;
size: 要写入内容的单字节数;
count: 要进行写入 size 字节的数据项的个数;
stream: 目标文件指针;
返回值:实际写入的数据项个数 count。

fopen 在标准 IO 库中用于打开文件,函数原型如下

FILE *fopen(char *filename, *type);
filename: 目标文件的路径
type: 打开方式的类型
返回值: 返回一个文件指针

总结一下 fopen 的操作是

  • 使用 malloc 分配 FILE 结构
  • 设置 FILE 结构的 vtable
  • 初始化分配的 FILE 结构
  • 将初始化的 FILE 结构链入 FILE 结构链表中
  • 调用系统调用打开文件

fclose 是标准 IO 库中用于关闭已打开文件的函数,其作用与 fopen 相反。

int fclose(FILE *stream)

关闭一个文件流,使用 fclose 就可以把缓冲区内最后剩余的数据输出到磁盘文件中,并释放文件指针和有关的缓冲区

2、伪造vtable劫持程序流程

伪造 vtable 劫持程序流程的中心思想就是针对_IO_FILE_plus 的 vtable 动手脚,通过把 vtable 指向我们控制的内存,并在其中布置函数指针来实现。vtable 劫持分为两种,一种是直接改写 vtable 中的函数指针,通过任意地址写就可以实现。另一种是覆盖 vtable 的指针指向我们控制的内存,然后在其中布置函数指针。

3、利用IO_FILE泄露地址

p64(0x0FBAD1887) +p64(0)*3 + p8(0x88)  #从flag位置开始,修改为这样就可以泄露地址

_flags规则:_flag的高两位字节是由libc固定的,不同的libc可能存在差异,但是基本上都一样:0xfbad0000。高两位字节其实就是作为一个标识,标志这是一个什么文件。而低两位字节的位数规则决定了程序的执行状态。
_IO_do_write就是我们需要执行的目标函数,这个函数执行后会调用系统调用write输出输出缓冲区,传入_IO_do_write函数的参数为:stdout结构体、_IO_write_base(输出缓冲区起始地址)和size(_IO_write_end - _IO_write_base计算得来),如果我们事先在stdout的_IO_write_base的位置部署要输出的起始地址,那么在去利用_IO_do_write函数,即可打印部分内存地址,打印出来的内容就包含我们所需要泄露的libc。

我们只需要满足如下几条对_flags的设定,即可利用_IO_2_1_stdout泄露libc

#define _IO_MAGIC 0xFBAD0000
#define _IO_NO_WRITES 8
#define _IO_CURRENTLY_PUTTING 0x800
#define _IO_IS_APPENDING 0x1000
1、设置_flags & _IO_NO_WRITES = 0
2、设置_flags & _IO_CURRENTLY_PUTTING = 1
3、设置_flags & _IO_IS_APPENDING = 1
_flags = 0xFBAD1800
4、设置_IO_write_base指向想要泄露的位置,_IO_write_ptr指向泄露结束的地址(不需要一定设置指向结尾,程序中自带地址足够泄露libc)

免费评分

参与人数 5吾爱币 +10 热心值 +5 收起 理由
willJ + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
allspark + 1 + 1 用心讨论,共获提升!
janken + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Zzzzzzz001 + 1 + 1 谢谢@Thanks!
lmx352470462 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

沙发
lmx352470462 发表于 2024-1-8 17:48
果断收藏
3#
FunnyBeast 发表于 2024-1-11 10:07
4#
风之子martin 发表于 2024-1-11 11:06
5#
owulf 发表于 2024-7-10 11:22

果断收藏
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 17:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表