diff --git a/tools/asar-fuses-bypass/.gitignore b/tools/asar-fuses-bypass/.gitignore new file mode 100644 index 0000000..b009893 --- /dev/null +++ b/tools/asar-fuses-bypass/.gitignore @@ -0,0 +1,78 @@ +# Build directories +/build/ +/build-debug/ +/build-release/ +/out/ + +# CMake generated files +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +CTestTestfile.cmake +Makefile +install_manifest.txt + +# Compiled binaries +*.o +*.obj +*.lo +*.la +*.a +*.so +*.so.* +*.dylib +*.dll +*.exe +*.out +*.app + +# Debug files +*.pch +*.pdb +*.mod +*.map + +# Generated configuration headers +config.h +config.hpp + +# Logs +*.log + +# IDE files +# VS Code +.vscode/ +*.code-workspace + +# CLion +.idea/ + +# Visual Studio +*.user +*.suo +*.vcxproj.user +*.vcxproj.* +*.sln + +# Xcode +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 +*.xcworkspace/ +xcuserdata/ + +# OS junk +# macOS +.DS_Store + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ + +# Backup files +*~ +*.swp +*.tmp diff --git a/tools/asar-fuses-bypass/CMakeLists.txt b/tools/asar-fuses-bypass/CMakeLists.txt new file mode 100644 index 0000000..7d8e507 --- /dev/null +++ b/tools/asar-fuses-bypass/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.16) +project(asar_fuses_bypass C) + +set(CMAKE_C_STANDARD 11) + +#[[ +add_executable(asar_fuses_bypass main.c) +]] + +set(CMAKE_SHARED_LIBRARY_PREFIX "") +set(CMAKE_STATIC_LIBRARY_PREFIX "") + +add_link_options(-static -static-libgcc -static-libstdc++) + +add_library(version SHARED library.c library.def fuses.c) \ No newline at end of file diff --git a/tools/asar-fuses-bypass/fuses.c b/tools/asar-fuses-bypass/fuses.c new file mode 100644 index 0000000..fcf4a4c --- /dev/null +++ b/tools/asar-fuses-bypass/fuses.c @@ -0,0 +1,190 @@ +// +// Created by kitbyte on 30.11.2025. +// + +#include +#include +#include + +#define ENABLE_LOGGING 0 + +#ifndef _DEBUG +#undef ENABLE_LOGGING +#define ENABLE_LOGGING 0 +#endif + +#define FUSE_SENTINEL_LENGTH 32 +#define FUSE_VERSION_SUPPORTED 1 +#define FUSE_MIN_WIRE_LENGTH 5 + +#define ALIGN8(ptr, mod) ((((ULONG_PTR)(ptr) + 7) & ~7) + ((mod) * 8)) + +#if defined(_WIN64) + #define SENTINEL_PART1 0x6E64474B70374C64ULL + #define SENTINEL_PART2 0x6262503639377A4EULL + #define SENTINEL_PART3 0x58486D4B4E57516AULL + #define SENTINEL_PART4 0x5873743942615A42ULL +#else + static const DWORD SENTINEL_PARTS[8] = { + 0x70374C64, 0x6E64474B, + 0x39377A4E, 0x62625036, + 0x4E57516A, 0x58486D4B, + 0x42615A42, 0x58737439 + }; +#endif + +typedef enum { + FUSE_RUN_AS_NODE = 0, + FUSE_COOKIE_ENCRYPTION = 1, + FUSE_NODE_OPTIONS = 2, + FUSE_NODE_CLI_INSPECT = 3, + FUSE_ASAR_INTEGRITY_VALIDATION = 4, + FUSE_ONLY_LOAD_APP_FROM_ASAR = 5, + FUSE_LOAD_BROWSER_V8_SNAPSHOT = 6, + FUSE_GRANT_FILE_PROTOCOL = 7 +} ElectronFuseIndex; + +typedef enum { + FUSE_STATE_DISABLED = '0', + FUSE_STATE_ENABLED = '1', + FUSE_STATE_REMOVED = 'r' +} FuseState; + +typedef struct { + char sentinel[FUSE_SENTINEL_LENGTH]; + unsigned char version; + unsigned char wire_length; + unsigned char fuses[]; +} FuseWire; + +#if ENABLE_LOGGING + +static FILE* g_logFile = NULL; + +static void log_init(void) { + char path[MAX_PATH]; + GetModuleFileNameA(NULL, path, MAX_PATH); + char* dot = strrchr(path, '.'); + if (dot) strcpy(dot, ".log"); + else strcat(path, ". log"); + + g_logFile = fopen(path, "a"); + if (g_logFile) { + time_t now = time(NULL); + fprintf(g_logFile, "\n=== Session: %s", ctime(&now)); + fflush(g_logFile); + } +} + +static void log_close(void) { + if (g_logFile) { + fclose(g_logFile); + g_logFile = NULL; + } +} + +static void log_msg(const char* fmt, .. .) { + if (!g_logFile) return; + va_list args; + va_start(args, fmt); + vfprintf(g_logFile, fmt, args); + va_end(args); + fflush(g_logFile); +} + +#else + #define log_init() ((void)0) + #define log_close() ((void)0) + #define log_msg(...) ((void)0) +#endif + +static FuseWire* find_fuse_wire(int offset) { + char* base = (char*)GetModuleHandleA(NULL); + if (!base) return NULL; + + IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base; + if (dos->e_magic != IMAGE_DOS_SIGNATURE) return NULL; + + IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew); + if (nt->Signature != IMAGE_NT_SIGNATURE) return NULL; + + DWORD size = nt->OptionalHeader.SizeOfImage; + char* start = (char*)ALIGN8(base, 1) + offset; + char* end = (char*)ALIGN8(base + size - FUSE_SENTINEL_LENGTH, -1) - offset; + +#if defined(_WIN64) + for (DWORD64* p = (DWORD64*)start; p < (DWORD64*)end; p++) { + if (p[0] == SENTINEL_PART1 && p[1] == SENTINEL_PART2 && + p[2] == SENTINEL_PART3 && p[3] == SENTINEL_PART4) { + log_msg("[+] Sentinel at: %p\n", p); + return (FuseWire*)p; + } + } +#else + for (DWORD* p = (DWORD*)start; p < (DWORD*)end; p += 2) { + if (p[0] == SENTINEL_PARTS[0] && p[1] == SENTINEL_PARTS[1] && + p[2] == SENTINEL_PARTS[2] && p[3] == SENTINEL_PARTS[3] && + p[4] == SENTINEL_PARTS[4] && p[5] == SENTINEL_PARTS[5] && + p[6] == SENTINEL_PARTS[6] && p[7] == SENTINEL_PARTS[7]) { + log_msg("[+] Sentinel at: %p\n", p); + return (FuseWire*)p; + } + } +#endif + return NULL; +} + +static BOOL patch_fuse(unsigned char* fuse) { + DWORD prot; + if (!VirtualProtect(fuse, 1, PAGE_READWRITE, &prot)) { + log_msg("[-] VirtualProtect failed: %lu\n", GetLastError()); + return FALSE; + } + *fuse = FUSE_STATE_REMOVED; + VirtualProtect(fuse, 1, prot, &prot); + return TRUE; +} + +BOOL disable_asar_integrity(void) { + log_init(); + + FuseWire* wire = find_fuse_wire(0); + if (! wire) wire = find_fuse_wire(4); + + if (! wire) { + log_msg("[-] Fuse wire not found\n"); + log_close(); + return FALSE; + } + + log_msg("[+] Wire at %p, ver=%d, len=%d\n", wire, wire->version, wire->wire_length); + + if (wire->version != FUSE_VERSION_SUPPORTED) { + log_msg("[-] Unsupported version: %d\n", wire->version); + log_close(); + return FALSE; + } + + if (wire->wire_length < FUSE_MIN_WIRE_LENGTH) { + log_msg("[*] Wire too short, skip\n"); + log_close(); + return TRUE; + } + + unsigned char* target = &wire->fuses[FUSE_ASAR_INTEGRITY_VALIDATION]; + + if (*target == FUSE_STATE_REMOVED) { + log_msg("[*] Already patched\n"); + log_close(); + return TRUE; + } + + log_msg("[*] Patching fuse[%d]: 0x%02X -> 0x%02X\n", + FUSE_ASAR_INTEGRITY_VALIDATION, *target, FUSE_STATE_REMOVED); + + BOOL result = patch_fuse(target); + log_msg(result ? "[+] Success\n" : "[-] Failed\n"); + + log_close(); + return result; +} \ No newline at end of file diff --git a/tools/asar-fuses-bypass/library.c b/tools/asar-fuses-bypass/library.c new file mode 100644 index 0000000..ed38581 --- /dev/null +++ b/tools/asar-fuses-bypass/library.c @@ -0,0 +1,88 @@ +// +// Created by kitbyte on 30.11.2025. +// +#include + +extern BOOL disable_asar_integrity(void); + +#ifdef _WIN64 + #define WRAPPER_GENFUNC(name) \ + FARPROC orig_##name; \ + void _##name(); \ + __asm__( \ + ".global _" #name "\n" \ + "_" #name ":\n" \ + " movq orig_" #name "(%rip), %rax\n" \ + " jmp *%rax\n" \ + ); +#else + #define WRAPPER_GENFUNC(name) \ + FARPROC orig_##name; \ + __declspec(naked) void _##name() \ + { \ + asm("jmp *_orig_"#name); \ + } +#endif + +WRAPPER_GENFUNC(GetFileVersionInfoA) +WRAPPER_GENFUNC(GetFileVersionInfoByHandle) +WRAPPER_GENFUNC(GetFileVersionInfoExW) +WRAPPER_GENFUNC(GetFileVersionInfoExA) +WRAPPER_GENFUNC(GetFileVersionInfoSizeA) +WRAPPER_GENFUNC(GetFileVersionInfoSizeExA) +WRAPPER_GENFUNC(GetFileVersionInfoSizeExW) +WRAPPER_GENFUNC(GetFileVersionInfoSizeW) +WRAPPER_GENFUNC(GetFileVersionInfoW) +WRAPPER_GENFUNC(VerFindFileA) +WRAPPER_GENFUNC(VerFindFileW) +WRAPPER_GENFUNC(VerInstallFileA) +WRAPPER_GENFUNC(VerInstallFileW) +WRAPPER_GENFUNC(VerLanguageNameA) +WRAPPER_GENFUNC(VerLanguageNameW) +WRAPPER_GENFUNC(VerQueryValueA) +WRAPPER_GENFUNC(VerQueryValueW) + +#define WRAPPER_FUNC(name) orig_##name = GetProcAddress(hOriginalDll, #name); + +void SourceInit() +{ + TCHAR source[MAX_PATH]; + GetSystemDirectory(source, MAX_PATH); + strcat_s(source, sizeof source, "\\version.dll"); + HMODULE hOriginalDll = LoadLibrary(source); + + WRAPPER_FUNC(GetFileVersionInfoA); + WRAPPER_FUNC(GetFileVersionInfoByHandle); + WRAPPER_FUNC(GetFileVersionInfoExW); + WRAPPER_FUNC(GetFileVersionInfoExA); + WRAPPER_FUNC(GetFileVersionInfoSizeA); + WRAPPER_FUNC(GetFileVersionInfoSizeExW); + WRAPPER_FUNC(GetFileVersionInfoSizeExA); + WRAPPER_FUNC(GetFileVersionInfoSizeW); + WRAPPER_FUNC(GetFileVersionInfoW); + WRAPPER_FUNC(VerFindFileA); + WRAPPER_FUNC(VerFindFileW); + WRAPPER_FUNC(VerInstallFileA); + WRAPPER_FUNC(VerInstallFileW); + WRAPPER_FUNC(VerLanguageNameA); + WRAPPER_FUNC(VerLanguageNameW); + WRAPPER_FUNC(VerQueryValueA); + WRAPPER_FUNC(VerQueryValueW); +} + + +void Payload() +{ + disable_asar_integrity(); +} + +BOOL WINAPI DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + { + DisableThreadLibraryCalls(hinstDLL); + SourceInit(); + Payload(); + } + return TRUE; +} \ No newline at end of file diff --git a/tools/asar-fuses-bypass/library.def b/tools/asar-fuses-bypass/library.def new file mode 100644 index 0000000..6917120 --- /dev/null +++ b/tools/asar-fuses-bypass/library.def @@ -0,0 +1,20 @@ +LIBRARY "VERSION" +EXPORTS + +GetFileVersionInfoA = _GetFileVersionInfoA +GetFileVersionInfoByHandle = _GetFileVersionInfoByHandle +GetFileVersionInfoExA = _GetFileVersionInfoExA +GetFileVersionInfoExW = _GetFileVersionInfoExW +GetFileVersionInfoSizeA = _GetFileVersionInfoSizeA +GetFileVersionInfoSizeExA = _GetFileVersionInfoSizeExA +GetFileVersionInfoSizeExW = _GetFileVersionInfoSizeExW +GetFileVersionInfoSizeW = _GetFileVersionInfoSizeW +GetFileVersionInfoW = _GetFileVersionInfoW +VerFindFileA = _VerFindFileA +VerFindFileW = _VerFindFileW +VerInstallFileA = _VerInstallFileA +VerInstallFileW = _VerInstallFileW +VerLanguageNameA = _VerLanguageNameA +VerLanguageNameW = _VerLanguageNameW +VerQueryValueA = _VerQueryValueA +VerQueryValueW = _VerQueryValueW \ No newline at end of file