diff --git a/ioperator/dllmain.cpp b/ioperator/dllmain.cpp index 2e747af..eb77bdc 100644 --- a/ioperator/dllmain.cpp +++ b/ioperator/dllmain.cpp @@ -14,32 +14,32 @@ struct Il2CppImage; // IL2CPP API function pointer type definitions using il2cpp_get_root_domain_prot = Il2CppDomain * (*)(); -static il2cpp_get_root_domain_prot il2cpp_get_root_domain = nullptr; +static il2cpp_get_root_domain_prot il2cpp_get_root_domain = nullptr; // harmless using il2cpp_thread_attach_prot = Il2CppThread * (*)(Il2CppDomain*); -static il2cpp_thread_attach_prot il2cpp_thread_attach = nullptr; +static il2cpp_thread_attach_prot il2cpp_thread_attach = nullptr; // harmless using il2cpp_domain_get_assemblies_prot = const Il2CppAssembly** (*)(Il2CppDomain*, size_t*); -static il2cpp_domain_get_assemblies_prot il2cpp_domain_get_assemblies = nullptr; +static il2cpp_domain_get_assemblies_prot il2cpp_domain_get_assemblies = nullptr; //harmless using il2cpp_class_from_name_prot = Il2CppClass * (*)(const Il2CppImage*, const char*, const char*); -static il2cpp_class_from_name_prot il2cpp_class_from_name = nullptr; +static il2cpp_class_from_name_prot il2cpp_class_from_name = nullptr; // not working, test needed using il2cpp_class_get_methods_prot = const Il2CppMethod* (*)(Il2CppClass*, void**); -static il2cpp_class_get_methods_prot il2cpp_class_get_methods = nullptr; +static il2cpp_class_get_methods_prot il2cpp_class_get_methods = nullptr; // not working, test needed using il2cpp_method_get_name_prot = const char* (*)(const Il2CppMethod*); -static il2cpp_method_get_name_prot il2cpp_method_get_name = nullptr; +static il2cpp_method_get_name_prot il2cpp_method_get_name = nullptr; // not working using il2cpp_assembly_get_image_prot = const Il2CppImage* (*)(const Il2CppAssembly*); -static il2cpp_assembly_get_image_prot il2cpp_assembly_get_image = nullptr; +static il2cpp_assembly_get_image_prot il2cpp_assembly_get_image = nullptr; // harmless using il2cpp_image_get_name_prot = const char* (*)(const Il2CppImage*); -static il2cpp_image_get_name_prot il2cpp_image_get_name = nullptr; +static il2cpp_image_get_name_prot il2cpp_image_get_name = nullptr; // harmless // IL2CPP runtime invoke function pointer type using il2cpp_runtime_invoke_prot = void* (*)(const Il2CppMethod*, void*, void**, void**); -static il2cpp_runtime_invoke_prot il2cpp_runtime_invoke = nullptr; +static il2cpp_runtime_invoke_prot il2cpp_runtime_invoke = nullptr; // harmless // Global variables for storing search results and log synchronization std::vector found_methods; @@ -73,6 +73,111 @@ static WNDPROC g_oOriginalWndProc = nullptr; #define STATIC_FIELDS_OFFSET 0xB8 +// il2cpp patch +// Helper: pattern scan with mask ('x' == match, '?' == wildcard) +static uint8_t* find_pattern(uint8_t* base, SIZE_T size, const unsigned char* pattern, const char* mask, SIZE_T pattern_len) +{ + if (!base || !pattern || !mask || pattern_len == 0) return nullptr; + SIZE_T max_scan = (size > pattern_len) ? (size - pattern_len) : 0; + for (SIZE_T i = 0; i <= max_scan; ++i) + { + bool matched = true; + for (SIZE_T j = 0; j < pattern_len; ++j) + { + if (mask[j] == '?') continue; + if (base[i + j] != pattern[j]) + { + matched = false; + break; + } + } + if (matched) + return base + i; + } + return nullptr; +} + +// Find the real il2cpp_class_from_name implementation by scanning GameAssembly for an IDA-provided signature. +// Returns the function pointer if found, otherwise nullptr. +static il2cpp_class_from_name_prot find_il2cpp_class_from_name(HMODULE handle) +{ + if (!handle) return nullptr; + + // Get module size via PE headers + PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)handle; + if (dos->e_magic != IMAGE_DOS_SIGNATURE) return nullptr; + PIMAGE_NT_HEADERS nt = (PIMAGE_NT_HEADERS)((uint8_t*)handle + dos->e_lfanew); + if (nt->Signature != IMAGE_NT_SIGNATURE) return nullptr; + SIZE_T module_size = nt->OptionalHeader.SizeOfImage; + uint8_t* base = (uint8_t*)handle; + + // IDA signature: + // 4C 89 44 24 ? 48 89 54 24 ? 53 55 56 57 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ?? + // Build pattern and mask (use 0x00 as placeholder for wildcard bytes) + const unsigned char pattern[] = { + 0x4C, 0x89, 0x44, 0x24, 0x00, // 4C 89 44 24 ? + 0x48, 0x89, 0x54, 0x24, 0x00, // 48 89 54 24 ? + 0x53, 0x55, 0x56, 0x57, + 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, + 0x48, 0x81, 0xEC, 0x00, 0x00, 0x00, 0x00 // 48 81 EC ?? ?? ?? ?? + }; + // Mask: 'x' for fixed bytes, '?' for wildcard + const char mask[] = "xxxx?xxxx?xxxxxxxxxxxx????"; + const SIZE_T pattern_len = sizeof(pattern); + + uint8_t* found = find_pattern(base, module_size, pattern, mask, pattern_len); + if (found) + { + // The found address should point to the real function entry. Return as function pointer. + return (il2cpp_class_from_name_prot)found; + } + + // If not found with this signature, attempt a looser fallback: + // Search for the common prologue bytes "53 55 56 57 41 54 41 55 41 56 41 57" (function push regs) + const unsigned char fallback_pattern[] = { + 0x53, 0x55, 0x56, 0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57 + }; + const char fallback_mask[] = "xxxxxxxxxxxx"; + uint8_t* fallback_found = find_pattern(base, module_size, fallback_pattern, fallback_mask, sizeof(fallback_pattern)); + if (fallback_found) + { + // Walk backwards up to a small range to try to find the full expected prologue start (heuristic). + // Limit to 32 bytes back to avoid scanning too far. + for (int back = 0; back < 32; ++back) + { + uint8_t* candidate = fallback_found - back; + // Check the bytes before candidate for the 0x4C 0x89 sequence which often starts the prologue we expect. + if (candidate >= base && candidate[0] == 0x4C && candidate[1] == 0x89) + { + return (il2cpp_class_from_name_prot)candidate; + } + } + // Otherwise return the fallback_found as best-effort. + return (il2cpp_class_from_name_prot)fallback_found; + } + + return nullptr; +} + +// Find the real il2cpp_class_get_methods. +// Returns the function pointer if found, otherwise nullptr. +static il2cpp_class_get_methods_prot find_il2cpp_class_get_methods(HMODULE handle) +{ + + if (!handle) return nullptr; + return (il2cpp_class_get_methods_prot)GetProcAddress(handle, "mono_class_get_methods"); +} + +static il2cpp_method_get_name_prot find_il2cpp_method_get_name(HMODULE handle) +{ + + if (!handle) return nullptr; + return (il2cpp_method_get_name_prot)GetProcAddress(handle, "mono_property_get_set_method"); +} + +// il2cpp patch end + + /// IMGUI START extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); @@ -410,10 +515,14 @@ const Il2CppMethod* find_battleye_init(Il2CppClass* main_application) if ((unsigned(name[0]) & 0xFF) == 0xEE && (unsigned(name[1]) & 0xFF) == 0x80 && (unsigned(name[2]) & 0xFF) == 0x81) + { return method; + } // In other versions, it might be ValidateAnticheat if (strcmp(name, "ValidateAnticheat") == 0) + { return method; + } } return nullptr; } @@ -558,9 +667,33 @@ void start() il2cpp_get_root_domain = (il2cpp_get_root_domain_prot)GetProcAddress(il2cpp, "il2cpp_domain_get"); il2cpp_thread_attach = (il2cpp_thread_attach_prot)GetProcAddress(il2cpp, "il2cpp_thread_attach"); il2cpp_domain_get_assemblies = (il2cpp_domain_get_assemblies_prot)GetProcAddress(il2cpp, "il2cpp_domain_get_assemblies"); - il2cpp_class_from_name = (il2cpp_class_from_name_prot)GetProcAddress(il2cpp, "il2cpp_class_from_name"); - il2cpp_class_get_methods = (il2cpp_class_get_methods_prot)GetProcAddress(il2cpp, "il2cpp_class_get_methods"); - il2cpp_method_get_name = (il2cpp_method_get_name_prot)GetProcAddress(il2cpp, "il2cpp_method_get_name"); + il2cpp_class_from_name = find_il2cpp_class_from_name(il2cpp); + if (! il2cpp_class_from_name) + { + printf("[-] il2cpp_class_from_name was not found."); + Sleep(10000); + exit(-1); + } + printf("[+] il2cpp_class_from_name loaded."); + + il2cpp_class_get_methods = find_il2cpp_class_get_methods(il2cpp); + if (!il2cpp_class_get_methods) + { + printf("[-] il2cpp_class_get_methods was not found."); + Sleep(10000); + exit(-1); + } + printf("[+] il2cpp_class_get_methods loaded."); + + il2cpp_method_get_name = find_il2cpp_method_get_name(il2cpp); + if (!il2cpp_method_get_name) + { + printf("[-] il2cpp_method_get_name was not found."); + Sleep(10000); + exit(-1); + } + printf("[+] il2cpp_method_get_name loaded."); + il2cpp_assembly_get_image = (il2cpp_assembly_get_image_prot)GetProcAddress(il2cpp, "il2cpp_assembly_get_image"); il2cpp_image_get_name = (il2cpp_image_get_name_prot)GetProcAddress(il2cpp, "il2cpp_image_get_name"); // Load runtime invoke function @@ -593,7 +726,7 @@ void start() // 3. Thread Attach: Must be done after the core DLL (Assembly-CSharp) is loaded il2cpp_thread_attach(domain); printf("[+] Successfully attached to IL2CPP domain\n"); - + Sleep(2000); // 4. Find and apply BattleEye & UI patches // Find EFT.TarkovApplication class @@ -805,4 +938,4 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) if (reason == DLL_PROCESS_ATTACH) CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)start, nullptr, 0, nullptr); return TRUE; -} \ No newline at end of file +}