通過pwndbg看看c中局部變量是如何在stack上放置的 此外 printf %n的作用終於弄明白了


先上一個例子:

#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().

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM