Добрый день, пытаюсь ради спортивного интереса написать драйвер без таблицы импорта. Знаю что с помощью MmGetSystemRoutineAddress можно динамически получать адрес процедуры модуля ntoskrnl.exe, но этого не достаточно для выполнения поставленной задачи. RtlFindExportedRoutineByName уже ближе, собственно эту функцию и нужно реализовать. Вот ее прототип: Код (Text): NTKERNELAPI PVOID NTAPI RtlFindExportedRoutineByName( _In_ PVOID ImageBase, _In_ PCCH RoutineName ); И сразу первый вопрос. Как получить imagebase ntoskrnl.exe без использования импорта? На данный момент использую PsLoadedModuleList. Второй вопрос. Как правильно парсить таблицу экспорта ntoskrnl.exe? Пробовал стандартным методом, но без использования ядерной функции RtlImageDirectoryEntryToData, не выходит правильно получить адреса. Буду рад любой помощи.
Искать адрес функции экспортируемой в ядре с помощью MmGetSystemRoutineAddress и им подобных функций ненадежно. Лучше парсите самостоятельно таблицу экспорта. Мне приходилось сталкиваться с тем, что в ядре может быть forwarding export, а MmGetSystemRoutineAddress() его не могла обработать и возвращался адрес не на функцию, а на соотв. заглушку-forwarding в экспорте. Парсить экспорт так же, как обычный pe. Базу ntoskrnl - кажется, можно было узнать, получив адрес gdt и взяв оттуда адрес обработчика, принадлежащего адресному пространству модуля ядра, далее - уже перейти к адресу базы.
Обработчик исключения установить, далее вызвать исключение и получить адрес возврата. Затем используя тот же обработчик для безопасного поиска в памяти найти заголовок PE.
Вы имеете ввиду KeGetPcr? Либо бсод во время вызова функции, либо неверные данные.. Есть примеры? Или почитать чего можно? С экспортом вроде разобрался, спасибо.
имелось ввиду инструкция SGDT это только для 32 битного шелкода для 64битного шелкода вроде нет способа динамической установки обработчика исключения
Не хватило у меня знаний разобраться с получением базового адреса ядра без вызовов апи. Итог: импорт с указателем на PsLoadedModuleList. Тред прошу не закрывать, может кто-нибудь захочет поделится мыслями по поводу данного вопроса. Благодарю всех участников за помощь.
vx1d, https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=vs-2019 Если не хочешь работать с исключениями, то единственный вариант - хардкодь KdVersionBlock.
Обсуждаются исключения в драйвере по ссылке выше обсуждается обработка исключений в юзермоде, для юзермоды в динамике проще использовать: AddVectoredExceptionHandler но все равно вопрос актуальный как в ядре в динамике установить обработчик исключений для x64 что если искать драйвер с секцией .pdata, секцию c атрибутом discarded, писать туда код и патчить .pdata для установки нашего обработчика
"For dynamically generated functions [JIT compilers], the runtime to support these functions must either use RtlInstallFunctionTableCallback or RtlAddFunctionTable to provide this information to the operating system" а в ядре есть аналог?
vx1d, Есть некая RtlInsertInverted.., но дело не в этом. Что бы получить импорт нужно знать базу ядра. Я посмотрел, наверно можно попробовать использовать следующее. При сервисной обработке есть безопасное место KiSystemServiceCopyStart - KiSystemServiceCopyEnd. Чтобы найти можно взять указатель KiSystemCall64 из мср(LSTAR).
Rel, Имеется ввиду динамический код. Обычная защита функций это фишка пе формата, но для этого образ должен содержать нужную инфу. Поэтому я и говорил что не нужно ничего вызывать. Так как у тс пе образ. В 64 из за защиты убрали динамику типо сех. Но всё равно методы найдутся, как выше например. Строим граф для значения из мср, формируем окружение и можем безопасно читать память. Обработчик не выполняет никаких проверок типо KPP, тупо безопасный диапазон выбирающих инструкций. Можно конечно установить ловушку в IDT. Но это не метод, так как что бы включить прерывания - нужно скопировать себе код, формирующий TF. Иначе нельзя обращаться в подкачиваемую память. Будет рекурсивный крэш.