### Initialize Scanner and Orchestrate Process Scanning Source: https://context7.com/joe-desimone/patriot/llms.txt The main function initializes the scanner, acquires necessary debug privileges, parses command-line arguments (e.g., -v for verbose mode), and iterates through all running processes to initiate scanning. It outputs findings or a 'System clean' message. ```cpp int main(int argc, char** argv) { printf("== Patriot Memory Scanner ==\n"); printf("Version: %s\n\n", PATRIOT_VERSION); // Acquire SeDebugPrivilege for cross-process access if (!GetPriv(SE_DEBUG_NAME)) { printf("Error getting debug privilege, err: %d\n", GetLastError()); } // Parse arguments (-v for verbose/debug mode) for (int i = 1; i < argc; ++i) { if (0 == _stricmp(argv[i], "-v")) { logLevel = debug; } } // Enumerate and scan all processes ProcessList processList; EnumProcess(processList); for (auto it = processList.begin(); it != processList.end(); ++it) { ScanProc(*it); } // Output findings if (Findings.size() == 0) { printf("[+] System clean\n"); } else { printf("[-] Findings detected!\n\n"); for (auto& finding : Findings) { printf("Level: %s\n", finding->level.c_str()); printf("Type: %s\n", finding->type.c_str()); printf("Detail: %s\n", finding->details.c_str()); printf("PID: %d\n", finding->pid); } } } ``` -------------------------------- ### Enumerate Process Memory Regions Source: https://context7.com/joe-desimone/patriot/llms.txt Walks the virtual address space of a process using VirtualQueryEx to build a memory map and list loaded modules. Detects elevated unbacked executable regions, which may indicate shellcode. Requires a Process object and a ModuleList. ```cpp bool EnumerateMemory(Process& process, ModuleList& moduleList) { DWORD_PTR pMem = 0; bool inModule = false; auto spModuleInfo = std::make_shared(); bool bModuleHasExec = false; while (true) { MEMORY_BASIC_INFORMATION mbi = {0}; if (0 == VirtualQueryEx(process.hProcess, (void*)pMem, &mbi, sizeof(mbi))) { if (ERROR_INVALID_PARAMETER == GetLastError()) break; // End of address space return false; // Process terminated } pMem += mbi.RegionSize; // Detect elevated unbacked executable regions (potential shellcode) if (process.bElevated && mbi.Type != MEM_IMAGE && IsExecuteSet(mbi.Protect) && mbi.State == MEM_COMMIT) { auto finding = std::make_unique(); finding->pid = process.pid; finding->processName = process.processName; finding->level = "suspect"; finding->type = "elevatedUnbackedExecute"; finding->details = std::format( "Elevated unbacked execute at Base: {:016x}, Protection: {:08x}, Size: {:016x}", (DWORD64)mbi.BaseAddress, mbi.Protect, mbi.RegionSize); Findings.push_back(std::move(finding)); } // Track committed regions in memory map if (mbi.State == MEM_COMMIT) { auto pMbi = std::make_unique(); memcpy(pMbi.get(), &mbi, sizeof(mbi)); process.memoryMap.push_back(std::move(pMbi)); } // Build module list from MEM_IMAGE regions if (mbi.Type == MEM_IMAGE) { if (IsExecuteSet(mbi.Protect)) bModuleHasExec = true; spModuleInfo->moduleSize += mbi.RegionSize; // ... module path resolution via GetMappedFileName } } return true; } ``` -------------------------------- ### Validate PE Header Integrity Source: https://context7.com/joe-desimone/patriot/llms.txt Compares memory and disk PE headers to detect tampering and handles .NET 32-to-64-bit up-conversion. Requires a valid PEFile and Process context. ```cpp bool PEFile::ValidateIntegrity(PEFile& peDisk, PEFile& peMem, Process& process) { // Compare DOS headers if ((peDisk.dosHeader.e_magic != peMem.dosHeader.e_magic) || (peDisk.dosHeader.e_lfanew != peMem.dosHeader.e_lfanew)) { peMem.NewFinding("suspect", "mzHeader", "MZ Header tampered in memory"); return true; } // Handle .NET MSIL binaries that up-convert 32->64 in memory if (peDisk.bDotNet && peDisk.ntHeader.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32) && peMem.ntHeader.FileHeader.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64)) { UpConvertNtHeader(peDisk.ntHeader); } // Compare NT headers if ((peDisk.ntHeader.Signature != peMem.ntHeader.Signature) || (memcmp(&peDisk.ntHeader.FileHeader, &peMem.ntHeader.FileHeader, sizeof(peDisk.ntHeader.FileHeader)) != 0)) { peMem.NewFinding("suspect", "ntHeader", "PE Header tampered in memory"); return true; } // Validate executable regions align with PE sections for (auto& pMbi : process.memoryMap) { if (pMbi->AllocationBase != (void*)peMem.moduleInfo->moduleBase || !IsExecuteSet(pMbi->Protect)) continue; // Check region alignment with section headers // ... // Detect modified code via unshared page analysis SIZE_T unsharedSize = 0; if (UnsharedSize(process.hProcess, pMbi->BaseAddress, pMbi->RegionSize, unsharedSize) && unsharedSize > 0x1000) { peMem.NewFinding("suspect", "modifiedCode", std::format("Executable region {:016x} likely modified", (DWORD_PTR)pMbi->BaseAddress)); } } return true; } ``` -------------------------------- ### Detect Sleep Obfuscation via CONTEXT Structures Source: https://context7.com/joe-desimone/patriot/llms.txt Scans memory buffers for CONTEXT structures that indicate sleep encryption techniques. It checks if RIP points to VirtualProtect functions and if R8/R9 registers contain execute permissions. Requires a Process object, a buffer, and its size. ```cpp bool FindSuspiciousContext(Process& process, void* pBuf, SIZE_T szBuf) { if (szBuf < sizeof(CONTEXT)) return false; // Build list of VirtualProtect-class functions to match against void* functions[10]; functions[0] = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtProtectVirtualMemory"); functions[1] = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "VirtualProtect"); functions[2] = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "VirtualProtectEx"); functions[3] = GetProcAddress(GetModuleHandle(L"kernelbase.dll"), "VirtualProtect"); functions[4] = GetProcAddress(GetModuleHandle(L"kernelbase.dll"), "VirtualProtectEx"); int count = 5; // Scan buffer for CONTEXT structures for (int i = 0; i < szBuf - sizeof(CONTEXT); i += 8) { CONTEXT* pCtx = (CONTEXT*)((char*)pBuf + i); // Check for suspicious CONTEXT: // - CONTEXT_CONTROL flag set // - RIP points to VirtualProtect function // - R8 or R9 contains execute protection flags if ((pCtx->ContextFlags & CONTEXT_CONTROL) && VirtualProtectFunction(functions, count, pCtx->Rip) && (IsExecuteSet((DWORD)pCtx->R8) || IsExecuteSet((DWORD)pCtx->R9))) { DWORD64 target = (pCtx->Rcx == (DWORD64)-1) ? pCtx->Rdx : pCtx->Rcx; auto finding = std::make_unique(); finding->pid = process.pid; finding->processName = process.processName; finding->level = "suspect"; finding->type = "CONTEXT"; finding->details = std::format( "Suspicious CONTEXT structure pointing to VirtualProtect class function. " "Target: {:016x}", target); Findings.push_back(std::move(finding)); } } return false; } ``` -------------------------------- ### Define Patriot Data Structures Source: https://context7.com/joe-desimone/patriot/llms.txt Structures for tracking process metadata, loaded modules, and detected anomalies during memory scanning. ```cpp // Finding - represents a detected anomaly typedef struct Finding { DWORD pid; // Process ID where finding was detected std::wstring processName; // Process executable name SPModule moduleInfo; // Associated module (if applicable) MEMORY_BASIC_INFORMATION mbi; // Memory region info std::string type; // Detection type identifier std::string details; // Human-readable description std::string level; // Severity: "suspect", "info", etc. } Finding; // Detection types reported: // - "CONTEXT" : Suspicious CONTEXT pointing to VirtualProtect // - "elevatedUnbackedExecute" : Unbacked +X memory in elevated process // - "peIntegrity" : PE header tampering detected // - subtype "mzHeader" : DOS header mismatch // - subtype "ntHeader" : NT header mismatch // - subtype "modifiedCode" : Executable pages modified // - subtype "executableSections" : +X region not matching sections // Process - tracks per-process scanning state typedef struct Process { DWORD pid; std::wstring processName; BOOL bElevated; // Is process running elevated? HANDLE hProcess; // Process handle for memory access MemoryMap memoryMap; // All committed memory regions ModuleList moduleList; // Loaded modules with +X sections } Process; // Module - represents a loaded PE module typedef struct Module { DWORD_PTR moduleBase; // Base address in memory SIZE_T moduleSize; // Total mapped size std::wstring modulePathNt; // NT-style path (\\Device\\HarddiskVolume...) std::wstring modulePathDos; // DOS-style path (C:\...) DWORD getPathError; // Error code if path lookup failed } Module; ``` -------------------------------- ### Detect Modified Code via Unshared Pages Source: https://context7.com/joe-desimone/patriot/llms.txt Uses QueryWorkingSetEx to identify private memory pages in executable regions, which often indicates code injection or hooking. Returns true if the working set query succeeds. ```cpp bool UnsharedSize(HANDLE hProcess, void* regionBase, SIZE_T regionSize, SIZE_T& unsharedSize) { unsharedSize = 0; SIZE_T pages = regionSize / 0x1000; PSAPI_WORKING_SET_EX_INFORMATION* pInfo = (PSAPI_WORKING_SET_EX_INFORMATION*) malloc(pages * sizeof(PSAPI_WORKING_SET_EX_INFORMATION)); // Set up virtual addresses to query for (SIZE_T i = 0; i < pages; i++) { pInfo[i].VirtualAddress = (void*)((DWORD_PTR)regionBase + (i * 0x1000)); } // Query working set information if (!QueryWorkingSetEx(hProcess, pInfo, (DWORD)(pages * sizeof(PSAPI_WORKING_SET_EX_INFORMATION)))) { printf("[!] QueryWorkingSet failed: %d\n", GetLastError()); free(pInfo); return false; } // Count unshared (private) pages for (SIZE_T i = 0; i < pages; i++) { if (0 == pInfo[i].VirtualAttributes.Shared) { unsharedSize += 0x1000; } } free(pInfo); return true; } // Example: Detecting inline hooks or code patches // If a module's .text section has > 0x1000 bytes of unshared pages, // it likely has been modified (hooks, patches, or code injection) ``` -------------------------------- ### Scan Individual Process for Suspicious Memory Patterns Source: https://context7.com/joe-desimone/patriot/llms.txt The ScanProc function opens a handle to a process, checks its elevation status, enumerates memory regions and modules, validates PE integrity against disk counterparts, and scans private memory regions for suspicious CONTEXT structures. It closes the process handle upon completion. ```cpp void* ScanProc(Process& process) { // Open process with required permissions process.hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process.pid ); if (0 == process.hProcess) { return 0; } Log(debug, "[+] Scanning Pid: %d, Process: %ws\n", process.pid, process.processName.c_str()); // Check if process is elevated (important for unbacked exec detection) (void)IsProcessElevated(process.hProcess, process.bElevated); // Build module list and memory map ModuleList moduleList; EnumerateMemory(process, moduleList); // Validate PE integrity for each module (disk vs memory) for (auto& module : moduleList) { PEFile peDisk; PEFile peMem; peMem.pid = process.pid; peMem.processName = process.processName; peMem.moduleInfo = module; if (peDisk.LoadHeaderFromDisk(module->modulePathNt) && peMem.LoadHeaderFromMemory(process.hProcess, module->moduleBase)) { PEFile::ValidateIntegrity(peDisk, peMem, process); } } // Scan private RW memory for suspicious CONTEXT structures for (auto& pMbi : process.memoryMap) { if (pMbi->State != MEM_COMMIT || pMbi->Protect != PAGE_READWRITE || pMbi->RegionSize > 1024 * 1024 * 50 || pMbi->Type != MEM_PRIVATE) { continue; } void* pBuf = malloc(pMbi->RegionSize); SIZE_T stRead = 0; if (ReadProcessMemory(process.hProcess, pMbi->BaseAddress, pBuf, pMbi->RegionSize, &stRead)) { FindSuspiciousContext(process, pBuf, pMbi->RegionSize); } free(pBuf); } CloseHandle(process.hProcess); return 0; } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.