BEService spoofer refactoring.
This commit is contained in:
parent
444ccad844
commit
4a2dbcad27
6 changed files with 156 additions and 114 deletions
27
service/core/WinApi.h
Normal file
27
service/core/WinApi.h
Normal 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
8
service/includes.h
Normal 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"
|
||||||
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
74
service/services/BEService.h
Normal file
74
service/services/BEService.h
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
service/services/GameMonitor.h
Normal file
44
service/services/GameMonitor.h
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue