Я столкнулся с довольно интересным article, который продемонстрировал, как удалить символы нулевого символа из shellcode. Среди используемых методик, инструкции по сборке shl
и shr
, казалось, занимали довольно важную роль в коде.Что сменяет инструкция по монтажу?
Я понимаю, что инструкции по сборке mov $0x3b, %rax
и mov $59, %rax
фактически генерируют инструкции машинного кода 48 c7 c0 3b 00 00 00
. Чтобы справиться с этим, автор вместо этого использует mov $0x1111113b, %rax
, чтобы заполнить регистр системным номером системы, который генерирует вместо этого машинный код 48 c7 c0 3b 11 11 11
, который успешно удаляет нулевые байты.
К сожалению, код по-прежнему не выполняется, поскольку syscall обрабатывает 3b 11 11 11
как незаконную инструкцию, или это приводит к сбою кода. Так что автор тогда сделал сдвиг %rax
назад и вперед 56 байт с командами
shl $0x38, %rax
shr $0x38, %rax
После этого сдвига, код выполняет отлично. Что я хочу знать, так это то, как инструкции по переносу исправляют проблему 48 c7 c0 3b 11 11 11
, и как-то делает собственно и syscall'able. Я знаю, что shl/shr
сдвигает биты влево и вправо, что означает, что сдвиг влево перемещает биты в более высокие биты, а смещение вправо заставляет их снова опускаться, потому что двоичный код читается справа налево. Но как это вообще меняет код и делает его исполняемым? Не перемещается ли взад и вперед по существу ничего не меняет, переставляя сдвинутые биты точно туда, где они были в начале?
Моя единственная теория заключается в том, что смещение битов оставляет за собой нули. Но я до сих пор не вижу, как смещение %rax
вперед, а затем назад исправляет решение, потому что не приведет ли он обратно в раздел 11 11 11
?
В любом случае, я думал, что это было интересно, поскольку я до сих пор не видел сдвиговых операндов. Заранее спасибо.