通过pwndbg看看c中局部变量是如何在stack上放置的 此外 printf %n的作用终于弄明白了

先上一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<stdio.h>
 
int main()
 
{
 
    int n,num;
 
    char*m2="Decimal";
 
    char*m3="Octal";
 
    char*m4="Hexadecimal";
 
    num = printf("%s%s%s%n",m2,m3,m4,&n);
 
    printf("\n\n%d\n",n);
 
 printf("\n\n%d\n",num);
 
  
 
    return 0;
 
}

 

 

────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────
In file: /data/test_n.c
   10
   11     char*m3="Octal";
   12
   13     char*m4="Hexadecimal";
   14
 ► 15     num = printf("%s%s%s%n",m2,m3,m4,&n);
   16
   17     printf("\n\n%d\n",n);
   18
   19  printf("\n\n%d\n",num);
   20
────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffec30 —▸ 0x5555555551c0 (__libc_csu_init) ◂— push   r15
01:0008│      0x7fffffffec38 —▸ 0x555555556012 ◂— 'Hexadecimal'  看下局部变量是如何放在stack里的
02:0010│      0x7fffffffec40 —▸ 0x55555555600c ◂— 0x6548006c6174634f /* 'Octal' */
03:0018│      0x7fffffffec48 —▸ 0x555555556004 ◂— 0x6c616d69636544 /* 'Decimal' */
04:0020│ rbp  0x7fffffffec50 —▸ 0x5555555551c0 (__libc_csu_init) ◂— push   r15
05:0028│      0x7fffffffec58 —▸ 0x7ffff7e27cca (__libc_start_main+234) ◂— mov    edi, eax
06:0030│      0x7fffffffec60 —▸ 0x7fffffffed48 —▸ 0x7fffffffef1a ◂— '/data/a.out'
07:0038│      0x7fffffffec68 ◂— 0x100000000
──────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────
 ► f 0     55555555515e main+41
   f 1     7ffff7e27cca __libc_start_main+234
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> p m2
$1 = 0x555555556004 "Decimal"
pwndbg> p m3
$2 = 0x55555555600c "Octal"
pwndbg> p m4
$3 = 0x555555556012 "Hexadecimal"

接下来单步运行分析程序的作用:

────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────
In file: /data/test_n.c
    4
    5 {
    6
    7     int n,num;
    8
 ►  9     char*m2="Decimal";
   10
   11     char*m3="Octal";
   12
   13     char*m4="Hexadecimal";
   14
────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffec30 —▸ 0x5555555551c0 (__libc_csu_init) ◂— push   r15
01:0008│      0x7fffffffec38 —▸ 0x555555555050 (_start) ◂— xor    ebp, ebp
02:0010│      0x7fffffffec40 —▸ 0x7fffffffed40 ◂— 0x1
03:0018│      0x7fffffffec48 ◂— 0x0
04:0020│ rbp  0x7fffffffec50 —▸ 0x5555555551c0 (__libc_csu_init) ◂— push   r15
05:0028│      0x7fffffffec58 —▸ 0x7ffff7e27cca (__libc_start_main+234) ◂— mov    edi, eax
06:0030│      0x7fffffffec60 —▸ 0x7fffffffed48 —▸ 0x7fffffffef1a ◂— '/data/a.out'
07:0038│      0x7fffffffec68 ◂— 0x100000000
──────────────────────────────────────────────────────────[ BACKTRACE ]───────────────────────────────────────────────────────────
 ► f 0     55555555513d main+8
   f 1     7ffff7e27cca __libc_start_main+234
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
pwndbg> p &n
$8 = (int *) 0x7fffffffec30
pwndbg> p n
$9 = 1431654848

 

运行到printf处stack的状态请注意:

────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────
In file: /data/test_n.c
   10
   11     char*m3="Octal";
   12
   13     char*m4="Hexadecimal";
   14
 ► 15     num = printf("%s%s%s%n",m2,m3,m4,&n);
   16
   17     printf("\n\n%d\n",n);
   18
   19  printf("\n\n%d\n",num);
   20
────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffec30 —▸ 0x5555555551c0 (__libc_csu_init) ◂— push   r15  # 这个地址就是存放局部变量n
01:0008│      0x7fffffffec38 —▸ 0x555555556012 ◂— 'Hexadecimal'
02:0010│      0x7fffffffec40 —▸ 0x55555555600c ◂— 0x6548006c6174634f /* 'Octal' */
03:0018│      0x7fffffffec48 —▸ 0x555555556004 ◂— 0x6c616d69636544 /* 'Decimal' */
04:0020│ rbp  0x7fffffffec50 —▸ 0x5555555551c0 (__libc_csu_init) ◂— push   r15
05:0028│      0x7fffffffec58 —▸ 0x7ffff7e27cca (__libc_start_main+234) ◂— mov    edi, eax
06:0030│      0x7fffffffec60 —▸ 0x7fffffffed48 —▸ 0x7fffffffef1a ◂— '/data/a.out'
07:0038│      0x7fffffffec68 ◂— 0x100000000

然后继续运行,

────────────────────────────────────────────────────────[ SOURCE (CODE) ]─────────────────────────────────────────────────────────
In file: /data/test_n.c
   12
   13     char*m4="Hexadecimal";
   14
   15     num = printf("%s%s%s%n",m2,m3,m4,&n);
   16
 ► 17     printf("\n\n%d\n",n);
   18
   19  printf("\n\n%d\n",num);
   20
   21  
   22
────────────────────────────────────────────────────────────[ STACK ]─────────────────────────────────────────────────────────────
00:0000│ rsp  0x7fffffffec30 ◂— 0x1700000017
01:0008│      0x7fffffffec38 —▸ 0x555555556012 ◂— 'Hexadecimal'
02:0010│      0x7fffffffec40 —▸ 0x55555555600c ◂— 0x6548006c6174634f /* 'Octal' */
03:0018│      0x7fffffffec48 —▸ 0x555555556004 ◂— 0x6c616d69636544 /* 'Decimal' */
04:0020│ rbp  0x7fffffffec50 —▸ 0x5555555551c0 (__libc_csu_init) ◂— push   r15
05:0028│      0x7fffffffec58 —▸ 0x7ffff7e27cca (__libc_start_main+234) ◂— mov    edi, eax
06:0030│      0x7fffffffec60 —▸ 0x7fffffffed48 —▸ 0x7fffffffef1a ◂— '/data/a.out'
07:0038│      0x7fffffffec68 ◂— 0x100000000

神奇的事情发生了,stack上0x7fffffffec30地址处的值修改了,变成了 0x1700000017。最终程序输出n和num都是23。

为啥是23,

>>> len("Decimal")
7
>>> len("Octal")
5
>>> len("Hexadecimal")
11

因为打印的字符总数是23.

 

但是%n的作用,终于在一篇英文中看到了。

What is use of %n in printf() ?

Last Updated: 09-10-2019

In C printf(), %n is a special format specifier which instead of printing something causes printf() to load the variable pointed by the corresponding argument with a value equal to the number of characters that have been printed by printf() before the occurrence of %n.

filter_none

edit

play_arrow

brightness_4

#include<stdio.h>
  
int main()
{
  int c;
  printf("geeks for %ngeeks ", &c);
  printf("%d", c);
  getchar();
  return 0;
}

The above program prints “geeks for geeks 10”. The first printf() prints “geeks for geeks”. The second printf() prints 10 as there are 10 characters printed (the 10 characters are “geeks for “) before %n in first printf() and c is set to 10 by first printf().

 

posted @   bonelee  阅读(757)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2019-10-06 python 中根据python版本(2或3)定义函数
点击右上角即可分享
微信分享提示