Невозможно понять код эксплуатации строки формата - PullRequest
16 голосов
/ 03 августа 2011

Я наткнулся на этот код, показывающий использование строки формата во время чтения этой статьи.

#include <stdio.h>

int main(void)
{
char secret[]="hack.se is lame";
char buffer[512];
char target[512];

printf("secret = %pn",&secret);

fgets(buffer,512,stdin);
snprintf(target,512,buffer);
printf("%s",target);
}

Выполнение его со следующим вводом

[root@knark]$ ./a.out
secret = 0xbffffc68
AAAA%x %x %x %x %x %x %x //Input given
AAAA4013fe20 0 0 0 41414141 33313034 30326566
- [root@knark]$ 

Что я понимаю доТеперь последовательность %x будет продолжать печатать значения по адресам выше текущего %esp (я предполагаю, что стек растет вниз по направлению к более низкому адресу).

Что я не могу понять, так это то, что введенные данные хранятся в массиве buffer, который не может быть меньше 512 байт от текущего %esp.Итак, как выходные данные могут содержать 41414141 (шестнадцатеричное представление AAAA) сразу после 4 %x, то есть чуть выше 4-х адресов текущего %esp.Я тоже старался смотреть на ассемблерный код, но думаю, что не мог следить за манипуляциями со строками в стеке.

Ответы [ 2 ]

4 голосов
/ 03 августа 2011

При входе в snprintf стек имеет следующее:

0xbfd257d0:     0xxxxxxxxx      0xxxxxxxxx      0xxxxxxxxx      0x080484d5
0xbfd257e0:     0xbfd25800      0x00000200      0xbfd25a00      0x00000000
0xbfd257f0:     0x00000000      0x00000000      0x00000000      0x00000000
0xbfd25800:     0x00000000      0x00000040      0xb7f22f2c      0x00000000
0xbfd25810:     0x00000000      0x00000000      0x00000000      0x00000000

0xbfd25800 -> target (initially 0x00000000 0x00000040 ...)
...        -> garbage
0xbfd257e8 -> pointer to buffer
0xbfd257e4 -> 512
0xbfd257e0 -> pointer to target
0xbfd257df -> return address

target перезаписывается с результатом snprintf, прежде чем snprintf использует свои слова в качестве аргументов: сначала он записывает «AAAA» (0x41414141) в 0xbfd25800, затем «% x» читает значение в 0xbfd257ec и записывает в 0xbfd25804, ..., затем "% x" читает значение в 0xbfd25800 (0x41414141) и записывает в 0xbfd25814, ...

1 голос
/ 03 августа 2011

Прежде всего, давайте посмотрим на стек после вызова snprintf ():

Reading symbols from /home/blackbear/a.out...done.
(gdb) run
Starting program: /home/blackbear/a.out 
secret = 0xbffff40c
ABCDEF%x %x %x %x %x %x %x

Breakpoint 1, main () at prova.c:13
13      printf("%s",target);
(gdb) x/20x $esp
0xbfffeff0: 0xbffff00c  0x00000200  0xbffff20c  0x00155d7c
0xbffff000: 0x00155d7c  0x000000f0  0x000000f0  0x44434241
0xbffff010: 0x35314645  0x63376435  0x35353120  0x20633764
0xbffff020: 0x66203066  0x34342030  0x32343334  0x33203134
0xbffff030: 0x34313335  0x20353436  0x37333336  0x35333436
(gdb) 

На самом деле, в 0xbffff00c мы можем увидеть строку, уже отформатированную, поэтому sprintf () написал прямо там.Мы также можем увидеть в 0xbfffeff0 последний аргумент для snprintf (): адрес цели, который на самом деле равен 0xbffff00c.Таким образом, я могу сделать вывод, что строки сохраняются с конца до начала их выделенного пространства в стеке, так как мы также можем видеть добавление strcpy ():

blackbear@blackbear-laptop:~$ cat prova.c
#include <stdio.h>
#include <string.h>

int main(void)
{
    char secret[]="hack.se is lame";
    char buffer[512];
    char target[512];

    printf("secret = %p\n", &secret);

    strcpy(target, "ABCDEF");   
    fgets(buffer,512,stdin);
    snprintf(target,512,buffer);
    printf("%s",target);
}
blackbear@blackbear-laptop:~$ gcc prova.c -g
prova.c: In function ‘main’:
prova.c:14: warning: format not a string literal and no format arguments
prova.c:14: warning: format not a string literal and no format arguments
blackbear@blackbear-laptop:~$ gdb ./a.out -q
Reading symbols from /home/blackbear/a.out...done.
(gdb) break 13
Breakpoint 1 at 0x8048580: file prova.c, line 13.
(gdb) run
Starting program: /home/blackbear/a.out 
secret = 0xbffff40c

Breakpoint 1, main () at prova.c:13
13      fgets(buffer,512,stdin);
(gdb) x/10x $esp
0xbfffeff0: 0xbffff00c  0x080486bd  0x00000007  0x00155d7c
0xbffff000: 0x00155d7c  0x000000f0  0x000000f0  0x44434241
0xbffff010: 0x00004645  0x00000004
(gdb) 

Вот и все!В заключение, мы нашли строку там, потому что строки хранятся в стеке в обратном порядке, и начало (или конец?) Цели близко к esp.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...