Значение регистра EIP превышает 100 байтов - PullRequest
1 голос
/ 16 января 2020

Эй, у меня проблемы с выполнением домашней работы.

Затем процессор x86 выполняет команды. Значение регистра (счетчика) EIP увеличивается на 1 байт или на несколько байт в зависимости от типа команды. Какие инструкции мы должны использовать, чтобы значение EIP могло go превышать 100 байт?

Ответы: JMP | ДОБАВИТЬ | SUB | PU SH | JNZ | MUL | ЗВОНОК | JZ

Как я понял, EIP - это регистр особого случая, который мы не можем использовать. Это называется расширенным указателем инструкций. И чтобы увеличить его значение более 100 байт, нам нужно выяснить, сколько каждая команда добавляет к значению EIP?

Ответы [ 2 ]

3 голосов
/ 16 января 2020

Любая из этих инструкций может #PF (исключение сбоя страницы) для операнда памяти (или другими способами в зависимости от инструкции) и изменять CS: EIP на абсолютно новое значение, загруженное из IDT. например, push dword [0]. Это может включать изменение EIP более чем на 100, если ваш текущий EIP не находится в пределах 100 байтов от адреса обработчика исключений ошибки страницы.

Или если мы говорим о том, куда возвращается обработчик исключения, если ваш процесс имел * Обработчик сигнала установлен для SIGSEGV, ядро ​​может доставить этот сигнал, эффективно меняя EIP в вашем процессе на ваш обработчик сигнала segfault.

Но я думаю, что цель вопроса заключается в изменении EIP с помощью конкретная c требуемая относительная сумма, например, для достижения другого блока кода. (Также не изменяя CS, кодовый сегмент, поэтому вы останетесь в пользовательском режиме, если бы вы были там с самого начала.) Т.е. 100 байтов от от текущего EIP. Формулировка неуклюжа и может быть прочитана как установка EIP для любого абсолютного значения> 100, но ветви x86 являются относительными, и вопрос имеет больше смысла в этом смысле.

Как указывает @ zx485, вам нужна инструкция передачи управления, иначе говоря, переход или ветка. 386 (т. Е. Любая машина с EIP, а не только 16-битным IP) поддерживает условный jcc rel32 условный ближний переход и более короткий jcc rel8 короткий прыжок, поэтому условные переходы могут достигаться где угодно во всем 32-разрядном адресном пространстве, так же как jmp rel32 и call rel32. https://www.felixcloutier.com/x86/jcc.

Но даже кодирование jcc rel8 (например, JZ или JNZ) или jmp rel8 может достигать от -128 до +127 байт относительно конца инструкции. (Смещение 8-битной ветки дополнения до 2-х знаков.)

2 голосов
/ 16 января 2020

Существует несколько возможных ответов на этот вопрос:

  1. Использовать относительный JMP rel8: Многие асемблеры используют такой синтаксис:

    JMP $+100 
    

    , где $ - текущее значение EIP (начало JMP), а 100 - десятичное значение, добавляемое к этой позиции. Сам JMP занимает два байта, которые вычитаются из вычисления 100 в кодировке команд. Таким образом, код

    EB 62               (Address after the JMP + 98d=62h)
    
  2. Вы можете использовать условные переходы, такие как JNZ и JZ, которые функционируют аналогичным образом.

  3. Вы также можете использовать относительный CALL rel32, например:

    CALL $+100
    

    В этом случае длина инструкции отличается (= 5). Счет начинается после CALL, поэтому инструкция

    E8 5F 00 00 00      (Address after the CALL + 95d=5Fh)
    

    Обратите внимание, что адрес после CALL также PUSH передается в стек до перехода выполняется.

  4. Инструкции ADD, SUB, PU SH, MUL не имеют никакого влияния на EIP, за исключением того, что они продвигаются на свою собственную длину инструкции.

    Так что вы также можете просто объединить их последовательно, чтобы прогрессировать в 100 байтов, но этот ответ тривиален.

...