Что находится в стеке до запуска моей программы? - PullRequest
6 голосов
/ 24 августа 2011

Сейчас я изучаю язык ассемблера высокого уровня и играю со стеком, чтобы лучше понять все.

Я отмечаю, что в следующей программе я могу вытолкнуть содержимое стека, даже не вставив ничего в него 37 раз, прежде чем программа завершится сбоем.

ike1: uns32 := 1;

begin test1;

while (ike1 < 38) do
pop(eax);
stdout.put(ike1, nl);
stdout.put("ESP: ", esp, nl);
stdout.put("EAX:", eax, nl, nl);
add(1, ike1);
endwhile;
end test1;

Каждый раз, когда стек вставляется в EAX, а вывод EAX каждый раз показывает случайные данные.

Во-первых, я не понимаю, как это возможно, поскольку я думал, что каждая программа сегрегирована в собственное пространство памяти?

В любом случае я извлекаю данные из стека ... что бы это могло быть, и повлияет ли это на другие запущенные программы?

Моя ОС - 64-битная Windows 7.

Ответы [ 2 ]

3 голосов
/ 24 августа 2011

Перед выполнением main() ОС должна выполнить кучу других операций, чтобы правильно настроить среду, прежде чем управление выполнением будет обработано вашим приложением.Таким образом, большая часть того, что находится в стеке на данный момент, является мусором, оставшимся от предыдущих операций.

Непосредственно перед выполнением main() можно ожидать, что в стеке также будут найдены argc и argv.

РЕДАКТИРОВАТЬ:

Комментарий от пользователя заставил меня пройти через процесс отладки приложения сборки в gdb и проверки стекачтобы сделать резервную копию заявления, сделанного мной в исходном ответе.

Поэтому, пожалуйста, рассмотрите следующий код сборки, написанный в nasm :

section .data

  mymsg db "hello, world", 0xa  ; string with a carriage-return
  mylen equ $-mymsg             ; string length in bytes

section .text
global mystart                ; make the main function externally visible

mystart:
    ; prepare the arguments for syscall write()
    push dword mylen          ; msg length                           
    push dword mymsg          ; msg to write
    push dword 1              ; file descriptor number

    ; call write()
    mov eax, 0x4              ; 0x4 identifies syscall write()
    sub esp, 4                ; OS X (and BSD) syscalls needs "extra space" on stack
    int 0x80                  ; trigger the call

    ; clean up the stack
    add esp, 16               ; 3 args * 4 bytes/arg + 4 bytes extra space = 16 bytes

    ; prepare argument for syscall exit()
    push dword 0              ; exit status returned to the operating system

    ; call exit()
    mov eax, 0x1              ; 0x1 identifies syscall exit()
    sub esp, 4                ; OS X (and BSD) system calls needs "extra space" on stack
    int 0x80                  ; trigger the call

Я скомпилировал это в Mac OS Xс:

nasm -f macho -o hello.o hello.nasm
ld -o hello -e mystart hello.o 

Как вы, вероятно, можете сказать по исходному коду, запуск приложения определяется как mystart, и он не принимает никаких параметров.

Теперь,давайте сделаем это исследование немного более захватывающим, открыв эту программу в gdb :

gdb ./hello

После загрузки gdb в образовательных целях важно установить cmdПараметр линии для этого приложения, хотя яt не было написано, чтобы принять что-либо.

set args deadbeef

Приложение все еще не запущено на данный момент.Нам нужно установить точку останова в начале функции main , чтобы можно было проверить стек, чтобы увидеть, что происходит, прежде чем наше приложение начнет выполнять свой собственный код:

break mystart

Выполните команду run на GDB, чтобы запустить приложение и прервать выполнение.Теперь мы можем проверить стек с:

x/20xw $esp

выходами:

(gdb) x/20xw $esp
0xbffff8cc: 0x00002000  0x00000000  0x00000002  0xbffff96c
0xbffff8dc: 0xbffff98b  0x00000000  0xbffff994  0xbffff9b0
0xbffff8ec: 0xbffff9c1  0xbffff9d1  0xbffffa0b  0xbffffa40
0xbffff8fc: 0xbffffa5b  0xbffffa86  0xbffffa97  0xbffffaad
0xbffff90c: 0xbffffad8  0xbffffafa  0xbffffb06  0xbffffb28

Да, сэр, эта команда печатает содержимое стека.Он gdb показывает 20 слов в шестнадцатеричном формате, начиная с адреса, сохраненного в регистре $esp.

Давайте посмотрим, $esp фактически указывает на 0xbffff8cc, хорошо, но исследуемчто хранится по этому адресу памяти, показывает другой адрес: 0x00002000.На что это указывает ???

(gdb) x/20sw 0x00002000
0x2000 <mymsg>:  "hello, world\n"

Не шокер, верно ?!Итак, давайте посмотрим, на что указывают некоторые другие адреса таблицы:

(gdb) x/1sw 0xbffff96c
0xbffff96c:  "/Developer/workspace/asm/hello"

Wow.На самом деле это имя и путь исходного приложения, хранящиеся прямо в стеке!Круто, давайте перейдем к следующему интересному адресу таблицы:

(gdb) x/1sw 0xbffff98b
0xbffff98b:  "deadbeef"

Джекпот!Аргумент строки cmd, который мы передали при выполнении нашего приложения, также был сохранен в стеке.Итак, как я уже говорил ранее, среди мусора, хранящегося в стеке перед выполнением вашего приложения, вы также можете найти параметры строки cmd, которые использовались для выполнения приложения, даже когда функция main() приложения имеет значение void и не выполняетне беру никаких параметров.

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

Область личной памяти, выделенная вашей программе, не гарантируется, что она будет очищена (т. Е. 0x0000).Доступ к нераспределенной памяти обычно не определен, что объясняет случайные данные, которые вы получаете.

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