diff --git a/cheat-library/src/user/cheat/debugger.cpp b/cheat-library/src/user/cheat/debugger.cpp index be93ca5..25e098b 100644 --- a/cheat-library/src/user/cheat/debugger.cpp +++ b/cheat-library/src/user/cheat/debugger.cpp @@ -1,15 +1,153 @@ #include +enum THREADINFOCLASS { ThreadHideFromDebugger = 0x11 }; + +typedef NTSTATUS(WINAPI* NtQueryInformationThread_t)(HANDLE, THREADINFOCLASS, PVOID, ULONG, LPVOID); +typedef NTSTATUS(WINAPI* NtSetInformationThread_t)(HANDLE, THREADINFOCLASS, PVOID, ULONG); +typedef void(WINAPI* DbgUiRemoteBreakin_t)(); + +NtQueryInformationThread_t fnNtQueryInformationThread = nullptr; +NtSetInformationThread_t fnNtSetInformationThread = nullptr; +DbgUiRemoteBreakin_t fnDbgUiRemoteBreakin = nullptr; + +static void RunVEH(); +static void FindAPI(); +static bool Patch_NtSetInformationThread(); +static bool Patch_DbgUiRemoteBreakin(); + +static long WINAPI DebugHandler(PEXCEPTION_POINTERS exception); +static void WINAPI DbgUiRemoteBreakin_Hook(); +static NTSTATUS WINAPI NtSetInformationThread_Hook(HANDLE handle, THREADINFOCLASS infoClass, PVOID pValue, ULONG pSize); + void DebuggerBypassPre() { -#ifdef _DEBUG - LOG_INFO("You have no implementation for anti-debugger bypass.\n\tSo if you try to attach VS debugger to process - game will crash."); -#endif - - // Sry, implementation is private for now + if (!Patch_NtSetInformationThread()) + LOG_ERROR("Failed to patch NtSetInformationThread, so main thread will be hidden from debugger. ^("); } void DebuggerBypassPost() { - // Sry, implementation is privite for now + if (!Patch_DbgUiRemoteBreakin()) + LOG_ERROR("Failed to patch DbgUiRemoteBreakin, so when debugger will try to attach, game crash. ^("); + + RunVEH(); +} + +static void RunVEH() +{ + AddVectoredExceptionHandler(1, DebugHandler); +} + +static bool Patch_NtSetInformationThread() +{ + if (fnNtSetInformationThread == nullptr && (FindAPI(), fnNtSetInformationThread == nullptr)) + return false; + + HookManager::install(fnNtSetInformationThread, NtSetInformationThread_Hook); + LOG_DEBUG("NtSetInformationThread api hooked. Origin at 0x%p", HookManager::getOrigin(NtSetInformationThread_Hook)); + return true; +} + +static bool Patch_DbgUiRemoteBreakin() +{ + if (fnDbgUiRemoteBreakin == nullptr && (FindAPI(), fnDbgUiRemoteBreakin == nullptr)) + return false; + + HookManager::install(fnDbgUiRemoteBreakin, DbgUiRemoteBreakin_Hook); + LOG_DEBUG("DbgUiRemoteBreakin api hooked. Origin at 0x%p", HookManager::getOrigin(DbgUiRemoteBreakin_Hook)); + return true; +} + +static void FindAPI() +{ + HMODULE hNTDLL = GetModuleHandle("ntdll.dll"); + if (hNTDLL == NULL) + { + LOG_LAST_ERROR("Failed to get the 'ntdll.dll' handle"); + return; + } + + if (fnDbgUiRemoteBreakin == nullptr) + { + fnDbgUiRemoteBreakin = reinterpret_cast(GetProcAddress(hNTDLL, "DbgUiRemoteBreakin")); + if (fnDbgUiRemoteBreakin == nullptr) + LOG_LAST_ERROR("GetProcAddress(ntdll::DbgUiRemoteBreakin) failed"); + } + + if (fnNtQueryInformationThread == nullptr) + { + fnNtQueryInformationThread = reinterpret_cast(GetProcAddress(hNTDLL, "NtQueryInformationThread")); + if (fnNtQueryInformationThread == nullptr) + LOG_LAST_ERROR("GetProcAddress(ntdll::NtQueryInformationThread) failed"); + } + + if (fnNtSetInformationThread == nullptr) + { + fnNtSetInformationThread = reinterpret_cast(GetProcAddress(hNTDLL, "NtSetInformationThread")); + if (fnNtSetInformationThread == nullptr) + LOG_LAST_ERROR("GetProcAddress(ntdll::NtSetInformationThread) failed"); + } +} + +// Modified version of https://guidedhacking.com/threads/how-to-find-hidden-threads-threadhidefromdebugger-antidebug-trick.14281/ +static bool IsThreadHidden(DWORD threadID) +{ + if (fnNtQueryInformationThread == nullptr && + (FindAPI(), fnNtQueryInformationThread == nullptr)) // Yeah, seems like a shit ^) + return false; + + HANDLE hThread = OpenThread( + THREAD_QUERY_INFORMATION, + false, + threadID); + + if (hThread == NULL) { + std::cout << " - Error :" << util::GetLastErrorAsString(); + return false; + } + + unsigned char lHideThread = 0; + ULONG lRet = 0; + NTSTATUS errorCode = fnNtQueryInformationThread(hThread, (THREADINFOCLASS)0x11, &lHideThread, sizeof(lHideThread), &lRet); + WaitForSingleObject(hThread, INFINITE); + return static_cast(lHideThread); +} + +static long WINAPI DebugHandler(PEXCEPTION_POINTERS exception) { + PEXCEPTION_RECORD record = exception->ExceptionRecord; + PCONTEXT context = exception->ContextRecord; + + if (record->ExceptionCode == EXCEPTION_SINGLE_STEP) { + SuspendThread(GetCurrentThread()); + return EXCEPTION_CONTINUE_EXECUTION; + } + else if (record->ExceptionCode == EXCEPTION_BREAKPOINT) + { + CONTEXT ctx = {}; + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + + DWORD threadID = GetThreadId(GetCurrentThread()); + LOG_WARNING("Breakpoint exception! Thread: %d; Hidden: %s", threadID, IsThreadHidden(threadID) ? "true" : "false"); + return EXCEPTION_CONTINUE_EXECUTION; + } + else if (context->Rip == 0x8887777) + { + SuspendThread(GetCurrentThread()); + return EXCEPTION_CONTINUE_EXECUTION; + } + return EXCEPTION_CONTINUE_SEARCH; +} + +static void WINAPI DbgUiRemoteBreakin_Hook() +{ + return; +} + +static NTSTATUS WINAPI NtSetInformationThread_Hook(HANDLE handle, THREADINFOCLASS infoClass, PVOID pValue, ULONG pSize) +{ + if (infoClass == ThreadHideFromDebugger) + { + return 1; + } + return CALL_ORIGIN(NtSetInformationThread_Hook, handle, infoClass, pValue, pSize); } \ No newline at end of file diff --git a/cheat-library/src/user/cheat/imap/InteractiveMap.cpp b/cheat-library/src/user/cheat/imap/InteractiveMap.cpp index cac502d..ec255b4 100644 --- a/cheat-library/src/user/cheat/imap/InteractiveMap.cpp +++ b/cheat-library/src/user/cheat/imap/InteractiveMap.cpp @@ -1379,12 +1379,6 @@ namespace cheat::feature void InteractiveMap::DrawExternal() { - // If any InputText is focused, the game will not respond any keyboard input. - auto ctx = ImGui::GetCurrentContext(); - if (ctx->IO.WantCaptureKeyboard && !renderer::IsInputLocked()) - renderer::SetInputLock(this, true); - else if (!ctx->IO.WantCaptureKeyboard && renderer::IsInputLocked()) - renderer::SetInputLock(this, false); if (IsMiniMapActive() && f_Enabled) DrawMinimapPoints(); @@ -1393,13 +1387,25 @@ namespace cheat::feature bool mapActive = IsMapActive(); if (mapActive != _lastMapActive) + { MapToggled(mapActive); + + if (!mapActive) + renderer::SetInputLock(this, false); + } _lastMapActive = mapActive; if (!mapActive) return; + // If any InputText is focused, the game will not respond any keyboard input. + auto ctx = ImGui::GetCurrentContext(); + if (ctx->IO.WantCaptureKeyboard && !renderer::IsInputLocked()) + renderer::SetInputLock(this, true); + else if (!ctx->IO.WantCaptureKeyboard && renderer::IsInputLocked()) + renderer::SetInputLock(this, false); + auto mapManager = GET_SINGLETON(MoleMole_MapManager); if (mapManager == nullptr) return; diff --git a/cheat-library/src/user/main.cpp b/cheat-library/src/user/main.cpp index 7666741..755daba 100644 --- a/cheat-library/src/user/main.cpp +++ b/cheat-library/src/user/main.cpp @@ -43,7 +43,7 @@ void Run(HMODULE* phModule) #ifdef _DEBUG LOG_DEBUG("Waiting 10sec for loading game library."); - Sleep(10000); + Sleep(15000); #else LOG_DEBUG("Waiting 15sec for game initialize."); Sleep(15000);