Недавно я написал 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-битных инжекторов.
У меня два вопроса, на которые я очень благодарен, если на них можно было ответить здесь:
- Есть ли более простой способ осуществить такую инъекцию?
- Есть ли возможные проблемы с применяемым мной подходом, о которых я не думал?
Любые ответы очень ценятся, спасибо!
РЕДАКТИРОВАТЬ: О, черт возьми ... Я только что понял, что неправильно описал ситуацию в своем первоначальном посте. ИНЖЕКТОР - 64-битный, а ЦЕЛЬ - 32-битный (изначально было наоборот, но я уже поправил). Комментарии Бена Фойгта ниже полностью верны, вызов EnumProcessModulesEx завершится ошибкой. Большой большой БОЛЬШОЙ извините за эту путаницу :(
x64->WOW64
нет проблем, так как указатель будет правильно усечен. Но сWOW64->x64
на данный момент я бы полагался на тот факт, что в большинстве случаев адрес 64-битной функции (включая базу загруженного модуля) не загружается с номером 0x80000000 или выше. Если только загрузчик (или программист) не решит это сделать, все должно быть в порядке (к вашему сведению, 64-битный файл kernel32.dll на моем компьютере в настоящий момент имеет базу образа по умолчанию 0x0000000078D20000). Но я вижу, что это как бы ... подвержено ошибкам. Надеюсь, мой взгляд на вещи имеет смысл. 08.01.2012SymFromName
иImageRvaToVa
я смог получить те же результаты, что и при самостоятельном анализе записей PE - спасибо, это значительно упростило мое решение! :) 11.01.2012