BEService spoofer refactoring.

This commit is contained in:
NukedBart 2025-12-11 23:35:30 +08:00
parent 444ccad844
commit 4a2dbcad27
6 changed files with 156 additions and 114 deletions

27
service/core/WinApi.h Normal file
View file

@ -0,0 +1,27 @@
// core/WinApi.h
#pragma once
#include <windows.h>
#include <tlhelp32.h>
#include <memory>
#include <utility> // 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<std::remove_pointer<HANDLE>::type, HandleDeleter>;
template <typename F>
struct ScopeExit
{
F func;
explicit ScopeExit(F&& f) noexcept : func(std::forward<F>(f)) {}
~ScopeExit() noexcept { func(); }
};
}

8
service/includes.h Normal file
View file

@ -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"

View file

@ -1,118 +1,7 @@
#include <windows.h> #include "includes.h"
#include <TlHelp32.h>
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);
}
// Entry point // Entry point
int wmain() int wmain()
{ {
SERVICE_TABLE_ENTRYW ServiceTable[] = { return BEService::Run() ? 0 : 1;
{ (LPWSTR)L"BEService", (LPSERVICE_MAIN_FUNCTIONW)ServiceMain },
{ NULL, NULL }
};
// This blocks until service is stopped
StartServiceCtrlDispatcherW(ServiceTable);
return 0;
} }

View file

@ -105,7 +105,7 @@
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard> <LanguageStandard>stdcpplatest</LanguageStandard>
<LanguageStandard_C>stdclatest</LanguageStandard_C> <LanguageStandard_C>stdclatest</LanguageStandard_C>
</ClCompile> </ClCompile>
<Link> <Link>

View file

@ -0,0 +1,74 @@
// service/BEService.h
#pragma once
#include "core/WinApi.h"
#include "services/GameMonitor.h"
#include <windows.h>
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<wchar_t*>(L"BEService"), ServiceMain },
{ nullptr, nullptr }
};
return StartServiceCtrlDispatcherW(table) != FALSE;
}
}

View file

@ -0,0 +1,44 @@
// services/GameMonitor.h
#pragma once
#include "core/WinApi.h"
#include <tlhelp32.h>
#include <string_view>
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;
}
}