На заметку Перехват WinApi функций.


MKII

Уважаемый пользователь
Форумчанин
Регистрация
03.10.2022
Сообщения
253
Репутация
177
Сегодня столкнулся с тем, что мне нужно перехватить WinApi функции и изменить результат который они передают в программу.
Первый раз решил пойти сложным путем, методом изменения таблицы импортов, пытаясь поменять адрес в таблице импортов на нужный мне (перед этим создав темплейт функции).
Сделать у меня это не получилось, по этому я решил использовать библиотеку Detours.

Для работы будем использовать библиотеку detours, вам её нужно будет установить через NuGet.
Сначала создадим темплейты наших функций, я покажу это на 2х примерах: GetUserNameW и RegOpenKeyExW.
C++:
typedef BOOL(WINAPI* GETUSERNAMEW)(LPWSTR lpBuffer, LPDWORD pcbBuffer);
typedef LONG(WINAPI* REGOPENKEYEXW)(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);

GETUSERNAMEW original_GetUserNameW;
REGOPENKEYEXW original_RegOpenKeyExW;
Далее, нам нужно создать "Прототип" функции которая будет заменятся на оригинальную.
Сначала я просто покажу код, потом более подробно расскажу что тут делается:
C++:
BOOL WINAPI My_GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer)
{
    WCHAR originalName[256];
    DWORD size = 256;
    original_GetUserNameW(originalName, &size);

    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_int_distribution<DWORD> dist(0, UINT32_MAX);
    DWORD mask = dist(mt);

    std::wstring username = L"MKII " + std::to_wstring(mask);

    std::wcout << L"Original GetUserNameW: " << originalName << L", new GetUserNameW: " << username << std::endl;

    std::wstring name = username;
    wcscpy(lpBuffer, name.c_str());
    *pcbBuffer = name.length();
    return TRUE;
}

LONG WINAPI My_RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
{
    std::wcout << L"RegOpenKeyExW called with subkey: " << lpSubKey << std::endl;
    return original_RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
}

И внедряем их через DetourAttach, вот код main функции:
C++:
BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        AllocConsole();
        freopen("CONOUT$", "w", stdout);
        std::cout << "Hooked:)\nCrack by MKII | https://ru-sfera.pw/" << std::endl;

        // Получаем адреса оригинальных функций
        original_GetUserNameW = (GETUSERNAMEW)GetProcAddress(GetModuleHandle(L"advapi32.dll"), "GetUserNameW");
        original_RegOpenKeyExW = (REGOPENKEYEXW)GetProcAddress(GetModuleHandle(L"advapi32.dll"), "RegOpenKeyExW");
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourAttach(&(PVOID&)original_GetUserNameW, My_GetUserNameW);
        DetourAttach(&(PVOID&)original_RegOpenKeyExW, My_RegOpenKeyExW);
        DetourTransactionCommit();
        break;
    }
    return TRUE;
}
Я использовал это для взлома программы, который возможно в скором времени залью на форум, по этому такой cout вначале.

Далее расскажу как это всё работает.
Возьму для примера функцию GetUserNameW.
1690140194512.png

В самом низу, оригинальная функция (Для примера, что бы понять разницу), а слева функция которую мы хукаем.
DetourAttach изменяет 1 инструкцию в функции на jmp с адресом нашей "псевдо-функции", тем самым происходит переход.
С самого начала мы вызываем оригинальную функцию GetUserNameW по её адресу, что бы получить имя пользователя (это делать не обязательно, но я сделал).
C++:
    WCHAR originalName[256];
    DWORD size = 256;
    original_GetUserNameW(originalName, &size);
Далее, я к имени MKII прибавляю случайное число, что бы рандомизировать имена.
C++:
std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_int_distribution<DWORD> dist(0, UINT32_MAX);
    DWORD mask = dist(mt);

    std::wstring username = L"MKII " + std::to_wstring(mask);

    std::wcout << L"Original GetUserNameW: " << originalName << L", new GetUserNameW: " << username << std::endl;
И после этого, я передаю результат и return TRUE, что бы программа думала, что функция отработала корректно.
C++:
    std::wstring name = username;
    wcscpy(lpBuffer, name.c_str());
    *pcbBuffer = name.length();
    return TRUE;

Теперь пару слов про функцию RegOpenKeyExW.
Наш прототип принимает параметры HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult (как оригинальная функция).
За имя ключа отвечает параметр lpSubKey, мы выводим его в консоль, тем самым, мы можем увидеть в какой раздел стучит программа:
C++:
std::wcout << L"RegOpenKeyExW called with subkey: " << lpSubKey << std::endl;
После этого, вызываем оригинальную функцию по её адресу, что бы программа отработала корректно:
C++:
return original_RegOpenKeyExW(hKey, lpSubKey, ulOptions, samDesired, phkResult);
При желании, можно посмотреть вывод, добавив переменную типа Long и в неё загрузить результат original_RegOpenKeyExW.
Даже можно изменить данные которые выдаст original_RegOpenKeyExW, думаю труда сделать это вам не составит.
На этом всё, надеюсь эта статья хоть кому-то будет полезна.
 
Последнее редактирование:

MKII

Уважаемый пользователь
Форумчанин
Регистрация
03.10.2022
Сообщения
253
Репутация
177
Кстати, хук нужно делать ДО выполнения функции (думаю это очевидно.)
 

HMCoba

Активный пользователь
Активный
Регистрация
22.04.2023
Сообщения
157
Репутация
114
На этом всё, надеюсь эта статья хоть кому-то будет полезна.
Очень даже полезная и нужная тема, хорошая работа!
Как раз на днях искал примеры, работы с библиотекой Detours.
Только я не понял здесь в коде ...
{ DetourAttach(&(PVOID&)original_GetUserNameW, My_GetUserNameW);
DetourAttach(&(PVOID&)original_RegOpenKeyExW, My_RegOpenKeyExW); }
я про вот этот участок кода, который из них указатель на планируемую функцию?
 
Последнее редактирование:

HMCoba

Активный пользователь
Активный
Регистрация
22.04.2023
Сообщения
157
Репутация
114
Может вы вкурсе, как с помощью даной библиотеку Detours перехватывать сетевые пакеты?
 
Последнее редактирование:

MKII

Уважаемый пользователь
Форумчанин
Регистрация
03.10.2022
Сообщения
253
Репутация
177
Очень даже полезная и нужная тема, хорошая работа!
Как раз на днях искал примеры, работы с библиотекой Detours.
Только я не понял здесь в коде ...
{ DetourAttach(&(PVOID&)original_GetUserNameW, My_GetUserNameW);
DetourAttach(&(PVOID&)original_RegOpenKeyExW, My_RegOpenKeyExW); }
я про вот этот участок кода, который из них указатель на планируемую функцию?
DetourAttach(&(PVOID&)original_GetUserNameW, My_GetUserNameW);

(PVOID&)original_GetUserNameW это указатель на оригинальную функцию.

My_GetUserNameW это функция на которую меняем.
 

MKII

Уважаемый пользователь
Форумчанин
Регистрация
03.10.2022
Сообщения
253
Репутация
177
Может вы вкурсе, как с помощью даной библиотеку Detours перехватывать сетевые пакеты?
На счет этого не знаю что ответить, это был мой первый опыт работы с этой библиотекой, не знаю как перехватывать сетевые пакеты.
Если в определенном приложении нужно перехватить, то можно так-же хук сделать, но это будет сложнее, я думаю.
 

HMCoba

Активный пользователь
Активный
Регистрация
22.04.2023
Сообщения
157
Репутация
114
На счет этого не знаю что ответить, это был мой первый опыт работы
На первый раз, очень даже не плохо! На счёт сетевых пакетов, придётся по юзать.. я тоже так думаю
что будет немного сложнее. Меня интересует перехват пакетоа, типа как в Wireshark, хотел возможно ли это с Detour?
 
Последнее редактирование:

HMCoba

Активный пользователь
Активный
Регистрация
22.04.2023
Сообщения
157
Репутация
114
Спасибо за работу, хороший пример для знакомства с перехватом, а так же с библиотекой Windows Detours!
 

MKII

Уважаемый пользователь
Форумчанин
Регистрация
03.10.2022
Сообщения
253
Репутация
177
На первый раз, очень даже не плохо у тебя всё получилось, на счёт сетевых пакетов, придётся по юзать.. я тоже так думаю
что будет немного сложнее. Меня интересует перехват пакетоа, типа как в Wireshark, и озможно ли это с Detour?
На сколько я понимаю, Detour предназначен только для хукинга функции, так что не получится перехватить весь трафик
 
Верх Низ