Часть полного текста документа:Вызов функции в другом процессе Сергей Холодилов I just called to say I love you, And I mean it from the bottom of my heart. Stevie Wonder Внедрению DLL так или иначе (обычно в связи с перехватом API) посвящено достаточно большое количество статей. Но ни в одной из тех, которые я читал, не говорится, как извне заставить эту DLL сделать что-нибудь полезное. Обычно авторы ограничиваются перехватом необходимых API-функций где-нибудь в DllMain и последующей реакцией на вызовы этих самых функций. Между тем, взаимодействие с внедрённой DLL даёт возможность корректировать и направлять её работу и, тем самым, позволяет добиваться значительно большего эффекта. Если внедрённая DLL создаёт свой поток, задача взаимодействия легко решается, так как в этом случае можно использовать любые методы IPC: сообщения, сокеты, именованные каналы, ... , при желании можно даже COM-сервер сделать :) ПРЕДУПРЕЖДЕНИЕ В описании DllMain сказано, что некоторые функции, в том числе CreateThread, из неё вызывать нельзя. Объяснение "почему они говорят, что нельзя" можно найти у Рихтера (в русском четвёртом издании это глава "DLL: более сложные методы программирования", раздел "Как система упорядочивает вызовы DllMain"), у него же написано, что на самом деле можно, если осторожно. :) Просто при создании потока надо не забывать, что его выполнение начнётся не раньше, чем текущий поток покинет DllMain. Но это всё более-менее очевидные и не очень красивые (на мой взгляд) способы. Мне кажется, я нашёл более интересный и элегантный метод. Ему и посвящена эта статья. Идея Идея тривиальна. Алгоритм состоит всего из четырёх шагов (плюс ещё один по желанию): Так или иначе загрузить в адресное пространство процесса-жертвы DLL, содержащую нужную функцию. ПРИМЕЧАНИЕ "Так или иначе" означает, что DLL может быть загружена любым способом. Например, это может быть advapi32.DLL, которую процесс-жертва грузит сам. Если вы хотите, чтобы исполнялся ваш код, скорее всего, DLL придётся внедрять. Описание внедрения DLL смотрите в дополнительных источниках в конце статьи. Получить адрес загрузки DLL. Получить адрес функции. Вызвать функцию при помощи CreateRemoteThread. (опционально) Дождаться завершения потока и получить возвращаемое значение функции вызовом GetExitCodeThread. А зачем нам DLL? При желании можно напрямую записать весь исполняемый код в адресное пространство процесса-жертвы и запустить его тем же CreateRemoteThread. При большом желании можно добиться, чтобы это заработало... Основная проблема, подстерегающая вас на этом пути, заключается в том, что все функции, которые вызывает ваш код, должны находиться точно по тем адресам, куда передаётся управление. С учётом того, что: код будет расположен в случайном месте адресного пространства, так как вам вряд ли удастся выделить память по тому же адресу; DLL могут быть загружены по другим адресам, "само собой" ничего не получится. Чтобы добиться работоспособности кода, нужно модифицировать используемые вашим кодом адреса, то есть, фактически, выполнить задачу загрузчика. А зачем выполнять её вручную, если можно положиться на загрузчик :) ? Ограничения Использование CreateRemoteThread связано с очевидными ограничениями: Поддерживается только линейка Windows NT/2000/XP. ............ |