internal injector update

This commit is contained in:
NukedBart 2025-12-09 16:02:47 +08:00
parent 2663963bc1
commit b8971674ed
31 changed files with 302 additions and 16 deletions

View file

@ -4,7 +4,87 @@
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <thread>
#include <regex>
#include <tlhelp32.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[1];
PVOID Reserved3[2];
PVOID Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
} PEB, * PPEB;
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
// ProcessBasicInformation = 0
#ifndef ProcessBasicInformation
#define ProcessBasicInformation 0
#endif
std::wstring GetCommandLine(DWORD pid)
{
std::wstring result;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (!hProcess) return result;
// Load ntdll
auto ntdll = GetModuleHandleA("ntdll.dll");
auto NtQueryInformationProcess = (LONG(WINAPI*)(HANDLE, int, PVOID, ULONG, PULONG))GetProcAddress(ntdll, "NtQueryInformationProcess");
if (!NtQueryInformationProcess) {
CloseHandle(hProcess);
return result;
}
PROCESS_BASIC_INFORMATION pbi{};
ULONG len;
if (NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(pbi), &len) == 0)
{
PEB peb{};
RTL_USER_PROCESS_PARAMETERS upp{};
if (ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), nullptr))
{
if (ReadProcessMemory(hProcess, peb.ProcessParameters, &upp, sizeof(upp), nullptr))
{
wchar_t* buffer = new wchar_t[8192];
if (ReadProcessMemory(hProcess, upp.CommandLine.Buffer, buffer, upp.CommandLine.Length, nullptr))
{
result = std::wstring(buffer, upp.CommandLine.Length / sizeof(wchar_t));
}
delete[] buffer;
}
}
}
CloseHandle(hProcess);
return result;
}
std::string GetExeDirectory()
{
wchar_t path[MAX_PATH] = { 0 };
@ -142,9 +222,9 @@ void verifyServiceDeletion(const std::wstring& svcName)
SERVICE_STATUS status{};
if (ControlService(hExisting, SERVICE_CONTROL_STOP, &status)) {
DWORD start = GetTickCount();
long long start = GetTickCount64();
std::cout << "Waiting for BEService to stop";
while (status.dwCurrentState != SERVICE_STOPPED && GetTickCount() - start < 10000) {
while (status.dwCurrentState != SERVICE_STOPPED && GetTickCount64() - start < 10000) {
Sleep(500);
std::cout << ".";
if (!QueryServiceStatus(hExisting, &status)) break;
@ -165,6 +245,207 @@ void verifyServiceDeletion(const std::wstring& svcName)
}
}
BOOL InjectDLL(DWORD processId, const char* dllPath)
{
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ,
FALSE, processId);
if (!hProcess) {
std::cout << "[-] OpenProcess failed: " << GetLastError() << std::endl;
return FALSE;
}
SIZE_T pathLen = strlen(dllPath) + 1;
LPVOID remoteMem = VirtualAllocEx(hProcess, nullptr, pathLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!remoteMem) {
std::cout << "[-] VirtualAllocEx failed: " << GetLastError() << std::endl;
CloseHandle(hProcess);
return FALSE;
}
if (!WriteProcessMemory(hProcess, remoteMem, dllPath, pathLen, nullptr)) {
std::cout << "[-] WriteProcessMemory failed: " << GetLastError() << std::endl;
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
if (!hKernel32) {
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
LPTHREAD_START_ROUTINE pLoadLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA");
HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, pLoadLibrary, remoteMem, 0, nullptr);
if (!hThread) {
std::cout << "[-] CreateRemoteThread failed: " << GetLastError() << std::endl;
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);
return FALSE;
}
WaitForSingleObject(hThread, 10000);
DWORD exitCode = 0;
GetExitCodeThread(hThread, &exitCode);
CloseHandle(hThread);
VirtualFreeEx(hProcess, remoteMem, 0, MEM_RELEASE);
CloseHandle(hProcess);
if (exitCode != 0) {
std::cout << "[+] Injected successfully! (hModule = 0x"
<< std::hex << exitCode << std::dec << ")\n";
return TRUE;
}
std::cout << "[-] LoadLibraryA returned NULL in target process\n";
return FALSE;
}
BOOL StealAndKillBE(std::wstring& outCmdLine, DWORD& outPid)
{
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE) return false;
PROCESSENTRY32 pe{ .dwSize = sizeof(pe) };
bool found = false;
if (!Process32First(hSnap, &pe))
goto not_found;
do {
if (_wcsicmp(pe.szExeFile, L"EscapeFromTarkov_BE.exe") != 0)
continue;
std::cout << std::endl;
found = true;
outPid = pe.th32ProcessID;
std::wcout << L"[+] Found BE process (PID: " << outPid << L") - Stealing command line...\n";
// 1. STEAL COMMAND LINE FIRST
outCmdLine = GetCommandLine(outPid);
if (outCmdLine.empty()) {
std::wcout << L"[-] Failed to read command line from PID " << outPid << L"\n";
continue; // try next instance
}
std::wcout << L"[+] Command line stolen successfully!\n";
// 2. NOW KILL IT
HANDLE hProc = OpenProcess(PROCESS_TERMINATE, FALSE, outPid);
if (hProc) {
TerminateProcess(hProc, 0);
CloseHandle(hProc);
std::cout << "[+] BE process terminated.\n";
}
// Don't break — kill ALL BE instances (in case of multiple)
} while (Process32Next(hSnap, &pe));
not_found:
CloseHandle(hSnap);
return found && !outCmdLine.empty();
}
BOOL Battleyent()
{
std::wstring stolenCmdLine;
DWORD bePid = 0;
// ── 1. Wait for BE and steal command line ───────────────────────
std::cout << "[.] Waiting for EscapeFromTarkov_BE.exe to appear";
while (!StealAndKillBE(stolenCmdLine, bePid))
{
std::cout << ".";
std::this_thread::sleep_for(std::chrono::seconds(1));
}
// ── 2. Replace BE executable with clean one ───────────────────
std::wstring cleanCmdLine = std::regex_replace(
stolenCmdLine,
std::wregex(L"EscapeFromTarkov_BE\\.exe", std::regex_constants::icase),
L"EscapeFromTarkov.exe");
// ── 3. Extract real executable path (remove quotes if any) ─────
std::wsmatch match;
std::wstring exeFullPath;
if (std::regex_search(cleanCmdLine, match, std::wregex(L"\"([^\"]+)\"")))
{
exeFullPath = match[1].str();
cleanCmdLine = std::regex_replace(cleanCmdLine,
std::wregex(L"\"[^\"]+\""),
exeFullPath,
std::regex_constants::format_first_only);
}
else if (cleanCmdLine.find(L' ') != std::wstring::npos)
{
exeFullPath = cleanCmdLine.substr(0, cleanCmdLine.find(L' '));
}
else
{
exeFullPath = cleanCmdLine;
}
// ── 4. Build correct working directory ───────────────────────
const std::wstring gameWorkingDir = exeFullPath.substr(0, exeFullPath.find_last_of(L"\\/"));
std::wcout << L"[+] Game path : " << exeFullPath << L'\n';
std::wcout << L"[+] Working directory: " << gameWorkingDir << L'\n';
std::wcout << L"[+] Final cmdline : " << cleanCmdLine << L'\n';
// ── 5. Launch the clean game (suspended) ─────────────────────
STARTUPINFOW si = { sizeof(si) };
PROCESS_INFORMATION pi = { };
const BOOL created = CreateProcessW(
nullptr,
cleanCmdLine.data(),
nullptr, nullptr,
FALSE,
CREATE_SUSPENDED, // start suspended -> safe injection
nullptr,
gameWorkingDir.c_str(), // avoid consistency crashes
&si,
&pi
);
if (!created)
{
std::cerr << "[-] CreateProcessW failed: " << GetLastError() << std::endl;
return FALSE;
}
std::cout << "[+] EscapeFromTarkov.exe launched (PID: " << pi.dwProcessId << ")\n";
// ── 6. Resume main thread ─────
ResumeThread(pi.hThread);
// ── 7. Inject our DLL ───────────────────────────────────────
const std::string dllPath = GetExeDirectory() + "\\iOperator.dll";
if (!InjectDLL(pi.dwProcessId, dllPath.c_str()))
{
std::cout << "[-] Injection failed!\n";
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return FALSE;
}
// ── 8. Success ───────────────────────────────────────────────
std::cout << "[+] iOperator.dll injected successfully!\n";
std::cout << "[+] Bootstrap done. Enjoy your raids!\n";
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
Sleep(3000);
return TRUE;
}
int main()
{
@ -229,16 +510,11 @@ int main()
CloseServiceHandle(hNew);
CloseServiceHandle(scm);
std::cout << std::endl;
std::cout << "Spinning up Battleyen't.\n";
char* path = _strdup(GetExeDirectory().c_str());
size_t path_buf_size = strlen(path) + strlen("battleyent.exe") + 1;
path = (char*)realloc(path, path_buf_size);
if (strcat_s(path, path_buf_size, "battleyent.exe") == 0) {
system(path);
}
free(path);
std::cout << "Spinning up. Launch EFT from launcher.\n";
while (!Battleyent());
std::cout << "Waiting for the game to start";
while (!isProcessRunning("EscapeFromTarkov.exe"))

View file

@ -42,7 +42,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
@ -105,6 +105,7 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
<LanguageStandard_C>stdclatest</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>