unload internal cheat

rhjossss

Новичок
Автор темы
3
0
Всех приветствую, столкнулся с проблемой , при добавлении в чит функционал анлоада (всего чита), получаю краш игры, подскажите пожалуйста какую последовательность нужно соблюдать при анхуке функций и после удаления их самих.
Сейчас логика такая:
Этап 1 — Cheat::Unload() (синхронный):
main.cpp:
void Cheat::Unload()
{
    // 1. Скрываем курсор SAMP если меню открыто
    if (pMenu->bOpen)
        pSAMP->toggleSAMPCursor(0);

    // 2. Удаляем хуки и основные компоненты
    delete pHooks;      // Снимаем хуки с игры
    delete pD3DHook;    // Снимаем хук DirectX
    delete pKeyHook;    // Снимаем хук клавиатуры
    delete pRakClient;  // Отключаем сетевой клиент
    delete pAimbot;     // Удаляем аимбот
    delete pVisuals;    // Удаляем визуалы

    // 3. Запускаем отдельный поток для финальной выгрузки
    CreateThread(NULL, NULL, LPTHREAD_START_ROUTINE(UnloadThread), g_hModule, NULL, NULL);
}

Этап 2 — UnloadThread() (асинхронный):
main.cpp:
DWORD WINAPI UnloadThread(HMODULE hModule)

{

    Sleep(100); // Ждём 100мс чтобы основной поток завершил работу

  

    delete pMenu; // Удаляем меню

    delete pTextures; // Удаляем текстуры

    delete pSAMP; // Удаляем SAMP интерфейс



    FreeLibraryAndExitThread(hModule, 0); // Выгружаем DLL из памяти

}


Почему два этапа?
А потому что:

Нельзя вызвать FreeLibrary из того же потока, который выполняет код DLL — это приведёт к крашу
FreeLibraryAndExitThread — специальная WinAPI функция, которая атомарно выгружает DLL и завершает поток
Sleep(100) даёт время основному потоку завершить рендеринг текущего кадра
Если ошибся то поправьте

Связь с g_hModule
В main.cpp при загрузке DLL сохраняется её handle:
main.cpp:
HMODULE g_hModule = NULL;

BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReasonForCall, LPVOID lpReserved)
{
    case DLL_PROCESS_ATTACH:
        g_hModule = hModule; // Сохраняем для последующей выгрузки
        ...
}


Этот g_hModule потом передаётся в UnloadThread для вызова FreeLibraryAndExitThread.
 

opmbaby

Новичок
4
3
вот пример как делал я у меня все работает

unload.cpp:
#include "unload.h"
#include <Windows.h>
#include "skStr.h"

extern "C" IMAGE_DOS_HEADER __ImageBase;

#include "menu.h"
#include "wallhack.h"
#include "player.h"
#include "silent.h"
#include "misc.h"
#include "imgui/imgui.h"
#include "imgui/imgui_impl_dx9.h"
#include "imgui/imgui_impl_win32.h"

extern volatile bool gShuttingDown;

namespace unload {
    static void ClearImGui() {
        if (ImGui::GetCurrentContext()) {
            ImGui_ImplDX9_Shutdown();
            ImGui_ImplWin32_Shutdown();
            ImGui::DestroyContext();
        }
    }

    static DWORD WINAPI UnloadWorker(LPVOID param) {
        gShuttingDown = true;
        Sleep(150);

        __try {
            wallhack::gESPEnabled = false;
            wallhack::gLinesEnabled = false;
            wallhack::gSkeletonEnabled = false;
            wallhack::gDistanceEnabled = false;
            wallhack::gHealthBarEnabled = false;
            wallhack::gArmorBarEnabled = false;
            wallhack::gNameEnabled = false;
            wallhack::gChamsEnabled = false;
            wallhack::gESPCarEnabled = false;
            wallhack::gPlatformDetectorEnabled = false;
        }
        __except (1) {}

        HMODULE hMod = nullptr;
        if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&__ImageBase, &hMod) && hMod) {
            FreeLibraryAndExitThread(hMod, 0);
        }
        return 0;
    }

    void Unload(bool removeFiles) {
        CreateThread(nullptr, 0, UnloadWorker, nullptr, 0, nullptr);
    }
}
 
  • Нравится
Реакции: rhjossss

g305noobo

Известный
Модератор
354
635
вот пример как делал я у меня все работает

unload.cpp:
#include "unload.h"
#include <Windows.h>
#include "skStr.h"

extern "C" IMAGE_DOS_HEADER __ImageBase;

#include "menu.h"
#include "wallhack.h"
#include "player.h"
#include "silent.h"
#include "misc.h"
#include "imgui/imgui.h"
#include "imgui/imgui_impl_dx9.h"
#include "imgui/imgui_impl_win32.h"

extern volatile bool gShuttingDown;

namespace unload {
    static void ClearImGui() {
        if (ImGui::GetCurrentContext()) {
            ImGui_ImplDX9_Shutdown();
            ImGui_ImplWin32_Shutdown();
            ImGui::DestroyContext();
        }
    }

    static DWORD WINAPI UnloadWorker(LPVOID param) {
        gShuttingDown = true;
        Sleep(150);

        __try {
            wallhack::gESPEnabled = false;
            wallhack::gLinesEnabled = false;
            wallhack::gSkeletonEnabled = false;
            wallhack::gDistanceEnabled = false;
            wallhack::gHealthBarEnabled = false;
            wallhack::gArmorBarEnabled = false;
            wallhack::gNameEnabled = false;
            wallhack::gChamsEnabled = false;
            wallhack::gESPCarEnabled = false;
            wallhack::gPlatformDetectorEnabled = false;
        }
        __except (1) {}

        HMODULE hMod = nullptr;
        if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)&__ImageBase, &hMod) && hMod) {
            FreeLibraryAndExitThread(hMod, 0);
        }
        return 0;
    }

    void Unload(bool removeFiles) {
        CreateThread(nullptr, 0, UnloadWorker, nullptr, 0, nullptr);
    }
}
Для чего булы обернул в SEH?
 

opmbaby

Новичок
4
3
Для чего булы обернул в SEH?
это чтобы игра не крашнулась при выгрузке, если при отключении функций возникнет ошибка памяти или конфликт потоков, seh её просто проигнорит и даст дллке спокойно выгрузиться, вместо того чтобы убить процесс игры
 

g305noobo

Известный
Модератор
354
635
это чтобы игра не крашнулась при выгрузке, если при отключении функций возникнет ошибка памяти или конфликт потоков, seh её просто проигнорит и даст дллке спокойно выгрузиться, вместо того чтобы убить процесс игры
Звучит как лютый костыль
 

opmbaby

Новичок
4
3
Звучит как лютый костыль
ну так и есть, но городить фулл синхронизацию потоков ради одного анлода — оверкилл. проще заглушить эксепшн, чем дебажить гонку в чужом процессе, главное что работает стабильно