首页
社区
课程
招聘
[原创]格式化字符串打出没有回头路(下)——回头望月
发表于: 2024-5-28 08:52 46437

[原创]格式化字符串打出没有回头路(下)——回头望月

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_table1-9代表的值都是8。REF (width)则代表真实的地址差。

当程序中进行JUMP (*++f, step0_jumps);跳转时,则调到step0_jumps[8]处所代表的值,则是程序的真实偏移地址。

同时,程序使用LABEL来定义跳转位置,并设置参数。

程序的输出主要使用outstring,最终还是调用IO_FILExsputn函数。代码在/stdio-common/vfprintf-internal.c中。

需要注意的是在glibc2.34后实现了outstring_func函数。

程序还有一个填充输出函数,类似于%100a在输出前填充的空格,

其中_IO_padn/libio/iopadn.c中,最终还是调用IO_FILExsputn函数。

程序中定义了2组共4个跳表,分别是STEP0_3_TABLESTEP0_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是可以实现长整型写入的,但是由于doneint类型,所以实际写入中前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处的值,是可行的。但实际上,libcmalloc一块内存,并把以前的参数单独保存下来,从而无法实现连打。

可以看出格式化字符串是危害性非常大的漏洞,如果是**栈上的格式化字符串漏洞,内存中有残存栈帧数据,同时输入长度超过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期)

收藏
免费 6
支持
分享
最新回复 (1)
雪    币: 233
活跃值: (2292)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
不明觉厉
2024-6-1 17:29
0
游客
登录 | 注册 方可回帖
返回
//