IO_FILE-Fopen函数详解

August 2, 2019 PWN 访问: 42 次

源码分析

简单的写一个demo

#include<stdio.h>
int main()
{
    FILE *file_point = fopen("test.txt","r");
    char *heap_point = malloc(0x20);
    return 0;
}

我在ubuntu16.04中调试的,使用的是gdb-pwndbg,glibc的版本是2.23,去官方上下载,glibc-2.23下载地址

编译C时,加上-g参数,这样会保留代码的文字信息
在gdb中附加glibc源码:directory ../glibc-2.23/libio/

首先在main函数下断点

pwndbg> start
Temporary breakpoint 2 at 0x40056e: file 123.c, line 4.
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────────────────────
 RAX  0x400566 (main) ◂— push   rbp
 RBX  0x0
 RCX  0x0
 RDX  0x7fffffffdf98 —▸ 0x7fffffffe312 ◂— 'XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0'
 RDI  0x1
 RSI  0x7fffffffdf88 —▸ 0x7fffffffe302 ◂— '/root/test/test'
 R8   0x400610 (__libc_csu_fini) ◂— ret
 R9   0x7ffff7de7ac0 (_dl_fini) ◂— push   rbp
 R10  0x846
 R11  0x7ffff7a2d740 (__libc_start_main) ◂— push   r14
 R12  0x400470 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffdf80 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffdea0 —▸ 0x4005a0 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffde90 —▸ 0x7fffffffdf80 ◂— 0x1
 RIP  0x40056e (main+8) ◂— mov    esi, 0x400624
──────────────────────────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────────────────────────
 ► 0x40056e <main+8>     mov    esi, 0x400624
   0x400573 <main+13>    mov    edi, 0x400626
   0x400578 <main+18>    call   fopen@plt <0x400450>
   0x40057d <main+23>    mov    qword ptr [rbp - 0x10], rax
   0x400581 <main+27>    mov    edi, 0x20
   0x400586 <main+32>    call   malloc@plt <0x400440>
   0x40058b <main+37>    mov    qword ptr [rbp - 8], rax
   0x40058f <main+41>    mov    eax, 0
   0x400594 <main+46>    leave
   0x400595 <main+47>    ret
   0x400596              nop    word ptr cs:[rax + rax]
──────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────
In file: /root/test/123.c
   1 #include<stdio.h>
   2 int main()
   3 {
 ► 4     FILE *file_point = fopen("test.txt","r");
   5     char *heap_point = malloc(0x20);
   6     return 0;
   7 }
──────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffde90 —▸ 0x7fffffffdf80 ◂— 0x1
01:0008│      0x7fffffffde98 ◂— 0x0
02:0010│ rbp  0x7fffffffdea0 —▸ 0x4005a0 (__libc_csu_init) ◂— push   r15
03:0018│      0x7fffffffdea8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
04:0020│      0x7fffffffdeb0 ◂— 0x1
05:0028│      0x7fffffffdeb8 —▸ 0x7fffffffdf88 —▸ 0x7fffffffe302 ◂— '/root/test/test'
06:0030│      0x7fffffffdec0 ◂— 0x1f7ffcca0
07:0038│      0x7fffffffdec8 —▸ 0x400566 (main) ◂— push   rbp
────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────
 ► f 0           40056e main+8
   f 1     7ffff7a2d830 __libc_start_main+240
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Breakpoint main
Breakpoint main
pwndbg>

在pwndbg中也可以看到C源程序的代码,有点舒服,到fopen函数处,使用s单步步入,可以看到,当我们使用fopen函数的时候,世纪上时调用了_IO_new_fopen函数,

pwndbg> s
_IO_new_fopen (filename=0x400626 "test.txt", mode=0x400624 "r") at iofopen.c:97
97    return __fopen_internal (filename, mode, 1);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────────────────────
 RAX  0x400566 (main) ◂— push   rbp
 RBX  0x0
 RCX  0x0
 RDX  0x7fffffffdf98 —▸ 0x7fffffffe312 ◂— 'XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0'
 RDI  0x400626 ◂— je     0x40068d /* 'test.txt' */
 RSI  0x400624 ◂— jb     0x400626 /* 'r' */
 R8   0x400610 (__libc_csu_fini) ◂— ret
 R9   0x7ffff7de7ac0 (_dl_fini) ◂— push   rbp
 R10  0xad
 R11  0x7ffff7a7ad70 (fopen64) ◂— mov    edx, 1
 R12  0x400470 (_start) ◂— xor    ebp, ebp
 R13  0x7fffffffdf80 ◂— 0x1
 R14  0x0
 R15  0x0
 RBP  0x7fffffffdea0 —▸ 0x4005a0 (__libc_csu_init) ◂— push   r15
 RSP  0x7fffffffde88 —▸ 0x40057d (main+23) ◂— mov    qword ptr [rbp - 0x10], rax
 RIP  0x7ffff7a7ad70 (fopen64) ◂— mov    edx, 1
──────────────────────────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────────────────────────
 ► 0x7ffff7a7ad70 <fopen64>                mov    edx, 1
   0x7ffff7a7ad75 <fopen64+5>              jmp    __fopen_internal <0x7ffff7a7acc0>
    ↓
   0x7ffff7a7acc0 <__fopen_internal>       push   r13
   0x7ffff7a7acc2 <__fopen_internal+2>     push   r12
   0x7ffff7a7acc4 <__fopen_internal+4>     mov    r13d, edx
   0x7ffff7a7acc7 <__fopen_internal+7>     push   rbp
   0x7ffff7a7acc8 <__fopen_internal+8>     push   rbx
   0x7ffff7a7acc9 <__fopen_internal+9>     mov    rbp, rdi
   0x7ffff7a7accc <__fopen_internal+12>    mov    edi, 0x228
   0x7ffff7a7acd1 <__fopen_internal+17>    mov    r12, rsi
   0x7ffff7a7acd4 <__fopen_internal+20>    sub    rsp, 8
──────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────
In file: /root/glibc-2.23/libio/iofopen.c
    92 }
    93
    94 _IO_FILE *
    95 _IO_new_fopen (const char *filename, const char *mode)
    96 {
 ►  97   return __fopen_internal (filename, mode, 1);
    98 }
    99
   100 #ifdef _LIBC
   101 strong_alias (_IO_new_fopen, __new_fopen)
   102 versioned_symbol (libc, _IO_new_fopen, _IO_fopen, GLIBC_2_1);
──────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffde88 —▸ 0x40057d (main+23) ◂— mov    qword ptr [rbp - 0x10], rax
01:0008│      0x7fffffffde90 —▸ 0x7fffffffdf80 ◂— 0x1
02:0010│      0x7fffffffde98 ◂— 0x0
03:0018│ rbp  0x7fffffffdea0 —▸ 0x4005a0 (__libc_csu_init) ◂— push   r15
04:0020│      0x7fffffffdea8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
05:0028│      0x7fffffffdeb0 ◂— 0x1
06:0030│      0x7fffffffdeb8 —▸ 0x7fffffffdf88 —▸ 0x7fffffffe302 ◂— '/root/test/test'
07:0038│      0x7fffffffdec0 ◂— 0x1f7ffcca0
────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────
 ► f 0     7ffff7a7ad70 fopen64
   f 1           40057d main+23
   f 2     7ffff7a2d830 __libc_start_main+240
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg>

_IO_new_fopen函数中是调用了__fopen_internal,再单步步入

_IO_FILE *
__fopen_internal (const char *filename, const char *mode, int is32)
{
  struct locked_FILE
  {
    struct _IO_FILE_plus fp;
#ifdef _IO_MTSAFE_IO
    _IO_lock_t lock;
#endif
    struct _IO_wide_data wd;
  } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
  if (new_f == NULL)
    return NULL;
#ifdef _IO_MTSAFE_IO
  new_f->fp.file._lock = &new_f->lock;
#endif
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
  _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps);
#else
  _IO_no_init (&new_f->fp.file, 1, 0, NULL, NULL);
#endif
  _IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
  _IO_file_init (&new_f->fp);
#if  !_IO_UNIFIED_JUMPTABLES
  new_f->fp.vtable = NULL;
#endif
  if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, is32) != NULL)
    return __fopen_maybe_mmap (&new_f->fp.file);
  _IO_un_link (&new_f->fp);
  free (new_f);
  return NULL;
}

首先是使用malloc分配空间(struct locked_FILE)

pwndbg> n
71    if (new_f == NULL)
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────────────────────
 RAX  0x602010 ◂— 0x0
 RBX  0x0
 RCX  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
 RDX  0x602010 ◂— 0x0
 RDI  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000
 RSI  0x602230 ◂— 0x0
 R8   0x602000 ◂— 0x0
 R9   0xd
 R10  0x7ffff7dd1b78 (main_arena+88) —▸ 0x602230 ◂— 0x0
 R11  0x0
 R12  0x400624 ◂— jb     0x400626 /* 'r' */
 R13  0x1
 R14  0x0
 R15  0x0
 RBP  0x400626 ◂— je     0x40068d /* 'test.txt' */
 RSP  0x7fffffffde60 ◂— 0x1
 RIP  0x7ffff7a7acdd (__fopen_internal+29) ◂— test   rax, rax
──────────────────────────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────────────────────────
   0x7ffff7a7acc9 <__fopen_internal+9>     mov    rbp, rdi
   0x7ffff7a7accc <__fopen_internal+12>    mov    edi, 0x228
   0x7ffff7a7acd1 <__fopen_internal+17>    mov    r12, rsi
   0x7ffff7a7acd4 <__fopen_internal+20>    sub    rsp, 8
   0x7ffff7a7acd8 <__fopen_internal+24>    call   0x7ffff7a2c8a0
 ► 0x7ffff7a7acdd <__fopen_internal+29>    test   rax, rax
   0x7ffff7a7ace0 <__fopen_internal+32>    je     __fopen_internal+157 <0x7ffff7a7ad5d>
   0x7ffff7a7ace2 <__fopen_internal+34>    mov    rbx, rax
   0x7ffff7a7ace5 <__fopen_internal+37>    lea    rax, [rax + 0xe0]
   0x7ffff7a7acec <__fopen_internal+44>    lea    r8, [rip + 0x35556d] <0x7ffff7dd0260>
   0x7ffff7a7acf3 <__fopen_internal+51>    lea    rcx, [rbx + 0xf0]
──────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────
In file: /root/glibc-2.23/libio/iofopen.c
   66     _IO_lock_t lock;
   67 #endif
   68     struct _IO_wide_data wd;
   69   } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));
   70
 ► 71   if (new_f == NULL)
   72     return NULL;
   73 #ifdef _IO_MTSAFE_IO
   74   new_f->fp.file._lock = &new_f->lock;
   75 #endif
   76 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
──────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffde60 ◂— 0x1
01:0008│      0x7fffffffde68 ◂— 0x0
02:0010│      0x7fffffffde70 —▸ 0x7fffffffdea0 —▸ 0x4005a0 (__libc_csu_init) ◂— push   r15
03:0018│      0x7fffffffde78 —▸ 0x400470 (_start) ◂— xor    ebp, ebp
04:0020│      0x7fffffffde80 —▸ 0x7fffffffdf80 ◂— 0x1
05:0028│      0x7fffffffde88 —▸ 0x40057d (main+23) ◂— mov    qword ptr [rbp - 0x10], rax
06:0030│      0x7fffffffde90 —▸ 0x7fffffffdf80 ◂— 0x1
07:0038│      0x7fffffffde98 ◂— 0x0
────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────
 ► f 0     7ffff7a7acdd __fopen_internal+29
   f 1           40057d main+23
   f 2     7ffff7a2d830 __libc_start_main+240
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> heap
0x602000 PREV_INUSE {
  prev_size = 0,
  size = 561,
  fd = 0x0,
  bk = 0x0,
  fd_nextsize = 0x0,
  bk_nextsize = 0x0
}
0x602230 PREV_INUSE {
  prev_size = 0,
  size = 134609,
  fd = 0x0,
  bk = 0x0,
  fd_nextsize = 0x0,
  bk_nextsize = 0x0
}
pwndbg>

可以看到new_f是一个0x230大小的chunk(带chunk的头部)
结构体数据如下:

$2 = {
  fp = {
    file = {
      _flags = 0,
      _IO_read_ptr = 0x0,
      _IO_read_end = 0x0,
      _IO_read_base = 0x0,
      _IO_write_base = 0x0,
      _IO_write_ptr = 0x0,
      _IO_write_end = 0x0,
      _IO_buf_base = 0x0,
      _IO_buf_end = 0x0,
      _IO_save_base = 0x0,
      _IO_backup_base = 0x0,
      _IO_save_end = 0x0,
      _markers = 0x0,
      _chain = 0x0,
      _fileno = 0,
      _flags2 = 0,
      _old_offset = 0,
      _cur_column = 0,
      _vtable_offset = 0 '\000',
      _shortbuf = "",
      _lock = 0x0,
      _offset = 0,
      _codecvt = 0x0,
      _wide_data = 0x0,
      _freeres_list = 0x0,
      _freeres_buf = 0x0,
      __pad5 = 0,
      _mode = 0,
      _unused2 = '\000' <repeats 19 times>
    },
    vtable = 0x0
  },
  lock = {
    lock = 0,
    cnt = 0,
    owner = 0x0
  },
  wd = {
    _IO_read_ptr = 0x0,
    _IO_read_end = 0x0,
    _IO_read_base = 0x0,
    _IO_write_base = 0x0,
    _IO_write_ptr = 0x0,
    _IO_write_end = 0x0,
    _IO_buf_base = 0x0,
    _IO_buf_end = 0x0,
    _IO_save_base = 0x0,
    _IO_backup_base = 0x0,
    _IO_save_end = 0x0,
    _IO_state = {
      __count = 0,
      __value = {
        __wch = 0,
        __wchb = "\000\000\000"
      }
    },
    _IO_last_state = {
      __count = 0,
      __value = {
        __wch = 0,
        __wchb = "\000\000\000"
      }
    },
    _codecvt = {
      __codecvt_destr = 0x0,
      __codecvt_do_out = 0x0,
      __codecvt_do_unshift = 0x0,
      __codecvt_do_in = 0x0,
      __codecvt_do_encoding = 0x0,
      __codecvt_do_always_noconv = 0x0,
      __codecvt_do_length = 0x0,
      __codecvt_do_max_length = 0x0,
      __cd_in = {
        __cd = {
          __nsteps = 0,
          __steps = 0x0,
          __data = 0x6021b8
        },
        __combined = {
          __cd = {
            __nsteps = 0,
            __steps = 0x0,
            __data = 0x6021b8
          },
          __data = {
            __outbuf = 0x0,
            __outbufend = 0x0,
            __flags = 0,
            __invocation_counter = 0,
            __internal_use = 0,
            __statep = 0x0,
            __state = {
              __count = 0,
              __value = {
                __wch = 0,
                __wchb = "\000\000\000"
              }
            }
          }
        }
      },
      __cd_out = {
        __cd = {
          __nsteps = 0,
          __steps = 0x0,
          __data = 0x6021f8
        },
        __combined = {
          __cd = {
            __nsteps = 0,
            __steps = 0x0,
            __data = 0x6021f8
          },
          __data = {
            __outbuf = 0x0,
            __outbufend = 0x0,
            __flags = 0,
            __invocation_counter = 0,
            __internal_use = 0,
            __statep = 0x0,
            __state = {
              __count = 0,
              __value = {
                __wch = 0,
                __wchb = "\000\000\000"
              }
            }
          }
        }
      }
    },
    _shortbuf = L"",
    _wide_vtable = 0x0
  }
}

然后判断是否分配成功

  if (new_f == NULL)
    return NULL;

然后调用_IO_no_init初始化new_f_IO_no_init内部代码在glibc-2.23/libio/genops.c

void
_IO_no_init (fp, flags, orientation, wd, jmp)
     _IO_FILE *fp;
     int flags;
     int orientation;
     struct _IO_wide_data *wd;
     struct _IO_jump_t *jmp;
{
  fp->_flags = _IO_MAGIC|flags;
  fp->_flags2 = 0;
  fp->_IO_buf_base = NULL;
  fp->_IO_buf_end = NULL;
  fp->_IO_read_base = NULL;
  fp->_IO_read_ptr = NULL;
  fp->_IO_read_end = NULL;
  fp->_IO_write_base = NULL;
  fp->_IO_write_ptr = NULL;
  fp->_IO_write_end = NULL;
  fp->_chain = NULL; /* Not necessary. */
  fp->_IO_save_base = NULL;
  fp->_IO_backup_base = NULL;
  fp->_IO_save_end = NULL;
  fp->_markers = NULL;
  fp->_cur_column = 0;
#if _IO_JUMPS_OFFSET
  fp->_vtable_offset = 0;
#endif
#ifdef _IO_MTSAFE_IO
  if (fp->_lock != NULL)
    _IO_lock_init (*fp->_lock);
#endif
  fp->_mode = orientation;
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
  if (orientation >= 0)
    {
      fp->_wide_data = wd;
      fp->_wide_data->_IO_buf_base = NULL;
      fp->_wide_data->_IO_buf_end = NULL;
      fp->_wide_data->_IO_read_base = NULL;
      fp->_wide_data->_IO_read_ptr = NULL;
      fp->_wide_data->_IO_read_end = NULL;
      fp->_wide_data->_IO_write_base = NULL;
      fp->_wide_data->_IO_write_ptr = NULL;
      fp->_wide_data->_IO_write_end = NULL;
      fp->_wide_data->_IO_save_base = NULL;
      fp->_wide_data->_IO_backup_base = NULL;
      fp->_wide_data->_IO_save_end = NULL;
      fp->_wide_data->_wide_vtable = jmp;
    }
#endif
}

初始化后的new_f结构体如下:

$3 = {
  fp = {
    file = {
      _flags = -72548352,
      _IO_read_ptr = 0x0,
      _IO_read_end = 0x0,
      _IO_read_base = 0x0,
      _IO_write_base = 0x0,
      _IO_write_ptr = 0x0,
      _IO_write_end = 0x0,
      _IO_buf_base = 0x0,
      _IO_buf_end = 0x0,
      _IO_save_base = 0x0,
      _IO_backup_base = 0x0,
      _IO_save_end = 0x0,
      _markers = 0x0,
      _chain = 0x0,
      _fileno = 0,
      _flags2 = 0,
      _old_offset = 0,
      _cur_column = 0,
      _vtable_offset = 0 '\000',
      _shortbuf = "",
      _lock = 0x6020f0,
      _offset = 0,
      _codecvt = 0x0,
      _wide_data = 0x602100,
      _freeres_list = 0x0,
      _freeres_buf = 0x0,
      __pad5 = 0,
      _mode = 0,
      _unused2 = '\000' <repeats 19 times>
    },
    vtable = 0x0
  },
  lock = {
    lock = 0,
    cnt = 0,
    owner = 0x0
  },
  wd = {
    _IO_read_ptr = 0x0,
    _IO_read_end = 0x0,
    _IO_read_base = 0x0,
    _IO_write_base = 0x0,
    _IO_write_ptr = 0x0,
    _IO_write_end = 0x0,
    _IO_buf_base = 0x0,
    _IO_buf_end = 0x0,
    _IO_save_base = 0x0,
    _IO_backup_base = 0x0,
    _IO_save_end = 0x0,
    _IO_state = {
      __count = 0,
      __value = {
        __wch = 0,
        __wchb = "\000\000\000"
      }
    },
    _IO_last_state = {
      __count = 0,
      __value = {
        __wch = 0,
        __wchb = "\000\000\000"
      }
    },
    _codecvt = {
      __codecvt_destr = 0x0,
      __codecvt_do_out = 0x0,
      __codecvt_do_unshift = 0x0,
      __codecvt_do_in = 0x0,
      __codecvt_do_encoding = 0x0,
      __codecvt_do_always_noconv = 0x0,
      __codecvt_do_length = 0x0,
      __codecvt_do_max_length = 0x0,
      __cd_in = {
        __cd = {
          __nsteps = 0,
          __steps = 0x0,
          __data = 0x6021b8
        },
        __combined = {
          __cd = {
            __nsteps = 0,
            __steps = 0x0,
            __data = 0x6021b8
          },
          __data = {
            __outbuf = 0x0,
            __outbufend = 0x0,
            __flags = 0,
            __invocation_counter = 0,
            __internal_use = 0,
            __statep = 0x0,
            __state = {
              __count = 0,
              __value = {
                __wch = 0,
                __wchb = "\000\000\000"
              }
            }
          }
        }
      },
      __cd_out = {
        __cd = {
          __nsteps = 0,
          __steps = 0x0,
          __data = 0x6021f8
        },
        __combined = {
          __cd = {
            __nsteps = 0,
            __steps = 0x0,
            __data = 0x6021f8
          },
          __data = {
            __outbuf = 0x0,
            __outbufend = 0x0,
            __flags = 0,
            __invocation_counter = 0,
            __internal_use = 0,
            __statep = 0x0,
            __state = {
              __count = 0,
              __value = {
                __wch = 0,
                __wchb = "\000\000\000"
              }
            }
          }
        }
      }
    },
    _shortbuf = L"",
    _wide_vtable = 0x7ffff7dd0260 <_IO_wfile_jumps>
  }
}

回到__fopen_internal函数,将_IO_FILE_plus结构体设置成了&_IO_file_jumps

_IO_JUMPS (&new_f->fp) = &_IO_file_jumps;

然后调用_IO_file_init函数将new_f中的_IO_FILE_plus结构体链到_IO_list_all中,在gdb中跟进(/root/glibc-2.23/libio/fileops.c):

void
_IO_new_file_init (struct _IO_FILE_plus *fp)
{
  /* POSIX.1 allows another file handle to be used to change the position
     of our file descriptor.  Hence we actually don't know the actual
     position before we do the first fseek (and until a following fflush). */
  fp->file._offset = _IO_pos_BAD;
  fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS;
  _IO_link_in (fp);
  fp->file._fileno = -1;
}

这个函数调用了_IO_link_in,源码跟进(/root/glibc-2.23/libio/genops.c

void
_IO_link_in (struct _IO_FILE_plus *fp)
{
  if ((fp->file._flags & _IO_LINKED) == 0)
    {
      fp->file._flags |= _IO_LINKED;
#ifdef _IO_MTSAFE_IO
      _IO_cleanup_region_start_noarg (flush_cleanup);
      _IO_lock_lock (list_all_lock);
      run_fp = (_IO_FILE *) fp;
      _IO_flockfile ((_IO_FILE *) fp);
#endif
      fp->file._chain = (_IO_FILE *) _IO_list_all;
      _IO_list_all = fp;
      ++_IO_list_all_stamp;
#ifdef _IO_MTSAFE_IO
      _IO_funlockfile ((_IO_FILE *) fp);
      run_fp = NULL;
      _IO_lock_unlock (list_all_lock);
      _IO_cleanup_region_end (0);
#endif
    }
}

然后调用_IO_file_fopen函数来打开文件句柄,源码跟进(/root/glibc-2.23/libio/fileops.c):

_IO_FILE *
_IO_new_file_fopen (_IO_FILE *fp, const char *filename, const char *mode,
            int is32not64)
{
  int oflags = 0, omode;
  int read_write;
  int oprot = 0666;
  int i;
  _IO_FILE *result;
#ifdef _LIBC
  const char *cs;
  const char *last_recognized;
#endif
  if (_IO_file_is_open (fp))
    return 0;
  switch (*mode)
    {
    case 'r':
      omode = O_RDONLY;
      read_write = _IO_NO_WRITES;
      break;
    case 'w':
      omode = O_WRONLY;
      oflags = O_CREAT|O_TRUNC;
      read_write = _IO_NO_READS;
      break;
    case 'a':
      omode = O_WRONLY;
      oflags = O_CREAT|O_APPEND;
      read_write = _IO_NO_READS|_IO_IS_APPENDING;
      break;
    default:
      __set_errno (EINVAL);
      return NULL;
    }
#ifdef _LIBC
  last_recognized = mode;
#endif
  for (i = 1; i < 7; ++i)
    {
      switch (*++mode)
    {
    case '\0':
      break;
    case '+':
      omode = O_RDWR;
      read_write &= _IO_IS_APPENDING;
#ifdef _LIBC
      last_recognized = mode;
#endif
      continue;
    case 'x':
      oflags |= O_EXCL;
#ifdef _LIBC
      last_recognized = mode;
#endif
      continue;
    case 'b':
#ifdef _LIBC
      last_recognized = mode;
#endif
      continue;
    case 'm':
      fp->_flags2 |= _IO_FLAGS2_MMAP;
      continue;
    case 'c':
      fp->_flags2 |= _IO_FLAGS2_NOTCANCEL;
      continue;
    case 'e':
#ifdef O_CLOEXEC
      oflags |= O_CLOEXEC;
#endif
      fp->_flags2 |= _IO_FLAGS2_CLOEXEC;
      continue;
    default:
      /* Ignore.  */
      continue;
    }
      break;
    }
  result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write,
              is32not64);
  if (result != NULL)
    {
#ifndef __ASSUME_O_CLOEXEC
      if ((fp->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 && __have_o_cloexec <= 0)
    {
      int fd = _IO_fileno (fp);
      if (__have_o_cloexec == 0)
        {
          int flags = __fcntl (fd, F_GETFD);
          __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
        }
      if (__have_o_cloexec < 0)
        __fcntl (fd, F_SETFD, FD_CLOEXEC);
    }
#endif
      /* Test whether the mode string specifies the conversion.  */
      cs = strstr (last_recognized + 1, ",ccs=");
      if (cs != NULL)
    {
      /* Yep.  Load the appropriate conversions and set the orientation
         to wide.  */
      struct gconv_fcts fcts;
      struct _IO_codecvt *cc;
      char *endp = __strchrnul (cs + 5, ',');
      char *ccs = malloc (endp - (cs + 5) + 3);
      if (ccs == NULL)
        {
          int malloc_err = errno;  /* Whatever malloc failed with.  */
          (void) _IO_file_close_it (fp);
          __set_errno (malloc_err);
          return NULL;
        }
      *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
      strip (ccs, ccs);
      if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
                   ? upstr (ccs, cs + 5) : ccs) != 0)
        {
          /* Something went wrong, we cannot load the conversion modules.
         This means we cannot proceed since the user explicitly asked
         for these.  */
          (void) _IO_file_close_it (fp);
          free (ccs);
          __set_errno (EINVAL);
          return NULL;
        }
      free (ccs);
      assert (fcts.towc_nsteps == 1);
      assert (fcts.tomb_nsteps == 1);
      fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
      fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
      /* Clear the state.  We start all over again.  */
      memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
      memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
      cc = fp->_codecvt = &fp->_wide_data->_codecvt;
      /* The functions are always the same.  */
      *cc = __libio_codecvt;
      cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps;
      cc->__cd_in.__cd.__steps = fcts.towc;
      cc->__cd_in.__cd.__data[0].__invocation_counter = 0;
      cc->__cd_in.__cd.__data[0].__internal_use = 1;
      cc->__cd_in.__cd.__data[0].__flags = __GCONV_IS_LAST;
      cc->__cd_in.__cd.__data[0].__statep = &result->_wide_data->_IO_state;
      cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps;
      cc->__cd_out.__cd.__steps = fcts.tomb;
      cc->__cd_out.__cd.__data[0].__invocation_counter = 0;
      cc->__cd_out.__cd.__data[0].__internal_use = 1;
      cc->__cd_out.__cd.__data[0].__flags
        = __GCONV_IS_LAST | __GCONV_TRANSLIT;
      cc->__cd_out.__cd.__data[0].__statep =
        &result->_wide_data->_IO_state;
      /* From now on use the wide character callback functions.  */
      _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;
      /* Set the mode now.  */
      result->_mode = 1;
    }
    }
  return result;
}

先判断文件是否打开,然后再获取文件打开的方式,再调用_IO_file_open来打开文件

_IO_FILE *
_IO_file_open (_IO_FILE *fp, const char *filename, int posix_mode, int prot,
           int read_write, int is32not64)
{
  int fdesc;
#ifdef _LIBC
  if (__glibc_unlikely (fp->_flags2 & _IO_FLAGS2_NOTCANCEL))
    fdesc = open_not_cancel (filename,
                 posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot);
  else
    fdesc = open (filename, posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot);
#else
  fdesc = open (filename, posix_mode, prot);
#endif
  if (fdesc < 0)
    return NULL;
  fp->_fileno = fdesc;
  _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
  /* For append mode, send the file offset to the end of the file.  Don't
     update the offset cache though, since the file handle is not active.  */
  if ((read_write & (_IO_IS_APPENDING | _IO_NO_READS))
      == (_IO_IS_APPENDING | _IO_NO_READS))
    {
      _IO_off64_t new_pos = _IO_SYSSEEK (fp, 0, _IO_seek_end);
      if (new_pos == _IO_pos_BAD && errno != ESPIPE)
    {
      close_not_cancel (fdesc);
      return NULL;
    }
    }
  _IO_link_in ((struct _IO_FILE_plus *) fp);
  return fp;
}

调用open函数打开文件,最后再次调用_IO_link_in确保这个结构体进入到_IO_list_all链表
最后new_f->$12->fp.vtable的值:

pwndbg> p *(struct _IO_jump_t *)0x7ffff7dd06e0
$19 = {
  __dummy = 0,
  __dummy2 = 0,
  __finish = 0x7ffff7a869c0 <_IO_new_file_finish>,
  __overflow = 0x7ffff7a87730 <_IO_new_file_overflow>,
  __underflow = 0x7ffff7a874a0 <_IO_new_file_underflow>,
  __uflow = 0x7ffff7a88600 <__GI__IO_default_uflow>,
  __pbackfail = 0x7ffff7a89980 <__GI__IO_default_pbackfail>,
  __xsputn = 0x7ffff7a861e0 <_IO_new_file_xsputn>,
  __xsgetn = 0x7ffff7a85ec0 <__GI__IO_file_xsgetn>,
  __seekoff = 0x7ffff7a854c0 <_IO_new_file_seekoff>,
  __seekpos = 0x7ffff7a88a00 <_IO_default_seekpos>,
  __setbuf = 0x7ffff7a85430 <_IO_new_file_setbuf>,
  __sync = 0x7ffff7a85370 <_IO_new_file_sync>,
  __doallocate = 0x7ffff7a7a180 <__GI__IO_file_doallocate>,
  __read = 0x7ffff7a861a0 <__GI__IO_file_read>,
  __write = 0x7ffff7a85b70 <_IO_new_file_write>,
  __seek = 0x7ffff7a85970 <__GI__IO_file_seek>,
  __close = 0x7ffff7a85340 <__GI__IO_file_close>,
  __stat = 0x7ffff7a85b60 <__GI__IO_file_stat>,
  __showmanyc = 0x7ffff7a89af0 <_IO_default_showmanyc>,
  __imbue = 0x7ffff7a89b00 <_IO_default_imbue>
}

添加新评论