2013-04-20 2 views
0

Я изучаю переполнение буфера и решая некоторые wargames. Была проблема, что вся память стеки выше буфера устанавливается в 0, за исключением того, обратный адрес главного, который будет:Почему значение LD_PRELOAD в стеке

buffer 
[0000000...][RET][000000...] 

и я могу переписать, что RET. Итак, я нашел несколько советов по решению этой проблемы. Должно было использовать LD_PRELOAD. Некоторые люди говорили, что значение LD_PRELOAD находится где-то в стеке не только в области переменных окружения стека. Поэтому я установил LD_PRELOAD и выполнил поиск и нашел его с помощью gdb.

$ export LD_PRELOAD=/home/coffee/test.so 
$ gdb -q abcde 
(gdb) b main 
Breakpoint 1 at 0x8048476 
(gdb) r 
Starting program: /home/coffee/abcde 

Breakpoint 1, 0x8048476 in main() 
(gdb) x/s 0xbffff6df 
0xbffff6df:  "@èC\[email protected]/home/coffee/test.so" 
(gdb) x/s 0xbffffc59 
0xbffffc59:  "LD_PRELOAD=/home/coffee/test.so" 
(gdb) q 
The program is running. Exit anyway? (y or n) y 
$ 

Так что есть! Теперь я знаю, что значение LD_PRELOAD находится в стеке ниже буфера, и теперь я могу использовать!

Но мне интересно, почему LD_PRELOAD загружается на этот адрес памяти. Значение также относится к переменной окружения среды стека!

Какова цель этого? Спасибо.

+1

Окружающая среда помещается в стек 'execve (2)' syscall, по спецификациям ABI –

+0

@Basile Starynkevitch Я имею в виду, что LD_PRELOAD помещается на два места. – lbyeoksan

+0

@lbyeoksan Я уверен, что Базиле Старынкевич знает, о чем он говорит. – 2013-04-20 14:35:55

ответ

0

код исследовать расположение стека:

#include <inttypes.h> 
#include <stdio.h> 

// POSIX 2008 declares environ in <unistd.h> (Mac OS X doesn't) 
extern char **environ; 

static void dump_list(const char *tag, char **list) 
{ 
    char **ptr = list; 
    while (*ptr) 
    { 
     printf("%s[%d] 0x%.16" PRIXPTR ": %s\n", 
       tag, (ptr - list), (uintptr_t)*ptr, *ptr); 
     ptr++; 
    } 
    printf("%s[%d] 0x%.16" PRIXPTR "\n", 
      tag, (ptr - list), (uintptr_t)*ptr); 
} 

int main(int argc, char **argv, char **envp) 
{ 
    printf("%d\n", argc); 
    printf("argv   0x%.16" PRIXPTR "\n", (uintptr_t)argv); 
    printf("argv[argc+1] 0x%.16" PRIXPTR "\n", (uintptr_t)(argv+argc+1)); 
    printf("envp   0x%.16" PRIXPTR "\n", (uintptr_t)envp); 
    printf("environ  0x%.16" PRIXPTR "\n", (uintptr_t)environ); 

    dump_list("argv", argv); 
    dump_list("envp", envp); 
    return(0); 
} 

С программой, составленной в x, я побежал с продезинфицировать среды:

$ env -i HOME=$HOME PATH=$HOME/bin:/bin:/usr/bin LANG=$LANG TERM=$TERM ./x a bb ccc 
4 
argv   0x00007FFF62074EC0 
argv[argc+1] 0x00007FFF62074EE8 
envp   0x00007FFF62074EE8 
environ  0x00007FFF62074EE8 
argv[0] 0x00007FFF62074F38: ./x 
argv[1] 0x00007FFF62074F3C: a 
argv[2] 0x00007FFF62074F3E: bb 
argv[3] 0x00007FFF62074F41: ccc 
argv[4] 0x0000000000000000 
envp[0] 0x00007FFF62074F45: HOME=/Users/jleffler 
envp[1] 0x00007FFF62074F5A: PATH=/Users/jleffler/bin:/bin:/usr/bin 
envp[2] 0x00007FFF62074F81: LANG=en_US.UTF-8 
envp[3] 0x00007FFF62074F92: TERM=xterm-color 
envp[4] 0x0000000000000000 
$ 

Если вы изучаете, что внимательно, вы увидите, что аргумент argv для main() является началом серии указателей на строки, расположенные дальше по стеку; envp (необязательный третий аргумент main() на машинах POSIX) совпадает с глобальной переменной environ и argv[argc+1], а также является началом серии указателей на строки, расположенные дальше по стеку; и строки, на которые указывают указатели argv и envp, следуют за двумя массивами.

Это макет в Mac OS X (10.7.5 если это имеет значение, чего, вероятно, нет), но я с уверенностью уверен, что вы найдете ту же схему на других Unix-подобных системах.

+0

сначала спасибо за ваш ответ. Я уже изучаю структуру стека процесса в unix-подобной ОС. Но мне интересно, почему значение LD_PRELOAD находится в двух местах: в окружении и где-то в стеке. И первый имеет формат «LD_PRELOAD = xxxxxx», но второй имеет формат «??? xxxxxxx», где ??? это неизменяемая строка. Я не фокусируюсь на среде или argv [argc + 1]. Что Вы думаете об этом? Я что-то упускаю или что-то недопонимаю? – lbyeoksan

+1

Данные для 'environ' находятся в той же области, что и стек, поэтому просмотр LD_PRELOAD в стеке не вызывает удивления. Стек также может использоваться кодом 'ld.so.1', и он, возможно, скопировал строковое значение' $ LD_PRELOAD' в буфер в стеке, и эта информация, возможно, еще не была перезаписана. В этом случае по совпадению данные из '$ LD_PRELOAD' включаются дважды в стек, когда среда хранится и когда динамический загрузчик копирует ее. –

+0

OK. Тогда значение LD_PRELOAD копируется динамическим загрузчиком. Хм. Это все еще остается любопытным, но я могу получить некоторый намек. Я должен прочитать исходный код динамического загрузчика. Благодарю. Это было очень полезно. – lbyeoksan