Можно ли переписать%eax, используя переполнение буфера?
Я знаю, что программный стек выглядит примерно так (от высокого до низкого):
EIP | EBP | local variables
Но где я могу найти %eax
а другие общие регистры? Можно ли их перезаписать, используя переполнение буфера?
Обновление: в конце концов, мне даже не пришлось перезаписывать %eax
потому что оказалось, что программа указала %eax
для пользовательского ввода в какой-то момент.
3 ответа
Регистр по определению отсутствует в оперативной памяти. Регистры находятся в ЦП и не имеют адресов, поэтому вы не можете перезаписать их переполнением буфера. Однако регистров очень мало, поэтому компилятор действительно использует их как своего рода кеш для наиболее используемых элементов стека. Это означает, что, хотя вы не можете переполнить регистры stricto sensu, значения, перезаписанные в ОЗУ, рано или поздно будут загружены в регистры.
(В ЦП Sparc политика кэширования регистров как стека является даже аппаратной.)
В вашей схеме EIP и EBP не находятся в стеке; соответствующие слоты в стеке являются областями, из которых эти два регистра будут перезагружены (после выхода из функции). EAX, с другой стороны, является регистром общего назначения, который код будет использовать здесь и там без строгого соглашения.
EAX, вероятно, никогда не появится в стеке. Для большинства компиляторов x86 EAX является 32-битным регистром возвращаемых значений и никогда не сохраняется в стеке и не восстанавливается из стека (RAX в 64-битных системах).
Это не означает, что переполнение буфера нельзя использовать для изменения содержимого EAX путем помещения исполняемого кода в стек; если выполнение кода в стеке не было отключено ОС, это можно сделать, или вы можете принудительно установить поддельный адрес возврата в стеке, который передает управление последовательности кода, которая загружает значение в EAX, но это довольно сложно выдернуть. Точно так же, если известно, что значение, возвращаемое функцией, хранится в локальной переменной, разрыв стека, который изменил эту переменную, изменит значение, скопированное в EAX, но оптимизирующие компиляторы могут изменить расположение стека по своей прихоти, так что эксплойт работает на одной версии может полностью выйти из строя на новом выпуске или исправлении.
Смотрите Томас Порнин (+1) и ответы Флудера (+1), они хороши. Я хочу добавить дополнительный ответ, на который можно было сослаться, но конкретно не указано, и который относится к разлитию регистра.
Хотя "где" исходного вопроса (по крайней мере, в том виде, в каком оно сформулировано), похоже, основано на ложной предпосылке, что%eax находится в стеке и является регистром, он не является частью стека в x86
(хотя вы можете эмулировать любой аппаратный набор регистров в стеке, и некоторые архитектуры фактически делают это, но это не имеет значения), кстати, регистры часто выливаются / заполняются из стека. Таким образом, можно разбить значение регистра переполнением стека, если регистр был разлит в стек. Это потребовало бы, чтобы вы знали механизм пролива конкретного компилятора, и для этого вызова функции вам нужно было бы знать, что%eax был разлит, куда он был разлит, и растоптать это расположение стека, и когда он следующий заполненный из его копии памяти, он получает новое значение. Как бы маловероятно это ни казалось, эти атаки обычно основаны на чтении исходного кода и знании чего-либо о рассматриваемом компиляторе, так что это не так уж и далеко.
Смотрите это для получения дополнительной информации о проливе регистра