[C++] Создание потока из левого модуля

Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
Шалом.

Давненько не писал тем, ебался с детектами.
Щас распишу как сделать так, чтобы ваш поток был создан от имени другого модуля.
Допустим: Kernel32.dll

Для начала возьмем две простые функции для поисков простого паттерна.
Взял первое что попалось, подойдет.

Код:
BOOL CompareMem(const BYTE* pData, const BYTE* bMask, const char* szMask)

{
    for (; *szMask; ++szMask, ++pData, ++bMask)
        if (*szMask == 'x' && *pData != *bMask)
            return false;
    return (*szMask) == NULL;
}
DWORD FindPatternMem(DWORD dwAddress, DWORD dwLen, BYTE *bMask, char * szMask)
{
    for (DWORD i = 0; i < dwLen; i++)
    {
        __try
        {
            if (CompareMem((BYTE*)(dwAddress + i), bMask, szMask))
            {
                return (DWORD)(dwAddress + i);
            }
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            return 0;
        }
    }
    return 0;
}
Теперь перейдем к более сладкому.
Мы будем искать в нужном нам модуле, 7 пустых байт под наши инструкции.
Действо будет таким:​
  1. Находим 7 пустых байт.
  2. Записываем в них инструкцию call dword ptr [адресс нашей функции] + ret
  3. Вызываем CreateThread по адресу в который записали инструкцию.
  4. Фактически поток будет указывать на длл на которую мы хотим чтобы он указывал, при этом, выполняя наш код.

Код:
DWORD ScanAddressTable()
{
    DWORD dwKernel32 = reinterpret_cast<DWORD>(GetModuleHandleW(L"kernel32.dll")); //Наш модуль, фактически может быть любым.
    if (dwKernel32)
    {
        DWORD dwAddress = FindPatternMem(dwKernel32, 0x700000, (PBYTE)"\xCC\xCC\xCC\xCC\xCC\xCC\xCC", "xxxxxxx");
        if (dwAddress)
        {
            return dwAddress;
        }
        DWORD dwAddress2 = FindPatternMem(dwKernel32, 0x700000, (PBYTE)"\x90\x90\x90\x90\x90\x90\x90", "xxxxxxx");
        if (dwAddress2)
        {
            return dwAddress2;
        }
    }
    return 0;
}
Теперь дописываем мелочи.
Патчинг памяти:​
Код:
void WriteMemory(void *adr, void *ptr, int size)
{
    DWORD OldProtection;
    VirtualProtect(adr, size, PAGE_EXECUTE_READWRITE, &OldProtection);
    memcpy(adr, ptr, size);
    VirtualProtect(adr, size, OldProtection, &OldProtection);
}
Структура для хранения списка наших потоков и сам контейнер:​
Код:
struct ThreadData
{
    DWORD  Adress;
    void * func;
    DWORD  JumpAdress;
};
std::vector<ThreadData*> adress_list;
Расписываем создание потока:​
Код:
HANDLE CreateThreadMemory(void * adress_func)
{
    if (adress_func)
    {
        DWORD adress = ScanAddressTable();

        if (adress) {
            //с
            CHAR ByteCode[] = "\xFF\x15\x00\x00\x00\x00\xC3";

            ThreadData * threadData = new ThreadData();

            threadData->Adress = adress;
            threadData->func = adress_func;
            threadData->JumpAdress = (DWORD)(adress_func);

            *(DWORD*)(&ByteCode[2]) = (DWORD)(&threadData->JumpAdress);

            WriteMemory((void*)adress, &ByteCode[0], 7);
   
            adress_list.push_back(threadData);
            return CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)adress, 0, 0, 0);
        }
    }
    return NULL;
}
Создадим тестовый поток и выведем его айди через месадж бокс чтобы убедится что все сработало как надо:​
Код:
DWORD WINAPI TestTherad(LPVOID)
{
    std::string data = "айди потока: " + std::to_string(GetCurrentThreadId());
    MessageBoxA(0, data.c_str(), "newThread",  0);
    return 0;
}

int main()
{
    CreateThreadMemory(reinterpret_cast<void*>(TestTherad));
    system("pause");
    return 0;
}
Открываем Process Hacker и сверяем айди потока с тем айдишником, который нам вывело.
Зависимости (для обезьянок):​
Код:
#include <windows.h>
#include <vector>
#include <string>

using namespace std;
 
Пользователь
Статус
Оффлайн
Регистрация
28 Дек 2017
Сообщения
149
Реакции[?]
118
Поинты[?]
0
можно вопрос, в какой игре какой АЧ имеет свойство ебать за потоки с аддресом старта вне легитных модулей?)
 
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
можно вопрос, в какой игре какой АЧ имеет свойство ебать за потоки с аддресом старта вне легитных модулей?)
открою секрет, аж все драйверные античиты вас так палят, даже когда вы инжектите маппингом, вы рано или поздно создаете поток из адрессного пространства своего модуля и указываете на него.
 
Пользователь
Статус
Оффлайн
Регистрация
15 Июн 2017
Сообщения
82
Реакции[?]
46
Поинты[?]
0
можно создать замороженный поток с рандомным стартовым адресом и потом вручную перенести eip в нужное русло via GetTreadContext SetTreadContext ну и еще вроде через eax передается регистр который записывается как стартовый адрес и его можно изменить таким же макаром
 
Я лучше тебя
Участник
Статус
Оффлайн
Регистрация
31 Июл 2017
Сообщения
383
Реакции[?]
448
Поинты[?]
1K
можно создать замороженный поток с рандомным стартовым адресом и потом вручную перенести eip в нужное русло via GetTreadContext SetTreadContext ну и еще вроде через eax передается регистр который записывается как стартовый адрес и его можно изменить таким же макаром
в случае с драйверными античитами, они подписку ставят на работу с дескрипторами процесса и его потоков, при старте потока его адресс светиться сходу, тоесть даже если заменишь в процессе выполнения на свое адрессное пространство укажешь.
 
Сверху Снизу