Издательский дом ООО "Гейм Лэнд"СПЕЦВЫПУСК ЖУРНАЛА ХАКЕР #58, СЕНТЯБРЬ 2005 г.

Windows на страже порядка

Deeoni$

Спецвыпуск: Хакер, номер #058, стр. 058-004-4


Итак, как же реализовать это на практике? Для начала создать в нужном нам процессе свой поток – для этого есть волшебная функция CreateRemoteThread. Вот ее описание:

HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);

Теперь быстренько рассмотрим параметры, передаваемые этой функции. hProcess - хэндл процесса, которому будет принадлежать новый поток. lpThreadAttributes – это указатель на структуру с security-атрибутами. dwStackSize определяет размер стека, отведенный новому потоку. lpStartAddress есть адрес функции потока, а lpParameter – параметр, передаваемый ей. dwCreationFlags устанавливает дополнительные флаги, управляющие потоком. Он принимает одно из двух значений: 0 (исполнение потока начинается немедленно) или CREATE_SUSPENDED. В последнем случае система создает поток, инициализирует его и приостанавливает до последующих указаний. Последний параметр - это адрес переменной типа DWORD, в которой функция возвращает идентификатор, приписанный системой новому потоку. Вообще, прототип CreateRemoteThread практически полностью идентичен CreateThread, за исключением хэндла процесса, которого в последней функции нет.

Теперь возникла проблема: как заставить созданный нами удаленный поток загрузить нужную DLL? Очень просто: вызвать LoadLibrary.

HMODULE LoadLibrary(LPCTSTR lpFileName);

Единственный передаваемый параметр – это указатель на строку, содержащую путь к DLL. Существуют две реализации этой API: LoadLibraryA, LoadLibraryW. Первая предназначена для работы со строкой в ANSI-кодировке, а вторая – в юникоде. Волею судеб прототипы LoadLibrary и функции потока почти идентичны: обе принимают единственный параметр и возвращают некое значение. Кроме того, обе используют одни и те же правила вызова - WINAPI. Теперь включим мозг и стараемся придумать, как использовать это… Догадался? Нужно создать новый поток, адрес функции которого является адресом LoadLibraryA или LoadLibraryW. Это должно выглядеть примерно так:

HANDLE hThread = CreateRemoteThread(hProcessRemote, NULL, 0, LoadlibraryA, "C:\\Windows\\SuperDLL.dll", 0, NULL);

Новый поток в удаленном процессе немедленно вызовет LoadlibraryA (или LoadlibraryW, если ты поклонник юникода), передавая ей адрес полного имени DLL. Возникает вопрос: "Неужели все так просто?" Ан нет! Есть пара проблемок, которые непременно требуют решения.

Первая заключается в том, что нельзя вот так просто передать CreateRemoteThread в четвертом параметре LoadlibraryA или LoadlibraryW. Причина этого кроется в устройстве раздела импорта, который состоит из шлюзов к импортируемым API. Так что когда код вызывает LoadlibraryA, в разделе импорта исполнительного файла генерируется вызов соответствующего шлюза, а уже оттуда происходит вызов нужной функции. Следовательно, прямая ссылка на LoadlibraryA в вызове CreateRemoteThread преобразуется в обращение к шлюзу в разделе импорта. Это заставит поток выполнять неизвестно что, и это приведет, скорее всего, к нарушению доступа. Чтобы напрямую вызывать LoadLibraryA, минуя шлюз, с помощью GetProcAddress нужно выяснить ее точный адрес в памяти.

Назад на стр. 058-004-3  Содержание  Вперед на стр. 058-004-5