added files.
This commit is contained in:
commit
e908ab2355
353 files changed
+130515
No files matched your search
@@ -0,0 +1,22 @@
|
||||
add_executable(Slinky
|
||||
src/Main.cpp
|
||||
src/Injector.cpp
|
||||
src/ProcessUtil.cpp
|
||||
src/ConsoleUI.cpp
|
||||
Slinky.rc
|
||||
)
|
||||
|
||||
target_include_directories(Slinky PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_compile_definitions(Slinky PRIVATE
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
WIN32_LEAN_AND_MEAN
|
||||
)
|
||||
|
||||
set_target_properties(Slinky PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
OUTPUT_NAME "Slinky"
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "include/Resource.h"
|
||||
|
||||
#ifdef EMBED_BUNDLED_DLL
|
||||
IDR_BUNDLED_DLL RCDATA "SlinkyNative.dll"
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
|
||||
namespace Slinky {
|
||||
|
||||
class ConsoleUI {
|
||||
public:
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
|
||||
static void PrintBanner();
|
||||
static void StartAnimation();
|
||||
static void StopAnimation();
|
||||
|
||||
static void SetStatusText(const char* text);
|
||||
static void PrintError(const char* action, DWORD errorCode);
|
||||
|
||||
private:
|
||||
static DWORD WINAPI AnimationThread(LPVOID lpParam);
|
||||
|
||||
static CRITICAL_SECTION s_CriticalSection;
|
||||
static char s_StatusText[512];
|
||||
static std::atomic<bool> s_Running;
|
||||
static HANDLE s_hAnimationThread;
|
||||
static DWORD s_OriginalConsoleMode;
|
||||
static HANDLE s_hConsole;
|
||||
};
|
||||
|
||||
} // namespace Slinky
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
|
||||
namespace Slinky {
|
||||
|
||||
class Injector {
|
||||
public:
|
||||
static bool ExtractBundledDll(std::wstring& outDllPath, std::wstring& outLogPath);
|
||||
static bool InjectDll(DWORD pid, const std::wstring& dllPath);
|
||||
static bool MonitorStartup(DWORD pid, const std::wstring& logPath);
|
||||
};
|
||||
|
||||
} // namespace Slinky
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Slinky {
|
||||
|
||||
struct TargetWindow {
|
||||
HWND hWnd = nullptr;
|
||||
DWORD pid = 0;
|
||||
std::wstring title;
|
||||
};
|
||||
|
||||
class ProcessUtil {
|
||||
public:
|
||||
static std::vector<DWORD> GetJavaProcessIds();
|
||||
static std::vector<TargetWindow> FindMinecraftWindows();
|
||||
static bool IsModuleLoaded(DWORD pid, const wchar_t* moduleName);
|
||||
static bool WaitForModuleLoad(DWORD pid, const wchar_t* moduleName, DWORD timeoutMs);
|
||||
};
|
||||
|
||||
} // namespace Slinky
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define IDR_BUNDLED_DLL 200
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "ConsoleUI.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
namespace Slinky {
|
||||
|
||||
CRITICAL_SECTION ConsoleUI::s_CriticalSection;
|
||||
char ConsoleUI::s_StatusText[512] = { 0 };
|
||||
std::atomic<bool> ConsoleUI::s_Running(false);
|
||||
HANDLE ConsoleUI::s_hAnimationThread = nullptr;
|
||||
DWORD ConsoleUI::s_OriginalConsoleMode = 0;
|
||||
HANDLE ConsoleUI::s_hConsole = INVALID_HANDLE_VALUE;
|
||||
|
||||
void ConsoleUI::PrintBanner() {
|
||||
const char* bannerLines[] = {
|
||||
" _____ __ _ __",
|
||||
" / ___// /__ (_)___/ /",
|
||||
" \\__ \\/ //_// / __ / ",
|
||||
" ___/ / ,< / / /_/ / ",
|
||||
"/____/_/|_|/_/\\__,_/ ",
|
||||
" _____ __ __ _ ",
|
||||
" / ___/____ / /_ __/ /_(_)___ ____ _____",
|
||||
" \\__ \\/ __ \\/ / / / / __/ / __ \\/ __ \\/ ___/",
|
||||
" ___/ / /_/ / / /_/ / /_/ / /_/ / / / (__ ) ",
|
||||
"/____/\\____/_/\\__,_/\\__/_/\\____/_/ /_/____/ "
|
||||
};
|
||||
|
||||
for (size_t lineIdx = 0; lineIdx < 10; ++lineIdx) {
|
||||
const char* line = bannerLines[lineIdx];
|
||||
size_t blockWidth = (lineIdx < 5) ? 24 : 45;
|
||||
size_t len = strlen(line);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
float ratio = (float)i / (float)(blockWidth - 1);
|
||||
if (ratio > 1.0f) ratio = 1.0f;
|
||||
int val = (int)(255 - ratio * 200.0f);
|
||||
if (val < 45) val = 45;
|
||||
printf("\x1b[38;2;%d;%d;%dm%c", val, val, val, line[i]);
|
||||
}
|
||||
printf("\x1b[0m\n");
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void ConsoleUI::Initialize() {
|
||||
InitializeCriticalSection(&s_CriticalSection);
|
||||
s_hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
|
||||
if (s_hConsole != INVALID_HANDLE_VALUE) {
|
||||
GetConsoleMode(s_hConsole, &s_OriginalConsoleMode);
|
||||
SetConsoleMode(s_hConsole, s_OriginalConsoleMode | 0x0004);
|
||||
}
|
||||
|
||||
SetConsoleTitleW(L"Slinky");
|
||||
strcpy_s(s_StatusText, "SCANNING");
|
||||
|
||||
PrintBanner();
|
||||
}
|
||||
|
||||
void ConsoleUI::Shutdown() {
|
||||
StopAnimation();
|
||||
if (s_hConsole != INVALID_HANDLE_VALUE && s_OriginalConsoleMode != 0) {
|
||||
SetConsoleMode(s_hConsole, s_OriginalConsoleMode);
|
||||
}
|
||||
DeleteCriticalSection(&s_CriticalSection);
|
||||
}
|
||||
|
||||
void ConsoleUI::SetStatusText(const char* text) {
|
||||
EnterCriticalSection(&s_CriticalSection);
|
||||
strncpy_s(s_StatusText, text, _TRUNCATE);
|
||||
LeaveCriticalSection(&s_CriticalSection);
|
||||
}
|
||||
|
||||
void ConsoleUI::PrintError(const char* action, DWORD errorCode) {
|
||||
wchar_t* msgBuf = nullptr;
|
||||
FormatMessageW(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPWSTR)&msgBuf, 0, nullptr);
|
||||
|
||||
char errorStr[512] = "unknown";
|
||||
if (msgBuf) {
|
||||
WideCharToMultiByte(CP_UTF8, 0, msgBuf, -1, errorStr, 512, nullptr, nullptr);
|
||||
LocalFree(msgBuf);
|
||||
|
||||
size_t len = strlen(errorStr);
|
||||
while (len > 0 && (errorStr[len - 1] == '\r' || errorStr[len - 1] == '\n')) {
|
||||
errorStr[--len] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
EnterCriticalSection(&s_CriticalSection);
|
||||
printf("\n[!] %s failed with error %lu: %s\n", action, errorCode, errorStr);
|
||||
fflush(stdout);
|
||||
LeaveCriticalSection(&s_CriticalSection);
|
||||
}
|
||||
|
||||
void ConsoleUI::StartAnimation() {
|
||||
if (s_Running) return;
|
||||
s_Running = true;
|
||||
s_hAnimationThread = CreateThread(nullptr, 0, AnimationThread, nullptr, 0, nullptr);
|
||||
}
|
||||
|
||||
void ConsoleUI::StopAnimation() {
|
||||
if (!s_Running) return;
|
||||
s_Running = false;
|
||||
if (s_hAnimationThread) {
|
||||
WaitForSingleObject(s_hAnimationThread, 1000);
|
||||
CloseHandle(s_hAnimationThread);
|
||||
s_hAnimationThread = nullptr;
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
DWORD WINAPI ConsoleUI::AnimationThread(LPVOID lpParam) {
|
||||
const char* spinner[] = { "-", "\\", "|", "/" };
|
||||
int frame = 0;
|
||||
|
||||
while (s_Running) {
|
||||
char currentStatus[512] = { 0 };
|
||||
EnterCriticalSection(&s_CriticalSection);
|
||||
strncpy_s(currentStatus, s_StatusText, _TRUNCATE);
|
||||
LeaveCriticalSection(&s_CriticalSection);
|
||||
|
||||
printf("\r\x1b[2K [%s] %s", spinner[frame % 4], currentStatus);
|
||||
fflush(stdout);
|
||||
|
||||
frame++;
|
||||
Sleep(160);
|
||||
}
|
||||
|
||||
char finalStatus[512] = { 0 };
|
||||
EnterCriticalSection(&s_CriticalSection);
|
||||
strncpy_s(finalStatus, s_StatusText, _TRUNCATE);
|
||||
LeaveCriticalSection(&s_CriticalSection);
|
||||
|
||||
printf("\r\x1b[2K [+] %s\n", finalStatus);
|
||||
fflush(stdout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Slinky
|
||||
@@ -0,0 +1,201 @@
|
||||
#include "Injector.hpp"
|
||||
#include "ProcessUtil.hpp"
|
||||
#include "ConsoleUI.hpp"
|
||||
#include "Resource.h"
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
namespace Slinky {
|
||||
|
||||
bool Injector::ExtractBundledDll(std::wstring& outDllPath, std::wstring& outLogPath) {
|
||||
wchar_t tempPath[MAX_PATH] = { 0 };
|
||||
if (!GetTempPathW(MAX_PATH, tempPath)) {
|
||||
ConsoleUI::PrintError("Finding temp folder", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
wchar_t slinkyTempDir[MAX_PATH] = { 0 };
|
||||
swprintf_s(slinkyTempDir, L"%lsslinky-%lu", tempPath, GetCurrentProcessId());
|
||||
|
||||
if (!CreateDirectoryW(slinkyTempDir, nullptr) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
ConsoleUI::PrintError("Creating temp folder", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
outDllPath = std::wstring(slinkyTempDir) + L"\\SlinkyNative.dll";
|
||||
outLogPath = std::wstring(slinkyTempDir) + L"\\slinky-native.log";
|
||||
|
||||
DeleteFileW(outLogPath.c_str());
|
||||
|
||||
HRSRC hRes = FindResourceW(nullptr, MAKEINTRESOURCEW(IDR_BUNDLED_DLL), (LPCWSTR)10);
|
||||
if (hRes) {
|
||||
DWORD resSize = SizeofResource(nullptr, hRes);
|
||||
HGLOBAL hLoad = LoadResource(nullptr, hRes);
|
||||
if (hLoad && resSize > 0) {
|
||||
const void* pData = LockResource(hLoad);
|
||||
if (pData) {
|
||||
HANDLE hFile = CreateFileW(outDllPath.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile != INVALID_HANDLE_VALUE) {
|
||||
DWORD written = 0;
|
||||
WriteFile(hFile, pData, resSize, &written, nullptr);
|
||||
CloseHandle(hFile);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t exePath[MAX_PATH] = { 0 };
|
||||
if (GetModuleFileNameW(nullptr, exePath, MAX_PATH) > 0) {
|
||||
wchar_t* lastSlash = wcsrchr(exePath, L'\\');
|
||||
if (lastSlash) {
|
||||
*lastSlash = L'\0';
|
||||
std::wstring localDll = std::wstring(exePath) + L"\\SlinkyNative.dll";
|
||||
if (GetFileAttributesW(localDll.c_str()) != INVALID_FILE_ATTRIBUTES) {
|
||||
if (CopyFileW(localDll.c_str(), outDllPath.c_str(), FALSE)) {
|
||||
return true;
|
||||
}
|
||||
outDllPath = localDll;
|
||||
outLogPath = std::wstring(exePath) + L"\\slinky-native.log";
|
||||
DeleteFileW(outLogPath.c_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("Could not extract bundled DLL.");
|
||||
ConsoleUI::PrintError("Reading bundled DLL", ERROR_FILE_NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Injector::InjectDll(DWORD pid, const std::wstring& dllPath) {
|
||||
if (ProcessUtil::IsModuleLoaded(pid, L"SlinkyNative.dll")) {
|
||||
ConsoleUI::SetStatusText("DLL already loaded.");
|
||||
return true;
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("Opening game process");
|
||||
HANDLE hProcess = OpenProcess(
|
||||
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_QUERY_INFORMATION,
|
||||
FALSE, pid);
|
||||
|
||||
if (!hProcess) {
|
||||
ConsoleUI::PrintError("OpenProcess", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("Allocating DLL path in game");
|
||||
SIZE_T pathSizeBytes = (dllPath.length() + 1) * sizeof(wchar_t);
|
||||
LPVOID pRemotePath = VirtualAllocEx(hProcess, nullptr, pathSizeBytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
|
||||
if (!pRemotePath) {
|
||||
ConsoleUI::PrintError("Allocating DLL path in game", GetLastError());
|
||||
CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("Copying DLL path into game");
|
||||
if (!WriteProcessMemory(hProcess, pRemotePath, dllPath.c_str(), pathSizeBytes, nullptr)) {
|
||||
ConsoleUI::PrintError("Copying DLL path into game", GetLastError());
|
||||
VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("Finding Windows DLL loader");
|
||||
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
|
||||
LPTHREAD_START_ROUTINE pLoadLibraryW = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW");
|
||||
|
||||
if (!pLoadLibraryW) {
|
||||
ConsoleUI::PrintError("Finding Windows DLL loader", GetLastError());
|
||||
VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("Starting DLL loader in game");
|
||||
HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, pLoadLibraryW, pRemotePath, 0, nullptr);
|
||||
if (!hThread) {
|
||||
ConsoleUI::PrintError("Starting DLL loader in game", GetLastError());
|
||||
VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("Reading DLL loader result");
|
||||
DWORD waitRes = WaitForSingleObject(hThread, 30000);
|
||||
if (waitRes != WAIT_OBJECT_0) {
|
||||
ConsoleUI::SetStatusText("Game did not finish loading the DLL.");
|
||||
CloseHandle(hThread);
|
||||
VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD dwExitCode = 0;
|
||||
GetExitCodeThread(hThread, &dwExitCode);
|
||||
CloseHandle(hThread);
|
||||
VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
|
||||
CloseHandle(hProcess);
|
||||
|
||||
if (!ProcessUtil::WaitForModuleLoad(pid, L"SlinkyNative.dll", 5000)) {
|
||||
ConsoleUI::SetStatusText("DLL not in game after load attempt.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("Injected successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Injector::MonitorStartup(DWORD pid, const std::wstring& logPath) {
|
||||
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
|
||||
ConsoleUI::SetStatusText("Still loading...");
|
||||
DWORD startTime = GetTickCount();
|
||||
const DWORD timeoutMs = 30000;
|
||||
|
||||
while (GetTickCount() - startTime < timeoutMs) {
|
||||
if (hProcess && WaitForSingleObject(hProcess, 0) == WAIT_OBJECT_0) {
|
||||
ConsoleUI::SetStatusText("Game process closed before startup finished.");
|
||||
CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* fp = nullptr;
|
||||
if (_wfopen_s(&fp, logPath.c_str(), L"r, ccs=UTF-8") == 0 && fp) {
|
||||
wchar_t line[1024];
|
||||
while (fgetws(line, 1024, fp)) {
|
||||
if (wcsstr(line, L"FINAL STATUS: RUNNING")) {
|
||||
ConsoleUI::SetStatusText("Press Right Shift in Minecraft.");
|
||||
fclose(fp);
|
||||
if (hProcess) CloseHandle(hProcess);
|
||||
return true;
|
||||
} else if (wcsstr(line, L"FINAL STATUS: RELOADED")) {
|
||||
ConsoleUI::SetStatusText("Slinky reloaded. Press Right Shift.");
|
||||
fclose(fp);
|
||||
if (hProcess) CloseHandle(hProcess);
|
||||
return true;
|
||||
} else if (wcsstr(line, L"FINAL STATUS: ALREADY_RUNNING")) {
|
||||
ConsoleUI::SetStatusText("Already running. Unload from menu first.");
|
||||
fclose(fp);
|
||||
if (hProcess) CloseHandle(hProcess);
|
||||
return false;
|
||||
} else if (wcsstr(line, L"FINAL STATUS: FAILED")) {
|
||||
ConsoleUI::SetStatusText("Slinky could not start.");
|
||||
fclose(fp);
|
||||
if (hProcess) CloseHandle(hProcess);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
Sleep(150);
|
||||
}
|
||||
|
||||
if (hProcess) CloseHandle(hProcess);
|
||||
ConsoleUI::SetStatusText("DLL loaded but Slinky never confirmed startup.");
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Slinky
|
||||
@@ -0,0 +1,80 @@
|
||||
#include <windows.h>
|
||||
#include "ConsoleUI.hpp"
|
||||
#include "Injector.hpp"
|
||||
#include "ProcessUtil.hpp"
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
using namespace Slinky;
|
||||
|
||||
int main() {
|
||||
ConsoleUI::Initialize();
|
||||
ConsoleUI::StartAnimation();
|
||||
|
||||
ConsoleUI::SetStatusText("Finding bundled DLL");
|
||||
std::wstring dllPath;
|
||||
std::wstring logPath;
|
||||
|
||||
if (!Injector::ExtractBundledDll(dllPath, logPath)) {
|
||||
Sleep(2500);
|
||||
ConsoleUI::StopAnimation();
|
||||
ConsoleUI::Shutdown();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ConsoleUI::SetStatusText("SCANNING");
|
||||
|
||||
DWORD startWait = GetTickCount();
|
||||
const DWORD timeoutWait = 180000;
|
||||
std::vector<TargetWindow> windows;
|
||||
int dotCount = 0;
|
||||
|
||||
while (GetTickCount() - startWait < timeoutWait) {
|
||||
windows = ProcessUtil::FindMinecraftWindows();
|
||||
if (!windows.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
const char* dots[] = { "", ".", "..", "..." };
|
||||
char waitMsg[64];
|
||||
sprintf_s(waitMsg, "Waiting for Minecraft%s", dots[dotCount % 4]);
|
||||
ConsoleUI::SetStatusText(waitMsg);
|
||||
dotCount++;
|
||||
|
||||
Sleep(500);
|
||||
}
|
||||
|
||||
if (windows.empty()) {
|
||||
ConsoleUI::SetStatusText("Minecraft not found after 3 minutes.");
|
||||
Sleep(3000);
|
||||
ConsoleUI::StopAnimation();
|
||||
ConsoleUI::Shutdown();
|
||||
return 1;
|
||||
}
|
||||
|
||||
TargetWindow target = windows[0];
|
||||
|
||||
char foundMsg[256];
|
||||
char titleUtf8[256] = { 0 };
|
||||
WideCharToMultiByte(CP_UTF8, 0, target.title.c_str(), -1, titleUtf8, 256, nullptr, nullptr);
|
||||
sprintf_s(foundMsg, "Found Minecraft %s", titleUtf8);
|
||||
ConsoleUI::SetStatusText(foundMsg);
|
||||
|
||||
Sleep(500);
|
||||
|
||||
ConsoleUI::SetStatusText("INJECTING ...");
|
||||
if (!Injector::InjectDll(target.pid, dllPath)) {
|
||||
Sleep(3000);
|
||||
ConsoleUI::StopAnimation();
|
||||
ConsoleUI::Shutdown();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool success = Injector::MonitorStartup(target.pid, logPath);
|
||||
|
||||
Sleep(3000);
|
||||
ConsoleUI::StopAnimation();
|
||||
ConsoleUI::Shutdown();
|
||||
|
||||
return success ? 0 : 1;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "ProcessUtil.hpp"
|
||||
#include <tlhelp32.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Slinky {
|
||||
|
||||
std::vector<DWORD> ProcessUtil::GetJavaProcessIds() {
|
||||
std::vector<DWORD> pids;
|
||||
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (hSnap == INVALID_HANDLE_VALUE) return pids;
|
||||
|
||||
PROCESSENTRY32W pe;
|
||||
pe.dwSize = sizeof(pe);
|
||||
|
||||
if (Process32FirstW(hSnap, &pe)) {
|
||||
do {
|
||||
if (_wcsicmp(pe.szExeFile, L"javaw.exe") == 0 ||
|
||||
_wcsicmp(pe.szExeFile, L"java.exe") == 0)
|
||||
{
|
||||
pids.push_back(pe.th32ProcessID);
|
||||
}
|
||||
} while (Process32NextW(hSnap, &pe));
|
||||
}
|
||||
|
||||
CloseHandle(hSnap);
|
||||
return pids;
|
||||
}
|
||||
|
||||
struct EnumData {
|
||||
std::vector<DWORD> javaPids;
|
||||
std::vector<TargetWindow> windows;
|
||||
};
|
||||
|
||||
static BOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam) {
|
||||
if (!IsWindowVisible(hWnd)) return TRUE;
|
||||
if (GetWindowTextLengthW(hWnd) == 0) return TRUE;
|
||||
|
||||
DWORD pid = 0;
|
||||
GetWindowThreadProcessId(hWnd, &pid);
|
||||
|
||||
EnumData* data = (EnumData*)lParam;
|
||||
if (std::find(data->javaPids.begin(), data->javaPids.end(), pid) == data->javaPids.end()) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
wchar_t titleBuf[512] = { 0 };
|
||||
if (GetWindowTextW(hWnd, titleBuf, 512) > 0) {
|
||||
TargetWindow tw;
|
||||
tw.hWnd = hWnd;
|
||||
tw.pid = pid;
|
||||
tw.title = titleBuf;
|
||||
data->windows.push_back(tw);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
std::vector<TargetWindow> ProcessUtil::FindMinecraftWindows() {
|
||||
EnumData data;
|
||||
data.javaPids = GetJavaProcessIds();
|
||||
if (data.javaPids.empty()) return {};
|
||||
|
||||
EnumWindows(EnumWindowsProc, (LPARAM)&data);
|
||||
return data.windows;
|
||||
}
|
||||
|
||||
bool ProcessUtil::IsModuleLoaded(DWORD pid, const wchar_t* moduleName) {
|
||||
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
|
||||
if (hSnap == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
MODULEENTRY32W me;
|
||||
me.dwSize = sizeof(me);
|
||||
|
||||
bool found = false;
|
||||
if (Module32FirstW(hSnap, &me)) {
|
||||
do {
|
||||
if (_wcsicmp(me.szModule, moduleName) == 0 ||
|
||||
wcsstr(me.szExePath, moduleName) != nullptr)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
} while (Module32NextW(hSnap, &me));
|
||||
}
|
||||
|
||||
CloseHandle(hSnap);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool ProcessUtil::WaitForModuleLoad(DWORD pid, const wchar_t* moduleName, DWORD timeoutMs) {
|
||||
DWORD elapsed = 0;
|
||||
while (elapsed < timeoutMs) {
|
||||
if (IsModuleLoaded(pid, moduleName)) return true;
|
||||
Sleep(50);
|
||||
elapsed += 50;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Slinky
|
||||
Reference in new issue
Block a user