У вас должно быть более 500 сообщений для просмотра скрытого контента.
В протекторе Themida есть опция X-Binder, которая позволяет зашифровать файлы и поместить в виртуальный контейнер, обращаться мы к ним можем точно так же как если бы они были на диске, но их там нет, все время они находятся в памяти
Собственно интересует именно загрузка DLL находящихся в таком контейнере посредством обычной LoadLibraryA\W, если с чтением \записью все понятно, простые хуки на NtCreateFile\NtReadFile\NtWriteFile, то с загрузкой DLL дела обстоят несколько мутней
Когда мы загружаем DLL через LoadLibraryA, поток уходит в ntdll и в конечном итоге файл загружается системным загрузчиком, ключевых момента тут три, первый это открытие файла DLL, через NtOpenFile, второе - создание секции NtCreateSection с флагом SEC_IMAGE и хендлом открытого файла, и третий ключевой момент зависит от второго, так как мы передали флаг SEC_IMAGE, то нам нет необходимости указывать размеры выделяемой памяти и некоторые другие параметры, после вызова NtMapViewOfSection образ из файла мапится по предпочтительному адресу указанному в заголовке, если адрес занят и файл имеет релоки, то он перемещается в другое место. Вызов NtMapViewOfSection это сискол, который отправляет нас из юзермода в ядро, а оттуда к нам прилетает уже размапленый образ.
Теперь вопрос, каким образом X-Binder позволяет перехватить считывание файла, если у нас нет возможности заменить данные из юзермода между NtOpenFile и NtMapViewOfSection, так как вплоть до вызова NtMapViewOfSection мы не имеем никакого буфера, который можно было бы подменить, файл считывается и мапится в ядре, во время системного вызова NtMapViewOfSection, и у фемиды нет драйвера, что бы перехватить все это в ядре. Напрашивается идея, перехватывать NtOpenFile и подсовывать аргументом строку на любой системный dll, ту же самую ntdll, далее при вызове NtMapViewOfSection она успешно запапится в память, проверка на наличие модуля в памяти происходит позже, после первого маппинга путем сравнения полей TimeDateStamp и некоторых других полей, поэтому сразу после маппинга можно заменить образ нужным нам образом, но тут есть 2 проблемы, мы не можем в таком случае записать в буфер образ больше по размеру чем ntdll (который мы загружаем в качестве куклы) и так же есть проблема с тем, что файл может быть без релоков, и он будет располагаться не по предпочтительному адресу, а по адресу который указан в ntdll. Решением данной проблемы будет динамичное сбрасывание на диск DLL, только с предварительным затиранием всех секций нулями или случайными байтами, но сохранив при этом все значения заголовков, затирать только содержимое секций. В таком случае подменив NtOpenFile на открытие только что сброшенной библиотеки мы даем загрузчику замапить ее в память по всем канонам, после этого заменить буфер на уже настоящую dll из памяти. Это будет работать, но это костыльно, и не красиво. К тому же я не видел что бы у фемиды дропались пустые DLL при загрузке.
Другим решением будет перехват NtCreateSection и передача вместо параметра SEC_IMAGE параметра SEC_COMMIT и последним аргументом 0, что означает маппинг не из файла, а просто создание виртуальной секции, вторым перехватом NtMapViewOfSection реализовать маппинг по предпочтительному адресу вручную без использования файлс с диска. Но здесь проблема в том, что память помечается не как SEC_IMAGE, а как SEC_COMMIT, поэтому ВОЗМОЖНО(еще не успел протестировать) будут проблемы с SAFESEH и DEP и не хочется еще делать лишние перехваты на NtQueryVirtualMemory что бы подсовывать тип SEC_IMAGE при запросе на адреса входящие в наш ручной маппинг.
Кто что думает по поводу реализации X-Binder фемиды ?
Собственно интересует именно загрузка DLL находящихся в таком контейнере посредством обычной LoadLibraryA\W, если с чтением \записью все понятно, простые хуки на NtCreateFile\NtReadFile\NtWriteFile, то с загрузкой DLL дела обстоят несколько мутней
Когда мы загружаем DLL через LoadLibraryA, поток уходит в ntdll и в конечном итоге файл загружается системным загрузчиком, ключевых момента тут три, первый это открытие файла DLL, через NtOpenFile, второе - создание секции NtCreateSection с флагом SEC_IMAGE и хендлом открытого файла, и третий ключевой момент зависит от второго, так как мы передали флаг SEC_IMAGE, то нам нет необходимости указывать размеры выделяемой памяти и некоторые другие параметры, после вызова NtMapViewOfSection образ из файла мапится по предпочтительному адресу указанному в заголовке, если адрес занят и файл имеет релоки, то он перемещается в другое место. Вызов NtMapViewOfSection это сискол, который отправляет нас из юзермода в ядро, а оттуда к нам прилетает уже размапленый образ.
Теперь вопрос, каким образом X-Binder позволяет перехватить считывание файла, если у нас нет возможности заменить данные из юзермода между NtOpenFile и NtMapViewOfSection, так как вплоть до вызова NtMapViewOfSection мы не имеем никакого буфера, который можно было бы подменить, файл считывается и мапится в ядре, во время системного вызова NtMapViewOfSection, и у фемиды нет драйвера, что бы перехватить все это в ядре. Напрашивается идея, перехватывать NtOpenFile и подсовывать аргументом строку на любой системный dll, ту же самую ntdll, далее при вызове NtMapViewOfSection она успешно запапится в память, проверка на наличие модуля в памяти происходит позже, после первого маппинга путем сравнения полей TimeDateStamp и некоторых других полей, поэтому сразу после маппинга можно заменить образ нужным нам образом, но тут есть 2 проблемы, мы не можем в таком случае записать в буфер образ больше по размеру чем ntdll (который мы загружаем в качестве куклы) и так же есть проблема с тем, что файл может быть без релоков, и он будет располагаться не по предпочтительному адресу, а по адресу который указан в ntdll. Решением данной проблемы будет динамичное сбрасывание на диск DLL, только с предварительным затиранием всех секций нулями или случайными байтами, но сохранив при этом все значения заголовков, затирать только содержимое секций. В таком случае подменив NtOpenFile на открытие только что сброшенной библиотеки мы даем загрузчику замапить ее в память по всем канонам, после этого заменить буфер на уже настоящую dll из памяти. Это будет работать, но это костыльно, и не красиво. К тому же я не видел что бы у фемиды дропались пустые DLL при загрузке.
Другим решением будет перехват NtCreateSection и передача вместо параметра SEC_IMAGE параметра SEC_COMMIT и последним аргументом 0, что означает маппинг не из файла, а просто создание виртуальной секции, вторым перехватом NtMapViewOfSection реализовать маппинг по предпочтительному адресу вручную без использования файлс с диска. Но здесь проблема в том, что память помечается не как SEC_IMAGE, а как SEC_COMMIT, поэтому ВОЗМОЖНО(еще не успел протестировать) будут проблемы с SAFESEH и DEP и не хочется еще делать лишние перехваты на NtQueryVirtualMemory что бы подсовывать тип SEC_IMAGE при запросе на адреса входящие в наш ручной маппинг.
Кто что думает по поводу реализации X-Binder фемиды ?
Хайд влупил большой потому что новореги вряд ли поймут суть всего этого
Последнее редактирование: