Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
385
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

BOOL ReadProcessMemory( HANDLE hProcess, PVOID pvAddressRemote, PVOID pvBufferLocal, DWORD dwSize, PDWORD pdwNumBytesRead);

BOOL WriteProcessMemory( HANDLE hProcess, PVOID pvAddressRemote, PVOTD pvBufferLocal, DWOHD dwSize, PDWORD pdwNumBytesWritten);

Параметр hProcess идентифицирует удаленный процесс, pvAddressRemote и pvBufferLocal определяют адреса в адресных пространствах удаленного и локального процесса, a dwSize

число передаваемых байтов. По адресу, на который указывает параметр pdwNumBytesRead или pdwNumBytesWritten, возвращается число фактически считанных или записанных байтов

Теперь, когда Вы понимаете, что я пьтаюсь сделать, давайте суммируем все сказанное и запишем это в виде последовательности операций, которые Вам надо будет выполнить

1.Выделите блок памяти в адресном пространстве удаленного процесса через

VirtualAllocEx.

2.Вызвав WriteProcessMemory, скопируйте строку с полным именем файла DLL в блок памяти, выделенный в п 1

3.Используя GetProcAddress, получите истинный адрес функции LoadLibraryA или

LoadLibraryW внутри Kernel32.dll.

4.Вызвав CreateRemoteThread, создайте поток в удаленном процессе, который вызовет соответствующую функцию LoadLibrary, передав ей адрес блока памяти, выделенного в п. 1.

На этом этапе DLL внедрена в удаленный процесс, а ее функция DllMam получила уведомление DLL_PROCESS_ATTACH и может приступить к выполнению нужного кода Когда DllMain вернет управление, удаленный поток выйдет из LoadLibrary и вернется в функцию BaseThreadStart (см. главу 6), которая в свою очередь вызовет ExitThread и завершит этот поток

Теперь в удаленном процессе имеется блок памяти, выделенный в п. 1, и DLL, все еще «сидящая» в его адресном пространстве. Для очистки после завершения удаленного потока потребуется несколько дополнительных операций.

1.Вызовом VirtualFreeEx освободите блок памяти, выделенный в п. 1.

2.С помощью GetProcAddress определите истинный адрес функции FreeLibrary

внутри Kernel32.dll.

3.Используя CreateRemoteThtead, создайте в удаленном процессе поток, который вызовет FreeLibrary с передачей HINSTANCE внедренной DLL.

Вот, собственно, и все. Единственный недостаток этого метода внедрения DLL (самого универсального из уже рассмотренных) — многие нужные функции в Windows 98 не поддерживаются. Так что данный метод применим только в Windows 2000.

Программа-пример lnjLib

Эта программа, «22 InjLib.exe» (см. листинг на рис. 22-3), внедряет DLL с помощью функции CreateRemoteThread Файлы исходного кода и ресурсов этой программы и DLL находятся в каталогах 22-InjLib и 22-ImgWalk на компакт-диске, прилагаемом к книге, После запуска InjLib на экране появляется диалоговое окно для ввода идентификатора выполняемого процесса, в который будет внедрена DLL. ,

Вы можете выяснить этот идентификатор через Task Manager Получив его, программа попытается открыть описатель этого процесса, вызвав OpenProcess и запросив соответствующие права доступа.

hProcess = OpenProcess(

PROCESS_CREATE THREAD | // для CreateRemoteThread PROCESS_VM_OPERATION | // для VirtualAllocEx/VirtualFreeEx PROCESS_VM_WRITE, // для WriteProcessMemory

FALSE, dwProcessId);

Если OpenProcess вернет NULL, значит, программа выполняется в контексте защиты, в котором открытие описателя этого процесса не разрешено Некоторые процессы вроде WinLogon, SvcHost и Csrss выполняются по локальной системной учетной записи, которую зарегистрированный пользователь не имеет права изменять. Описатель такого процесса можно открыть, только если Вы получили полномочия на отладку этих процессов. Программа ProcessInfo из главы 4 демонстрирует, как это делается.

При успешном выполнении OpenProcess записывает в буфер полное имя внедряемой DLL. Далее программа вызывает lnject!ib и передает сй описатель удаленного процесса. И, наконец, после возврата из InjectLib программа выводит окно, где сообщает, успешно ли внедрена DLL, а потом закрывает описатель процесса.

Наверное, Вы заметили, что я специально проверяю, нс равен ли идентификатор процесса нулю. Если да, то вместо идентификатора удаленного процесса я передаю идентификатор процесса самой InjLib.exe, получаемый вызовом GetCurrenlProtessId. Тогда при вызове Injectlib библиотека внедряется в адресное пространство процесса InjLib. Я сделал это для упрощения отладки. Сами понимаете, при возникновении ошибки иногда трудно определить, в каком процессе она находится: локальном или удаленном. Поначалу я отлаживал код с помощью двух отладчиков: один наблюдал за InjLib, другой — за удаленным процессом Это оказалось стратттно неудобно Потом меня осенило, что InjLib способна внедрить DLL и в себя, т. e. в адресное пространство вызывающего процесса. И это сразу упростило отладку.

Просмотрев начало исходного кода модуля, Вы увидите, что InjectLib — на самом деле макрос, заменяемый на InjectLibA или InjectLibW в зависимости от того, как компилируется исходный код. В исходном коде достаточно комментариев, и я добавлю лишь одно. Функция lnjectLibA весьма компактна. Она просто преобразует полное имя DLL из ANSI в Unicode и вызывает lnjetlLibW, которая и делает всю работу. Тут я придерживаюсь того подхода, который я рекомендовал в главе 2.

Библиотека lmgWalk.dll

ImgWalk.dll (см. листинг на рис. 22-4) — это DI,I., которая, будучи внедрена в адресное пространство процесса, выдает список всех DLL, используемых этим процессом. Файлы исходного кода и ресурсов этой DLL находятся в каталоге 22-ImgWalk на компакт-диске, прилагаемом к книге. Если, например, сначала запустить Notepad, a потом InjLib, передав ей идентификатор процесса Notepad, то InjLib внедрит ImgWalk.dll в адресное пространство Notepad. Попав туда, ImgWalk определит, образы каких файлов (EXE и DLL) используются процессом Notepad, и покажет результаты в следующем окне.

Модуль ImgWalk сканирует адресное пространство процесса и ищет спроецированные файлы, вызывая в цикле функцию VirtualQuery, которая заполняет структуру MEMORY_BASIC_INFORMATION На каждой итерации цикла ImgWalk проверяет, нет ли строки с полным именем файла, которую можно было бы добавить в список, выводимый на экран

Char szBuf[MAX_PAIH * 100] = { 0 };

PBYTE pb = NULL;

MEMORY_BASIC_INFORMATION mbi;

while (VirtualQuery(pb, &mbi, sizeof(mbi}) == sizeof(mbi))

{

int nLen;

char szModName[MAX_PATH];

lf (mbl StatP == MEM_FRFF)

mbi.AllocationBase = mbi.BaseAddress;

if ((mbi.AllocationBase == hinstDll) || (mbi.Allocation8ase != mbi.BaseAddress} || (mbi.AllocationBase == NULL))

{

//Имя модуля не включается в список, если

//истинно хотя бы одно из следующих условий

//1 Данный регион содержит нашу DLL

//2 Данный блок НЕ является началом региона

//3 Адрес равен NULL

nLen = 0;