Исправление CALLL путем замены NOP работает в пространстве пользователя, но не в пространстве ядра.

У меня есть драйвер устройства, который я хочу исправить. Этот драйвер устройства вызывает IOLog, и я хочу избавиться от ведения журнала.

Если я заменю CALLL на IOLog на (соответствующее количество) NOP внутри драйвера устройства (kext), ядро ​​рухнет с тем, что выглядит как разбитый стек («Backtrace завершен-недопустимый указатель кадра 0»).

Однако тот же метод отлично работает в пользовательском пространстве (например, NOPping NSLogs внутри двоичного файла OS X).

Что мне здесь не хватает?


person diciu    schedule 04.11.2008    source источник


Ответы (1)


Вы не объяснили, выполняете ли вы холодное исправление (драйвер на диске) или горячее исправление (драйвер в памяти). При исправлении в памяти могут возникать всевозможные проблемы, например, драйвер, выполняемый при его исправлении, процессор(ы), имеющие кэшированные части кода и т. д. См. раздел руководства Intel, посвященный самоизменяющемуся коду.

Для исправления на диске может оказаться, что у вас есть запись о перемещении для целевого адреса. Поэтому при загрузке драйвера динамический загрузчик модулей исправит адрес IOLog в коде, заменив его реальным адресом. Это перезапишет ваши инструкции nop.

person Martin v. Löwis    schedule 04.11.2008
comment
Я делаю исправления на диске. Если бы мои NOP были заменены как побочный эффект перемещения, разве тогда драйвер не работал бы так же, как до исправления? Переезд действительно может сыграть свою роль, но я еще не понял, как это работает. otool перечисляет 390 записей о перемещении в образе машины драйвера. - person diciu; 04.11.2008
comment
Перемещение работает путем замены байтов в инструкции целевым адресом. Таким образом, если вызов E8 xx xx xx xx, то он перезаписывает xxs. Если вы замените E8 и все xxs на nops, он оставит первый nop и перезапишет остальные целевыми, эти байты затем станут инструкциями. - person Martin v. Löwis; 04.11.2008
comment
Хорошо, это имеет смысл. И это объясняет, почему, когда я использовал GDB для просмотра драйвера устройства, я увидел вызов 0x0, в то время как отладчик, поддерживающий символы, показал вызов _IOLog. Отладчик, поддерживающий работу с символами, должен просмотреть таблицу перемещений. Спасибо за подсказки, буду копать дальше. - person diciu; 04.11.2008
comment
x86 (в отличие от большинства RISC ISA) гарантирует согласованный I-кэш; на самом деле безопасно атомарно хранить или сравнивать и обменивать некоторые байты кода в памяти, если любые границы предыдущих инструкций (где в настоящее время может находиться другой поток) являются допустимыми местами для выполнения в новом коде. например 8-байтовый RMW, который заменяет 5-байтовый call rel32 на 5-байтовый NOP или, что еще хуже, 5x 1-байтовый NOPS, должен быть безопасным. - person Peter Cordes; 15.12.2020