从零开始学IO_FILE的堆利用:理解IO_FILE之fwrite

​ 要学习基于IO_FILE的堆利用就得了解它的本质,以下会介绍几个主要的IO函数,结合源码和动态调试去学习。 调试环境搭建可参考环境从零开始配置pwn环境:从零开始配置pwn环境:优化pwn虚拟机配置支持libc等指令-CSDN博客

1.在开始上源码之前,还是将fwrite的总体流程先描述一遍,好让大家有个大概的概念。

​ 1.1 fwrite函数的总体流程图如下。

1.2 fwrite的主要实现在_IO_new_file_xsputn中,整体流程包含四个部分。

  1. 首先判断输出缓冲区还有多少剩余,如果有剩余则将目标输出数据拷贝到输出缓冲区。

  2. 如果输出缓冲区没有剩余(输出缓冲区未建立也是没有剩余)或输出缓冲区不够则调用_IO_OVERFLOW建立输出缓冲区或刷新输出缓冲区。

  3. 输出缓冲区刷新后判断剩余的目标输出数据是否超过块的size,如果超过块的size,则不通过输出缓冲区直接以块为单位,使用sys_write输出目标数据。

  4. 如果按块输出数据后还剩一点数据则调用_IO_default_xsputn将数据拷贝到输出缓冲区。

1.3​ 接着介绍一下其中涉及的几个IO_FILE结构体的指针。

指针描述
_IO_buf_base输入输出缓冲区基地址
_IO_buf_end输入输出缓冲区结束地址
_IO_write_base输出缓冲区基地址
_IO_write_ptr输入缓冲区当前地址
_IO_write_end输出缓冲区结束地址

​ 其中_IO_buf_base和_IO_buf_end是缓冲区建立函数_IO_doallocbuf(上小结详细描述过)会在里面建立输入输出缓冲区,并把基地址保存在_IO_buf_base中,结束地址保存在_IO_buf_end中。在建立输入输出缓冲区后,如果缓冲区作为输出缓冲区使用,会将基址给_IO_write_base,结束地址给_IO_write_end,同时_IO_write_ptr表示为已经使用的地址。即_IO_write_base到_IO_write_ptr之间的空间是已经使用的缓冲区,_IO_write_ptr到_IO_write_end之间为剩余的输出缓冲区。

​ 1.4 fwrite函数的原型

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
# ptr-- 这是指向要被写入的元素数组的指针。
# size-- 这是要被写入的每个元素的大小,以字节为单位。
# nmemb-- 这是元素的个数,每个元素的大小为 size 字节。
# stream-- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。

1.5 首先是编写一个简单的调用fwrite函数的C程序 

#include<stdio.h>
#include<stdlib.h>
int main(){FILE* fp = fopen("test","wb");char *ptr = malloc(0x20);fwrite(ptr, 1, 0x20, fp);return 0;
} 

2.调试fopen程序

2.1 获得可执行程序 

gcc -g fwrite.c -o fwrite

2.2 ​ 编译完成之后,使用gdb进行调试,在fwrite处下断点。看到程序首先断在_IO_fwrite处。

下载相关程序并复制到相应目录https://github.com/balexios/glibc2.23/blob/master/libio/iofwrite.c

pwndbg> n
7           fwrite(ptr, 1, 0x20, fp);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x602240 ◂— 0x0RBX  0x0RCX  0x7ffff7dd1b20 (main_arena) ◂— 0x100000000RDX  0x602240 ◂— 0x0RDI  0x0RSI  0x602260 ◂— 0x0R8   0x4R9   0x1R10  0x4a1R11  0x7ffff7a91130 (malloc) ◂— push   rbpR12  0x4004c0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400610 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe5b0 —▸ 0x602010 ◂— 0xfbad2484RIP  0x4005df (main+41) ◂— mov    rdx, qword ptr [rbp - 0x10]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x4005c8 <main+18>    call   fopen@plt <0x400490>0x4005cd <main+23>    mov    qword ptr [rbp - 0x10], rax0x4005d1 <main+27>    mov    edi, 0x200x4005d6 <main+32>    call   malloc@plt <0x400480>0x4005db <main+37>    mov    qword ptr [rbp - 8], rax► 0x4005df <main+41>    mov    rdx, qword ptr [rbp - 0x10]0x4005e3 <main+45>    mov    rax, qword ptr [rbp - 8]0x4005e7 <main+49>    mov    rcx, rdx0x4005ea <main+52>    mov    edx, 0x200x4005ef <main+57>    mov    esi, 10x4005f4 <main+62>    mov    rdi, rax
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/fwrite.c2 #include<stdlib.h>3 int main(){4 5     FILE* fp = fopen("test","wb");6     char *ptr = malloc(0x20);► 7     fwrite(ptr, 1, 0x20, fp);8     return 0;9 } 
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe5b0 —▸ 0x602010 ◂— 0xfbad2484
01:0008│      0x7fffffffe5b8 —▸ 0x602240 ◂— 0x0
02:0010│ rbp  0x7fffffffe5c0 —▸ 0x400610 (__libc_csu_init) ◂— push   r15
03:0018│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
04:0020│      0x7fffffffe5d0 —▸ 0x7fffffffe6a8 —▸ 0x7fffffffe8db ◂— '/ctf/work/wolf/iofile/fwrite'
... ↓
06:0030│      0x7fffffffe5e0 ◂— 0x1f7b99608
07:0038│      0x7fffffffe5e8 —▸ 0x4005b6 (main) ◂— push   rbp
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0           4005df main+41f 1     7ffff7a2d830 __libc_start_main+240
pwndbg> s
__GI__IO_fwrite (buf=0x602240, size=1, count=32, fp=0x602010) at iofwrite.c:31
warning: Source file is more recent than executable.
31      {
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x602240 ◂— 0x0RBX  0x0RCX  0x602010 ◂— 0xfbad2484RDX  0x20RDI  0x602240 ◂— 0x0RSI  0x1R8   0x4R9   0x1R10  0x62cR11  0x7ffff7a7b6e0 (fwrite) ◂— push   r14R12  0x4004c0 (_start) ◂— xor    ebp, ebpR13  0x7fffffffe6a0 ◂— 0x1R14  0x0R15  0x0RBP  0x7fffffffe5c0 —▸ 0x400610 (__libc_csu_init) ◂— push   r15RSP  0x7fffffffe5a8 —▸ 0x4005fc (main+70) ◂— mov    eax, 0RIP  0x7ffff7a7b6e0 (fwrite) ◂— push   r14
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x7ffff7a7b6e0 <fwrite>       push   r140x7ffff7a7b6e2 <fwrite+2>     push   r130x7ffff7a7b6e4 <fwrite+4>     push   r120x7ffff7a7b6e6 <fwrite+6>     push   rbp0x7ffff7a7b6e7 <fwrite+7>     push   rbx0x7ffff7a7b6e8 <fwrite+8>     mov    rbx, rsi0x7ffff7a7b6eb <fwrite+11>    imul   rbx, rdx0x7ffff7a7b6ef <fwrite+15>    test   rbx, rbx0x7ffff7a7b6f2 <fwrite+18>    je     fwrite+264 <0x7ffff7a7b7e8>0x7ffff7a7b6f8 <fwrite+24>    mov    eax, dword ptr [rcx]0x7ffff7a7b6fa <fwrite+26>    mov    r12, rdi
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/iofwrite.c26 27 #include "libioP.h"28 29 _IO_size_t30 _IO_fwrite (const void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)► 31 {32   _IO_size_t request = size * count;33   _IO_size_t written = 0;34   CHECK_FILE (fp, 0);35   if (request == 0)36     return 0;
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe5a8 —▸ 0x4005fc (main+70) ◂— mov    eax, 0
01:0008│      0x7fffffffe5b0 —▸ 0x602010 ◂— 0xfbad2484
02:0010│      0x7fffffffe5b8 —▸ 0x602240 ◂— 0x0
03:0018│ rbp  0x7fffffffe5c0 —▸ 0x400610 (__libc_csu_init) ◂— push   r15
04:0020│      0x7fffffffe5c8 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax
05:0028│      0x7fffffffe5d0 —▸ 0x7fffffffe6a8 —▸ 0x7fffffffe8db ◂— '/ctf/work/wolf/iofile/fwrite'
... ↓
07:0038│      0x7fffffffe5e0 ◂— 0x1f7b99608
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a7b6e0 fwritef 1           4005fc main+70f 2     7ffff7a2d830 __libc_start_main+240
pwndbg> 

​ 2.3 在开始调试之前,还是先把传入的IO_FILE的fp值看一下,如下图所示。

pwndbg> p *_IO_list_all
$1 = {file = {_flags = -72539004, _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 = 0x7ffff7dd2540 <_IO_2_1_stderr_>, _fileno = 3, _flags2 = 0, _old_offset = 0, _cur_column = 0, _vtable_offset = 0 '\000', _shortbuf = "", _lock = 0x6020f0, _offset = -1, _codecvt = 0x0, _wide_data = 0x602100, _freeres_list = 0x0, _freeres_buf = 0x0, __pad5 = 0, _mode = 0, _unused2 = '\000' <repeats 19 times>}, vtable = 0x7ffff7dd06e0 <_IO_file_jumps>
}
pwndbg> 

​ 2.4 此时vtable中的内容如下图。

​pwndbg> p *_IO_list_all->vtable 
$2 = {__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>
}
pwndbg> ​​​

​ 2.5 从图中可以看出刚经过fopen初始化,输入输出缓冲区没有建立,此时所有指针都为空。_IO_fwrite函数在文件/libio/iofwrite.c中。

_IO_size_t
_IO_fwrite (const void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp)
{_IO_size_t request = size * count;...if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1)written = _IO_sputn (fp, (const char *) buf, request);...
}
libc_hidden_def (_IO_fwrite)

​ 2.6 没有做过多操作就调用了_IOsputn函数,该函数是vtable中的__xsputn(_IO_new_file_xsputn)在文件/libio/fileops.c中。源码分析从四个部分进行,其中下面每部分代码都是_IO_new_file_xsputn函数中的源码。

​ 第一部分所包含的代码如下。

_IO_size_t
_IO_new_file_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
{ _IO_size_t count = 0;
...# 判断输出缓冲区还有多少空间else if (f->_IO_write_end > f->_IO_write_ptr)count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */# 如果输出缓冲区有空间,则先把数据拷贝至输出缓冲区if (count > 0){if (count > to_do)count = to_do;...memcpy (f->_IO_write_ptr, s, count);f->_IO_write_ptr += count;# 计算是否还有目标输出数据剩余s += count;to_do -= count;

​ 主要功能就是判断输出缓冲区还有多少空间,其中像示例程序所示的f->_IO_write_end以及f->_IO_write_ptr均为0,此时的输出缓冲区为0。

​ 另一部分则是如果输出缓冲区仍有剩余空间的话,则将目标输出数据拷贝至输出缓冲区,并计算在输出缓冲区填满后,是否仍然剩余目标输出数据。

​ 第二部分代码如下。

  # 如果还有目标数据剩余,此时则表明输出缓冲区未建立或输出缓冲区已经满了if (to_do + must_flush > 0){_IO_size_t block_size, do_write;# 函数实现清空输出缓冲区或建立缓冲区的功能if (_IO_OVERFLOW (f, EOF) == EOF)return to_do == 0 ? EOF : n - to_do;# 检查输出数据是否是大块block_size = f->_IO_buf_end - f->_IO_buf_base;do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);

​ 2.7 经过了上一步骤,如果还有目标输出数据,表明输出缓冲区未建立或输出缓冲区已经满了,此时调用_IO_OVERFLOW函数。该函数功能主要是实现刷新输出缓冲区或建立缓冲区,它就是vtable中的__overlfow(_IO_new_file_overflow),文件在/libio/fileops.c中。

pwndbg> s
1331          if (_IO_OVERFLOW (f, EOF) == EOF)
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x0RBX  0x602010 ◂— 0xfbad2484RCX  0x602010 ◂— 0xfbad2484RDX  0x0RDI  0x0RSI  0x602240 ◂— 0x0R8   0x6020f0 ◂— 0x100000001R9   0x602010 ◂— 0xfbad2484R10  0x1R11  0x7ffff7a7b6e0 (fwrite) ◂— push   r14R12  0x20R13  0x602240 ◂— 0x0R14  0x1R15  0x0RBP  0x602010 ◂— 0xfbad2484RSP  0x7fffffffe540 ◂— 0x1RIP  0x7ffff7a86278 (_IO_file_xsputn+152) ◂— mov    rax, qword ptr [rbx + 0xd8]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────► 0x7ffff7a86278 <_IO_file_xsputn+152>    mov    rax, qword ptr [rbx + 0xd8]0x7ffff7a8627f <_IO_file_xsputn+159>    mov    esi, 0xffffffff0x7ffff7a86284 <_IO_file_xsputn+164>    mov    rdi, rbx0x7ffff7a86287 <_IO_file_xsputn+167>    mov    rbp, r120x7ffff7a8628a <_IO_file_xsputn+170>    call   qword ptr [rax + 0x18]0x7ffff7a8628d <_IO_file_xsputn+173>    cmp    eax, -10x7ffff7a86290 <_IO_file_xsputn+176>    je     _IO_file_xsputn+123 <0x7ffff7a8625b>0x7ffff7a86292 <_IO_file_xsputn+178>    mov    rcx, qword ptr [rbx + 0x40]0x7ffff7a86296 <_IO_file_xsputn+182>    sub    rcx, qword ptr [rbx + 0x38]0x7ffff7a8629a <_IO_file_xsputn+186>    xor    edx, edx0x7ffff7a8629c <_IO_file_xsputn+188>    cmp    rcx, 0x7f
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/fileops.c1326     }1327   if (to_do + must_flush > 0)1328     {1329       _IO_size_t block_size, do_write;1330       /* Next flush the (full) buffer. */► 1331       if (_IO_OVERFLOW (f, EOF) == EOF)1332         /* If nothing else has to be written we must not signal the1333            caller that everything has been written.  */1334         return to_do == 0 ? EOF : n - to_do;1335 1336       /* Try to maintain alignment: write a whole number of blocks.  */
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe540 ◂— 0x1
01:0008│      0x7fffffffe548 ◂— 0x20 /* ' ' */
02:0010│      0x7fffffffe550 —▸ 0x602010 ◂— 0xfbad2484
03:0018│      0x7fffffffe558 —▸ 0x602240 ◂— 0x0
04:0020│      0x7fffffffe560 ◂— 0x20 /* ' ' */
05:0028│      0x7fffffffe568 ◂— 0x1
06:0030│      0x7fffffffe570 ◂— 0x0
07:0038│      0x7fffffffe578 —▸ 0x7ffff7a7b7bb (fwrite+219) ◂— cmp    rax, -1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a86278 _IO_file_xsputn+152f 1     7ffff7a7b7bb fwrite+219f 2           4005fc main+70f 3     7ffff7a2d830 __libc_start_main+240
pwndbg> 
int
_IO_new_file_overflow (_IO_FILE *f, int ch)
{# 判断标志位是否包含_IO_NO_WRITESif (f->_flags & _IO_NO_WRITES) /* SET ERROR */{f->_flags |= _IO_ERR_SEEN;__set_errno (EBADF);return EOF;}# 判断输出缓冲区是否为空if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL){/* Allocate a buffer if needed. */if (f->_IO_write_base == NULL){# 分配输出缓冲区_IO_doallocbuf (f);_IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);}# 初始化指针if (f->_IO_read_ptr == f->_IO_buf_end)f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;f->_IO_write_ptr = f->_IO_read_ptr;f->_IO_write_base = f->_IO_write_ptr;f->_IO_write_end = f->_IO_buf_end;f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;f->_flags |= _IO_CURRENTLY_PUTTING;if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))f->_IO_write_end = f->_IO_write_ptr;}# 输出输出缓冲区 if (ch == EOF)return _IO_do_write (f, f->_IO_write_base,f->_IO_write_ptr - f->_IO_write_base);if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */if (_IO_do_flush (f) == EOF) ## return EOF;*f->_IO_write_ptr++ = ch;if ((f->_flags & _IO_UNBUFFERED)|| ((f->_flags & _IO_LINE_BUF) && ch == '\n'))if (_IO_do_write (f, f->_IO_write_base,f->_IO_write_ptr - f->_IO_write_base) == EOF)return EOF;return (unsigned char) ch;
}
libc_hidden_ver (_IO_new_file_overflow, _IO_file_overflow)

​ __overflow函数首先检测_IO_FILE的flags是否包含_IO_NO_WRITES标志位,如果包含的话直接返回。

​ 接着判断f->_IO_write_base是否为空,如果为空表明输出缓冲区尚未建立,就调用_IO_doallocbuf函数去分配输出缓冲区,_IO_doallocbuf函数源码在上小节fread中已经分析过了,就不继续跟进分析了,总结下它功能就是分配输出输出缓冲区并将指针_IO_buf_base和_IO_buf_end赋值。

​ 在执行_IO_doallocbuf分配完空间后调用_IO_setg宏,该宏的定义如下,它将输出相关的缓冲区指针赋值为_IO_buf_base指针。

#define _IO_setg(fp, eb, g, eg)  ((fp)->_IO_read_base = (eb),
(fp)->_IO_read_ptr = (g), (fp)->_IO_read_end = (eg))

​ 2.8 经过上面这些步骤,此时IO_FILE的指针如下图所示。可以看到_IO_buf_base和_IO_buf_end被赋值了,且输出相关缓冲区指针被赋值为_IO_buf_base。

pwndbg> n
_IO_new_file_overflow (f=0x602010, ch=-1) at fileops.c:821
821               _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x1RBX  0x602010 ◂— 0xfbad2484RCX  0x1RDX  0xfbad2484RDI  0x0RSI  0x602270 ◂— 0x0R8   0x6020f0 ◂— 0x100000001R9   0x602010 ◂— 0xfbad2484R10  0x1R11  0x346R12  0x20R13  0x602240 ◂— 0x0R14  0x1R15  0x0RBP  0xffffffffRSP  0x7fffffffe520 —▸ 0x602010 ◂— 0xfbad2484RIP  0x7ffff7a878f8 (_IO_file_overflow+456) ◂— mov    rdx, qword ptr [rbx + 0x38]
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a878f0 <_IO_file_overflow+448>    mov    rdi, rbx0x7ffff7a878f3 <_IO_file_overflow+451>    call   _IO_doallocbuf <0x7ffff7a88560>► 0x7ffff7a878f8 <_IO_file_overflow+456>    mov    rdx, qword ptr [rbx + 0x38]0x7ffff7a878fc <_IO_file_overflow+460>    mov    ecx, dword ptr [rbx]0x7ffff7a878fe <_IO_file_overflow+462>    mov    qword ptr [rbx + 0x18], rdx0x7ffff7a87902 <_IO_file_overflow+466>    mov    qword ptr [rbx + 8], rdx0x7ffff7a87906 <_IO_file_overflow+470>    mov    qword ptr [rbx + 0x10], rdx0x7ffff7a8790a <_IO_file_overflow+474>    jmp    _IO_file_overflow+119 <0x7ffff7a877a7>↓0x7ffff7a877a7 <_IO_file_overflow+119>    test   ch, 10x7ffff7a877aa <_IO_file_overflow+122>    jne    _IO_file_overflow+256 <0x7ffff7a87830>0x7ffff7a877b0 <_IO_file_overflow+128>    mov    rax, qword ptr [rbx + 0x40]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/fileops.c816     {817       /* Allocate a buffer if needed. */818       if (f->_IO_write_base == NULL)819  {820    _IO_doallocbuf (f);► 821    _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);822  }823       /* Otherwise must be currently reading.824   If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,825   logically slide the buffer forwards one block (by setting the826   read pointers to all point at the beginning of the block).  This
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe520 —▸ 0x602010 ◂— 0xfbad2484
01:0008│      0x7fffffffe528 ◂— 0x20 /* ' ' */
... ↓
03:0018│      0x7fffffffe538 —▸ 0x7ffff7a8628d (_IO_file_xsputn+173) ◂— cmp    eax, -1
04:0020│      0x7fffffffe540 ◂— 0x1
05:0028│      0x7fffffffe548 ◂— 0x20 /* ' ' */
06:0030│      0x7fffffffe550 —▸ 0x602010 ◂— 0xfbad2484
07:0038│      0x7fffffffe558 —▸ 0x602240 ◂— 0x0
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a878f8 _IO_file_overflow+456f 1     7ffff7a8628d _IO_file_xsputn+173f 2     7ffff7a7b7bb fwrite+219f 3           4005fc main+70f 4     7ffff7a2d830 __libc_start_main+240
pwndbg> n
830           if (__glibc_unlikely (_IO_in_backup (f)))
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x1RBX  0x602010 ◂— 0xfbad2484RCX  0xfbad2484RDX  0x602270 ◂— 0x0RDI  0x0RSI  0x602270 ◂— 0x0R8   0x6020f0 ◂— 0x100000001R9   0x602010 ◂— 0xfbad2484R10  0x1R11  0x346R12  0x20R13  0x602240 ◂— 0x0R14  0x1R15  0x0RBP  0xffffffffRSP  0x7fffffffe520 —▸ 0x602010 ◂— 0xfbad2484RIP  0x7ffff7a877a7 (_IO_file_overflow+119) ◂— test   ch, 1
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a878fc <_IO_file_overflow+460>    mov    ecx, dword ptr [rbx]0x7ffff7a878fe <_IO_file_overflow+462>    mov    qword ptr [rbx + 0x18], rdx0x7ffff7a87902 <_IO_file_overflow+466>    mov    qword ptr [rbx + 8], rdx0x7ffff7a87906 <_IO_file_overflow+470>    mov    qword ptr [rbx + 0x10], rdx0x7ffff7a8790a <_IO_file_overflow+474>    jmp    _IO_file_overflow+119 <0x7ffff7a877a7>↓► 0x7ffff7a877a7 <_IO_file_overflow+119>    test   ch, 10x7ffff7a877aa <_IO_file_overflow+122>    jne    _IO_file_overflow+256 <0x7ffff7a87830>0x7ffff7a877b0 <_IO_file_overflow+128>    mov    rax, qword ptr [rbx + 0x40]0x7ffff7a877b4 <_IO_file_overflow+132>    cmp    rax, rdx0x7ffff7a877b7 <_IO_file_overflow+135>    je     _IO_file_overflow+400 <0x7ffff7a878c0>0x7ffff7a877bd <_IO_file_overflow+141>    mov    rsi, qword ptr [rbx + 0x10]
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/fileops.c825   logically slide the buffer forwards one block (by setting the826   read pointers to all point at the beginning of the block).  This827   makes room for subsequent output.828   Otherwise, set the read pointers to _IO_read_end (leaving that829   alone, so it can continue to correspond to the external position). */► 830       if (__glibc_unlikely (_IO_in_backup (f)))831  {832    size_t nbackup = f->_IO_read_end - f->_IO_read_ptr;833    _IO_free_backup_area (f);834    f->_IO_read_base -= MIN (nbackup,835                             f->_IO_read_base - f->_IO_buf_base);
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe520 —▸ 0x602010 ◂— 0xfbad2484
01:0008│      0x7fffffffe528 ◂— 0x20 /* ' ' */
... ↓
03:0018│      0x7fffffffe538 —▸ 0x7ffff7a8628d (_IO_file_xsputn+173) ◂— cmp    eax, -1
04:0020│      0x7fffffffe540 ◂— 0x1
05:0028│      0x7fffffffe548 ◂— 0x20 /* ' ' */
06:0030│      0x7fffffffe550 —▸ 0x602010 ◂— 0xfbad2484
07:0038│      0x7fffffffe558 —▸ 0x602240 ◂— 0x0
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a877a7 _IO_file_overflow+119f 1     7ffff7a8628d _IO_file_xsputn+173f 2     7ffff7a7b7bb fwrite+219f 3           4005fc main+70f 4     7ffff7a2d830 __libc_start_main+240
pwndbg> p *_IO_list_all
$6 = {file = {_flags = -72539004, _IO_read_ptr = 0x602270 "", _IO_read_end = 0x602270 "", _IO_read_base = 0x602270 "", _IO_write_base = 0x0, _IO_write_ptr = 0x0, _IO_write_end = 0x0, _IO_buf_base = 0x602270 "", _IO_buf_end = 0x603270 "", _IO_save_base = 0x0, _IO_backup_base = 0x0, _IO_save_end = 0x0, _markers = 0x0, _chain = 0x7ffff7dd2540 <_IO_2_1_stderr_>, _fileno = 3, _flags2 = 0, _old_offset = 0, _cur_column = 0, _vtable_offset = 0 '\000', _shortbuf = "", _lock = 0x6020f0, _offset = -1, _codecvt = 0x0, _wide_data = 0x602100, _freeres_list = 0x0, _freeres_buf = 0x0, __pad5 = 0, _mode = -1, _unused2 = '\000' <repeats 19 times>}, vtable = 0x7ffff7dd06e0 <_IO_file_jumps>
}
pwndbg> 

pwndbg> p *_IO_list_all
$6 = {
  file = {
    _flags = -72539004, 
    _IO_read_ptr = 0x602270 "", 
    _IO_read_end = 0x602270 "", 
    _IO_read_base = 0x602270 "", 

    _IO_write_base = 0x0, 
    _IO_write_ptr = 0x0, 
    _IO_write_end = 0x0, 
    _IO_buf_base = 0x602270 "", 
    _IO_buf_end = 0x603270 "", 

    _IO_save_base = 0x0, 
    _IO_backup_base = 0x0, 
    _IO_save_end = 0x0, 
    _markers = 0x0, 
    _chain = 0x7ffff7dd2540 <_IO_2_1_stderr_>, 
    _fileno = 3, 
    _flags2 = 0, 
    _old_offset = 0, 
    _cur_column = 0, 
    _vtable_offset = 0 '\000', 
    _shortbuf = "", 
    _lock = 0x6020f0, 
    _offset = -1, 
    _codecvt = 0x0, 
    _wide_data = 0x602100, 
    _freeres_list = 0x0, 
    _freeres_buf = 0x0, 
    __pad5 = 0, 
    _mode = -1, 
    _unused2 = '\000' <repeats 19 times>
  }, 
  vtable = 0x7ffff7dd06e0 <_IO_file_jumps>
}
pwndbg> 
 

​ 然后代码初始化其他相关指针,最主要的就是将f->_IO_write_base以及f->_IO_write_ptr设置成f->_IO_read_ptr指针;将f->_IO_write_end赋值为f->_IO_buf_end指针。

​2.9 接着就执行_IO_do_write来调用系统调用write输出输出缓冲区,输出的内容为f->_IO_write_ptr到f->_IO_write_base之间的内容。跟进去该函数,函数在/libio/fileops.c中。

int
_IO_new_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do)
{return (to_do == 0|| (_IO_size_t) new_do_write (fp, data, to_do) == to_do) ? 0 : EOF;
}
libc_hidden_ver (_IO_new_do_write, _IO_do_write)

​2.10 该函数调用了new_do_write,跟进去,函数在/libio/fileops.c中。

static
_IO_size_t
new_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do)
{_IO_size_t count;...# 额外判断else if (fp->_IO_read_end != fp->_IO_write_base){_IO_off64_t new_pos= _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);if (new_pos == _IO_pos_BAD)return 0;fp->_offset = new_pos;}# 调用函数输出输出缓冲区count = _IO_SYSWRITE (fp, data, to_do);...# 刷新设置缓冲区指针_IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;fp->_IO_write_end = (fp->_mode <= 0&& (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))? fp->_IO_buf_base : fp->_IO_buf_end);return count;
}

​ 这里有一个判断,判断fp->_IO_read_end是否等于fp->_IO_write_base,如果不等的话,调用_IO_SYSSEEK去调整文件偏移。

2.11​ 接着就调用_IO_SYSWRITE函数,该函数时vtable中的__write(_IO_new_file_write)函数,也就是最终执行系统调用的地方,跟进去看,文件在/libio/fileops.c中。

_IO_ssize_t
_IO_new_file_write (_IO_FILE *f, const void *data, _IO_ssize_t n)
{_IO_ssize_t to_do = n;while (to_do > 0){# 系统调用write输出_IO_ssize_t count = (__builtin_expect (f->_flags2& _IO_FLAGS2_NOTCANCEL, 0)? write_not_cancel (f->_fileno, data, to_do): write (f->_fileno, data, to_do));...   return n;
}

​ 执行完_IO_SYSWRITE函数后,回到new_do_write函数,刷新设置缓冲区指针并返回。

​ 经历了缓冲区建立以及刷新缓冲区,程序返回到_IO_new_file_xsputn函数中,进入到以下代码块。

  # 检查输出数据是否是大块block_size = f->_IO_buf_end - f->_IO_buf_base;do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);if (do_write){# 如果是大块的话则不使用输出缓冲区而直接输出。count = new_do_write (f, s, do_write);to_do -= count;if (count < do_write)return n - to_do;}

2.12 ​ 运行到此处,此时已经经过了_IO_OVERFLOW函数(对输出缓冲区进行了初始化或刷新),也就是说此时的IO_FILE缓冲区指针的状态是处于刷新的初始化状态,输出缓冲区中也没用数据。

​ 上面这部分代码检查剩余目标输出数据大小,如果超过输出缓冲区f->_IO_write_end – f->_IO_write_base的大小,则为了提高效率,不在使用输出缓冲区,而是以块(4kb)为基本单位直接将缓冲区调用new_do_write输出。new_do_write函数在上面已经跟过了,就是输出,并刷新指针设置。

​ 由于示例程序只输出0x20大小的数据,而它的输出缓冲区大小为0x1000,因此不会进入这部分代码。

​ 在以大块为基本单位把数据直接输出后可能还剩余小数据,IO采用的策略是将剩余目标输出数据放入到输出缓冲区里面,相关源码如下。

 # 剩余的数据拷贝至输出缓冲区if (to_do)to_do -= _IO_default_xsputn (f, s+do_write, to_do);

​ 2.13 程序调用_IO_default_xsputn函数对剩下的s + do_write数据进行操作,跟进去该函数,在/libio/genops.c中。

_IO_size_t
_IO_default_xsputn (_IO_FILE *f, const void *data, _IO_size_t n)
{const char *s = (char *) data;_IO_size_t more = n;if (more <= 0)return 0;for (;;){/* Space available. */if (f->_IO_write_ptr < f->_IO_write_end){_IO_size_t count = f->_IO_write_end - f->_IO_write_ptr;if (count > more)count = more;if (count > 20){# 输出长度大于20,则调用memcpy拷贝memcpy (f->_IO_write_ptr, s, count);f->_IO_write_ptr += count;
#endifs += count;}else if (count){# 小于20则直接赋值char *p = f->_IO_write_ptr;_IO_ssize_t i;for (i = count; --i >= 0; )*p++ = *s++;f->_IO_write_ptr = p;}more -= count;}# 如果输出缓冲区为空,则调用_IO_OVERFLOW直接输出。if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)break;more--;}return n - more;
}
libc_hidden_def (_IO_default_xsputn)

​ 可以看到函数最主要的作用就是将剩余的目标输出数据拷贝到输出缓冲区里。为了性能优化,当长度大于20时,使用memcpy拷贝,当长度小于20时,使用for循环赋值拷贝。如果输出缓冲区为空,则调用_IO_OVERFLOW进行输出。

​ 2.14 根据源码可知,示例程序最终会进入_IO_default_xsputn中,并且把数据拷贝到输出缓冲区里,执行完成后,看到IO_FILE结构体的数据如下。

pwndbg> n
459       return n - more;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x602290 ◂— 0x0RBX  0x20RCX  0x0RDX  0x0RDI  0x602290 ◂— 0x0RSI  0x602260 ◂— 0x0R8   0x0R9   0x0R10  0x0R11  0x346R12  0x602010 ◂— 0xfbad2c84R13  0x20R14  0x602260 ◂— 0x0R15  0x0RBP  0x0RSP  0x7fffffffe510 —▸ 0x602010 ◂— 0xfbad2c84RIP  0x7ffff7a886d8 (_IO_default_xsputn+168) ◂— mov    rax, r13
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a886d5 <_IO_default_xsputn+165>    nop    dword ptr [rax]► 0x7ffff7a886d8 <_IO_default_xsputn+168>    mov    rax, r130x7ffff7a886db <_IO_default_xsputn+171>    pop    rbx0x7ffff7a886dc <_IO_default_xsputn+172>    sub    rax, rbp0x7ffff7a886df <_IO_default_xsputn+175>    pop    rbp0x7ffff7a886e0 <_IO_default_xsputn+176>    pop    r120x7ffff7a886e2 <_IO_default_xsputn+178>    pop    r130x7ffff7a886e4 <_IO_default_xsputn+180>    pop    r140x7ffff7a886e6 <_IO_default_xsputn+182>    ret    ↓0x7ffff7a862c7 <_IO_file_xsputn+231>       sub    rbp, rax0x7ffff7a862ca <_IO_file_xsputn+234>       jmp    _IO_file_xsputn+123 <0x7ffff7a8625b>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/genops.c454  }455       if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)456  break;457       more--;458     }► 459   return n - more;460 }461 libc_hidden_def (_IO_default_xsputn)462 463 _IO_size_t464 _IO_sgetn (_IO_FILE *fp, void *data, _IO_size_t n)
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe510 —▸ 0x602010 ◂— 0xfbad2c84
01:0008│      0x7fffffffe518 ◂— 0x20 /* ' ' */
... ↓
03:0018│      0x7fffffffe528 —▸ 0x602240 ◂— 0x0
04:0020│      0x7fffffffe530 ◂— 0x0
05:0028│      0x7fffffffe538 —▸ 0x7ffff7a862c7 (_IO_file_xsputn+231) ◂— sub    rbp, rax
06:0030│      0x7fffffffe540 ◂— 0x1
07:0038│      0x7fffffffe548 ◂— 0x20 /* ' ' */
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a886d8 _IO_default_xsputn+168f 1     7ffff7a862c7 _IO_file_xsputn+231f 2     7ffff7a7b7bb fwrite+219f 3           4005fc main+70f 4     7ffff7a2d830 __libc_start_main+240
pwndbg> n
460     }
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x20RBX  0x20RCX  0x0RDX  0x0RDI  0x602290 ◂— 0x0RSI  0x602260 ◂— 0x0R8   0x0R9   0x0R10  0x0R11  0x346R12  0x602010 ◂— 0xfbad2c84R13  0x20R14  0x602260 ◂— 0x0R15  0x0RBP  0x0RSP  0x7fffffffe510 —▸ 0x602010 ◂— 0xfbad2c84RIP  0x7ffff7a886db (_IO_default_xsputn+171) ◂— pop    rbx
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a886d5 <_IO_default_xsputn+165>    nop    dword ptr [rax]0x7ffff7a886d8 <_IO_default_xsputn+168>    mov    rax, r13► 0x7ffff7a886db <_IO_default_xsputn+171>    pop    rbx0x7ffff7a886dc <_IO_default_xsputn+172>    sub    rax, rbp0x7ffff7a886df <_IO_default_xsputn+175>    pop    rbp0x7ffff7a886e0 <_IO_default_xsputn+176>    pop    r120x7ffff7a886e2 <_IO_default_xsputn+178>    pop    r130x7ffff7a886e4 <_IO_default_xsputn+180>    pop    r140x7ffff7a886e6 <_IO_default_xsputn+182>    ret    ↓0x7ffff7a862c7 <_IO_file_xsputn+231>       sub    rbp, rax0x7ffff7a862ca <_IO_file_xsputn+234>       jmp    _IO_file_xsputn+123 <0x7ffff7a8625b>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/genops.c455       if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)456  break;457       more--;458     }459   return n - more;► 460 }461 libc_hidden_def (_IO_default_xsputn)462 463 _IO_size_t464 _IO_sgetn (_IO_FILE *fp, void *data, _IO_size_t n)465 {
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe510 —▸ 0x602010 ◂— 0xfbad2c84
01:0008│      0x7fffffffe518 ◂— 0x20 /* ' ' */
... ↓
03:0018│      0x7fffffffe528 —▸ 0x602240 ◂— 0x0
04:0020│      0x7fffffffe530 ◂— 0x0
05:0028│      0x7fffffffe538 —▸ 0x7ffff7a862c7 (_IO_file_xsputn+231) ◂— sub    rbp, rax
06:0030│      0x7fffffffe540 ◂— 0x1
07:0038│      0x7fffffffe548 ◂— 0x20 /* ' ' */
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a886db _IO_default_xsputn+171f 1     7ffff7a862c7 _IO_file_xsputn+231f 2     7ffff7a7b7bb fwrite+219f 3           4005fc main+70f 4     7ffff7a2d830 __libc_start_main+240
pwndbg> n
459       return n - more;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x20RBX  0x602010 ◂— 0xfbad2c84RCX  0x0RDX  0x0RDI  0x602290 ◂— 0x0RSI  0x602260 ◂— 0x0R8   0x0R9   0x0R10  0x0R11  0x346R12  0x602010 ◂— 0xfbad2c84R13  0x20R14  0x602260 ◂— 0x0R15  0x0RBP  0x0RSP  0x7fffffffe518 ◂— 0x20 /* ' ' */RIP  0x7ffff7a886dc (_IO_default_xsputn+172) ◂— sub    rax, rbp
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a886d5 <_IO_default_xsputn+165>    nop    dword ptr [rax]0x7ffff7a886d8 <_IO_default_xsputn+168>    mov    rax, r130x7ffff7a886db <_IO_default_xsputn+171>    pop    rbx► 0x7ffff7a886dc <_IO_default_xsputn+172>    sub    rax, rbp0x7ffff7a886df <_IO_default_xsputn+175>    pop    rbp0x7ffff7a886e0 <_IO_default_xsputn+176>    pop    r120x7ffff7a886e2 <_IO_default_xsputn+178>    pop    r130x7ffff7a886e4 <_IO_default_xsputn+180>    pop    r140x7ffff7a886e6 <_IO_default_xsputn+182>    ret    ↓0x7ffff7a862c7 <_IO_file_xsputn+231>       sub    rbp, rax0x7ffff7a862ca <_IO_file_xsputn+234>       jmp    _IO_file_xsputn+123 <0x7ffff7a8625b>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/genops.c454  }455       if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)456  break;457       more--;458     }► 459   return n - more;460 }461 libc_hidden_def (_IO_default_xsputn)462 463 _IO_size_t464 _IO_sgetn (_IO_FILE *fp, void *data, _IO_size_t n)
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe518 ◂— 0x20 /* ' ' */
... ↓
02:0010│      0x7fffffffe528 —▸ 0x602240 ◂— 0x0
03:0018│      0x7fffffffe530 ◂— 0x0
04:0020│      0x7fffffffe538 —▸ 0x7ffff7a862c7 (_IO_file_xsputn+231) ◂— sub    rbp, rax
05:0028│      0x7fffffffe540 ◂— 0x1
06:0030│      0x7fffffffe548 ◂— 0x20 /* ' ' */
07:0038│      0x7fffffffe550 —▸ 0x602010 ◂— 0xfbad2c84
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a886dc _IO_default_xsputn+172f 1     7ffff7a862c7 _IO_file_xsputn+231f 2     7ffff7a7b7bb fwrite+219f 3           4005fc main+70f 4     7ffff7a2d830 __libc_start_main+240
pwndbg> n
460     }
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x20RBX  0x602010 ◂— 0xfbad2c84RCX  0x0RDX  0x0RDI  0x602290 ◂— 0x0RSI  0x602260 ◂— 0x0R8   0x0R9   0x0R10  0x0R11  0x346R12  0x602010 ◂— 0xfbad2c84R13  0x20R14  0x602260 ◂— 0x0R15  0x0RBP  0x0RSP  0x7fffffffe518 ◂— 0x20 /* ' ' */RIP  0x7ffff7a886df (_IO_default_xsputn+175) ◂— pop    rbp
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a886d5 <_IO_default_xsputn+165>    nop    dword ptr [rax]0x7ffff7a886d8 <_IO_default_xsputn+168>    mov    rax, r130x7ffff7a886db <_IO_default_xsputn+171>    pop    rbx0x7ffff7a886dc <_IO_default_xsputn+172>    sub    rax, rbp► 0x7ffff7a886df <_IO_default_xsputn+175>    pop    rbp0x7ffff7a886e0 <_IO_default_xsputn+176>    pop    r120x7ffff7a886e2 <_IO_default_xsputn+178>    pop    r130x7ffff7a886e4 <_IO_default_xsputn+180>    pop    r140x7ffff7a886e6 <_IO_default_xsputn+182>    ret    ↓0x7ffff7a862c7 <_IO_file_xsputn+231>       sub    rbp, rax0x7ffff7a862ca <_IO_file_xsputn+234>       jmp    _IO_file_xsputn+123 <0x7ffff7a8625b>
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/genops.c455       if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)456  break;457       more--;458     }459   return n - more;► 460 }461 libc_hidden_def (_IO_default_xsputn)462 463 _IO_size_t464 _IO_sgetn (_IO_FILE *fp, void *data, _IO_size_t n)465 {
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe518 ◂— 0x20 /* ' ' */
... ↓
02:0010│      0x7fffffffe528 —▸ 0x602240 ◂— 0x0
03:0018│      0x7fffffffe530 ◂— 0x0
04:0020│      0x7fffffffe538 —▸ 0x7ffff7a862c7 (_IO_file_xsputn+231) ◂— sub    rbp, rax
05:0028│      0x7fffffffe540 ◂— 0x1
06:0030│      0x7fffffffe548 ◂— 0x20 /* ' ' */
07:0038│      0x7fffffffe550 —▸ 0x602010 ◂— 0xfbad2c84
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a886df _IO_default_xsputn+175f 1     7ffff7a862c7 _IO_file_xsputn+231f 2     7ffff7a7b7bb fwrite+219f 3           4005fc main+70f 4     7ffff7a2d830 __libc_start_main+240
pwndbg> n
_IO_new_file_xsputn (f=0x602010, data=<optimized out>, n=32) at fileops.c:1354
1354      return n - to_do;
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x20RBX  0x602010 ◂— 0xfbad2c84RCX  0x0RDX  0x0RDI  0x602290 ◂— 0x0RSI  0x602260 ◂— 0x0R8   0x0R9   0x0R10  0x0R11  0x346R12  0x20R13  0x602240 ◂— 0x0R14  0x0R15  0x0RBP  0x0RSP  0x7fffffffe540 ◂— 0x1RIP  0x7ffff7a8625b (_IO_file_xsputn+123) ◂— mov    rax, r12
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a862bc <_IO_file_xsputn+220>    mov    rdx, rbp0x7ffff7a862bf <_IO_file_xsputn+223>    mov    rdi, rbx0x7ffff7a862c2 <_IO_file_xsputn+226>    call   _IO_default_xsputn <0x7ffff7a88630>0x7ffff7a862c7 <_IO_file_xsputn+231>    sub    rbp, rax0x7ffff7a862ca <_IO_file_xsputn+234>    jmp    _IO_file_xsputn+123 <0x7ffff7a8625b>↓► 0x7ffff7a8625b <_IO_file_xsputn+123>    mov    rax, r120x7ffff7a8625e <_IO_file_xsputn+126>    sub    rax, rbp0x7ffff7a86261 <_IO_file_xsputn+129>    add    rsp, 80x7ffff7a86265 <_IO_file_xsputn+133>    pop    rbx0x7ffff7a86266 <_IO_file_xsputn+134>    pop    rbp0x7ffff7a86267 <_IO_file_xsputn+135>    pop    r12
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/fileops.c1349          buffer, but it's somewhat messier for line-buffered files,1350          so we let _IO_default_xsputn handle the general case. */1351       if (to_do)1352         to_do -= _IO_default_xsputn (f, s+do_write, to_do);1353     }► 1354   return n - to_do;1355 }1356 libc_hidden_ver (_IO_new_file_xsputn, _IO_file_xsputn)1357 1358 _IO_size_t1359 _IO_file_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe540 ◂— 0x1
01:0008│      0x7fffffffe548 ◂— 0x20 /* ' ' */
02:0010│      0x7fffffffe550 —▸ 0x602010 ◂— 0xfbad2c84
03:0018│      0x7fffffffe558 —▸ 0x602240 ◂— 0x0
04:0020│      0x7fffffffe560 ◂— 0x20 /* ' ' */
05:0028│      0x7fffffffe568 ◂— 0x1
06:0030│      0x7fffffffe570 ◂— 0x0
07:0038│      0x7fffffffe578 —▸ 0x7ffff7a7b7bb (fwrite+219) ◂— cmp    rax, -1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a8625b _IO_file_xsputn+123f 1     7ffff7a7b7bb fwrite+219f 2           4005fc main+70f 3     7ffff7a2d830 __libc_start_main+240
pwndbg> n
1355    }
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x20RBX  0x602010 ◂— 0xfbad2c84RCX  0x0RDX  0x0RDI  0x602290 ◂— 0x0RSI  0x602260 ◂— 0x0R8   0x0R9   0x0R10  0x0R11  0x346R12  0x20R13  0x602240 ◂— 0x0R14  0x0R15  0x0RBP  0x0RSP  0x7fffffffe540 ◂— 0x1RIP  0x7ffff7a86261 (_IO_file_xsputn+129) ◂— add    rsp, 8
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a862c2 <_IO_file_xsputn+226>    call   _IO_default_xsputn <0x7ffff7a88630>0x7ffff7a862c7 <_IO_file_xsputn+231>    sub    rbp, rax0x7ffff7a862ca <_IO_file_xsputn+234>    jmp    _IO_file_xsputn+123 <0x7ffff7a8625b>↓0x7ffff7a8625b <_IO_file_xsputn+123>    mov    rax, r120x7ffff7a8625e <_IO_file_xsputn+126>    sub    rax, rbp► 0x7ffff7a86261 <_IO_file_xsputn+129>    add    rsp, 80x7ffff7a86265 <_IO_file_xsputn+133>    pop    rbx0x7ffff7a86266 <_IO_file_xsputn+134>    pop    rbp0x7ffff7a86267 <_IO_file_xsputn+135>    pop    r120x7ffff7a86269 <_IO_file_xsputn+137>    pop    r130x7ffff7a8626b <_IO_file_xsputn+139>    pop    r14
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/fileops.c1350          so we let _IO_default_xsputn handle the general case. */1351       if (to_do)1352         to_do -= _IO_default_xsputn (f, s+do_write, to_do);1353     }1354   return n - to_do;► 1355 }1356 libc_hidden_ver (_IO_new_file_xsputn, _IO_file_xsputn)1357 1358 _IO_size_t1359 _IO_file_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n)1360 {
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe540 ◂— 0x1
01:0008│      0x7fffffffe548 ◂— 0x20 /* ' ' */
02:0010│      0x7fffffffe550 —▸ 0x602010 ◂— 0xfbad2c84
03:0018│      0x7fffffffe558 —▸ 0x602240 ◂— 0x0
04:0020│      0x7fffffffe560 ◂— 0x20 /* ' ' */
05:0028│      0x7fffffffe568 ◂— 0x1
06:0030│      0x7fffffffe570 ◂— 0x0
07:0038│      0x7fffffffe578 —▸ 0x7ffff7a7b7bb (fwrite+219) ◂— cmp    rax, -1
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a86261 _IO_file_xsputn+129f 1     7ffff7a7b7bb fwrite+219f 2           4005fc main+70f 3     7ffff7a2d830 __libc_start_main+240
pwndbg> n
__GI__IO_fwrite (buf=0x602240, size=1, count=32, fp=0x602010) at iofwrite.c:37
37        _IO_acquire_lock (fp);
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]───────────────────────────────────────────────────────────────────────────────────────────────────RAX  0x20RBX  0x20RCX  0x0RDX  0x0RDI  0x602290 ◂— 0x0RSI  0x602200 ◂— 0x0R8   0x20R9   0x0R10  0x0R11  0x346R12  0x602240 ◂— 0x0R13  0x20R14  0x1R15  0x0RBP  0x602010 ◂— 0xfbad2c84RSP  0x7fffffffe580 ◂— 0x0RIP  0x7ffff7a7b7c6 (fwrite+230) ◂— test   dword ptr [rbp], 0x8000
────────────────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]─────────────────────────────────────────────────────────────────────────────────────────────────────0x7ffff7a7b7b5 <fwrite+213>    mov    rdi, rbp0x7ffff7a7b7b8 <fwrite+216>    call   qword ptr [rax + 0x38]0x7ffff7a7b7bb <fwrite+219>    cmp    rax, -10x7ffff7a7b7bf <fwrite+223>    mov    r8, rax0x7ffff7a7b7c2 <fwrite+226>    sete   sil► 0x7ffff7a7b7c6 <fwrite+230>    test   dword ptr [rbp], 0x80000x7ffff7a7b7cd <fwrite+237>    je     fwrite+280 <0x7ffff7a7b7f8>↓0x7ffff7a7b7f8 <fwrite+280>    mov    rdx, qword ptr [rbp + 0x88]0x7ffff7a7b7ff <fwrite+287>    sub    dword ptr [rdx + 4], 10x7ffff7a7b803 <fwrite+291>    jne    fwrite+239 <0x7ffff7a7b7cf>0x7ffff7a7b805 <fwrite+293>    mov    qword ptr [rdx + 8], 0
─────────────────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────────────────────────────────────────────
In file: /ctf/work/wolf/iofile/iofwrite.c34   CHECK_FILE (fp, 0);35   if (request == 0)36     return 0;37   _IO_acquire_lock (fp);38   if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1)► 39     written = _IO_sputn (fp, (const char *) buf, request);40   _IO_release_lock (fp);41   /* We have written all of the input in case the return value indicates42      this or EOF is returned.  The latter is a special case where we43      simply did not manage to flush the buffer.  But the data is in the44      buffer and therefore written as far as fwrite is concerned.  */
─────────────────────────────────────────────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffe580 ◂— 0x0
01:0008│      0x7fffffffe588 —▸ 0x7fffffffe5c0 —▸ 0x400610 (__libc_csu_init) ◂— push   r15
02:0010│      0x7fffffffe590 —▸ 0x4004c0 (_start) ◂— xor    ebp, ebp
03:0018│      0x7fffffffe598 —▸ 0x7fffffffe6a0 ◂— 0x1
04:0020│      0x7fffffffe5a0 ◂— 0x0
05:0028│      0x7fffffffe5a8 —▸ 0x4005fc (main+70) ◂— mov    eax, 0
06:0030│      0x7fffffffe5b0 —▸ 0x602010 ◂— 0xfbad2c84
07:0038│      0x7fffffffe5b8 —▸ 0x602240 ◂— 0x0
───────────────────────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────────────────────────────────────────────► f 0     7ffff7a7b7c6 fwrite+230f 1           4005fc main+70f 2     7ffff7a2d830 __libc_start_main+240
pwndbg> p *_IO_list_all
$7 = {file = {_flags = -72536956, _IO_read_ptr = 0x602270 "", _IO_read_end = 0x602270 "", _IO_read_base = 0x602270 "", _IO_write_base = 0x602270 "", _IO_write_ptr = 0x602290 "", _IO_write_end = 0x603270 "", _IO_buf_base = 0x602270 "", _IO_buf_end = 0x603270 "", _IO_save_base = 0x0, _IO_backup_base = 0x0, _IO_save_end = 0x0, _markers = 0x0, _chain = 0x7ffff7dd2540 <_IO_2_1_stderr_>, _fileno = 3, _flags2 = 0, _old_offset = 0, _cur_column = 0, _vtable_offset = 0 '\000', _shortbuf = "", _lock = 0x6020f0, _offset = -1, _codecvt = 0x0, _wide_data = 0x602100, _freeres_list = 0x0, _freeres_buf = 0x0, __pad5 = 0, _mode = -1, _unused2 = '\000' <repeats 19 times>}, vtable = 0x7ffff7dd06e0 <_IO_file_jumps>
}
pwndbg> 

​ 可以看到此时的_IO_write_base为0x602270,而_IO_write_ptr为0x602290,大小正好是0x20。至此,源码分析结束。

3.参考材料

https://wiki.wgpsec.org/knowledge/ctf/iofile.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/263506.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【嵌入式实践】【芝麻】【目录】从0到1给电动车添加指纹锁

0. 前言 该项目是基于stm32F103和指纹模块做了一个通过指纹锁控制电动车的小工具。支持添加指纹、删除指纹&#xff0c;电动车进入P档等待时计时&#xff0c;计时超过5min则自动锁车&#xff0c;计时过程中按刹车可中断P档状态&#xff0c;同时中断锁车计时。改项目我称之为“芝…

FlinkCDC详解

1、FlinkCDC是什么 1.1 CDC是什么 CDC是Chanage Data Capture&#xff08;数据变更捕获&#xff09;的简称。其核心原理就是监测并捕获数据库的变动&#xff08;例如增删改&#xff09;&#xff0c;将这些变更按照发生顺序捕获&#xff0c;将捕获到的数据&#xff0c;写入数据…

ThreeJS 几何体顶点position、法向量normal及uv坐标 | UV映射 - 法向量 - 包围盒

文章目录 几何体的顶点position、法向量normal及uv坐标UV映射UV坐标系UV坐标与顶点坐标设置UV坐标案例1&#xff1a;使用PlaneGeometry创建平面缓存几何体案例2&#xff1a;使用BufferGeometry创建平面缓存几何体 法向量 - 顶点法向量光照计算案例1&#xff1a;不设置顶点法向量…

从故宫修建看「软件物料清单」的重要性 @安全历史01

故宫&#xff0c;这座中国传统文化的重要代表和象征性建筑已屹立近600年&#xff0c;是世界上现存规模最大、保存最为完整的木质结构古建筑之一。 故宫之所以能至今保存完好&#xff0c;除持续保护和修缮外&#xff0c;其使用的木材和砖石等材料也经过了精挑细选&#xff0c;保…

数据库增删改查

DDL: 数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库、表、字段&#xff09;DML: 数据操作语言&#xff0c;用来对数据库表中的数据进行增删改DQL: 数据查询语言&#xff0c;用来查询数据库中表的记录DCL: 数据控制语言&#xff0c;用来创建数据库用户、控制数…

c语言字符函数和字符串函数

目录 1. 字符分类函数2. 字符转换函数3. strlen的使用和模拟实现4. strcpy的使用和模拟实现5. strcat的使用和模拟实现6. strcmp的使用和模拟实现7. strncpy函数的使用8. strncat函数的使用9. strncmp函数的使用10. strstr的使用和模拟实现11. strtok函数的使用12. strerror函数…

设计模式-创建型模式-建造者模式

建造者模式&#xff08;Builder Pattern&#xff09;&#xff1a;将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。 建造者模式一步一步地创建一个复杂的对象&#xff0c;它允许用户只通过指定复杂对象…

Linux-基础知识(黑马学习笔记)

硬件和软件 我们所熟知的计算机是由&#xff1a;硬件和软件组成。 硬件&#xff1a;计算机系统中电子&#xff0c;机械和光电元件等组成的各种物理装置的总称。 软件&#xff1a;是用户和计算机硬件之间的接口和桥梁&#xff0c;用户通过软件与计算机进行交流。 而操作系统…

gensim 实现 TF-IDF

目录 介绍 代码 介绍 TF-IDF&#xff08;Term Frequency-Inverse Document Frequency&#xff09; 含义&#xff1a; TF (Term Frequency): 词频&#xff0c;是指一个词语在当前文档中出现的次数。它衡量的是词语在文档内部的重要性&#xff0c;直观上讲&#xff0c;一个词…

【机器学习科学库】全md文档笔记:Jupyter Notebook和Matplotlib使用(已分享,附代码)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论人工智能相关知识。主要内容包括&#xff0c;了解机器学习定义以及应用场景&#xff0c;掌握机器学习基础环境的安装和使用&#xff0c;掌握利用常用的科学计算库对数据进行展示、分析&#xff0c;学会使用jupyter note…

完美解决ubuntu+windows双系统下时间不正确问题

在同一台电脑上安装ubuntuwindows双系统时&#xff0c;会出现某个系统的时间不正确的问题&#xff0c;而由于windows同步时间实在是太慢了&#xff0c;如果不去解决&#xff0c;windows上的时间大概率一直都是不对的。 原因分析 windows采用LocalTime机制设置时间&#xff0c…

Centos服务器部署前后端项目

目录 准备工作1. 准备传输软件2. 连接服务器 部署Mysql1.下载Mysql(Linux版本)2. 解压3. 修改配置4. 启动服务另一种方法Docker 部署后端1. 在项目根目录中创建Dockerfile文件写入2. 启动 部署前端1. 在项目根目录中创建Dockerfile文件写入2. 启动 准备工作 1. 准备传输软件 …

【C++那些事儿】C++入门 | 命名空间 | 缺省参数 | 引用 | 内联函数 | auto关键字 | 范围for循环 | nullptr

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C那些事儿 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 前言1. C关键字(C98)2. 命名空间2.1 命名空间定义2.2 命名空间使用 3. C输入&输出4. 缺…

【C++】构造函数和析构函数详解

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 类的6个默认成员函数2. 构造函数2.1 概念2.2 构造函数特性2.2.1 语法特性2.2.2 其他特性 3. 析构函数3.1 概念3.2 特性 4. 构造与析构顺序 1. 类的6个默认成员函数 如果一…

一周学会Django5 Python Web开发-Http请求HttpRequest请求类

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计25条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

Repeater:创建大量类似项

Repeater 类型用于创建大量类似项。与其它视图类型一样&#xff0c;Repeater有一个model和一个delegate。 首次创建Repeater时&#xff0c;会创建其所有delegate项。若存在大量delegate项&#xff0c;并且并非所有项都必须同时可见&#xff0c;则可能会降低效率。 有2种方式可…

设计模式学习笔记 - 面向对象 - 7.为什么要多用组合少用继承?如何决定该用组合还是继承?

前言 在面向对象编程中&#xff0c;有一条非常经典的设计原则&#xff1a;组合优于继承&#xff0c;多用组合少用继承。 为什么不推荐使用继承&#xff1f; 组合比继承有哪些优势&#xff1f; 如何判断该用组合还是继承&#xff1f; 为什么不推荐使用继承&#xff1f; 继承…

【2024.02.22】定时执行专家 V7.0 发布 - TimingExecutor V7.0 Release - 龙年春节重大更新版本

目录 ▉ 新版本 V7.0 下载地址 ▉ V7.0 新功能 ▼2024-02-21 V7.0 - 更新日志▼ ▉ V7.0 新UI设计 ▉ 新版本 V7.0 下载地址 BoomWorks软件的最新版本-CSDN博客文章浏览阅读10w次&#xff0c;点赞9次&#xff0c;收藏41次。▉定时执行专家—毫秒精度、专业级的定时任务执行…

【LeetCode每日一题】 单调栈的案例84 柱状图中最大的矩形

84 柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights [2,1,5,6,2,3] 输出&#xff1a;10 解释…

神经网络系列---权重初始化方法

文章目录 权重初始化方法Xavier初始化&#xff08;Xavier initialization&#xff09;Kaiming初始化&#xff0c;也称为He初始化LeCun 初始化正态分布与均匀分布Orthogonal InitializationSparse Initializationn_in和n_out代码实现 权重初始化方法 Xavier初始化&#xff08;X…