DLL-инъекция

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

Microsoft Windows

править

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

  • DLL-файлы, указанные в списке системного реестра по ключу HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs, будут загружаться в каждом процессе, загружающем библиотеку User32.dll при её начальном вызове.[7][8][9]
  • DLL-файлы по ключу HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDLLs будут загружаться в каждом процессе, которые вызывают функции Windows API CreateProcess, CreateProcessAsUser, CreateProcessWithLogonW, CreateProcessWithTokenW и WinExec. Это один из законных методов DLL-инъекции на Windows 10 при условии, что DLL-файл подписан корректным сертификатом.
  • Функции манипуляции процессами, такие как CreateRemoteThread, либо технологии внедрения кода, например AtomBombing[10], которых возможно использовать для внедрения DLL в программу после её запуска.[5][6][11][12][13][14]
  • Перехватывающие вызовы Windows, например SetWindowsHookEx.[2][5][6][15][16][17]
  • Применение функций SuspendThread или NtSuspendThread, чтобы приостановить все потоки, а также использование функций SetThreadContext или NtSetContextThread, чтобы модифицировать контекст существующих потоков в приложении с целью запустить внедряемый код, который сможет загрузить DLL.[4][18][19]
  • Эксплуатация ограничений Windows и приложений, вызывающих LoadLibrary или LoadLibraryEx без указания пути к загружаемой DLL.[20][21][22]
  • Оперирование прослойками системного уровня.
  • Подмена одного из зависимых DLL-файлов приложения на поддельный, который содержит те же экспортированные объекты, что и оригинал.[23]

Unix-подобные операционные системы

править

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

Например, на Linux-системе, данная команда запускает процесс "prog" вместе с разделяемой библиотекой "test.so", сопоставленной в него во время запуска:

LD_PRELOAD="./test.so" prog

Такие библиотеки создаются тем же способом, что и разделяемые объекты. Библиотека имеет доступ к внешним символам, указанным в программе, как и любая другая библиотека. На macOS, данная команда запускает процесс "prog" вместе с разделяемой библиотекой "test.dylib", сопоставленной в него во время запуска:[25]

DYLD_INSERT_LIBRARIES="./test.dylib" DYLD_FORCE_FLAT_NAMESPACE=1 prog

В Unix-подобных системах также возможно использовать методы, основанные на отладчиках.[26]

Пример кода

править

Использование 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;
}

Примечания

править
  1. 1 2 James Shewmaker. Analyzing DLL Injection. GSM Presentation. Bluenotch. Дата обращения: 31 августа 2008. Архивировано 3 декабря 2008 года.
  2. 1 2 Iczelion. Tutorial 24: Windows Hooks. Iczelion's Win32 Assembly Homepage (август 2002). Дата обращения: 31 августа 2008. Архивировано 1 августа 2008 года.
  3. Rocky Pulley. Extending Task Manager with DLL Injection. CodeProject. CodeProject (19 мая 2005). Дата обращения: 1 сентября 2008. Архивировано 6 февраля 2009 года.
  4. 1 2 Nasser R. Rowhani. DLL Injection and function interception tutorial. CodeProject. CodeProject (23 октября 2003). Дата обращения: 31 августа 2008. Архивировано 15 июня 2008 года.
  5. 1 2 3 Ivo Ivanov. API hooking revealed. CodeProject. CodeProject (2 декабря 2002). Дата обращения: 31 августа 2008. Архивировано 14 октября 2008 года.
  6. 1 2 3 Robert Kuster. Three Ways to Inject Your Code into Another Process. CodeProject. CodeProject (20 августа 2003). Дата обращения: 31 августа 2008. Архивировано 20 июля 2008 года.
  7. Working with the AppInit_DLLs registry value (англ.). Microsoft (21 ноября 2006). Дата обращения: 28 декабря 2021. Архивировано 1 января 2017 года.
  8. Raymond Chen. AppInit_DLLs should be renamed Deadlock_Or_Crash_Randomly_DLLs (англ.). The Old New Thing. Microsoft (13 декабря 2007). Дата обращения: 28 декабря 2021. Архивировано 17 декабря 2007 года.
  9. dllmain.c (англ.) (недоступная ссылка — история). ReactOS. ReactOS Foundation.
  10. "'AtomBombing' Microsoft Windows Via Code Injection". Dark Reading. 2016-10-27. Архивировано 17 мая 2021. Дата обращения: 28 декабря 2021.
  11. Trent Waddington. InjectDLL (англ.) (31 августа 2008). Дата обращения: 28 декабря 2021. Архивировано из оригинала 30 декабря 2019 года.
  12. Dll Injection (англ.). DreamInCode.net. MediaGroup1 (31 августа 2008). Архивировано из оригинала 2 сентября 2008 года.
  13. Greg Jenkins. DLL Injection Framework (англ.). Ring3 Circus (1 ноября 2007). Дата обращения: 28 декабря 2021. Архивировано из оригинала 28 июня 2020 года.
  14. Drew Benton. A More Complete DLL Injection Solution Using CreateRemoteThread (англ.). CodeProject. CodeProject (17 августа 2007). Дата обращения: 28 декабря 2021. Архивировано 28 декабря 2021 года.
  15. SetWindowsHookEx Function (англ.). Platform SDK for Windows XP SP2. Microsoft (31 августа 2008). Дата обращения: 28 декабря 2021. Архивировано 17 августа 2016 года.
  16. AppInit_DLLs Registry Value and Windows 95 (англ.). Microsoft Help and Support. Microsoft (1 марта 2005). Дата обращения: 28 декабря 2021. Архивировано 20 марта 2016 года.
  17. Dll Injection using SetWindowsHookEx() Method (англ.). Game Reversal (3 апреля 2008). Дата обращения: 28 декабря 2021. Архивировано 4 апреля 2016 года.
  18. SetThreadContext DLL Injection (англ.) (16 января 2007). Дата обращения: 28 декабря 2021. Архивировано 28 декабря 2021 года.
  19. Ben Botto. DLL Injector (англ.) (6 сентября 2008). Архивировано из оригинала 7 февраля 2009 года.
  20. Insecure Library Loading Could Allow Remote Code Execution (англ.). Microsoft (20 апреля 2016). Дата обращения: 28 декабря 2021. Архивировано 2 июля 2017 года.
  21. Secure loading of libraries to prevent DLL preloading attacks (англ.). Microsoft (10 июня 2011). Дата обращения: 28 декабря 2021. Архивировано 23 сентября 2016 года.
  22. Microsoft Security Advisory: Insecure library loading could allow remote code execution. support.microsoft.com. Дата обращения: 28 декабря 2021. Архивировано 28 декабря 2021 года.
  23. Endpoint Protection - Symantec Enterprise. community.broadcom.com. Дата обращения: 28 декабря 2021. Архивировано 28 декабря 2021 года.
  24. Торвальдс, Линус; Linus Torvalds, David Engel, Eric Youngdale, Peter MacDonald, Hongjiu Lu, Lars Wirzenius, Mitch D'Souza.: ld.so/ld-linux.so – dynamic linker/loader (англ.). UNIX man pages (14 марта 1998). Архивировано из оригинала 6 февраля 2009 года.
  25. Peter Goldsborough. The LD_PRELOAD trick. Peter Goldsborough. Дата обращения: 28 декабря 2021. Архивировано 9 декабря 2021 года.
  26. Code Injection into Running Linux Application (амер. англ.). CodeProject (12 февраля 2009). Дата обращения: 28 декабря 2021. Архивировано 28 декабря 2021 года.