📰 来源: 博客园
当c语言进行输入输出,打开关闭文件这些操作时,除了read,write,open,close等系统调用函数之外,其他的函数都是通过IO结构体来实现的。IO结构就是_IO_FILE_plus,而 _IO_FILE_plus包含 _IO_FILE 与IO_jump_t (虚表,vtable)
虚表结构如下
pwndbg> p __GI__IO_file_jumps
$5 = {
__dummy = 0,
__dummy2 = 0,
__finish = 0x7a09c20799d0 <_IO_new_file_finish>,
__overflow = 0x7a09c207a740 <_IO_new_file_overflow>,
__underflow = 0x7a09c207a4b0 <_IO_new_file_underflow>,
__uflow = 0x7a09c207b610 <__GI__IO_default_uflow>,
__pbackfail = 0x7a09c207c990 <__GI__IO_default_pbackfail>,
__xsputn = 0x7a09c20791f0 <_IO_new_file_xsputn>,
__xsgetn = 0x7a09c2078ed0 <__GI__IO_file_xsgetn>,
__seekoff = 0x7a09c20784d0 <_IO_new_file_seekoff>,
__seekpos = 0x7a09c207ba10 <_IO_default_seekpos>,
__setbuf = 0x7a09c2078440 <_IO_new_file_setbuf>,
__sync = 0x7a09c2078380 <_IO_new_file_sync>,
__doallocate = 0x7a09c206d190 <__GI__IO_file_doallocate>,
__read = 0x7a09c20791b0 <__GI__IO_file_read>,
__write = 0x7a09c2078b80 <_IO_new_file_write>,
__seek = 0x7a09c2078980 <__GI__IO_file_seek>,
__close = 0x7a09c2078350 <__GI__IO_file_close>,
__stat = 0x7a09c2078b70 <__GI__IO_file_stat>,
__showmanyc = 0x7a09c207cb00 <_IO_default_showmanyc>,
__imbue = 0x7a09c207cb10 <_IO_default_imbue>
}
在c语言里是这样的
const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_wstr_finish),
JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstrn_overflow),
JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
JUMP_INIT(xsputn, _IO_wdefault_xsputn),
JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
JUMP_INIT(seekoff, _IO_wstr_seekoff),
JUMP_INIT(seekpos, _IO_default_seekpos),
JUMP_INIT(setbuf, _IO_default_setbuf),
JUMP_INIT(sync, _IO_default_sync),
JUMP_INIT(doallocate, _IO_wdefault_doallocate),
JUMP_INIT(read, _IO_default_read),
JUMP_INIT(write, _IO_default_write),
JUMP_INIT(seek, _IO_default_seek),
JUMP_INIT(close, _IO_default_close),
JUMP_INIT(stat, _IO_default_stat),
JUMP_INIT(showmanyc, _IO_default_showmanyc),
JUMP_INIT(imbue, _IO_default_imbue)
};#每个指针的间隔在64位下是0x8
通过虚表可以找到很多的函数指针(就是尖括号/括号里面的这些名字)。从 _IO_FILE 到虚表的偏移32位下是0x94,64位下是0xd8。在libc2.24之前可以通过伪造虚表结构,当这些io函数需要call对应虚表函数时,就会call我们伪造的虚表结构上函数,进而实现call任意函数,在这之后会检查虚表,就需要用虚表内的函数,不能直接位置了。
pwndbg> p __GI__IO_file_jumps
$5 = {
__dummy = 0,
__dummy2 = 0,
__finish = 0x7a09c20799d0 <_IO_new_file_finish>,
__overflow = 0x7a09c207a740 <_IO_new_file_overflow>,
__underflow = 0x7a09c207a4b0 <_IO_new_file_underflow>,
__uflow = 0x7a09c207b610 <__GI__IO_default_uflow>,
__pbackfail = 0x7a09c207c990 <__GI__IO_default_pbackfail>,
__xsputn = 0x7a09c20791f0 <_IO_new_file_xsputn>,
__xsgetn = 0x7a09c2078ed0 <__GI__IO_file_xsgetn>,
__seekoff = 0x7a09c20784d0 <_IO_new_file_seekoff>,
__seekpos = 0x7a09c207ba10 <_IO_default_seekpos>,
__setbuf = 0x7a09c2078440 <_IO_new_file_setbuf>,
__sync = 0x7a09c2078380 <_IO_new_file_sync>,
__doallocate = 0x7a09c206d190 <__GI__IO_file_doallocate>,
__read = 0x7a09c20791b0 <__GI__IO_file_read>,
__write = 0x7a09c2078b80 <_IO_new_file_write>,
__seek = 0x7a09c2078980 <__GI__IO_file_seek>,
__close = 0x7a09c2078350 <__GI__IO_file_close>,
__stat = 0x7a09c2078b70 <__GI__IO_file_stat>,
__showmanyc = 0x7a09c207cb00 <_IO_default_showmanyc>,
__imbue = 0x7a09c207cb10 <_IO_default_imbue>
}
const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden =
{
JUMP_INIT_DUMMY,
JUMP_INIT(finish, _IO_wstr_finish),
JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstrn_overflow),
JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_unde
🔗 原文链接: 点击阅读原文
文章评论