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

_Vine_

Активный
154
57
Проблемy с разным адресом процедуры из-за релокаций можно решить так
C++:
DWORD RVA = ((DWORD_PTR)GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateRemoteThread") - (DWORD_PTR)GetModuleHandleA("kernel32.dll"));
auto ObtainRemoteBase = [](HANDLE hProc, const char *dllName) -> DWORD_PTR
{
    HMODULE hMods[1024]; DWORD cbNeeded;
    EnumProcessModules(hProc, hMods, sizeof(hMods), &cbNeeded);
    for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
    {
        CHAR ModulePath[MAX_PATH + 1]; memset(ModulePath, 0, sizeof(ModulePath));
        K32GetModuleFileNameExA(hProc, hMods[i], ModulePath, MAX_PATH + 1);
        if (strstr(ModulePath, dllName) != nullptr)
        {
            return reinterpret_cast<DWORD_PTR>(hMods[i]);
        }
    }
};
auto FindProcessId = [](char* processName) -> DWORD
{
    char* p = strrchr(processName, '\\');
    if (p) processName = p + 1;
    PROCESSENTRY32 processInfo;
    processInfo.dwSize = sizeof(processInfo);
    HANDLE processesSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    if (processesSnapshot == INVALID_HANDLE_VALUE) return 0;
    Process32First(processesSnapshot, &processInfo);
    if (!strcmp(processName, processInfo.szExeFile))
    {
        CloseHandle(processesSnapshot);
        return processInfo.th32ProcessID;
    }
    while (Process32Next(processesSnapshot, &processInfo))
    {
        if (!strcmp(processName, processInfo.szExeFile))
        {
            CloseHandle(processesSnapshot);
            return processInfo.th32ProcessID;
        }
    }
    CloseHandle(processesSnapshot);
    return 0;
};
DWORD procID = GetProcID("имя_процесса.ехе");
if (procID == NULL) return;
HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, procID);
if (hProc != NULL)
{
    DWORD_PTR funcAddr = RVA + ObtainRemoteBase(hProc, "kernel32.dll");
    CloseHandle(hProc);
}
В funcAddr можно записать адрес WinApi функции текущего процесса, базовый адрес системных библиотек во процессах(одинаковой архитектуры) одинаковый.
Так же находят адрес LoadLibraryA инжекторы
 

ntharbinger

Потрачен
13
37
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
В funcAddr можно записать адрес WinApi функции текущего процесса, базовый адрес системных библиотек во процессах(одинаковой архитектуры) одинаковый.
Так же находят адрес LoadLibraryA инжекторы
а вот и нихуя, про ASLR слышал? Ну вот)
 

iqvw64e.sys

Новичок
0
1
Спроси разработчиков виндовс. Если бы так было, то тот же АнтиСтилер ставил свои хуки не только внутри гта, а на весь комп в целом. А изменение кода в какой-то функции могло бы уронить систему.

Большинство библиотек (как правило системные) загружаются по одинаковому адресу, но виндовс не гарантирует этого.

На скрине ниже, можно заметить что у samp.dll отличаются базовые адреса в разных процессах.
Посмотреть вложение 29158


hint: PspAllocateProcess
 
  • Нравится
Реакции: #Rin

ALF

Известный
Проверенный
320
539
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() {}

(DWORD_PTR)RemoteThread_end - (DWORD_PTR)RemoteThread

только вот ты забыл сказать, что при таком варианте должна быть отключена оптимизация, иначе мы можем получить неопределённое поведение
 

Vintik

Через тернии к звёздам
Проверенный
1,556
1,027
@CleanLegend помоги братец
C++:
#include <iostream>
#include <string>
#include <Windows.h>
#include <TlHelp32.h>

int processId;

int GetProcessIdByWindowName(std::string windowName)
{
    HWND window = FindWindowA(NULL, reinterpret_cast<LPCSTR>(windowName.c_str()));
    int pId = 0;
    GetWindowThreadProcessId(window, reinterpret_cast<LPDWORD>(&pId));
    return pId;
}

template <typename T>
T readMem(int address)
{
    T buf;
    HANDLE h = OpenProcess(PROCESS_VM_READ, false, processId);
    ReadProcessMemory(h, reinterpret_cast<LPCVOID>(address), &buf, sizeof(T), NULL);
    CloseHandle(h);
    return buf;
}

template <typename T>
void writeMem(int address, T buf)
{
    HANDLE h = OpenProcess(PROCESS_VM_WRITE, false, processId);
    int oldProtect = 0;
    VirtualProtectEx(h, reinterpret_cast<LPVOID>(address), sizeof(T), PAGE_READWRITE, reinterpret_cast<PDWORD>(&oldProtect));
    WriteProcessMemory(h, reinterpret_cast<LPVOID>(address), &buf, sizeof(T), NULL);
    VirtualProtectEx(h, reinterpret_cast<LPVOID>(address), sizeof(T), oldProtect, reinterpret_cast<PDWORD>(&oldProtect));
    CloseHandle(h);
}

struct AddMessageArg
{
    DWORD arg1;
    int arg2;
    const char *arg3;
    int arg4;
    int arg5;
    int arg6;
};

typedef void(__cdecl* AddMessage)(DWORD, int, const char*, int, int, int);

DWORD __stdcall RemoteThread(AddMessageArg* arg)
{
    AddMessage msg = (AddMessage)(reinterpret_cast<DWORD>(GetModuleHandleA("samp.dll") + 0x64010)); // передаем адрес
    msg(arg->arg1, arg->arg2, arg->arg3, arg->arg4, arg->arg5, arg->arg6); // вызываем
    return 0;
}

void __stdcall RemoteThread_end() {}

void AddSampMessage(std::string message, int color)
{
    AddMessageArg funcArg;
    funcArg.arg1 = readMem<DWORD>(reinterpret_cast<DWORD>(GetModuleHandleA("samp.dll") + 0x21A0E4));
    funcArg.arg2 = 4;
    funcArg.arg3 = message.c_str();
    funcArg.arg4 = 0;
    funcArg.arg5 = color;
    funcArg.arg6 = 0;
    HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
    LPVOID pRemoteThread = VirtualAllocEx(h, NULL, reinterpret_cast<DWORD_PTR>(RemoteThread_end) - reinterpret_cast<DWORD_PTR>(RemoteThread), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(h, pRemoteThread, reinterpret_cast<LPVOID>(RemoteThread), (reinterpret_cast<DWORD_PTR>(RemoteThread_end) - reinterpret_cast<DWORD_PTR>(RemoteThread)), 0);
    AddMessageArg* myArg = reinterpret_cast<AddMessageArg*>(VirtualAllocEx(h, NULL, sizeof(AddMessageArg), MEM_COMMIT, PAGE_READWRITE));
    writeMem<AddMessageArg>(reinterpret_cast<int>(myArg), funcArg);
    HANDLE h2 = CreateRemoteThread(h, 0, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, myArg, 0, 0);
    CloseHandle(h2);
    VirtualFreeEx(h, myArg, sizeof(AddMessageArg), MEM_RELEASE);
    CloseHandle(h);
}

int main()
{
    processId = GetProcessIdByWindowName("GTA:SA:MP");
    AddSampMessage("This is C++, wow!", 0);
}

Укажите на ошибки, почему сообщение в чат не отправляется, непон.

И да, на эту строку
C++:
VirtualFreeEx(h, myArg, sizeof(AddMessageArg), MEM_RELEASE);
Выдаёт пред, очково
Код:
Предупреждение    C6333    Недопустимый параметр:  передача MEM_RELEASE и ненулевого параметра dwSize в "VirtualFreeEx" не допускается.  Это приведет к сбою вызова.
 

CleanLegend

Известный
Автор темы
Всефорумный модератор
478
935
@CleanLegend помоги братец
C++:
DWORD __stdcall RemoteThread(AddMessageArg* arg)
{
    AddMessage msg = (AddMessage)(reinterpret_cast<DWORD>(GetModuleHandleA("samp.dll") + 0x64010)); // передаем адрес
    msg(arg->arg1, arg->arg2, arg->arg3, arg->arg4, arg->arg5, arg->arg6); // вызываем
    return 0;
}
GetModuleHandleA не может быть вызвана таким путем, нужно получить адрес на него через GetProcAdress и позже уже передать в структуру.
Тоже самое и с текстом: "samp.dll", в памяти игры у тебя его нет, поэтому тоже ошибка, передавай в структуру.


C++:
 HANDLE h2 = CreateRemoteThread(h, 0, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, myArg, 0, 0);
 CloseHandle(h2);
 VirtualFreeEx(h, myArg, sizeof(AddMessageArg), MEM_RELEASE);

Ошибка с освобождением памяти. Нужно ждать пока поток закончится, а только после освобождать память:

C++:
WaitForSingleObject(h2, INFINITE); // после CreateRemoteThread


C++:
VirtualFreeEx(h, myArg, sizeof(AddMessageArg), MEM_RELEASE);
Выдаёт пред, очково
Код:
Предупреждение    C6333    Недопустимый параметр:  передача MEM_RELEASE и ненулевого параметра dwSize в "VirtualFreeEx" не допускается.  Это приведет к сбою вызова.
Вместо размера нужно указывать 0, компилятор тебе об это написал.
 
  • Нравится
Реакции: Vintik

Vintik

Через тернии к звёздам
Проверенный
1,556
1,027
@CleanLegend опять какая-то ерунда.
1594114830318.png

Что уж теперь не так то? Я всё пофиксил из того, что ты сказал.
C++:
#include <iostream>
#include <string>
#include <Windows.h>
#include <TlHelp32.h>

int processId;
DWORD sampdll;

int GetProcessIdByWindowName(std::string windowName)
{
    HWND window = FindWindowA(NULL, reinterpret_cast<LPCSTR>(windowName.c_str()));
    int pId = 0;
    GetWindowThreadProcessId(window, reinterpret_cast<LPDWORD>(&pId));
    return pId;
}

DWORD GetModuleBaseAddress(DWORD pid, const char* name)
{
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
    MODULEENTRY32 mEntry;
    mEntry.dwSize = sizeof(MODULEENTRY32);
    do
    {
        if (!strcmp((const char*)mEntry.szModule, name))
        {
            CloseHandle(snapshot);
            return (DWORD)mEntry.modBaseAddr;
        }
    } while (Module32Next(snapshot, &mEntry));
}

template <typename T>
T readMem(int address)
{
    T buf;
    HANDLE h = OpenProcess(PROCESS_VM_READ, false, processId);
    ReadProcessMemory(h, reinterpret_cast<LPCVOID>(address), &buf, sizeof(T), NULL);
    CloseHandle(h);
    return buf;
}

template <typename T>
void writeMem(int address, T buf)
{
    HANDLE h = OpenProcess(PROCESS_VM_WRITE, false, processId);
    int oldProtect = 0;
    VirtualProtectEx(h, reinterpret_cast<LPVOID>(address), sizeof(T), PAGE_READWRITE, reinterpret_cast<PDWORD>(&oldProtect));
    WriteProcessMemory(h, reinterpret_cast<LPVOID>(address), &buf, sizeof(T), NULL);
    VirtualProtectEx(h, reinterpret_cast<LPVOID>(address), sizeof(T), oldProtect, reinterpret_cast<PDWORD>(&oldProtect));
    CloseHandle(h);
}

struct AddMessageArg
{
    DWORD arg1;
    int arg2;
    const char *arg3;
    int arg4;
    int arg5;
    int arg6;
    DWORD addr;
};

typedef void(__cdecl* AddMessage)(DWORD, int, const char*, int, int, int);

DWORD __stdcall RemoteThread(AddMessageArg* arg)
{
    AddMessage msg = (AddMessage)arg->addr;
    msg(arg->arg1, arg->arg2, arg->arg3, arg->arg4, arg->arg5, arg->arg6);
    return 0;
}

void __stdcall RemoteThread_end() {}

void AddSampMessage(std::string message, int color)
{
    AddMessageArg funcArg;
    funcArg.arg1 = readMem<DWORD>(sampdll + 0x21A0E4);
    funcArg.arg2 = 4;
    funcArg.arg3 = message.c_str();
    funcArg.arg4 = 0;
    funcArg.arg5 = color;
    funcArg.arg6 = 0;
    funcArg.addr = sampdll + 0x64010;
    HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
    LPVOID pRemoteThread = VirtualAllocEx(h, NULL, reinterpret_cast<DWORD_PTR>(RemoteThread_end) - reinterpret_cast<DWORD_PTR>(RemoteThread), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    WriteProcessMemory(h, pRemoteThread, reinterpret_cast<LPVOID>(RemoteThread), (reinterpret_cast<DWORD_PTR>(RemoteThread_end) - reinterpret_cast<DWORD_PTR>(RemoteThread)), 0);
    AddMessageArg* myArg = reinterpret_cast<AddMessageArg*>(VirtualAllocEx(h, NULL, sizeof(AddMessageArg), MEM_COMMIT, PAGE_READWRITE));
    writeMem<AddMessageArg>(reinterpret_cast<int>(myArg), funcArg);
    HANDLE h2 = CreateRemoteThread(h, 0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(pRemoteThread), myArg, 0, 0);
    WaitForSingleObject(h2, INFINITE);
    CloseHandle(h2);
    VirtualFreeEx(h, myArg, 0, MEM_RELEASE);
    CloseHandle(h);
}

int main()
{
    processId = GetProcessIdByWindowName("GTA:SA:MP");
    sampdll = GetModuleBaseAddress(processId, "samp.dll");
    AddSampMessage("This is C++, wow!", 0);
}
 
Последнее редактирование:

CleanLegend

Известный
Автор темы
Всефорумный модератор
478
935
@CleanLegend опять какая-то ерунда.

C++:
#include <iostream>


struct AddMessageArg
{
    DWORD arg1;
    int arg2;
    const char *arg3;
    int arg4;
    int arg5;
    int arg6;
    DWORD addr;
};
скорее всего из за того, что ты передаешь в указатель arg3 строку из локального процесса, но в самом процессе gta_sa по этому указатлю такого нет, поэтому лучше заполнить буфер: char arg3[256]. в гайде у меня пример на этом построен
 
  • Нравится
Реакции: Vintik

Vintik

Через тернии к звёздам
Проверенный
1,556
1,027
скорее всего из за того, что ты передаешь в указатель arg3 строку из локального процесса, но в самом процессе gta_sa по этому указатлю такого нет, поэтому лучше заполнить буфер: char arg3[256]. в гайде у меня пример на этом построен
Хорошо, спасибо, проверю. И еще скажи, пожалуйста, а как узнавать количество аргументов функций? Чтобы вызвать функцию, надо знать все её аргументы (и, соответственно, их количество).
Второй второй. Я сделал на DLL коллбэк (обычный 5-байтовый jmp в начале функции) на исходящее от тебя в чат сообщение и хотел бы понять, как игнорировать (не пропускать сообщение) в некоторых случаях (например, если текст содержит мат) – пытался сделать jmp в конец функции, но краш.
 

CleanLegend

Известный
Автор темы
Всефорумный модератор
478
935
Хорошо, спасибо, проверю. И еще скажи, пожалуйста, а как узнавать количество аргументов функций? Чтобы вызвать функцию, надо знать все её аргументы (и, соответственно, их количество).
Второй второй. Я сделал на DLL коллбэк (обычный 5-байтовый jmp в начале функции) на исходящее от тебя в чат сообщение и хотел бы понять, как игнорировать (не пропускать сообщение) в некоторых случаях (например, если текст содержит мат) – пытался сделать jmp в конец функции, но краш.
самый простой вариант через IDA.

что бы игнорировать функцию просто поставь ret(если функция не возвращает никаких аргументов)
 

Vintik

Через тернии к звёздам
Проверенный
1,556
1,027
самый простой вариант через IDA.

что бы игнорировать функцию просто поставь ret(если функция не возвращает никаких аргументов)
1) IDA в CE норм? как конкретно?
2) а если возвращает чтот?
 

CleanLegend

Известный
Автор темы
Всефорумный модератор
478
935
1) IDA в CE норм? как конкретно?
2) а если возвращает чтот?
1. у IDA есть декомпилятор, она покажет псевдокод
2. анализируй функцию, если возврат идет в виде true/false , то будет примерно так:

C++:
true:

mov eax, 0x1
ret

false(обычно используется второй вариант):

mov eax, 0x0
ret


либо

xor eax,eax
ret
 
  • Нравится
Реакции: Vintik и AnWu

p1cador

cerf
Проверенный
221
359
Также следует добавить, что взвращаемое функцией значение можно получить, разместив следуюищий код между созданием удаленного потока и закрытием хендла процесса:
C:
unsigned __int32 retValue = 0;
while(WaitForSingleObject(hThread, 0) != 0)
{ }
GetExitCodeThread(hThread, &retValue);
 
Последнее редактирование: