Почему я получаю нарушение прав доступа при записи в сегмент кода в сборке?
Я делаю эксперименты по шифрованию сегмента кода PE с помощью XOR для каждого байта с некоторым значением ключа. До сих пор мне удалось XOR этого сегмента и вставить в конце сегмента кода двоичный код, который снова декодируется с помощью XORing с тем же значением. Конечно, я также обновил AddressOfEntryPoint, чтобы он был равен адресу декодера.
Но когда я вычисляю адрес первого байта для XORed (он равен первому байту перед декодером - потому что я буду идти вверх), и я пытаюсь сделать это, я получаю нарушение доступа.
Теперь подробности:
1) в качестве тестового PE я использую супер простое консольное приложение "hello world" на простом C++
2) введенный код декодера записывается на ассемблере NASM, затем собирается в двоичный файл и затем вводится в конце секции.text тестового PE. Его код ниже:
call get_proc ; push return address
get_proc:
pop esi ; pop current address
sub esi, 0x5 ; esi = address of injected code, 0x5 = size of call instruction
xor ebx, ebx ; clear registers
xor ecx, ecx ;
mov bl, <DECODER_KEY> ; decoder key
mov ecx, <CODE_SIZE> ; encoded code size
sub esi, ecx ; esi = address of encoded code
decoder_loop:
mov edx, esi ; construct encoded byte address
add edx, ecx ;
dec edx ;
xor byte [cs:edx], bl ; decode
loop decoder_loop ; loop back
jmp esi ; jump back to decoded code
3) <DECODER_KEY>
а также <CODE_SIZE>
заменены (перед сборкой) правильными значениями моим другим приложением, которое делает инъекцию
4) когда проходит первая итерация цикла, окончательное значение EDX равно адресу байта непосредственно перед call get_proc
, проверено с помощью Immunity Debugger
5) здесь я выкладываю скриншот, представляющий ситуацию, когда у меня возникает нарушение прав доступа при попытке выполнить XOR для первого байта (красной линией я отметил свой введенный код, который выполняется в начале)
6) Мне известно о том, что по умолчанию сегмент кода доступен только для чтения и выполнения, но мое приложение для инъекций также добавляет разрешение на запись.
7) Я использую Windows 8.1 64-bit
И, наконец, вопросы:
А) Представлен ли код, делающий то, что я хочу?
Б) Достаточно ли добавить разрешение на запись в сегмент кода для выполнения этой операции (я знаю, что есть некоторые механизмы "защиты от записи", но я не знаю подробностей)?
Эксплойты часто используют эту технику (или, по крайней мере, раньше), поэтому мне интересно, почему это не работает. Кроме того, я должен сказать, что когда я удаляю только операции XOR, программа работает нормально (поэтому рассчитанные адреса верны).
1 ответ
Я нашел решение своей проблемы. В общем: в коде ассемблера произошла ошибка - ссылка [cs:edx]
в операции xor неправильно, должно быть просто [edx]
, Зачем?
Кажется, что теперь регистры сегментов делают не то, что мы (или, по крайней мере, я) думаем. Я слышал, что ранее они использовались в качестве базового адреса для каждого сегмента и инструкции [cs:addr]
было смещение в сегменте кода.
Но если вы посмотрите поближе на значения регистров сегментов на фотографии, которую я предоставил, вы увидите, что эти регистры на самом деле являются некоторыми дескрипторами, которые ссылаются в основном на адрес 0xFFFFFFFF! Когда я удалил cs
из инструкции это сработало! Но затем я загрузил двоичный файл в отладчик, и, как ни странно, он был переведен в ds:[edx]
! Опять же, почему DS (сегмент данных)? Тот, который я не знаю. Но урок из этой проблемы должен состоять в том, чтобы не использовать эти регистры.
Если вы не согласны или у вас есть какие-либо разъяснения, пожалуйста, прокомментируйте этот ответ.