Во-первых, спасибо за дует мне в голову. Когда я впервые посмотрел на ваш код, я не верил, что он будет работать вообще. Затем я попробовал и воспроизвел ваши результаты. Теперь это имеет для меня смысл, хотя и извращенным. :-) Я попытаюсь это объяснить.
Прежде всего, давайте посмотрим на более здравый путь для достижения этой цели. Определите строку в части данных файла ASM:
section .data
string: db "Hey, is this thing on?", 0
Затем нажмите адрес этой строки в стек перед вызовом Printf:
push string
call printf
Итак, что первый параметр Е (последний параметр нажатие на стек перед вызовом) является указателем на строку формата. То, что сделал ваш код, это нажать строку в стеке, а затем указатель стека, который затем указал на строку.
Далее я собираюсь заменить строки так, чтобы они легче отслеживать в разборке:
push '567'
push '123'
push esp
call printf
Assemble с NASM, а затем разобрать с objdump:
nasm string.s -f elf32 -o string.o
objdump -d -Mintel string.o
Когда ты push, например, '123', который преобразуется в 32-разрядную шестую цифру - 0x333231 в этом случае. Обратите внимание, что полные 32 бита - 0x00333231.
3: 68 35 36 37 00 push 0x373635
8: 68 31 32 33 00 push 0x333231
d: 54 push esp
Нажатие на стек уменьшает указатель стека. Предполагая, что начальный указатель стека 0x70 (придуманный для простоты), это состояние стеки перед вызовом Printf:
64: 68: 6c: 70:
68 00 00 00 31 32 33 00 35 36 37 00 ...
Так, при печати называется, он использует первый параметр как указатель строки и начинает печать до тех пор, пока не увидит NULL (0x00).
Именно поэтому этот пример печатает только «123» («sud» в оригинале).
Так что давайте нажмем «1234» вместо «123». Это означает, что мы нажимаем значение 0x34333231.При вызове Printf стек теперь выглядит следующим образом:
64: 68: 6c: 70:
68 00 00 00 31 32 33 34 35 36 37 00 ...
Теперь нет никакого зазора NULL между этими 2 строками в стеке и в этом примере будет печатать «1234567» (или «sudobor» в оригинале).
Последствия: Попробуйте нажать «5678» вместо «567». Вероятно, вы получите ошибку сегментации, потому что printf будет просто читать символы для печати до тех пор, пока не попытается прочитать память, в которой у нее нет разрешения на чтение. Кроме того, попробуйте нажать строку длиной более 4 символов (например, «push» 12345 »). Ассемблер не позволит вам, потому что он не может преобразовать это в 32-разрядное число.
Нужно ли исковерять строку? – Jeff
@Jeff: Я думал, что мне нужно будет явно добавить NULL. Однако приведенный выше код работал. Возможно, в правильном месте был другой НУЛЛ, по совпадению. –
В качестве теста я объявлял бы другую строку сразу после первой и посмотрел бы, работает ли она так, как ожидалось. Я бы включил нулевой терминатор и никогда не знал, требуется ли это или нет. – Jeff