 |
|

28.12.2025, 06:52
|
|
Новичок
Регистрация: 28.07.2024
Сообщений: 3
С нами:
946126
Репутация:
1
|
|
Всех приветствую, столкнулся с проблемой , при добавлении в чит функционал анлоада (всего чита), получаю краш игры, подскажите пожалуйста какую последовательность нужно соблюдать при анхуке функций и после удаления их самих.
Сейчас логика такая:
Этап 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.
|
|
|

28.12.2025, 12:34
|
|
Постоянный
Регистрация: 24.09.2020
Сообщений: 364
С нами:
2966237
Репутация:
148
|
|
|
|
|

28.12.2025, 12:37
|
|
Новичок
Регистрация: 25.12.2025
Сообщений: 8
С нами:
204694
Репутация:
3
|
|
вот пример как делал я у меня все работает
unload.cpp:
Код:
#include "unload.h"
#include
#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
)
;
}
}
|
|
|

28.12.2025, 12:43
|
|
Постоянный
Регистрация: 24.09.2020
Сообщений: 364
С нами:
2966237
Репутация:
148
|
|
Сообщение от opmbaby
вот пример как делал я у меня все работает
unload.cpp:
Код:
#include "unload.h"
#include
#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?
|
|
|

28.12.2025, 12:48
|
|
Новичок
Регистрация: 25.12.2025
Сообщений: 8
С нами:
204694
Репутация:
3
|
|
Сообщение от g305noobo
Для чего булы обернул в SEH?
это чтобы игра не крашнулась при выгрузке, если при отключении функций возникнет ошибка памяти или конфликт потоков, seh её просто проигнорит и даст дллке спокойно выгрузиться, вместо того чтобы убить процесс игры
|
|
|

28.12.2025, 13:47
|
|
Постоянный
Регистрация: 24.09.2020
Сообщений: 364
С нами:
2966237
Репутация:
148
|
|
Сообщение от opmbaby
это чтобы игра не крашнулась при выгрузке, если при отключении функций возникнет ошибка памяти или конфликт потоков, seh её просто проигнорит и даст дллке спокойно выгрузиться, вместо того чтобы убить процесс игры
Звучит как лютый костыль
|
|
|

28.12.2025, 15:13
|
|
Новичок
Регистрация: 25.12.2025
Сообщений: 8
С нами:
204694
Репутация:
3
|
|
Сообщение от g305noobo
Звучит как лютый костыль
ну так и есть, но городить фулл синхронизацию потоков ради одного анлода — оверкилл. проще заглушить эксепшн, чем дебажить гонку в чужом процессе, главное что работает стабильно
|
|
|

29.12.2025, 22:51
|
|
Постоянный
Регистрация: 03.05.2020
Сообщений: 385
С нами:
3174020
Репутация:
213
|
|
Сообщение от opmbaby
дебажить гонку в чужом процессе
на твоем куске единственные переменные которые ты изменяешь это свои - поэтому рейс ты сам и создал лол. хуевый аргумент какой-то
|
|
|

29.12.2025, 23:28
|
|
Новичок
Регистрация: 25.12.2025
Сообщений: 8
С нами:
204694
Репутация:
3
|
|
Сообщение от sc6ut
на твоем куске единственные переменные которые ты изменяешь это свои - поэтому рейс ты сам и создал лол. хуевый аргумент какой-то
дело не в записи, а в чтении - эти переменные чекает рендер-поток игры каждый кадр, если в момент анлода игра находится внутри цикла отрисовки и пытается обратиться к памяти/структурам, которые я уже освобождаю — будет краш, я не могу повесить мьютекс на рендер самой игры, поэтому seh страхует от таймингов, когда дллка уже выходит, а игра еще пытается что-то отрисовать
|
|
|

02.01.2026, 22:11
|
|
Флудер
Регистрация: 19.06.2022
Сообщений: 2,997
С нами:
2055431
Репутация:
3
|
|
Сообщение от opmbaby
дело не в записи, а в чтении - эти переменные чекает рендер-поток игры каждый кадр, если в момент анлода игра находится внутри цикла отрисовки и пытается обратиться к памяти/структурам, которые я уже освобождаю — будет краш, я не могу повесить мьютекс на рендер самой игры, поэтому seh страхует от таймингов, когда дллка уже выходит, а игра еще пытается что-то отрисовать
можно же по идее, если нет нужды, изменять переменные в методе Unload, либо заюзать std::atomic для какой-то переменной, которая будет проверяться в потоке игры и изменяться в твоем потоке
|
|
|
|
 |
|
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|