JMP rel16 (вместо JMP rel32)

Мне нужно сделать код операции перехода для демонстрации эксплойта.

Мне нужно перейти примерно на 200 байт после инструкции перехода. Это слишком много для jmp short.

Если я сгенерирую код операции с обычным переходом, jmp $200 я получу следующее:

e9 fb 01 00 00

Проблема здесь в том, что код операции содержит 00, который интерпретируется как конец строки при передаче строки программе (поэтому я не могу передать полный шелл-код с этим в нем).

Я думал, что мой подход ошибся, но затем я проверил руководство, и во второй строке есть очевидно, «прыжок на близком расстоянии», который занимает 2 байта (есть еще один, который занимает 4 байта, тот, который я показал выше). Оба этих перехода начинаются с одного и того же байта e9.

Как я могу передать e9 fb 01 в качестве ближайшего перехода, который принимает только два байта аргумента? Как мне запретить ОС искать четыре байта после e9, то есть: e9 fb 01 90 90?


person Juicy    schedule 22.01.2015    source источник
comment
Зачем нужно передавать программу в виде строки? Можете ли вы использовать строку с префиксом длины?   -  person phuclv    schedule 23.01.2015
comment
Определенно не ОС ищет четыре байта, а процессор.   -  person rebrec    schedule 25.09.2017


Ответы (2)


Тебе нельзя.

Код операции 0xE9 использует 32-битное смещение, когда процессор работает в 32-битном режиме, и 16-битное смещение, только когда процессор находится в 16-битном режиме.

person 500 - Internal Server Error    schedule 22.01.2015
comment
Спасибо, вот о чем я подумал. Я так понимаю, что тогда нет способа сделать этот относительный переход без нулевых байтов. - person Juicy; 23.01.2015
comment
Технически это неправда. Вы можете использовать переопределение размера операнда. Проблема в том, что EIP назначения будет замаскирован до 16 бит. @Juicy: в качестве обходного пути вы можете использовать 2 прыжка, чтобы преодолеть разрыв. - person Jester; 23.01.2015
comment
@Jester Спасибо, я посмотрю, смогу ли я как-нибудь найти способ сделать это двумя короткими прыжками - person Juicy; 23.01.2015
comment
@Jester Да, я узнал об операнде 66 в другом посте, но, как вы сказали, он маскируется для 16-битного назначения eip, так что это не помогает. - person Juicy; 23.01.2015

Если у вас есть доступ к текущему адресу EIP в шеллкоде, а область памяти доступна для записи, вы можете сделать что-то вроде этого:

; say in ECX you have shellcode start address
; (calculated with delta offset etc.)
_start:

...

; ECX = offset _start

; decrypt zero bytes in jmp instruction relative address

; 80 69 xx  AB
sub byte ptr[ecx+(_fix1-_start)], 0ABh

; 80 69 xx+1 BA
sub byte ptr[ecx+(_fix2-_start) + 1], 0BAh

; jmp instruction with those 00s encrypted
_jmp  db 0E9h, 0FBh, 01h ; first 3 bytes of jmp near instruction
_fix1 db 0 + 0ABh        ; encrypted displacement (last 2 bytes)
_fix2 db 0 + 0BAh     

Таким образом, относительный адрес, закодированный в инструкции jmp near, не содержит 00, но во время выполнения эти байты восстанавливаются.

Имейте в виду, что инструкция дешифрования может содержать 00 также, если разница с вычислением (_fix1-_start) содержит нули, более вероятно, если сгенерированная инструкция представляет собой длинную форму sub [r32 + imm32], imm8), поэтому проверьте и ее вручную.

person Bartosz Wójcik    schedule 23.01.2015
comment
Если у вас есть доступ к EIP, вы можете просто выполнить непрямой переход, не нужно возиться с самомодифицирующимся кодом. - person Jester; 23.01.2015
comment
Что ж, вы всегда можете рассчитать его с помощью дельта-смещения или FPU (последняя выполненная инструкция), поэтому получить текущий EIP не составляет большого труда в коде. - person Bartosz Wójcik; 23.01.2015