• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Туториал по перехвату Windows API (пример с внедрением DLL)

yashechka

Генератор контента.Фанат Ильфака и Рикардо Нарвахи
Эксперт
Регистрация
24.11.2012
Сообщения
2 344
Реакции
3 563
Эта статья посвящена простому подходу к настройке глобальных перехватчиков API в масштабе всей системы. Для инъекции DLL мы будем использовать ключ реестра с именем AppInit_DLLs, а для выполнения перехвата API в Windows мы будем использовать библиотеку Mhook. В этой статье также будет представлен пример внедрения DLL: мы покажем, как можно легко сделать процесс calc.exe невидимым в списке запущенных процессов.

О перехвате API

Перехват Windows API — это процесс, позволяющий перехватывать вызовы API-функций. Это дает вам контроль над тем, как ведет себя операционная система или часть программного обеспечения. Некоторые из программных решений, использующих перехватчики, включают: программное обеспечение для защиты от вредоносных программ, решения для обеспечения безопасности приложений, инструменты мониторинга безопасности, системные утилиты, инструменты для программирования и многие другие.

Типы хуков API

Хуки API можно разделить на следующие типы:

- Локальные хуки: они влияют только на определенные приложения.
- Глобальные хуки: они влияют на все системные процессы.


Тип метода перехвата для Windows, который мы здесь рассматриваем, относится к глобальному типу. Он влияет на все процессы во всех сеансах (в отличие от метода SetWindowsHooks, который ограничен только выбранным рабочим столом).


Инфраструктура AppInit_DLL

Инфраструктура AppInit_DLLs загружает предопределенный набор DLL во все процессы пользовательского режима, связанные с библиотекой User32.dll (на самом деле исполняемых файлов, которые не были бы связаны с ней, почти нет). Когда User32.dll инициализируется, она загружает соответствующие библиотеки DLL, тем самым выполняя внедрение DLL в процессы.

Чтобы изменить поведение инфраструктуры AppInit_DLL, необходимо настроить значения раздела реестра HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows.


ЗначениеОписаниеПример
LoadAppInit_DLLs
(REG_DWORD)
Позволяет включать и выключать AppInit_DLL в глобальном масштабе.0x0 отключает AppInit_DLL.
0x1 включает AppInit_DLL

AppInit_DLLs
(REG_SZ)
Позволяет указать список DLL для загрузки. Элементы должны быть разделены запятыми или пробелами. Чтобы указать полный путь к DLL, используйте короткие имена файлов.C:\PROGRA~1\Test\Sample.dll
RequireSignedAppInit_DLLs
(REG_DWORD)
Позволяет ограничить диапазон библиотек DLL только подписанными кодом.0x0 позволяет загружать любые библиотеки DLL
0x1 позволяет загружать только библиотеки DLL с кодовой подписью.

Библиотека Mhook

Существует несколько библиотек перехвата API. Как правило, они делают следующее:

- Заменяют начальную часть кода определенной функции нашим собственным кодом (также известным как трамплин). После выполнения функция переходит к обработчику ловушек.
- Сохраняет исходную версию замененного кода определенной функции. Это необходимо для правильной работы определенной функции.
- Восстанливает замененную часть определенной функции.


Как я упоминал ранее, при создании наших глобальных хуков мы будем использовать библиотеку Mhook. Это бесплатная и простая в использовании библиотека с открытым исходным кодом для перехвата Windows API, поддерживающая системные архитектуры x32 и x64. Его интерфейс не сложен и не требует пояснений:

BOOL Mhook_SetHook(PVOID *ppSystemFunction, PVOID pHookFunction);
BOOL Mhook_Unhook(PVOID *ppHookedFunction);


Более подробная информация о том, как использовать библиотеку, доступна далее в статье и на домашней странице Mhook.

Пример реализации

В этом примере мы будем использовать C++ для написания DLL пользовательского режима, чтобы проиллюстрировать методы внедрения DLL. Для этого необходима последняя версия исходников Mhook, которые будут добавлены в ваш проект. Обратите внимание, что любые предварительно скомпилированные заголовки должны быть отключены для файлов Mhook.

Как мы уже говорили, чтобы привести пример перехвата API, мы сделаем процесс calc.exe невидимым в списке процессов — для любого инструмента Windows, представляющего такой список. Этот пример продемонстрирует, как создать и внедрить DLL в процесс, тем самым установив глобальную перехватчик API — и создав своего рода руткит appinit_dlls.

Функция источника

Чтобы получить список запущенных процессов, вам нужно вызвать функцию NtQuerySystemInformationNTAPI. Это означает, что для нашего проекта требуется кое-что из NTAPI. Поскольку мы не можем найти полную информацию в заголовке winternl.h, типы данных должны быть определены вручную:

Код:
//
// Defines and typedefs
#define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
typedef struct _MY_SYSTEM_PROCESS_INFORMATION
{
    ULONG                   NextEntryOffset;
    ULONG                   NumberOfThreads;
    LARGE_INTEGER           Reserved[3];
    LARGE_INTEGER           CreateTime;
    LARGE_INTEGER           UserTime;
    LARGE_INTEGER           KernelTime;
    UNICODE_STRING          ImageName;
    ULONG                   BasePriority;
    HANDLE                  ProcessId;
    HANDLE                  InheritedFromProcessId;
} MY_SYSTEM_PROCESS_INFORMATION, *PMY_SYSTEM_PROCESS_INFORMATION;
typedef NTSTATUS (WINAPI *PNT_QUERY_SYSTEM_INFORMATION)(
    __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,
    __inout    PVOID SystemInformation,
    __in       ULONG SystemInformationLength,
    __out_opt  PULONG ReturnLength
    );


Создание и инициализация глобальной переменной позволяет нам хранить адрес исходной функции.

//
// Original function
PNT_QUERY_SYSTEM_INFORMATION OriginalNtQuerySystemInformation =
(PNT_QUERY_SYSTEM_INFORMATION)::GetProcAddress:):GetModuleHandle(L"ntdll"),
"NtQuerySystemInformation");

Функция после хука

После того, как функция была перехвачена, сначала она вызывает исходную функцию. Затем мы исследуем SystemInformationClass. Если окажется, что это SystemProcessInformation, в списке запущенных процессов нам нужно найти и удалить все записи, связанные с calc.exe. Вот и все!

Обратите внимание, что исходная и перехваченная функции должны иметь одинаковые cсигнатуры.

Код:
//
// Hooked function
NTSTATUS WINAPI HookedNtQuerySystemInformation(
    __in       SYSTEM_INFORMATION_CLASS SystemInformationClass,
    __inout    PVOID                    SystemInformation,
    __in       ULONG                    SystemInformationLength,
    __out_opt  PULONG                   ReturnLength
    )
{
    NTSTATUS status = OriginalNtQuerySystemInformation(SystemInformationClass,
        SystemInformation,
        SystemInformationLength,
        ReturnLength);
    if (SystemProcessInformation == SystemInformationClass && STATUS_SUCCESS == status)
    {
        //
        // Loop through the list of processes
        //
        PMY_SYSTEM_PROCESS_INFORMATION pCurrent = NULL;
        PMY_SYSTEM_PROCESS_INFORMATION pNext    = (PMY_SYSTEM_PROCESS_INFORMATION)
        SystemInformation;
       
        do
        {
            pCurrent = pNext;
            pNext    = (PMY_SYSTEM_PROCESS_INFORMATION)((PUCHAR)pCurrent + pCurrent->
            NextEntryOffset);
            if (!wcsncmp(pNext->ImageName.Buffer, L"calc.exe", pNext->ImageName.Length))
            {
                if (0 == pNext->NextEntryOffset)
                {
                    pCurrent->NextEntryOffset = 0;
                }
                else
                {
                    pCurrent->NextEntryOffset += pNext->NextEntryOffset;
                }
                pNext = pCurrent;
            }          
        }
        while(pCurrent->NextEntryOffset != 0);
    }
    return status;
}


Настройка хука Windows

Настройка хука не требует особых усилий: вам просто нужно вызвать Mhook_SetHook из DllMain после загрузки DLL в новый процесс:

Код:
//
// Entry point
BOOL WINAPI DllMain(
    __in HINSTANCE  hInstance,
    __in DWORD      Reason,
    __in LPVOID     Reserved
    )
{      
    switch (Reason)
    {
    case DLL_PROCESS_ATTACH:
        Mhook_SetHook((PVOID*)&OriginalNtQuerySystemInformation,
        HookedNtQuerySystemInformation);
        break;

Отвязка

Для обратного перехвата вам нужно вызвать Mhook_Unhook из DllMain после выгрузки DLL из процесса:

Код:
//
// Entry point
BOOL WINAPI DllMain(
    __in HINSTANCE  hInstance,
    __in DWORD      Reason,
    __in LPVOID     Reserved
    )
{      
    switch (Reason)
    {
    ...
    case DLL_PROCESS_DETACH:
        Mhook_Unhook((PVOID*)&OriginalNtQuerySystemInformation);
        break;
    }


Выполнение перехвата API

Теперь мы продемонстрируем, как работает наш DLL-хук. Следуй этим шагам:

- Соберите проект и поместите AppInitHook.dll, который у вас получится в результате, в корень диска C.

1646133962131.png


- В редакторе реестра Windows найдите ключ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows и выберите значение AppInit_DLLs.

1646133973691.png


- Отредактируйте значение и введите путь к хуку DLL (в нашем примере это C:\AppInitHook.dll).
- После того, как вы закончите редактирование реестра, хуки начнут работать.

Теперь запустим несколько экземпляров скрытого процесса. После этого проверьте процессы в диспетчере задач Windows: calc.exe отсутствует в списке.

1646134005002.png


Поскольку предоставленный хук API является глобальным, мы можем видеть, что тот же результат отображается другими программами с функциональностью, аналогичной диспетчеру задач Windows. Например, Process Explorer от Марка Руссиновича.

1646134016191.png


Последняя проверка: откройте командную строку и запустите tasklist.exe.

1646134027187.png


Процесс стандартного калькулятора Windows и все его экземпляры были успешно скрыты. Хук API работает, как и ожидалось.

Ограничения

Теперь нужно сказать несколько слов об ограничениях этого метода:

- Подключение к User32.dll: Как мы уже говорили в начале статьи, затронуты могут быть только те процессы, которые подключены к User32.dll.
- Могут быть вызваны только функции из Ntdll.dll и Kernel32.dll: Причина этого в том, что перехват DLL происходит в DllMain из User32.dll и никакая другая библиотека в этот момент не инициализируется.
- Функции безопасности Windows 7 и Windows 2008 R2: для этих функций требуются библиотеки DLL AppInit с цифровыми подписями. На самом деле это не большая проблема, поскольку функции можно отключить с помощью редактора реестра Windows.
- Пробелы в полном пути к AppInit DLL не допускаются.


Переведено специально для xss.pro
Автор перевода: yashechka
Источник: https://www.apriorit.com/dev-blog/160-apihooks
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Метод неплохой, но надо учитывать, что начиная с вин 8.1 , если включен Secure boot в uefi - эти длл работать не будут.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Метод неплохой, но надо учитывать, что начиная с вин 8.1 , если включен Secure boot в uefi - эти длл работать не будут.
А каков шанс, что Secure boot включён?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
А каков шанс, что Secure boot включён?
На новых ноутах , с десяткой по дефолту вроде как включен. Точной статистики у меня нет.
 
На новых ноутах , с десяткой по дефолту вроде как включен. Точной статистики у меня нет.
Да, в этом ты прав.

Но есть ряд случаев когда его отрубают, потому что есть масса софта (белого) которые отказываются работать с включенным sb/fb.

Но все равно скорее всего это да же не 10-20 % из всех новых тачек.
 
Метод неплохой, но надо учитывать, что начиная с вин 8.1 , если включен Secure boot в uefi - эти длл работать не будут.

Можно узнать как именно влияет включение/отключение secure boot на инжект dll в уже загруженной ОС?
В моем понимании эта опция в UEFI просто разрешает загрузку ОС/загрузчика с внешних источников.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
В моем понимании эта опция в UEFI просто разрешает загрузку ОС/загрузчика с внешних источников.
Помимо этого UEFI предоставляет возможность определить, включена ли опция, прочитав EFI переменную с GUID EFI_GLOBAL_VARIABLE ("{8be4df61-93ca-11d2-aa0d-00e098032b8c}") и именем SecureBoot. Т.е. можно вызвать GetFirmwareEnvironmentVariableA() и узнать, будет ли работать AppInit_DLLs.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх