This commit is contained in:
nitrogenoliquido committed 2026-10-14 22:51:32 -05:00
1 parent 82004f6b5e
commit e0347fe1cb
8 files changed
+97 -13

No files matched your search

+1
View File
@@ -10,6 +10,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
if(MSVC) if(MSVC)
add_compile_options(/W3 /utf-8 /MP) add_compile_options(/W3 /utf-8 /MP)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif() endif()
add_subdirectory(Slinky) add_subdirectory(Slinky)
+10
View File
@@ -8,6 +8,10 @@
--- ---
<p align="center">
<a href="https://discord.gg/AEwatvnvSf">https://discord.gg/AEwatvnvSf</a>
</p>
<p align="center"> <p align="center">
<img src="assets/jak.jpg" alt="jak" height="150" /> <img src="assets/jak.jpg" alt="jak" height="150" />
<img src="assets/hack.jpg" alt="hack" height="150" /> <img src="assets/hack.jpg" alt="hack" height="150" />
@@ -17,6 +21,12 @@
--- ---
<p align="center">
<img src="assets/proof.png" alt="proof" width="500" />
</p>
---
## How to build ## How to build
### Prerequisites ### Prerequisites
+1
View File
@@ -18,6 +18,7 @@ public:
static std::vector<TargetWindow> FindMinecraftWindows(); static std::vector<TargetWindow> FindMinecraftWindows();
static bool IsModuleLoaded(DWORD pid, const wchar_t* moduleName); static bool IsModuleLoaded(DWORD pid, const wchar_t* moduleName);
static bool WaitForModuleLoad(DWORD pid, const wchar_t* moduleName, DWORD timeoutMs); static bool WaitForModuleLoad(DWORD pid, const wchar_t* moduleName, DWORD timeoutMs);
static bool UnloadModule(DWORD pid, const wchar_t* moduleName);
}; };
} // namespace Slinky } // namespace Slinky
+11 -2
View File
@@ -70,8 +70,12 @@ bool Injector::ExtractBundledDll(std::wstring& outDllPath, std::wstring& outLogP
bool Injector::InjectDll(DWORD pid, const std::wstring& dllPath) { bool Injector::InjectDll(DWORD pid, const std::wstring& dllPath) {
if (ProcessUtil::IsModuleLoaded(pid, L"SlinkyNative.dll")) { if (ProcessUtil::IsModuleLoaded(pid, L"SlinkyNative.dll")) {
ConsoleUI::SetStatusText("DLL already loaded."); ConsoleUI::SetStatusText("Unloading previous instance...");
return true; if (!ProcessUtil::UnloadModule(pid, L"SlinkyNative.dll")) {
ConsoleUI::SetStatusText("Could not unload previous instance.");
return false;
}
Sleep(300);
} }
ConsoleUI::SetStatusText("Opening game process"); ConsoleUI::SetStatusText("Opening game process");
@@ -138,6 +142,11 @@ bool Injector::InjectDll(DWORD pid, const std::wstring& dllPath) {
VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE); VirtualFreeEx(hProcess, pRemotePath, 0, MEM_RELEASE);
CloseHandle(hProcess); CloseHandle(hProcess);
if (dwExitCode == 0) {
ConsoleUI::SetStatusText("LoadLibraryW failed in game process.");
return false;
}
if (!ProcessUtil::WaitForModuleLoad(pid, L"SlinkyNative.dll", 5000)) { if (!ProcessUtil::WaitForModuleLoad(pid, L"SlinkyNative.dll", 5000)) {
ConsoleUI::SetStatusText("DLL not in game after load attempt."); ConsoleUI::SetStatusText("DLL not in game after load attempt.");
return false; return false;
+51
View File
@@ -97,4 +97,55 @@ bool ProcessUtil::WaitForModuleLoad(DWORD pid, const wchar_t* moduleName, DWORD
return false; return false;
} }
bool ProcessUtil::UnloadModule(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);
HMODULE hTargetModule = nullptr;
if (Module32FirstW(hSnap, &me)) {
do {
if (_wcsicmp(me.szModule, moduleName) == 0 ||
wcsstr(me.szExePath, moduleName) != nullptr)
{
hTargetModule = me.hModule;
break;
}
} while (Module32NextW(hSnap, &me));
}
CloseHandle(hSnap);
if (!hTargetModule) return true;
HANDLE hProcess = OpenProcess(
PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION,
FALSE, pid);
if (!hProcess) return false;
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
LPTHREAD_START_ROUTINE pFreeLibrary = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "FreeLibrary");
if (!pFreeLibrary) {
CloseHandle(hProcess);
return false;
}
HANDLE hThread = CreateRemoteThread(hProcess, nullptr, 0, pFreeLibrary, (LPVOID)hTargetModule, 0, nullptr);
if (hThread) {
WaitForSingleObject(hThread, 5000);
CloseHandle(hThread);
}
CloseHandle(hProcess);
DWORD elapsed = 0;
while (elapsed < 3000) {
if (!IsModuleLoaded(pid, moduleName)) return true;
Sleep(50);
elapsed += 50;
}
return !IsModuleLoaded(pid, moduleName);
}
} // namespace Slinky } // namespace Slinky
+17 -5
View File
@@ -6,11 +6,7 @@
static HMODULE g_hModule = nullptr; static HMODULE g_hModule = nullptr;
DWORD WINAPI SlinkyNativeWorkerThread(LPVOID lpParam) { static DWORD RunWorker(HMODULE hModule) {
HMODULE hModule = (HMODULE)lpParam;
SlinkyNative::Logger::Initialize(hModule);
if (!SlinkyNative::JvmManager::Initialize()) { if (!SlinkyNative::JvmManager::Initialize()) {
SlinkyNative::Logger::Log(L"FINAL STATUS: FAILED"); SlinkyNative::Logger::Log(L"FINAL STATUS: FAILED");
return 1; return 1;
@@ -27,6 +23,22 @@ DWORD WINAPI SlinkyNativeWorkerThread(LPVOID lpParam) {
return (status == SlinkyNative::InjectionStatus::Success || status == SlinkyNative::InjectionStatus::AlreadyRunning) ? 0 : 1; return (status == SlinkyNative::InjectionStatus::Success || status == SlinkyNative::InjectionStatus::AlreadyRunning) ? 0 : 1;
} }
DWORD WINAPI SlinkyNativeWorkerThread(LPVOID lpParam) {
HMODULE hModule = (HMODULE)lpParam;
SlinkyNative::Logger::Initialize(hModule);
DWORD ret = 1;
__try {
ret = RunWorker(hModule);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
SlinkyNative::Logger::Log(L"SlinkyNativeWorkerThread crashed with exception 0x%08X", GetExceptionCode());
SlinkyNative::Logger::Log(L"FINAL STATUS: FAILED");
ret = 1;
}
return ret;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) { BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) {
switch (fdwReason) { switch (fdwReason) {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
+6 -6
View File
@@ -355,11 +355,7 @@ bool PayloadLoader::DefinePayloadClasses(JNIEnv* env, jobject classLoader, const
env->ReleaseStringUTFChars(nameStr, nameChars); env->ReleaseStringUTFChars(nameStr, nameChars);
if (entryName.rfind("dev/slinky/", 0) == 0 && entryName.size() > 6 && entryName.substr(entryName.size() - 6) == ".class") { if (entryName.rfind("dev/slinky/", 0) == 0 && entryName.size() > 6 && entryName.substr(entryName.size() - 6) == ".class") {
// Convert "dev/slinky/Foo.class" -> "dev.slinky.Foo" std::string internalName = entryName.substr(0, entryName.size() - 6);
std::string className = entryName.substr(0, entryName.size() - 6);
for (char& c : className) {
if (c == '/') c = '.';
}
// Read bytes // Read bytes
jobject inputStream = env->CallObjectMethod(jarObj, jarGetInputStream, entry); jobject inputStream = env->CallObjectMethod(jarObj, jarGetInputStream, entry);
@@ -375,7 +371,11 @@ bool PayloadLoader::DefinePayloadClasses(JNIEnv* env, jobject classLoader, const
jsize byteLen = env->GetArrayLength(classBytesArr); jsize byteLen = env->GetArrayLength(classBytesArr);
jbyte* rawBytes = env->GetByteArrayElements(classBytesArr, nullptr); jbyte* rawBytes = env->GetByteArrayElements(classBytesArr, nullptr);
if (rawBytes) { if (rawBytes) {
jclass definedClass = env->DefineClass(nullptr, classLoader, rawBytes, byteLen); jclass definedClass = env->DefineClass(internalName.c_str(), classLoader, rawBytes, byteLen);
if (!definedClass) {
env->ExceptionClear();
definedClass = env->DefineClass(nullptr, classLoader, rawBytes, byteLen);
}
if (definedClass) { if (definedClass) {
definedCount++; definedCount++;
env->DeleteLocalRef(definedClass); env->DeleteLocalRef(definedClass);
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 806 KiB