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>
}