DLL-инъекция () — в программировании, метод, используемый для запуска кода в адресном пространстве другого процесса, заставляя его загружать динамически подключаемую библиотеку. DLL-инъекции часто используются внешними программами, чтобы повлиять на поведение другой программы так, как её авторы не задумывали и не предполагали. Например, внедрённый код может перехватывать системные вызовы функций или прочитать содержимое текстовых полей пароля, что невозможно сделать обычным способом. Программа, используемая для внедрения произвольного кода в произвольные процессы, называется DLL-инжектором.

Microsoft Windows На Microsoft Windows имеется множество способов заставить процесс загрузить код в DLL-библиотеке против воли автора приложения:

DLL-файлы, указанные в списке системного реестра по ключу HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs, будут загружаться в каждом процессе, загружающем библиотеку User32.dll при её начальном вызове. DLL-файлы по ключу HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDLLs будут загружаться в каждом процессе, которые вызывают функции Windows API CreateProcess, CreateProcessAsUser, CreateProcessWithLogonW, CreateProcessWithTokenW и WinExec. Это один из законных методов DLL-инъекции на Windows 10 при условии, что DLL-файл подписан корректным сертификатом. Функции манипуляции процессами, такие как CreateRemoteThread, либо технологии внедрения кода, например AtomBombing, которых возможно использовать для внедрения DLL в программу после её запуска. Перехватывающие вызовы Windows, например SetWindowsHookEx. Применение функций SuspendThread или NtSuspendThread, чтобы приостановить все потоки, а также использование функций SetThreadContext или NtSetContextThread, чтобы модифицировать контекст существующих потоков в приложении с целью запустить внедряемый код, который сможет загрузить DLL. Эксплуатация ограничений Windows и приложений, вызывающих LoadLibrary или LoadLibraryEx без указания пути к загружаемой DLL. Оперирование прослойками системного уровня. Подмена одного из зависимых DLL-файлов приложения на поддельный, который содержит те же экспортированные объекты, что и оригинал.

Unix-подобные операционные системы На Unix-подобных операционных системах, с помощью динамического линковщика, основанном на ld.so (на BSD) и на ld-linux.so (на Linux), можно подгружать произвольные библиотеки в новый процесс, указав путь к библиотеке с помощью переменной среды LD_PRELOAD, которую можно как назначить глобально, так и назначить конкретному процессу индивидуально.

Например, на Linux-системе, данная команда запускает процесс "prog" вместе с разделяемой библиотекой "test.so", сопоставленной в него во время запуска:LD_PRELOAD="./test.so" progТакие библиотеки создаются тем же способом, что и разделяемые объекты. Библиотека имеет доступ к внешним символам, указанным в программе, как и любая другая библиотека.

На macOS, данная команда запускает процесс "prog" вместе с разделяемой библиотекой "test.dylib", сопоставленной в него во время запуска:DYLD_INSERT_LIBRARIES="./test.dylib" DYLD_FORCE_FLAT_NAMESPACE=1 progВ Unix-подобных системах также возможно использовать методы, основанные на отладчиках.

Пример кода

Использование API-функции LoadLibrary Пример функции, представленный ниже, использует метод DLL-инъекции, который эксплуатирует тот факт, что kernel32.dll сопоставлен с тем же адресом, что и почти все процессы. Поэтому, LoadLibrary (которая является функцией из kernel32.dll) также сопоставлена с тем же адресом. LoadLibrary также подходит для процедуры запуска потока, необходимой для CreateRemoteThread.#include <windows.h>

HANDLE inject_DLL(const char* file_name, int PID) { HANDLE h_process, h_rThread; char fullDLLPath[_MAX_PATH]; LPVOID DLLPath_addr, LoadLib_addr; DWORD exit_code;

/* Извлечение handle-идентификатора целевого процесса */ h_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);

/* Получение полного пути к DLL-файлу */ GetFullPathName(file_name, _MAX_PATH, fullDLLPath, NULL);

/* Выделение памяти в целевом процессе */ DLLPath_addr = VirtualAllocEx(h_process, NULL, _MAX_PATH, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

/* Запись пути к DLL-файлу в недавно созданный блок памяти */ WriteProcessMemory(h_process, DLLPath_addr, fullDLLPath, strlen(fullDLLPath), NULL);

/* Получение адреса LoadLibraryA (такой же для всех процессов), чтобы начать его запуск */ LoadLib_addr = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA");

/* Запуск удалённого потока в LoadLibraryA, и проброс пути к DLL в качестве аргумента */ h_rThread = CreateRemoteThread(h_process, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLib_addr, DLLPath_addr, 0, NULL);

/* Ожидание его завершения */ WaitForSingleObject(h_rThread, INFINITE);

/* Получение кода завершения (то есть, значение handle, возвращённый вызовом LoadLibraryA */ GetExitCodeThread(h_rThread, &exit_code);

/* Освобождение носителя внедрённого потока. */ CloseHandle(h_rThread); /* А также память, выделенная для пути к DLL */ VirtualFreeEx(h_process, DLLPath_addr, 0, MEM_RELEASE); /* А также handle-иднетификатор целевого процесса */ CloseHandle(h_process);

return (HANDLE)exit_code; }

Примечания

Категория:Исследование программ Категория:Информационная безопасность Категория:Системное программирование Категория:Управление потоком