Информация Гайд Вызываем удаленно игровую функцию и WinAPI

Тема в разделе "C/C++", создана пользователем CleanLegend, 15 апр 2019.

Метки:
  1. CleanLegend

    Всефорумный модератор

    Регистрация:
    28 мар 2013
    Сообщения:
    313
    Симпатии:
    582
    Привет, сегодня мы будем вызывать игровую функцию из exe.
    Пример вызова в dll:
    
    #define FUNC_CMessages__AddMessageJumpQ 0x69F1E0
    void AddMessageJumpQ(char *text, unsigned int time, unsigned short flag, bool bPreviousBrief)
    {
        ((void(__cdecl *)(char *, unsigned int, unsigned short, bool))FUNC_CMessages__AddMessageJumpQ)(text, time, flag, bPreviousBrief);
    }
    
    AddMessageJumpQ("hello", 500, NULL,false); // вызываем
    
    Для вызова из exe мы будем использовать:
    -OpenProcess
    -VirtualAllocEx
    -WriteProcessMemory
    -CreateRemoteThread

    Создаем структуру для передачи аргументов в удаленный поток(CreateRemoteThread):
    struct Struct
    {
        char text[256];
        unsigned int time;
        unsigned short flag;
        bool bPreviousBrief;
        DWORD pAdr;
    }FuncArgs;
    Создаем прототип:
    typedef void(__cdecl *_SendMSG)(char*, unsigned int, unsigned short, bool);
    Создаем нашу функцию, которую будем вызывать. Под ней создаем еще одну, для получения размера
    DWORD __stdcall RemoteThread(Struct *sArg)
    {
        _SendMSG msg = (_SendMSG)sArg->pAdr; // передаем адрес
        msg(sArg->text, sArg->time, sArg->flag, sArg->bPreviousBrief); // вызываем
        return 0;
    }
    void __stdcall RemoteThread_end() {}
    Заполняем структуру:
    
    strcpy(FuncArgs.text, "Hello world!");
    FuncArgs.time = 500;
    FuncArgs.flag = NULL;
    FuncArgs.bPreviousBrief = false;
    FuncArgs.pAdr = 0x69F1E0;
    
    Функция для получения id процесса:
    DWORD GetProcId(const char* procname)
    {
        PROCESSENTRY32 pe;
        HANDLE hSnap;
    
        pe.dwSize = sizeof(PROCESSENTRY32);
        hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
        if (Process32First(hSnap, &pe)) {
            do {
                if (strcmp(pe.szExeFile, procname) == 0)
                    break;
            } while (Process32Next(hSnap, &pe));
        }
        return pe.th32ProcessID;
    }
    // получаем хэндл процесса
        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcId("gta_sa.exe"));
        // Выделяем память под наш поток в gta_sa
        LPVOID pRemoteThread = VirtualAllocEx(hProcess, NULL, (DWORD_PTR)RemoteThread_end - (DWORD_PTR)RemoteThread, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        // Записываем его
        WriteProcessMemory(hProcess, pRemoteThread, (LPVOID)RemoteThread, ((DWORD_PTR)RemoteThread_end - (DWORD_PTR)RemoteThread), 0);
        // Выделяем память для нашего объекта в gta_sa
        Struct *myArg = (Struct*)VirtualAllocEx(hProcess, NULL, sizeof(Struct), MEM_COMMIT, PAGE_READWRITE);
        // Записываем его
        WriteProcessMemory(hProcess, myArg, &FuncArgs, sizeof(Struct), NULL);
        // Запускаем наш поток pRemoteThread с аргументами myArg
        HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, myArg, 0, 0);
        // Закрываем дескриптор потока
        CloseHandle(hThread);
        // Освобождаем выделенную память
        VirtualFreeEx(hProcess, myArg, sizeof(Struct), MEM_RELEASE);
        // Закрываем дескриптор процесса
        CloseHandle(hProcess);
    Получаем:
    [​IMG]

    Пример с WinAPI(Beep):

    Создаем структуру и прототип:
    typedef BOOL(__stdcall *__Beep)(DWORD, DWORD);
    struct sBeep
    {
        DWORD Freq;
        DWORD Duration;
        DWORD pAdr;
    
    } myBeep;
    Заполняем структуру:
    
    myBeep.Freq = 500;
    myBeep.Duration = 50;
    HMODULE kernel = LoadLibrary("Kernel32.dll"); // Получаем адрес kernel32
    myBeep.pAdr = (DWORD)GetProcAddress(kernel,"Beep"); // получаем адрес функции Beep
    FreeLibrary(kernel);
    
    DWORD __stdcall RemoteThread(sBeep *sArg)
    {
        __Beep msg = (__Beep)sArg->pAdr;
        msg(sArg->Freq, sArg->Duration);
        return 0;
    }
    void __stdcall RemoteThread_end() {}
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetProcId("gta_sa.exe"));
        // Выделяем память под наш поток в gta_sa
        LPVOID pRemoteThread = VirtualAllocEx(hProcess, NULL, (DWORD_PTR)RemoteThread_end - (DWORD_PTR)RemoteThread, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
        // Записываем его
        WriteProcessMemory(hProcess, pRemoteThread, (LPVOID)RemoteThread, ((DWORD_PTR)RemoteThread_end - (DWORD_PTR)RemoteThread), 0);
        // Выделяем память для нашего объекта в gta_sa
        sBeep *myArg = (sBeep*)VirtualAllocEx(hProcess, NULL, sizeof(sBeep), MEM_COMMIT, PAGE_READWRITE);
        // Записываем его
        WriteProcessMemory(hProcess, myArg, &myBeep, sizeof(sBeep), NULL);
        // Запускаем наш поток pRemoteThread с аргументами myArg
        HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, myArg, 0, 0);
        // Закрываем дескриптор потока
        CloseHandle(hThread);
        // Освобождаем выделенную память
        VirtualFreeEx(hProcess, myArg, sizeof(sBeep), MEM_RELEASE);
        // Закрываем дескриптор процесса
        CloseHandle(hProcess);
     
    #1 CleanLegend, 15 апр 2019
    Последнее редактирование: 16 апр 2019
    F11GAR0., AppleThe, iAmerican и 12 другим нравится это.
  2. SR_team

    SR_team BH Team
    BH Team

    Регистрация:
    26 окт 2013
    Сообщения:
    3.199
    Симпатии:
    3.203
    а самое интересное не написал. Переключение процессов планировщиком происходит в момент вызова CreateRemoteThread или по истечению кванта? Т.е. поток выполняется сразу или отложено, при переключение процесса?
     
  3. CleanLegend

    Всефорумный модератор

    Регистрация:
    28 мар 2013
    Сообщения:
    313
    Симпатии:
    582
    Сразу
     
    SR_team нравится это.
  4. CleanLegend

    Всефорумный модератор

    Регистрация:
    28 мар 2013
    Сообщения:
    313
    Симпатии:
    582
    Обновил. Изменил реализацию, добавил пример с WinAPI
     
  5. SR_team

    SR_team BH Team
    BH Team

    Регистрация:
    26 окт 2013
    Сообщения:
    3.199
    Симпатии:
    3.203
    вот это уже выглядит круто, но компилятор может расположить функции в ином порядке
     
    CleanLegend нравится это.
  6. iAmerican

    Друг

    Регистрация:
    17 фев 2014
    Сообщения:
    572
    Симпатии:
    234
    клёвый гайд , взял себе
     
    SiTrak нравится это.
  7. Rinat_Namazov

    Rinat_Namazov ( ͡° ͜ʖ ͡°)
    Всефорумный модератор

    Регистрация:
    9 авг 2015
    Сообщения:
    1.134
    Симпатии:
    576
    Может windows и гарантирует загрузку такой системной библиотеки по одинаковому адресу. Но адрес библиотеки в разных процессах может и будет отличаться.
    Поэтому что бы найти адрес функции относительно другого процесса, нужно:
    Использовать CreateToolhelp32Snapshot, Module32First, Module32Next для нахождения адреса библиотеки в чужом процессе.
    Затем загрузить туже библиотеку в свой процесс через LoadLibrary.
    А после найти адрес функции относительно своего процесса через GetProcAddress.
    Затем просто вычисляем: адрес_библиотеки_в_чужом процессе + адрес_функции_в_нашем_процессе - адрес_библиотеки_в_нашем_процессе.
     
    SAMP.ASI, BBooGG, Cucumber и 3 другим нравится это.
  8. SR_team

    SR_team BH Team
    BH Team

    Регистрация:
    26 окт 2013
    Сообщения:
    3.199
    Симпатии:
    3.203
    фича библиотек в том, что один и тот же код, один раз загруженный в память, используется всеми процессами. Различаются лишь данные
     
  9. Rinat_Namazov

    Rinat_Namazov ( ͡° ͜ʖ ͡°)
    Всефорумный модератор

    Регистрация:
    9 авг 2015
    Сообщения:
    1.134
    Симпатии:
    576
    Я читал что в Линуксе, библиотека загруженная в память, используется всеми процессами.
    Но в Виндоусе на каждый процесс свой экземпляр библиотеки.
     
  10. SR_team

    SR_team BH Team
    BH Team

    Регистрация:
    26 окт 2013
    Сообщения:
    3.199
    Симпатии:
    3.203
    1. нахуй они тогда нужны в винде?
    2. Почему тогда фокус с получением адреса библиотечной функции из своего процесса работает?
     
  11. Rinat_Namazov

    Rinat_Namazov ( ͡° ͜ʖ ͡°)
    Всефорумный модератор

    Регистрация:
    9 авг 2015
    Сообщения:
    1.134
    Симпатии:
    576
    Спроси разработчиков виндовс. Если бы так было, то тот же АнтиСтилер ставил свои хуки не только внутри гта, а на весь комп в целом. А изменение кода в какой-то функции могло бы уронить систему.
    Большинство библиотек (как правило системные) загружаются по одинаковому адресу, но виндовс не гарантирует этого.

    На скрине ниже, можно заметить что у samp.dll отличаются базовые адреса в разных процессах.
    upload_2019-5-1_22-57-9.png
     
  12. SR_team

    SR_team BH Team
    BH Team

    Регистрация:
    26 окт 2013
    Сообщения:
    3.199
    Симпатии:
    3.203
    да ты прав. Кстати, что касаемо адресов, в PE можно указать желаемое адрессное пространство для библиотеки, и если оно не занято, то библиотека всегда будет грузится в него. По дефолту вроде адрес 0x10000000
     
    Rinat_Namazov нравится это.
  13. Vadim.dll

    Vadim.dll Интересующийся

    Регистрация:
    4 июл 2015
    Сообщения:
    181
    Симпатии:
    58
    При попытке выполнения этого кода gta просто выключается, без ошибок, как будто завершается процесс