From 4a2dbcad27411b868a53b4fc79600bb3332a49fd Mon Sep 17 00:00:00 2001 From: NukedBart Date: Thu, 11 Dec 2025 23:35:30 +0800 Subject: [PATCH] BEService spoofer refactoring. --- service/core/WinApi.h | 27 ++++++++ service/includes.h | 8 +++ service/service.cpp | 115 +-------------------------------- service/service.vcxproj | 2 +- service/services/BEService.h | 74 +++++++++++++++++++++ service/services/GameMonitor.h | 44 +++++++++++++ 6 files changed, 156 insertions(+), 114 deletions(-) create mode 100644 service/core/WinApi.h create mode 100644 service/includes.h create mode 100644 service/services/BEService.h create mode 100644 service/services/GameMonitor.h diff --git a/service/core/WinApi.h b/service/core/WinApi.h new file mode 100644 index 0000000..da9a1e3 --- /dev/null +++ b/service/core/WinApi.h @@ -0,0 +1,27 @@ +// core/WinApi.h +#pragma once +#include +#include +#include +#include // for std::forward + +namespace WinApi +{ + struct HandleDeleter + { + void operator()(HANDLE h) const noexcept + { + if (h && h != INVALID_HANDLE_VALUE) CloseHandle(h); + } + }; + + using UniqueHandle = std::unique_ptr::type, HandleDeleter>; + + template + struct ScopeExit + { + F func; + explicit ScopeExit(F&& f) noexcept : func(std::forward(f)) {} + ~ScopeExit() noexcept { func(); } + }; +} \ No newline at end of file diff --git a/service/includes.h b/service/includes.h new file mode 100644 index 0000000..f8df75c --- /dev/null +++ b/service/includes.h @@ -0,0 +1,8 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX + +#include "core/WinApi.h" +#include "services/GameMonitor.h" +#include "services/BEService.h" \ No newline at end of file diff --git a/service/service.cpp b/service/service.cpp index 42ae5ac..3191fbd 100644 --- a/service/service.cpp +++ b/service/service.cpp @@ -1,118 +1,7 @@ -#include -#include - -SERVICE_STATUS ServiceStatus = { 0 }; -SERVICE_STATUS_HANDLE hStatus = NULL; -bool g_shouldExit = false; - -// Check if EscapeFromTarkov.exe is running -bool IsGameRunning() -{ - HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (hSnapshot == INVALID_HANDLE_VALUE) - return false; - - PROCESSENTRY32W pe32; - pe32.dwSize = sizeof(PROCESSENTRY32W); - bool found = false; - - if (Process32FirstW(hSnapshot, &pe32)) - { - do - { - if (_wcsicmp(pe32.szExeFile, L"EscapeFromTarkov.exe") == 0) - { - found = true; - break; - } - } while (Process32NextW(hSnapshot, &pe32)); - } - - CloseHandle(hSnapshot); - return found; -} - -// Service control handler - handles stop requests -VOID WINAPI ServiceCtrlHandler(DWORD dwControl) -{ - if (dwControl == SERVICE_CONTROL_STOP || dwControl == SERVICE_CONTROL_SHUTDOWN) - { - g_shouldExit = true; - ServiceStatus.dwCurrentState = SERVICE_STOPPED; - ServiceStatus.dwWin32ExitCode = 0; - SetServiceStatus(hStatus, &ServiceStatus); - } -} - -// Main service function -VOID WINAPI ServiceMain(DWORD argc, LPTSTR* argv) -{ - // Set up service status - ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - ServiceStatus.dwCurrentState = SERVICE_RUNNING; - ServiceStatus.dwWin32ExitCode = 0; - ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; - - // Register control handler - hStatus = RegisterServiceCtrlHandlerW(L"BEService", ServiceCtrlHandler); - if (hStatus == NULL) - return; - - // Tell Windows we're running - SetServiceStatus(hStatus, &ServiceStatus); - - // Phase 1: Wait for game to start (30 minute timeout) - bool gameDetected = false; - DWORD waitTime = 0; - const DWORD maxWaitTime = 30 * 60 * 1000; // 30 minutes in milliseconds - - while (!g_shouldExit && !gameDetected && waitTime < maxWaitTime) - { - if (IsGameRunning()) - { - gameDetected = true; - break; - } - Sleep(1000); - waitTime += 1000; - } - - // If game never started or we were told to stop, exit - if (!gameDetected || g_shouldExit) - { - ServiceStatus.dwCurrentState = SERVICE_STOPPED; - SetServiceStatus(hStatus, &ServiceStatus); - return; - } - - // Phase 2: Keep running while game is active - while (!g_shouldExit && IsGameRunning()) - { - Sleep(1000); - } - - // Phase 3: Game closed or service stopped - // Wait 5 seconds before exiting (gives bypass time to clean up) - if (!g_shouldExit) - { - Sleep(5000); - } - - // Mark service as stopped - ServiceStatus.dwCurrentState = SERVICE_STOPPED; - ServiceStatus.dwWin32ExitCode = 0; - SetServiceStatus(hStatus, &ServiceStatus); -} +#include "includes.h" // Entry point int wmain() { - SERVICE_TABLE_ENTRYW ServiceTable[] = { - { (LPWSTR)L"BEService", (LPSERVICE_MAIN_FUNCTIONW)ServiceMain }, - { NULL, NULL } - }; - - // This blocks until service is stopped - StartServiceCtrlDispatcherW(ServiceTable); - return 0; + return BEService::Run() ? 0 : 1; } \ No newline at end of file diff --git a/service/service.vcxproj b/service/service.vcxproj index 952a16f..8b63971 100644 --- a/service/service.vcxproj +++ b/service/service.vcxproj @@ -105,7 +105,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - stdcpp20 + stdcpplatest stdclatest diff --git a/service/services/BEService.h b/service/services/BEService.h new file mode 100644 index 0000000..9801966 --- /dev/null +++ b/service/services/BEService.h @@ -0,0 +1,74 @@ +// service/BEService.h +#pragma once +#include "core/WinApi.h" +#include "services/GameMonitor.h" +#include + +namespace BEService +{ + inline struct State + { + bool shouldStop = false; + SERVICE_STATUS_HANDLE statusHandle = nullptr; + + void ReportRunning() const noexcept + { + SERVICE_STATUS STATUS + { + SERVICE_WIN32_OWN_PROCESS, + SERVICE_RUNNING, + SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN, + NO_ERROR, 0, 0, 0 + }; + SetServiceStatus(statusHandle, &STATUS); + } + + void ReportStopped() const noexcept + { + SERVICE_STATUS STATUS + { + SERVICE_WIN32_OWN_PROCESS, + SERVICE_STOPPED, + 0, NO_ERROR, 0, 0, 0 + }; + SetServiceStatus(statusHandle, &STATUS); + } + } g_state; + + VOID WINAPI CtrlHandler(DWORD control) noexcept + { + if (control == SERVICE_CONTROL_STOP || control == SERVICE_CONTROL_SHUTDOWN) + g_state.shouldStop = true; + } + + VOID WINAPI ServiceMain(DWORD, LPWSTR*) noexcept + { + g_state.statusHandle = RegisterServiceCtrlHandlerW(L"BEService", CtrlHandler); + if (!g_state.statusHandle) + return; + + g_state.ReportRunning(); + + if (!GameMonitor::WaitForGame() || g_state.shouldStop) + goto cleanup; + + while (!g_state.shouldStop && GameMonitor::IsGameRunning()) + Sleep(1000); + + if (!g_state.shouldStop) + Sleep(5000); + + cleanup: + g_state.ReportStopped(); + } + + [[nodiscard]] inline bool Run() noexcept + { + SERVICE_TABLE_ENTRYW table[] = { + { const_cast(L"BEService"), ServiceMain }, + { nullptr, nullptr } + }; + + return StartServiceCtrlDispatcherW(table) != FALSE; + } +} \ No newline at end of file diff --git a/service/services/GameMonitor.h b/service/services/GameMonitor.h new file mode 100644 index 0000000..c6fe045 --- /dev/null +++ b/service/services/GameMonitor.h @@ -0,0 +1,44 @@ +// services/GameMonitor.h +#pragma once +#include "core/WinApi.h" +#include +#include + +namespace GameMonitor +{ + [[nodiscard]] inline bool IsGameRunning() noexcept + { + WinApi::UniqueHandle snapshot{ CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) }; + if (!snapshot || snapshot.get() == INVALID_HANDLE_VALUE) + return false; + + PROCESSENTRY32W entry{ sizeof(entry) }; + if (!Process32FirstW(snapshot.get(), &entry)) + return false; + + do + { + if (_wcsicmp(entry.szExeFile, L"EscapeFromTarkov.exe") == 0) + return true; + } while (Process32NextW(snapshot.get(), &entry)); + + return false; + } + + [[nodiscard]] inline bool WaitForGame(DWORD maxWaitMs = 30 * 60 * 1000) noexcept + { + DWORD elapsed = 0; + const DWORD stepMs = 1000; + + while (elapsed < maxWaitMs) + { + if (IsGameRunning()) + return true; + + Sleep(stepMs); + elapsed += stepMs; + } + + return false; + } +} \ No newline at end of file