Как XOR предотвращает NULL-байты в шелл-коде

Я пытался следовать этому руководству (https://paraschetal.in/writing-your-own-shellcode) о том, как написать собственный шеллкод. На 99% это имеет для меня смысл, но у меня есть только два непрекращающихся сомнения - это относится к написанию шеллкода в целом.

Во-первых, я думаю, что понимаю, почему мы хотим избежать нулевого байта, но как использование следующего позволяет избежать нулевых байтов?

xor eax, eax

Разве eax теперь не содержит точно нулевые байты? Или он содержит 0s? Когда мы выполняем операцию XOR с самим собой, она возвращает False, верно?

Во-вторых, в инструкции сказано:

Наконец, мы загрузим номер системного вызова (11 или 0xb) в регистр eax. Однако, если мы используем eax в нашей инструкции, результирующий шеллкод будет содержать несколько байтов NULL(\x00), а нам это не нужно. Наш регистр eax уже имеет значение NULL. Поэтому мы просто загрузим номер системного вызова в регистр al вместо всего регистра eax.

mov byte  al, 0x0b

Теперь я понимаю, что здесь происходит, число 11 (для execve) загружается в первые 8 бит регистра eax (то есть al). Но остальная часть eax по-прежнему содержит нулевые байты, так что же именно здесь достигается?

Обратите внимание, я пришел сюда в крайнем случае, проведя большую часть дня, пытаясь понять это, поэтому, пожалуйста, будьте со мной полегче :)


person ak1652    schedule 29.12.2018    source источник
comment
Смысл в том, чтобы избежать нулевого байта в самом машинном коде, а не в регистре во время выполнения. Если вы напишите mov eax, 0, в полезной нагрузке будет ноль. xor eax, eax имеет машинный код, который не включает нулевой байт, но во время выполнения он создаст ноль по мере необходимости. Просто создайте полезную нагрузку для двух версий и наблюдайте за нулевыми байтами.   -  person Jester    schedule 29.12.2018
comment
Вы очень сильно противоречите себе, говоря, что полностью понимаете, почему следует избегать нулевых байтов, а затем путаете их со значениями регистров...   -  person Antti Haapala    schedule 29.12.2018
comment
Извиняюсь, отредактирую.   -  person ak1652    schedule 29.12.2018


Ответы (2)


Эксплойты обычно атакуют код C, поэтому код оболочки часто приходится доставлять в виде строки, заканчивающейся NUL. Если шелл-код содержит нулевые байты, эксплуатируемый код C может проигнорировать и удалить остальную часть кода, начиная с первого нулевого байта.

Это касается только машинного кода. Если вам нужно вызвать системный вызов с номером 0xb, то естественно нужно уметь выдавать число 0xb в регистре EAX, но вы можете использовать только те формы машинного кода, которые не содержат нулевых байтов в самом машинном коде .


xor eax, eax

инвертирует все 1 биты в eax, т. е. обнуляет их. Это функциональный эквивалент

mov eax, 0

за исключением того, что последний будет иметь 0, закодированный как нулевые байты в машинном коде.


Машинный код для

xor eax, eax
mov byte al, 0x0b

is

31 c0 b0 0b

Как видите, в нем нет встроенных нулевых байтов. Машинный код для

mov eax, 0xb

is

b8 0b 00 00 00

Обе эти программы функционально эквивалентны в том, что они устанавливают значение регистра EAX равным 0xb.

Если последний шелл-код обрабатывается программой на языке C как строка с завершающим нулем, остальная его часть после b8 0b 00 может быть отброшена программой и заменена другими байтами в памяти, что по существу делает шелл-код неработоспособным.

person Antti Haapala    schedule 29.12.2018
comment
Дополнительный вопрос: по сути, eax содержит байты, семантически эквивалентные нулевому байту, но не содержащие фактических нулевых байтов, верно? - person ak1652; 29.12.2018
comment
@ ak1652 Единственная проблема заключается в том, что код оболочки не может содержать нулевые байты. Чтобы записать значение 0 без использования цифры 0, вы можете написать 1-1. Результат по-прежнему равен 0. МЫ ХОТИМ 0 В РЕЗУЛЬТАТЕ. Точно так же EAX будет содержать нулевые байты, потому что мы ХОТИМ, чтобы они были. Нам просто поставили задачу не использовать цифру 0 при ее написании. - person Antti Haapala; 29.12.2018
comment
Спасибо, цените ваше время. - person ak1652; 30.12.2018

Инструкция mov eax, 0 собирается

b8 00 00 00 00

который содержит байты NUL. Однако инструкция xor eax, eax ассемблируется в

31 c0

который свободен от байтов NUL, что делает его подходящим для шелл-кода.

То же самое относится и к mov al, 0x0b. Если вы делаете mov eax, 0x0b, кодировка

b8 0b 00 00 00

который содержит байты NUL. Однако mov al, 0x0b кодирует в

b0 0b

избегая байтов NUL.

person fuz    schedule 29.12.2018