-
-
[原创]格式化字符串打出没有回头路(下)——回头望月
-
发表于: 2024-5-28 08:52 46437
-
在我的前篇文章的最后提出了以下问题。在只有一次的格式字符串过程中,如果采用-z noww
的编译选项该如何处理,代码如下。
题目存在的困难如下
保护情况如下
要攻击printf
函数内部栈,就需要对函数进行更进一步的源码了解。以下以glibc2.31
为例,其他版本差距不大。
printf
涉及主要有3个函数__vfprintf_internal buffered_vfprintf printf_positional
,其中,buffered_vfprintf
是关闭缓冲区才需要调用的函数,printf_positional
时需要定位时才调用的函数(类似于%4$p
),函数对字符的处理并没有像IO_FILE
一样使用虚表,而是使用了goto
这种反人类的编程语句,并且为c语言标准预留了所有的可执行虚表空间,如果以后增加标准格式可以快速实现。在关闭缓冲区后一般的调用过程如下。
printf
使用的是goto
来进行跳转,它定义了一个跳表数组来表示格式化字符,其中字符所对应的数字是由stepX_jumps
中的跳表偏移进行计算。
以step0_jumps
为例,其中'REF (width)
与REF (form_unknown)
偏移为8,所以jump_table
中1-9
代表的值都是8。REF (width)
则代表真实的地址差。
当程序中进行JUMP (*++f, step0_jumps);
跳转时,则调到step0_jumps[8]
处所代表的值,则是程序的真实偏移地址。
同时,程序使用LABEL
来定义跳转位置,并设置参数。
程序的输出主要使用outstring
,最终还是调用IO_FILE
的xsputn
函数。代码在/stdio-common/vfprintf-internal.c
中。
需要注意的是在glibc2.34
后实现了outstring_func
函数。
程序还有一个填充输出函数,类似于%100a
在输出前填充的空格,
其中_IO_padn
在/libio/iopadn.c
中,最终还是调用IO_FILE
的xsputn
函数。
程序中定义了2组共4个跳表,分别是STEP0_3_TABLE
和STEP0_4_TABLE
,跳表是按照字符顺序进行。例如,第一个跳表基本上所有的都有定义,到了第四个跳表则定义很少,如下。
典型的GUN
软链接,调用__vfprintf_internal
,在/stdio-common/printf.c
中。
简单宏定义,即为vfprintf
函数,在/stdio-common/vfprintf-internal.c
中。
vfprintf
经过一系列参数定义、格式化字符定义、检测及非格式化字符输出之后就进入格式化字符处理流程,在每一个处理流程过程中设置相应的参数。
大部分跳转我们并不在意,只重点说明以下几个,LABEL (form_unknown)
就执行结束了,也就是遇到非格式化字符串就是啥都不干。
当存在$
时则执行goto do_positional
printf_positional
函数是对我们来说比较重要的,属于但独立于vfprintf
的函数,需要参数很多。在cccccccccccc
中。
里面函数的处理方式与vfprintf
大致相同,不再过多说明。
这个函数只是在vprintf
输出流没有缓冲区时进行调用,它会新建一个带有缓冲区的IO_FILE
,最后执行完时在将数据拷贝出来。执行过程仍然是调用vprintf
进行输出。在 /stdio-common/vfprintf-internal.c
中
通过printf
函数分析可以看出,使用格式化字符串漏洞主要起到作用的是在__vfprintf_internal printf_positional
等函数中,特别是写入功能主要依赖printf_positional
函数。那么,我们就可以想办法修改printf __vfprintf_internal
等函数的返回地址,从而达到一次格式化字符串利用的方法。但是题目仍存在一些需要解决地方。
既然存在格式化字符串漏洞,那么泄露是非常简单的事情,可以一次泄露出栈地址,libc
地址和程序加载地址,现在面临的问题是:**在不知道栈地址的情况下如何修改程序返回地址。**因为程序在buf[BUFLEN]
变量定义时没有赋值,所以内存中必然保存了之前程序执行过程中的栈地址,可以利用内存中残留的数据进行爆破。
具体流程如下
通过爆破栈的最后一个字节,修改printf
返回地址,并泄露出需要信息。
利用格式化字符串漏洞布置栈帧,通过ROP
实现getshell
。
攻击成功如下
格式化字符串的写入比较重要的,所以单独说明。写入过程是在字符串的处理宏中process_arg
(2.36宏变为#include /stdio-common/vfprintf-process-arg.c
),程序太长,截取关键部分。
通过上面看出,如果使用%XXXX$YYln
是可以实现长整型写入的,但是由于done
是int
类型,所以实际写入中前4个字节写入的是done
的符号。
vprintf
中存在以下过程,
printf_positional
中可以看到__printf_function_table
就是一个自定义函数跳表,执行自己所设计好的流程,但是参数不可控。有个比较有意思的是,glibc
提供__register_printf_specifier
这种函数来为他人添加字符串处理函数,但实际攻击并不好实现。
这就是一般意义上的house of husk
,但是,攻击printf
最简单的还是攻击IO,可以利用现有的攻击体系。
主要是定位参数时使用了read_int
函数,
read_int
函数在/stdio-common/printf-parse.h
中,可以看出程序对retval
进行了大小判断,INT_MAX == 0x7fffffff
,所以%xxx$p
这种情况下,xxx
最大只能是0xccccccc
左右,超出后便做溢出异常处理。
对于以下情况,假设0x10000
地址处为第10个参数,能否一次性用%24c$10hhn%100c$11hhn
修改0x10018
处的值。
从理论上来说,payload
第一段修改了0x10008
处的值为0x10018
,第二段再修改0x10018
处的值,是可行的。但实际上,libc
会malloc
一块内存,并把以前的参数单独保存下来,从而无法实现连打。
可以看出格式化字符串是危害性非常大的漏洞,如果是**栈上的格式化字符串漏洞,内存中有残存栈帧数据,同时输入长度超过0x40,**就可以只利用1次格式化字符串完成攻击。本人利用此方法通杀了至少10+的题目。
相关视频https://www.bilibili.com/video/BV1NC411Y7DU/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFLEN 0x60
int
init_func(){
setvbuf
(stdin,0,2,0);
setvbuf
(stdout,0,2,0);
setvbuf
(stderr,0,2,0);
return
0;
}
int
dofunc(){
char
buf[BUFLEN];
puts
(
"input"
);
read(0, buf, BUFLEN);
printf
(buf);
_exit(0);
return
0;
}
int
main(){
init_func();
dofunc();
return
0;
}
// gcc -z now fmt_st.c -o fmt_strx64
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFLEN 0x60
int
init_func(){
setvbuf
(stdin,0,2,0);
setvbuf
(stdout,0,2,0);
setvbuf
(stderr,0,2,0);
return
0;
}
int
dofunc(){
char
buf[BUFLEN];
puts
(
"input"
);
read(0, buf, BUFLEN);
printf
(buf);
_exit(0);
return
0;
}
int
main(){
init_func();
dofunc();
return
0;
}
// gcc -z now fmt_st.c -o fmt_strx64
Arch: amd64
-
64
-
little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
Arch: amd64
-
64
-
little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled
printf
=> __vfprintf_internal => buffered_vfprintf => __vfprintf_internal => printf_positional
printf
=> __vfprintf_internal => buffered_vfprintf => __vfprintf_internal => printf_positional
// /stdio-common/vfprintf-internal.c
static
const
uint8_t jump_table[] =
{
/* ' ' */
1, 0, 0,
/* '#' */
4,
0,
/* '%' */
14, 0,
/* '\''*/
6,
0, 0,
/* '*' */
7,
/* '+' */
2,
0,
/* '-' */
3,
/* '.' */
9, 0,
/* '0' */
5,
/* '1' */
8,
/* '2' */
8,
/* '3' */
8,
/* '4' */
8,
/* '5' */
8,
/* '6' */
8,
/* '7' */
8,
/* '8' */
8,
/* '9' */
8, 0, 0,
0, 0, 0, 0,
0,
/* 'A' */
26, 0,
/* 'C' */
25,
0,
/* 'E' */
19,
/* F */
19,
/* 'G' */
19,
0,
/* 'I' */
29, 0, 0,
/* 'L' */
12, 0, 0, 0,
0, 0, 0,
/* 'S' */
21,
0, 0, 0, 0,
/* 'X' */
18, 0,
/* 'Z' */
13, 0,
0, 0, 0, 0,
0,
/* 'a' */
26, 0,
/* 'c' */
20,
/* 'd' */
15,
/* 'e' */
19,
/* 'f' */
19,
/* 'g' */
19,
/* 'h' */
10,
/* 'i' */
15,
/* 'j' */
28, 0,
/* 'l' */
11,
/* 'm' */
24,
/* 'n' */
23,
/* 'o' */
17,
/* 'p' */
22,
/* 'q' */
12, 0,
/* 's' */
21,
/* 't' */
27,
/* 'u' */
16, 0, 0,
/* 'x' */
18, 0,
/* 'z' */
13
};
#define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
// /stdio-common/vfprintf-internal.c
static
const
uint8_t jump_table[] =
{
/* ' ' */
1, 0, 0,
/* '#' */
4,
0,
/* '%' */
14, 0,
/* '\''*/
6,
0, 0,
/* '*' */
7,
/* '+' */
2,
0,
/* '-' */
3,
/* '.' */
9, 0,
/* '0' */
5,
/* '1' */
8,
/* '2' */
8,
/* '3' */
8,
/* '4' */
8,
/* '5' */
8,
/* '6' */
8,
/* '7' */
8,
/* '8' */
8,
/* '9' */
8, 0, 0,
0, 0, 0, 0,
0,
/* 'A' */
26, 0,
/* 'C' */
25,
0,
/* 'E' */
19,
/* F */
19,
/* 'G' */
19,
0,
/* 'I' */
29, 0, 0,
/* 'L' */
12, 0, 0, 0,
0, 0, 0,
/* 'S' */
21,
0, 0, 0, 0,
/* 'X' */
18, 0,
/* 'Z' */
13, 0,
0, 0, 0, 0,
0,
/* 'a' */
26, 0,
/* 'c' */
20,
/* 'd' */
15,
/* 'e' */
19,
/* 'f' */
19,
/* 'g' */
19,
/* 'h' */
10,
/* 'i' */
15,
/* 'j' */
28, 0,
/* 'l' */
11,
/* 'm' */
24,
/* 'n' */
23,
/* 'o' */
17,
/* 'p' */
22,
/* 'q' */
12, 0,
/* 's' */
21,
/* 't' */
27,
/* 'u' */
16, 0, 0,
/* 'x' */
18, 0,
/* 'z' */
13
};
#define CHAR_CLASS(Ch) (jump_table[(INT_T) (Ch) - L_(' ')])
static
JUMP_TABLE_TYPE step0_jumps[30] = \
{ \
REF (form_unknown), \
REF (flag_space),
/* for ' ' */
\
REF (flag_plus),
/* for '+' */
\
REF (flag_minus),
/* for '-' */
\
REF (flag_hash),
/* for '<hash>' */
\
REF (flag_zero),
/* for '0' */
\
REF (flag_quote),
/* for '\'' */
\
REF (width_asterics),
/* for '*' */
\
REF (width),
/* for '1'...'9' */
\
REF (precision),
/* for '.' */
\
REF (mod_half),
/* for 'h' */
\
REF (mod_long),
/* for 'l' */
\
REF (mod_longlong),
/* for 'L', 'q' */
\
REF (mod_size_t),
/* for 'z', 'Z' */
\
REF (form_percent),
/* for '%' */
\
REF (form_integer),
/* for 'd', 'i' */
\
REF (form_unsigned),
/* for 'u' */
\
REF (form_octal),
/* for 'o' */
\
REF (form_hexa),
/* for 'X', 'x' */
\
REF (form_float),
/* for 'E', 'e', 'F', 'f', 'G', 'g' */
\
REF (form_character),
/* for 'c' */
\
REF (form_string),
/* for 's', 'S' */
\
REF (form_pointer),
/* for 'p' */
\
REF (form_number),
/* for 'n' */
\
REF (form_strerror),
/* for 'm' */
\
REF (form_wcharacter),
/* for 'C' */
\
REF (form_floathex),
/* for 'A', 'a' */
\
REF (mod_ptrdiff_t),
/* for 't' */
\
REF (mod_intmax_t),
/* for 'j' */
\
REF (flag_i18n),
/* for 'I' */
\
};
# define JUMP_TABLE_BASE_LABEL do_form_unknown
# define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL
static
JUMP_TABLE_TYPE step0_jumps[30] = \
{ \
REF (form_unknown), \
REF (flag_space),
/* for ' ' */
\
REF (flag_plus),
/* for '+' */
\
REF (flag_minus),
/* for '-' */
\
REF (flag_hash),
/* for '<hash>' */
\
REF (flag_zero),
/* for '0' */
\
REF (flag_quote),
/* for '\'' */
\
REF (width_asterics),
/* for '*' */
\
REF (width),
/* for '1'...'9' */
\
REF (precision),
/* for '.' */
\
REF (mod_half),
/* for 'h' */
\
REF (mod_long),
/* for 'l' */
\
REF (mod_longlong),
/* for 'L', 'q' */
\
REF (mod_size_t),
/* for 'z', 'Z' */
\
REF (form_percent),
/* for '%' */
\
REF (form_integer),
/* for 'd', 'i' */
\
REF (form_unsigned),
/* for 'u' */
\
REF (form_octal),
/* for 'o' */
\
REF (form_hexa),
/* for 'X', 'x' */
\
REF (form_float),
/* for 'E', 'e', 'F', 'f', 'G', 'g' */
\
REF (form_character),
/* for 'c' */
\
REF (form_string),
/* for 's', 'S' */
\
REF (form_pointer),
/* for 'p' */
\
REF (form_number),
/* for 'n' */
\
REF (form_strerror),
/* for 'm' */
\
REF (form_wcharacter),
/* for 'C' */
\
REF (form_floathex),
/* for 'A', 'a' */
\
REF (mod_ptrdiff_t),
/* for 't' */
\
REF (mod_intmax_t),
/* for 'j' */
\
REF (flag_i18n),
/* for 'I' */
\
};
# define JUMP_TABLE_BASE_LABEL do_form_unknown
# define REF(Name) &&do_##Name - &&JUMP_TABLE_BASE_LABEL
JUMP (*++f, step0_jumps);
# define JUMP(ChExpr, table) \
do
\
{ \
const
void
*ptr; \
spec = (ChExpr); \
ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
: table[CHAR_CLASS (spec)]; \
goto
*ptr; \
} \
while
(0)
#endif
JUMP (*++f, step0_jumps);
# define JUMP(ChExpr, table) \
do
\
{ \
const
void
*ptr; \
spec = (ChExpr); \
ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \
: table[CHAR_CLASS (spec)]; \
goto
*ptr; \
} \
while
(0)
#endif
#define LABEL(Name) do_##Name
LABEL (flag_space):
space = 1;
JUMP (*++f, step0_jumps);
#define LABEL(Name) do_##Name
LABEL (flag_space):
space = 1;
JUMP (*++f, step0_jumps);
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
#define outchar(Ch) \
do
\
{ \
const
INT_T outc = (Ch); \
if
(PUTC (outc, s) == EOF || done == INT_MAX) \
{ \
done = -1; \
goto
all_done; \
} \
++done; \
} \
while
(0)
#define outstring(String, Len) \
do
\
{ \
assert
((
size_t
) done <= (
size_t
) INT_MAX); \
if
((
size_t
) PUT (s, (String), (Len)) != (
size_t
) (Len)) \
{ \
done = -1; \
goto
all_done; \
} \
if
(__glibc_unlikely (INT_MAX - done < (Len))) \
{ \
done = -1; \
__set_errno (EOVERFLOW); \
goto
all_done; \
} \
done += (Len); \
} \
while
(0)
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
#define outchar(Ch) \
do
\
{ \
const
INT_T outc = (Ch); \
if
(PUTC (outc, s) == EOF || done == INT_MAX) \
{ \
done = -1; \
goto
all_done; \
} \
++done; \
} \
while
(0)
#define outstring(String, Len) \
do
\
{ \
assert
((
size_t
) done <= (
size_t
) INT_MAX); \
if
((
size_t
) PUT (s, (String), (Len)) != (
size_t
) (Len)) \
{ \
done = -1; \
goto
all_done; \
} \
if
(__glibc_unlikely (INT_MAX - done < (Len))) \
{ \
done = -1; \
__set_errno (EOVERFLOW); \
goto
all_done; \
} \
done += (Len); \
} \
while
(0)
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
static
inline
int
outstring_func (
FILE
*s,
const
UCHAR_T *string,
size_t
length,
int
done)
{
assert
((
size_t
) done <= (
size_t
) INT_MAX);
if
((
size_t
) PUT (s, string, length) != (
size_t
) (length))
return
-1;
return
done_add_func (length, done);
}
#define outstring(String, Len) \
do
\
{ \
const
void
*string_ = (String); \
done = outstring_func (s, string_, (Len), done); \
if
(done < 0) \
goto
all_done; \
} \
while
(0)
# define PUT(F, S, N) _IO_sputn ((F), (S), (N))
static
inline
int
outstring_func (
FILE
*s,
const
UCHAR_T *string,
size_t
length,
int
done)
{
assert
((
size_t
) done <= (
size_t
) INT_MAX);
if
((
size_t
) PUT (s, string, length) != (
size_t
) (length))
return
-1;
return
done_add_func (length, done);
}
#define outstring(String, Len) \
do
\
{ \
const
void
*string_ = (String); \
done = outstring_func (s, string_, (Len), done); \
if
(done < 0) \
goto
all_done; \
} \
while
(0)
static
inline
int
pad_func (
FILE
*s, CHAR_T padchar,
int
width,
int
done)
{
if
(width > 0)
{
ssize_t written;
#ifndef COMPILE_WPRINTF
written = _IO_padn (s, padchar, width);
#else
written = _IO_wpadn (s, padchar, width);
#endif
if
(__glibc_unlikely (written != width))
return
-1;
return
done_add_func (width, done);
}
return
done;
}
#define PAD(Padchar) \
do
\
{ \
done = pad_func (s, (Padchar), width, done); \
if
(done < 0) \
goto
all_done; \
} \
while
(0)
static
inline
int
pad_func (
FILE
*s, CHAR_T padchar,
int
width,
int
done)
{
if
(width > 0)
{
ssize_t written;
#ifndef COMPILE_WPRINTF
written = _IO_padn (s, padchar, width);
#else
written = _IO_wpadn (s, padchar, width);
#endif
if
(__glibc_unlikely (written != width))
return
-1;
return
done_add_func (width, done);
}
return
done;
}
#define PAD(Padchar) \
do
\
{ \
done = pad_func (s, (Padchar), width, done); \
if
(done < 0) \
goto
all_done; \
} \
while
(0)
ssize_t
_IO_padn (
FILE
*fp,
int
pad, ssize_t count)
{
char
padbuf[PADSIZE];
const
char
*padptr;
int
i;
size_t
written = 0;
size_t
w;
if
(pad ==
' '
)
padptr = blanks;
else
if
(pad ==
'0'
)
padptr = zeroes;
else
{
for
(i = PADSIZE; --i >= 0; )
padbuf[i] = pad;
padptr = padbuf;
}
for
(i = count; i >= PADSIZE; i -= PADSIZE)
{
w = _IO_sputn (fp, padptr, PADSIZE);
written += w;
if
(w != PADSIZE)
return
written;
}
if
(i > 0)
{
w = _IO_sputn (fp, padptr, i);
written += w;
}
return
written;
}
libc_hidden_def (_IO_padn)
ssize_t
_IO_padn (
FILE
*fp,
int
pad, ssize_t count)
{
char
padbuf[PADSIZE];
const
char
*padptr;
int
i;
size_t
written = 0;
size_t
w;
if
(pad ==
' '
)
padptr = blanks;
else
if
(pad ==
'0'
)
padptr = zeroes;
else
{
for
(i = PADSIZE; --i >= 0; )
padbuf[i] = pad;
padptr = padbuf;
}
for
(i = count; i >= PADSIZE; i -= PADSIZE)
{
w = _IO_sputn (fp, padptr, PADSIZE);
written += w;
if
(w != PADSIZE)
return
written;
}
if
(i > 0)
{
w = _IO_sputn (fp, padptr, i);
written += w;
}
return
written;
}
libc_hidden_def (_IO_padn)
#define STEP4_TABLE \
/* Step 4: processing format specifier. */
\
static
JUMP_TABLE_TYPE step4_jumps[30] = \
{ \
REF (form_unknown), \
REF (form_unknown),
/* for ' ' */
\
REF (form_unknown),
/* for '+' */
\
REF (form_unknown),
/* for '-' */
\
REF (form_unknown),
/* for '<hash>' */
\
REF (form_unknown),
/* for '0' */
\
REF (form_unknown),
/* for '\'' */
\
REF (form_unknown),
/* for '*' */
\
REF (form_unknown),
/* for '1'...'9' */
\
REF (form_unknown),
/* for '.' */
\
REF (form_unknown),
/* for 'h' */
\
REF (form_unknown),
/* for 'l' */
\
REF (form_unknown),
/* for 'L', 'q' */
\
REF (form_unknown),
/* for 'z', 'Z' */
\
REF (form_percent),
/* for '%' */
\
REF (form_integer),
/* for 'd', 'i' */
\
REF (form_unsigned),
/* for 'u' */
\
REF (form_octal),
/* for 'o' */
\
REF (form_hexa),
/* for 'X', 'x' */
\
REF (form_float),
/* for 'E', 'e', 'F', 'f', 'G', 'g' */
\
REF (form_character),
/* for 'c' */
\
REF (form_string),
/* for 's', 'S' */
\
REF (form_pointer),
/* for 'p' */
\
REF (form_number),
/* for 'n' */
\
REF (form_strerror),
/* for 'm' */
\
REF (form_wcharacter),
/* for 'C' */
\
REF (form_floathex),
/* for 'A', 'a' */
\
REF (form_unknown),
/* for 't' */
\
REF (form_unknown),
/* for 'j' */
\
REF (form_unknown)
/* for 'I' */
\
}
#define STEP4_TABLE \
/* Step 4: processing format specifier. */
\
static
JUMP_TABLE_TYPE step4_jumps[30] = \
{ \
REF (form_unknown), \
REF (form_unknown),
/* for ' ' */
\
REF (form_unknown),
/* for '+' */
\
REF (form_unknown),
/* for '-' */
\
REF (form_unknown),
/* for '<hash>' */
\
REF (form_unknown),
/* for '0' */
\
REF (form_unknown),
/* for '\'' */
\
REF (form_unknown),
/* for '*' */
\
REF (form_unknown),
/* for '1'...'9' */
\
REF (form_unknown),
/* for '.' */
\
REF (form_unknown),
/* for 'h' */
\
REF (form_unknown),
/* for 'l' */
\
REF (form_unknown),
/* for 'L', 'q' */
\
REF (form_unknown),
/* for 'z', 'Z' */
\
REF (form_percent),
/* for '%' */
\
REF (form_integer),
/* for 'd', 'i' */
\
REF (form_unsigned),
/* for 'u' */
\
REF (form_octal),
/* for 'o' */
\
REF (form_hexa),
/* for 'X', 'x' */
\
REF (form_float),
/* for 'E', 'e', 'F', 'f', 'G', 'g' */
\
REF (form_character),
/* for 'c' */
\
REF (form_string),
/* for 's', 'S' */
\
REF (form_pointer),
/* for 'p' */
\
REF (form_number),
/* for 'n' */
\
REF (form_strerror),
/* for 'm' */
\
REF (form_wcharacter),
/* for 'C' */
\
REF (form_floathex),
/* for 'A', 'a' */
\
REF (form_unknown),
/* for 't' */
\
REF (form_unknown),
/* for 'j' */
\
REF (form_unknown)
/* for 'I' */
\
}
// /stdio-common/printf.c
int
__printf (
const
char
*format, ...)
{
va_list
arg;
int
done;
va_start
(arg, format);
// 主要函数
done = __vfprintf_internal (stdout, format, arg, 0);
va_end
(arg);
return
done;
}
#undef _IO_printf
ldbl_strong_alias (__printf,
printf
);
ldbl_strong_alias (__printf, _IO_printf);
// /stdio-common/printf.c
int
__printf (
const
char
*format, ...)
{
va_list
arg;
int
done;
va_start
(arg, format);
// 主要函数
done = __vfprintf_internal (stdout, format, arg, 0);
va_end
(arg);
return
done;
}
#undef _IO_printf
ldbl_strong_alias (__printf,
printf
);
ldbl_strong_alias (__printf, _IO_printf);
# define vfprintf __vfprintf_internal
int
vfprintf
(
FILE
*s,
const
CHAR_T *format,
va_list
ap, unsigned
int
mode_flags)
# define vfprintf __vfprintf_internal
int
vfprintf
(
FILE
*s,
const
CHAR_T *format,
va_list
ap, unsigned
int
mode_flags)
LABEL (flag_space):
space = 1;
JUMP (*++f, step0_jumps);
LABEL (flag_space):
space = 1;
JUMP (*++f, step0_jumps);
LABEL (form_unknown):
if
(spec == L_(
'\0'
))
{
/* The format string ended before the specifier is complete. */
__set_errno (EINVAL);
done = -1;
goto
all_done;
}
LABEL (form_unknown):
if
(spec == L_(
'\0'
))
{
/* The format string ended before the specifier is complete. */
__set_errno (EINVAL);
done = -1;
goto
all_done;
}
do_positional:
done = printf_positional (s, format, readonly_format, ap, &ap_save,
done, nspecs_done, lead_str_end, work_buffer,
save_errno, grouping, thousands_sep, mode_flags);
do_positional:
done = printf_positional (s, format, readonly_format, ap, &ap_save,
done, nspecs_done, lead_str_end, work_buffer,
save_errno, grouping, thousands_sep, mode_flags);
int
printf_positional (
FILE
*s,
const
CHAR_T *format,
int
readonly_format,
va_list
ap,
va_list
*ap_savep,
int
done,
int
nspecs_done,
const
UCHAR_T *lead_str_end,
CHAR_T *work_buffer,
int
save_errno,
const
char
*grouping, THOUSANDS_SEP_T thousands_sep,
unsigned
int
mode_flags)
// 传入参数定义如下
/* The character used as thousands separator. */
THOUSANDS_SEP_T thousands_sep = 0;
/* The string describing the size of groups of digits. */
const
char
*grouping;
/* Place to accumulate the result. */
int
done;
// 其中,done是个int类型所以,写入最大为0x7fffffff
/* Current character in format string. */
const
UCHAR_T *f;
/* End of leading constant string. */
const
UCHAR_T *lead_str_end;
/* Points to next format specifier. */
const
UCHAR_T *end_of_spec;
/* Buffer intermediate results. */
CHAR_T work_buffer[WORK_BUFFER_SIZE];
CHAR_T *workend;
/* We have to save the original argument pointer. */
va_list
ap_save;
/* Count number of specifiers we already processed. */
int
nspecs_done;
/* For the %m format we may need the current `errno' value. */
int
save_errno =
errno
;
/* 1 if format is in read-only memory, -1 if it is in writable memory,
0 if unknown. */
int
readonly_format = 0;
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
- [原创]反序列化的前生今世 9469
- [原创]gdb在逆向爆破中的应用 3124
- [原创]EOP编程 9260
- [原创]格式化字符串打出没有回头路(下)——回头望月 46438
- [原创]格式化字符串打出没有回头路(上) 17883