Nano Hash - криптовалюты, майнинг, программирование

C ++: внедрение 32-битных целей из 64-битного процесса

Недавно я написал DLL-инжектор на C ++, к которому предъявлялись следующие требования.

  • ПРОЦЕСС ВНЕДРЕНИЯ (назовем его «Инжектор»), а также DLL ДЛЯ ВНЕДРЕНИЯ (Внедрение) существуют в 64- и 32-битных вариантах. В зависимости от цели пытаются ввести соответствующую версию инъекции.
  • Должна быть возможность внедрять целевые процессы, которые являются 32-битными (WOW64), даже если инжектор работает в 64-битном режиме.

Я быстро заметил, что вызов GetProcAddress ("LoadLibraryA") в инжекторе возвращает "непригодный" дескриптор, поскольку 32-битная цель имеет загруженный другой файл kernel32.dll и адрес функции. есть другое, поэтому внедрение не удается (удаленный поток не может быть запущен с использованием возвращенного адреса / дескриптора). Кроме того, в 32-битном процессе kernel32.dll загружается по другому базовому адресу, что делает создание удаленного потока еще более невозможным.

Чтобы прояснить, что я имею в виду, происходит следующее:

  • Инжектор имеет 64-разрядную версию kernel32.dll, загруженную по адресу 0x12340000.
  • Инжектор извлекает дескриптор для LoadLibraryA 0x00005678 из этого kernel32.dll
  • У цели есть 32-разрядная версия kernel32.dll, загруженная по адресу 0xABCD0000.
  • Ожидается, что дескриптор для LoadLibrary этого kernel32.dll будет 0x0000EFAB
  • Инжектор пытается запустить удаленный поток в цели с функцией 0x12345678, но ожидается 0xABCDEFAB

При внедрении 64-битного процесса из 64-битного процесса и 32-битного из 32-битного обычно нет проблем, поскольку kernel32.dll (скорее всего) загружается по тому же базовому адресу, и можно использовать тот же адрес функции - это мое непонимание до сих пор. Однако в этом случае условия отличаются.

Чтобы решить эту проблему, я сделал следующие шаги:

  • 64-битный инжектор получает адрес kernel32.dll, загруженный 32-битной целью, используя EnumProcessModulesEx () (должно быть 0xABCD000)
  • Получите имя файла этого kernel32.dll, проанализируйте заголовок PE и получите RVA LoadLibraryA (должно быть 0x000EFAB).
  • На этом этапе мы знаем, где загружается файл kernel32.dll в 32-битном целевом объекте и адрес функции из этой библиотеки DLL.
  • 64-битный инжектор запускает удаленный поток в 32-битной цели с помощью ImageBase + Function RVA, в данном случае волшебного 0xABCDEFAB

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

У меня два вопроса, на которые я очень благодарен, если на них можно было ответить здесь:

  1. Есть ли более простой способ осуществить такую ​​инъекцию?
  2. Есть ли возможные проблемы с применяемым мной подходом, о которых я не думал?

Любые ответы очень ценятся, спасибо!

РЕДАКТИРОВАТЬ: О, черт возьми ... Я только что понял, что неправильно описал ситуацию в своем первоначальном посте. ИНЖЕКТОР - 64-битный, а ЦЕЛЬ - 32-битный (изначально было наоборот, но я уже поправил). Комментарии Бена Фойгта ниже полностью верны, вызов EnumProcessModulesEx завершится ошибкой. Большой большой БОЛЬШОЙ извините за эту путаницу :(


  • Ах, в этом гораздо больше смысла. 08.01.2012

Ответы:


1

Я думаю, вы могли бы использовать API отладочных символов, чтобы избавиться от анализа заголовка PE и таблицы экспорта. Этот маршрут должен дать необходимую информацию для 32-битного инжектора; 64-битный целевой случай тоже, хотя я до сих пор не понимаю, как вы собираетесь передать 64-битный адрес CreateRemoteThread.

Обычно для работы этих функций отладочных символов требуется файл .pdb или .sym, однако я почти уверен, что они также получают информацию из таблицы экспорта DLL (просто исходя из опыта того, что показывает отладчик для файлов, в которых у меня нет символов. настоящее время).

08.01.2012
  • Спасибо за подсказки, завтра попробую поработать с этими функциями, а потом выложу результаты. 08.01.2012
  • Что касается 64-битного адреса: From x64->WOW64 нет проблем, так как указатель будет правильно усечен. Но с WOW64->x64 на данный момент я бы полагался на тот факт, что в большинстве случаев адрес 64-битной функции (включая базу загруженного модуля) не загружается с номером 0x80000000 или выше. Если только загрузчик (или программист) не решит это сделать, все должно быть в порядке (к вашему сведению, 64-битный файл kernel32.dll на моем компьютере в настоящий момент имеет базу образа по умолчанию 0x0000000078D20000). Но я вижу, что это как бы ... подвержено ошибкам. Надеюсь, мой взгляд на вещи имеет смысл. 08.01.2012
  • С SymFromName и ImageRvaToVa я смог получить те же результаты, что и при самостоятельном анализе записей PE - спасибо, это значительно упростило мое решение! :) 11.01.2012
  • @PuerNoctis У меня такая же проблема, не могли бы вы предоставить мне фрагмент кода для этого? Мне нужно знать, как использовать SymFromName и IMageRvaToVa для получения RVA LoadLibraryA :) tnx 14.12.2012

  • 2

    Я наткнулся на эту ветку в поисках решения той же проблемы.

    Пока склоняюсь к другому более простому решению. Чтобы получить 32-битный адрес процесса ядра, 64-битный процесс может просто выполнить 32-битную программу, которая будет искать для нас адреса процесса:

    #include <Windows.h>
    
    int main(int argc, const char**)
    {
        if(argc > 1)
            return (int) LoadLibraryA;
        else
            return (int) GetProcAddress;
    }
    
    30.10.2012
  • Это практически единственный способ сделать это в пользовательском режиме. На самом деле то же самое и на MacOS. В любом случае, если вы не сделаете инъекцию из модуля ядра, вам придется иметь дело с этим, поскольку 32-битный процесс будет иметь загруженный файл kernel32.dll для 64-битного и 32-битного, и если вы не сможете получить доступ к PEB, у вас будет сложный время получить адрес, который вы ищете. 19.10.2016

  • 3

    Этот ответ касается более ранней версии вопроса, он в основном не имеет отношения к случаю 64-битного инжектора.


    Вы хотите сказать, что этот подход работает? Поскольку согласно документации, вы не можете получить информация о 64-битных процессах из WOW64:

    Если функция вызывается 32-разрядным приложением, работающим под WOW64, параметр dwFilterFlag игнорируется, и функция дает те же результаты, что и функция EnumProcessModules.

    (EnumProcessModules объясняет ограничение далее)

    Если эта функция вызывается из 32-битного приложения, работающего на WOW64, она может перечислять только модули 32-битного процесса. Если процесс является 64-битным, эта функция не работает, и последний код ошибки - ERROR_PARTIAL_COPY (299).

    Но вам действительно нужно найти базовый адрес, по которому загружен kernel32.dll, из-за ASLR.

    08.01.2012
  • Да, работает отлично. Модули EnumProcessModules (которые * Ex variante ведет себя как на WOW64 согласно документации) вполне достаточны для процедуры. Я все еще использую его в своем коде, потому что, если работает 64-битная версия Injector, я явно извлекаю дескрипторы модуля 32/64, чтобы они были более чистыми, но в 32-битной версии это на самом деле не повредит. Я могу получить ВСЕ дескрипторы, но в списке модулей есть только один файл kernel32.dll, который всегда является правильным. 08.01.2012
  • Хм, ваша редакция интересна. Я, должно быть, наблюдал за этим отрывком, в котором говорилось, что можно получить только дескрипторы 32-битного процесса, но по какой-то причине он работает без сбоев на нескольких машинах ... странно. Что касается базового адреса kernel32.dll: насколько я понимаю (что может быть неправильным, поэтому я и спрашиваю), функции CreateRemoteThread требуется полный адрес функции в памяти процесса для вызова. Одного только RVA LoadLibrary недостаточно, поэтому необходимо смещение, которое в данном случае является базовым адресом загруженного ядра32. 08.01.2012
  • @PuerNoctis: Я также не вижу никакой функции CreateRemoteThread64, так как вы передаете 64-битный адрес LoadLibrary в качестве процедуры потока? 08.01.2012
  • Я добавляю базовый адрес и RVA функции вместе как DWORD и привожу его к LPTHREAD_START_ROUTINE. В конце концов, это просто число, адрес, и гарантировано (я где-то читал, но уже не знаю, где именно), что любые функции, предоставляемые WinAPI, не имеют адреса больше 32-битного. Итак, я посчитал, что передача такого адреса действительна. 08.01.2012
  • @PuerNoctis: Если kernel32.dll всегда загружается в пределах первых 2 ГБ адресного пространства, то, вероятно, поэтому все работает. Но это может не работать в будущих версиях Windows. 08.01.2012
  • Хм, тогда я думаю принять это во внимание, когда он больше не работает. Любые предложения, как (и если) можно вводить 64-битные цели из 32-битных процессов другим способом? 08.01.2012
  • Пожалуйста, прочтите правку в моем исходном посте внизу. Я искренне извиняюсь за это. 08.01.2012
  • @BenVoigt ASLR не влияет на разделяемые библиотеки DLL, такие как Kernel32 или ntdll. Адрес LoadLibraryA / W всегда будет одинаковым для разных процессов. После того, как вы определите адрес функции для любого 32-битного процесса, адрес будет одинаковым для любых 32-битных процессов во время этого сеанса до перезагрузки. 24.09.2016
  • @ E.T .: Часть моего ответа, о которой вы говорите, была написана с учетом инъекции через разную разрядность. Потом вопрос изменился. 24.09.2016
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..