Значение регистра EIP превышает 100 байт

Эй, мне трудно решить домашнюю работу.

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

Ответы: JMP | ДОБАВИТЬ | СУБ | НАЖМИТЕ | JNZ | МУЛ | ЗВОНОК | ЮЗ

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


person RimveBiceps    schedule 15.01.2020    source источник
comment
Обычно инструкции выполняются по порядку, не пропуская ни одной инструкции. Какие инструкции могут привести к тому, что программа будет выполняться не по порядку?   -  person Mark Snyder    schedule 16.01.2020


Ответы (2)


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

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

Но я думаю, что цель вопроса заключается в изменении EIP на определенную желаемую относительную сумму, например. для достижения другого блока кода. (Также не изменяя 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.)

person Peter Cordes    schedule 15.01.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, PUSH, MUL не имеют никакого влияния на EIP, за исключением того, что они увеличивают его длину на собственную длину инструкции.

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

person zx485    schedule 15.01.2020