From 94f6ab5ca972783ce59b7680e3997043f48fa2c4 Mon Sep 17 00:00:00 2001 From: Mohannad Raafat <62453654+para0x0dise@users.noreply.github.com> Date: Thu, 26 Jun 2025 10:21:45 +0300 Subject: [PATCH 1/8] Filtering Processes Before Injection --- CAPE/Injection.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- CAPE/Injection.h | 3 ++- config.c | 8 +++++++- config.h | 3 +++ hook_process.c | 2 +- 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/CAPE/Injection.c b/CAPE/Injection.c index 248b0836..e7e1af43 100644 --- a/CAPE/Injection.c +++ b/CAPE/Injection.c @@ -677,7 +677,7 @@ void CreateProcessHandler(LPWSTR lpApplicationName, LPWSTR lpCommandLine, LPPROC DebugOutput("CreateProcessHandler: Injection info set for new process %d, ImageBase: 0x%p", CurrentInjectionInfo->ProcessId, CurrentInjectionInfo->ImageBase); } -PCHAR OpenProcessHandler(HANDLE ProcessHandle, DWORD Pid) +PCHAR OpenProcessHandler(HANDLE ProcessHandle, DWORD Pid, ACCESS_MASK DesiredAccess) { struct InjectionInfo *CurrentInjectionInfo; char DevicePath[MAX_PATH]; @@ -694,6 +694,7 @@ PCHAR OpenProcessHandler(HANDLE ProcessHandle, DWORD Pid) if (CurrentInjectionInfo) { CurrentInjectionInfo->ProcessHandle = ProcessHandle; + CurrentInjectionInfo->DesiredAccess = DesiredAccess; CurrentInjectionInfo->EntryPoint = (DWORD_PTR)NULL; CurrentInjectionInfo->ImageDumped = FALSE; @@ -1133,6 +1134,45 @@ void ProcessMessage(DWORD ProcessId, DWORD ThreadId) return; } + // Add injection filtering logic here to prevent false positives + if (g_config.filter_system_injection) { + ACCESS_MASK DesiredAccess = 0; + + // Get the access flags used to open this process (reuse existing CurrentInjectionInfo) + if (CurrentInjectionInfo && CurrentInjectionInfo->DesiredAccess) { + DesiredAccess = CurrentInjectionInfo->DesiredAccess; + } + + // Define malicious injection access patterns + ACCESS_MASK MALICIOUS_FLAGS = PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION; + ACCESS_MASK LEGITIMATE_FLAGS = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION | + SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_VM_READ; + + // If process was opened with only legitimate flags, don't inject + if (DesiredAccess && !(DesiredAccess & MALICIOUS_FLAGS)) { + if (DesiredAccess & LEGITIMATE_FLAGS) { + DebugOutput("ProcessMessage: INJECTION BLOCKED - Legitimate access pattern 0x%x for PID %d", DesiredAccess, ProcessId); + return; + } + } + + // Log the access pattern for analysis + if (DesiredAccess) { + BOOL bHighRisk = (DesiredAccess & MALICIOUS_FLAGS) != 0; + BOOL bAllAccess = (DesiredAccess == PROCESS_ALL_ACCESS); + + if (bHighRisk || bAllAccess) { + DebugOutput("ProcessMessage: INJECTION ALLOWED - Malicious access pattern 0x%x for PID %d (%s)", + DesiredAccess, ProcessId, bAllAccess ? "ALL_ACCESS" : "INJECTION_FLAGS"); + } else { + DebugOutput("ProcessMessage: INJECTION ALLOWED - Unknown access pattern 0x%x for PID %d", DesiredAccess, ProcessId); + } + } else { + // No access info available (process created, not opened) + DebugOutput("ProcessMessage: INJECTION ALLOWED - Process created (not opened) PID %d", ProcessId); + } + } + if (g_config.standalone) { BOOL Wow64Process; @@ -1194,7 +1234,7 @@ void ProcessMessage(DWORD ProcessId, DWORD ThreadId) swprintf_s(CommandLine, MAX_PATH, L"%s inject %u %u %s", Loader, ProcessId, ThreadId, our_dll_path_w); } #endif - } + } hook_disable(); if (CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfoEx.StartupInfo, &ProcInfo)) { diff --git a/CAPE/Injection.h b/CAPE/Injection.h index 54d4f650..23684e0a 100644 --- a/CAPE/Injection.h +++ b/CAPE/Injection.h @@ -45,6 +45,7 @@ typedef struct InjectionInfo { DWORD ProcessId; HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; DWORD InitialThreadId; DWORD_PTR ImageBase; DWORD_PTR EntryPoint; @@ -66,7 +67,7 @@ PINJECTIONINFO GetInjectionInfoFromHandle(HANDLE ProcessHandle); PINJECTIONINFO CreateInjectionInfo(DWORD ProcessId); BOOL DropInjectionInfo(HANDLE ProcessHandle); void CreateProcessHandler(LPWSTR lpApplicationName, LPWSTR lpCommandLine, LPPROCESS_INFORMATION lpProcessInformation); -PCHAR OpenProcessHandler(HANDLE ProcessHandle, DWORD Pid); +PCHAR OpenProcessHandler(HANDLE ProcessHandle, DWORD Pid, ACCESS_MASK DesiredAccess); void ResumeProcessHandler(HANDLE ProcessHandle, DWORD Pid); void MapSectionViewHandler(HANDLE ProcessHandle, HANDLE SectionHandle, PVOID BaseAddress, SIZE_T ViewSize); void UnmapSectionViewHandler(PVOID BaseAddress); diff --git a/config.c b/config.c index e0715656..85c87b1b 100644 --- a/config.c +++ b/config.c @@ -1249,11 +1249,16 @@ void parse_config_line(char* line) else if (g_config.unpacker == 2) DebugOutput("Active unpacking of payloads enabled\n"); } - else if (!stricmp(key, "injection")) { //When set to 1 this will enable CAPE’s capture of injected payloads between processes + else if (!stricmp(key, "injection")) { //When set to 1 this will enable CAPE�s capture of injected payloads between processes g_config.injection = value[0] == '1'; if (g_config.injection) DebugOutput("Capture of injected payloads enabled.\n"); } + else if (!stricmp(key, "filter-system-injection")) { //When set to 1 this will enable filtering of system injection based on process access rights to reduce false positives + g_config.filter_system_injection = value[0] == '1'; + if (g_config.filter_system_injection) + DebugOutput("System injection filtering enabled - will filter based on process access rights.\n"); + } else if (!stricmp(key, "dump-config-region")) { g_config.dump_config_region = value[0] == '1'; if (g_config.dump_config_region) @@ -1405,6 +1410,7 @@ void read_config(void) g_config.dump_limit = DUMP_LIMIT; g_config.dropped_limit = 0; g_config.injection = 1; + g_config.filter_system_injection = 1; // Enable by default to prevent false positives g_config.unpacker = 1; g_config.api_cap = 5000; g_config.api_rate_cap = 1; diff --git a/config.h b/config.h index c10ceae3..43373cc3 100644 --- a/config.h +++ b/config.h @@ -168,6 +168,9 @@ struct _g_config { int unpacker; int injection; + // filter system injection based on process access rights + int filter_system_injection; + // should we dump each process on exit/analysis timeout? int procdump; int procmemdump; diff --git a/hook_process.c b/hook_process.c index 6b342b5d..dad7c957 100644 --- a/hook_process.c +++ b/hook_process.c @@ -520,7 +520,7 @@ HOOKDEF(NTSTATUS, WINAPI, NtOpenProcess, ret = Old_NtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); if (NT_SUCCESS(ret) && g_config.injection) - ProcessName = OpenProcessHandler(*ProcessHandle, pid); + ProcessName = OpenProcessHandler(*ProcessHandle, pid, DesiredAccess); if (ProcessName) LOQ_ntstatus("process", "Phis", "ProcessHandle", ProcessHandle, "DesiredAccess", DesiredAccess, "ProcessIdentifier", pid, "ProcessName", ProcessName); From 14b39615238e3fb076bb3e606b69a6225e1b646b Mon Sep 17 00:00:00 2001 From: Mohannad Raafat <62453654+para0x0dise@users.noreply.github.com> Date: Sun, 6 Jul 2025 00:18:08 +0300 Subject: [PATCH 2/8] Testing Getting Blocked Processes By name --- CAPE/Injection.c | 106 +++++++++++++++++++++++++++++++---------------- CAPE/Injection.h | 2 +- 2 files changed, 72 insertions(+), 36 deletions(-) diff --git a/CAPE/Injection.c b/CAPE/Injection.c index e7e1af43..18db568e 100644 --- a/CAPE/Injection.c +++ b/CAPE/Injection.c @@ -53,6 +53,7 @@ PINJECTIONINFO GetInjectionInfo(DWORD ProcessId) DWORD CurrentProcessId; PINJECTIONINFO CurrentInjectionInfo = InjectionInfoList; + while (CurrentInjectionInfo) { CurrentProcessId = CurrentInjectionInfo->ProcessId; @@ -1128,49 +1129,84 @@ void ProcessMessage(DWORD ProcessId, DWORD ThreadId) return; } - if (g_config.single_process) - { - DebugOutput("ProcessMessage: Skipping monitoring process %d as single-process mode set.", ProcessId); - return; - } - - // Add injection filtering logic here to prevent false positives + // Injection filtering logic based on process name and desired access if (g_config.filter_system_injection) { - ACCESS_MASK DesiredAccess = 0; - - // Get the access flags used to open this process (reuse existing CurrentInjectionInfo) - if (CurrentInjectionInfo && CurrentInjectionInfo->DesiredAccess) { - DesiredAccess = CurrentInjectionInfo->DesiredAccess; + // Get process name for filtering + char processName[MAX_PATH] = {0}; + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, ProcessId); + if (hProcess) { + char processPath[MAX_PATH]; + if (GetProcessImageFileName(hProcess, processPath, MAX_PATH)) { + char *fileName = strrchr(processPath, '\\'); + if (fileName) { + strncpy(processName, fileName + 1, MAX_PATH - 1); + } + } + CloseHandle(hProcess); } - // Define malicious injection access patterns - ACCESS_MASK MALICIOUS_FLAGS = PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION; - ACCESS_MASK LEGITIMATE_FLAGS = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION | - SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_VM_READ; + // Process name filtering - exclude system processes + const char *systemProcesses[] = { + "services.exe", "svchost.exe", "WmiPrvSE.exe", "wininit.exe", + "winlogon.exe", "lsass.exe", "csrss.exe", "smss.exe", + "explorer.exe", "dwm.exe", "conhost.exe", "audiodg.exe" + }; - // If process was opened with only legitimate flags, don't inject - if (DesiredAccess && !(DesiredAccess & MALICIOUS_FLAGS)) { - if (DesiredAccess & LEGITIMATE_FLAGS) { - DebugOutput("ProcessMessage: INJECTION BLOCKED - Legitimate access pattern 0x%x for PID %d", DesiredAccess, ProcessId); - return; + for (int i = 0; i < sizeof(systemProcesses) / sizeof(systemProcesses[0]); i++) { + if (!_stricmp(processName, systemProcesses[i])) { + DebugOutput("ProcessMessage: INJECTION BLOCKED - System process: %s (PID %d)", processName, ProcessId); + if (CurrentInjectionInfo) + DebugOutput("ProcessMessage: processhandle: 0x%x", CurrentInjectionInfo->ProcessHandle); + else + DebugOutput("ProcessMessage: processhandle: not set for process %s (PID %d)", processName, ProcessId); + + // if (CurrentInjectionInfo->DesiredAccess) + // DebugOutput("ProcessMessage: DesiredAccess: 0x%x", CurrentInjectionInfo->DesiredAccess); + // else + // DebugOutput("ProcessMessage: DesiredAccess: not set for process %s (PID %d)", processName, ProcessId); + // return; } } - // Log the access pattern for analysis - if (DesiredAccess) { - BOOL bHighRisk = (DesiredAccess & MALICIOUS_FLAGS) != 0; - BOOL bAllAccess = (DesiredAccess == PROCESS_ALL_ACCESS); + // // Desired access filtering + // if (CurrentInjectionInfo && CurrentInjectionInfo->DesiredAccess) { + // ACCESS_MASK DesiredAccess = CurrentInjectionInfo->DesiredAccess; - if (bHighRisk || bAllAccess) { - DebugOutput("ProcessMessage: INJECTION ALLOWED - Malicious access pattern 0x%x for PID %d (%s)", - DesiredAccess, ProcessId, bAllAccess ? "ALL_ACCESS" : "INJECTION_FLAGS"); - } else { - DebugOutput("ProcessMessage: INJECTION ALLOWED - Unknown access pattern 0x%x for PID %d", DesiredAccess, ProcessId); - } - } else { - // No access info available (process created, not opened) - DebugOutput("ProcessMessage: INJECTION ALLOWED - Process created (not opened) PID %d", ProcessId); - } + // // Define malicious injection access patterns + // ACCESS_MASK MALICIOUS_FLAGS = PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION; + // ACCESS_MASK LEGITIMATE_FLAGS = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION | + // SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_VM_READ; + + // // If process was opened with only legitimate flags, don't inject + // if (!(DesiredAccess & MALICIOUS_FLAGS)) { + // if (DesiredAccess & LEGITIMATE_FLAGS) { + // DebugOutput("ProcessMessage: INJECTION BLOCKED - Legitimate access pattern 0x%x for %s (PID %d)", + // DesiredAccess, processName, ProcessId); + // return; + // } + // } + + // // Log the access pattern for analysis + // BOOL bHighRisk = (DesiredAccess & MALICIOUS_FLAGS) != 0; + // BOOL bAllAccess = (DesiredAccess == PROCESS_ALL_ACCESS); + + // if (bHighRisk || bAllAccess) { + // DebugOutput("ProcessMessage: INJECTION ALLOWED - Malicious access pattern 0x%x for %s (PID %d) (%s)", + // DesiredAccess, processName, ProcessId, bAllAccess ? "ALL_ACCESS" : "INJECTION_FLAGS"); + // } else { + // DebugOutput("ProcessMessage: INJECTION ALLOWED - Unknown access pattern 0x%x for %s (PID %d)", + // DesiredAccess, processName, ProcessId); + // } + // } else { + // // No access info available (process created, not opened) + // DebugOutput("ProcessMessage: INJECTION ALLOWED - Process created (not opened) %s (PID %d)", processName, ProcessId); + // } + } + + if (g_config.single_process) + { + DebugOutput("ProcessMessage: Skipping monitoring process %d as single-process mode set.", ProcessId); + return; } if (g_config.standalone) diff --git a/CAPE/Injection.h b/CAPE/Injection.h index 23684e0a..ddd74397 100644 --- a/CAPE/Injection.h +++ b/CAPE/Injection.h @@ -45,7 +45,6 @@ typedef struct InjectionInfo { DWORD ProcessId; HANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; DWORD InitialThreadId; DWORD_PTR ImageBase; DWORD_PTR EntryPoint; @@ -55,6 +54,7 @@ typedef struct InjectionInfo unsigned int BufferSizeOfImage; HANDLE SectionHandle; BOOL DontMonitor; + ACCESS_MASK DesiredAccess; // struct InjectionSectionView *SectionViewList; struct InjectionInfo *NextInjectionInfo; } INJECTIONINFO, *PINJECTIONINFO; From d81c6e4c14634ccb129e7572c49f9455cb2c9b7a Mon Sep 17 00:00:00 2001 From: Mohannad Raafat <62453654+para0x0dise@users.noreply.github.com> Date: Sun, 6 Jul 2025 00:18:28 +0300 Subject: [PATCH 3/8] Adding Filter Injection Flag --- config.c | 6 +++--- config.h | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/config.c b/config.c index 85c87b1b..23455ea8 100644 --- a/config.c +++ b/config.c @@ -1254,10 +1254,10 @@ void parse_config_line(char* line) if (g_config.injection) DebugOutput("Capture of injected payloads enabled.\n"); } - else if (!stricmp(key, "filter-system-injection")) { //When set to 1 this will enable filtering of system injection based on process access rights to reduce false positives + else if (!stricmp(key, "filter-system-injection")) { //When set to 1 this will enable filtering of system injection based on process names and access patterns g_config.filter_system_injection = value[0] == '1'; if (g_config.filter_system_injection) - DebugOutput("System injection filtering enabled - will filter based on process access rights.\n"); + DebugOutput("System injection filtering enabled.\n"); } else if (!stricmp(key, "dump-config-region")) { g_config.dump_config_region = value[0] == '1'; @@ -1410,7 +1410,7 @@ void read_config(void) g_config.dump_limit = DUMP_LIMIT; g_config.dropped_limit = 0; g_config.injection = 1; - g_config.filter_system_injection = 1; // Enable by default to prevent false positives + g_config.filter_system_injection = 1; g_config.unpacker = 1; g_config.api_cap = 5000; g_config.api_rate_cap = 1; diff --git a/config.h b/config.h index 43373cc3..815cb007 100644 --- a/config.h +++ b/config.h @@ -167,8 +167,6 @@ struct _g_config { // behavioural payload extraction options int unpacker; int injection; - - // filter system injection based on process access rights int filter_system_injection; // should we dump each process on exit/analysis timeout? From 79bdc5e59096cf7dc651eda1d2caff5e390441a8 Mon Sep 17 00:00:00 2001 From: Mohannad Raafat <62453654+para0x0dise@users.noreply.github.com> Date: Sun, 6 Jul 2025 00:20:16 +0300 Subject: [PATCH 4/8] Revert "Adding Filter Injection Flag" This reverts commit d81c6e4c14634ccb129e7572c49f9455cb2c9b7a. --- config.c | 6 +++--- config.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config.c b/config.c index 23455ea8..85c87b1b 100644 --- a/config.c +++ b/config.c @@ -1254,10 +1254,10 @@ void parse_config_line(char* line) if (g_config.injection) DebugOutput("Capture of injected payloads enabled.\n"); } - else if (!stricmp(key, "filter-system-injection")) { //When set to 1 this will enable filtering of system injection based on process names and access patterns + else if (!stricmp(key, "filter-system-injection")) { //When set to 1 this will enable filtering of system injection based on process access rights to reduce false positives g_config.filter_system_injection = value[0] == '1'; if (g_config.filter_system_injection) - DebugOutput("System injection filtering enabled.\n"); + DebugOutput("System injection filtering enabled - will filter based on process access rights.\n"); } else if (!stricmp(key, "dump-config-region")) { g_config.dump_config_region = value[0] == '1'; @@ -1410,7 +1410,7 @@ void read_config(void) g_config.dump_limit = DUMP_LIMIT; g_config.dropped_limit = 0; g_config.injection = 1; - g_config.filter_system_injection = 1; + g_config.filter_system_injection = 1; // Enable by default to prevent false positives g_config.unpacker = 1; g_config.api_cap = 5000; g_config.api_rate_cap = 1; diff --git a/config.h b/config.h index 815cb007..43373cc3 100644 --- a/config.h +++ b/config.h @@ -167,6 +167,8 @@ struct _g_config { // behavioural payload extraction options int unpacker; int injection; + + // filter system injection based on process access rights int filter_system_injection; // should we dump each process on exit/analysis timeout? From 331ffb04bce054ab80bc181bea107752cb98af69 Mon Sep 17 00:00:00 2001 From: Mohannad Raafat <62453654+para0x0dise@users.noreply.github.com> Date: Sun, 6 Jul 2025 00:20:23 +0300 Subject: [PATCH 5/8] Revert "Testing Getting Blocked Processes By name" This reverts commit 14b39615238e3fb076bb3e606b69a6225e1b646b. --- CAPE/Injection.c | 106 ++++++++++++++++------------------------------- CAPE/Injection.h | 2 +- 2 files changed, 36 insertions(+), 72 deletions(-) diff --git a/CAPE/Injection.c b/CAPE/Injection.c index 18db568e..e7e1af43 100644 --- a/CAPE/Injection.c +++ b/CAPE/Injection.c @@ -53,7 +53,6 @@ PINJECTIONINFO GetInjectionInfo(DWORD ProcessId) DWORD CurrentProcessId; PINJECTIONINFO CurrentInjectionInfo = InjectionInfoList; - while (CurrentInjectionInfo) { CurrentProcessId = CurrentInjectionInfo->ProcessId; @@ -1129,84 +1128,49 @@ void ProcessMessage(DWORD ProcessId, DWORD ThreadId) return; } - // Injection filtering logic based on process name and desired access + if (g_config.single_process) + { + DebugOutput("ProcessMessage: Skipping monitoring process %d as single-process mode set.", ProcessId); + return; + } + + // Add injection filtering logic here to prevent false positives if (g_config.filter_system_injection) { - // Get process name for filtering - char processName[MAX_PATH] = {0}; - HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, ProcessId); - if (hProcess) { - char processPath[MAX_PATH]; - if (GetProcessImageFileName(hProcess, processPath, MAX_PATH)) { - char *fileName = strrchr(processPath, '\\'); - if (fileName) { - strncpy(processName, fileName + 1, MAX_PATH - 1); - } - } - CloseHandle(hProcess); + ACCESS_MASK DesiredAccess = 0; + + // Get the access flags used to open this process (reuse existing CurrentInjectionInfo) + if (CurrentInjectionInfo && CurrentInjectionInfo->DesiredAccess) { + DesiredAccess = CurrentInjectionInfo->DesiredAccess; } - // Process name filtering - exclude system processes - const char *systemProcesses[] = { - "services.exe", "svchost.exe", "WmiPrvSE.exe", "wininit.exe", - "winlogon.exe", "lsass.exe", "csrss.exe", "smss.exe", - "explorer.exe", "dwm.exe", "conhost.exe", "audiodg.exe" - }; + // Define malicious injection access patterns + ACCESS_MASK MALICIOUS_FLAGS = PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION; + ACCESS_MASK LEGITIMATE_FLAGS = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION | + SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_VM_READ; - for (int i = 0; i < sizeof(systemProcesses) / sizeof(systemProcesses[0]); i++) { - if (!_stricmp(processName, systemProcesses[i])) { - DebugOutput("ProcessMessage: INJECTION BLOCKED - System process: %s (PID %d)", processName, ProcessId); - if (CurrentInjectionInfo) - DebugOutput("ProcessMessage: processhandle: 0x%x", CurrentInjectionInfo->ProcessHandle); - else - DebugOutput("ProcessMessage: processhandle: not set for process %s (PID %d)", processName, ProcessId); - - // if (CurrentInjectionInfo->DesiredAccess) - // DebugOutput("ProcessMessage: DesiredAccess: 0x%x", CurrentInjectionInfo->DesiredAccess); - // else - // DebugOutput("ProcessMessage: DesiredAccess: not set for process %s (PID %d)", processName, ProcessId); - // return; + // If process was opened with only legitimate flags, don't inject + if (DesiredAccess && !(DesiredAccess & MALICIOUS_FLAGS)) { + if (DesiredAccess & LEGITIMATE_FLAGS) { + DebugOutput("ProcessMessage: INJECTION BLOCKED - Legitimate access pattern 0x%x for PID %d", DesiredAccess, ProcessId); + return; } } - // // Desired access filtering - // if (CurrentInjectionInfo && CurrentInjectionInfo->DesiredAccess) { - // ACCESS_MASK DesiredAccess = CurrentInjectionInfo->DesiredAccess; - - // // Define malicious injection access patterns - // ACCESS_MASK MALICIOUS_FLAGS = PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION; - // ACCESS_MASK LEGITIMATE_FLAGS = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION | - // SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_VM_READ; - - // // If process was opened with only legitimate flags, don't inject - // if (!(DesiredAccess & MALICIOUS_FLAGS)) { - // if (DesiredAccess & LEGITIMATE_FLAGS) { - // DebugOutput("ProcessMessage: INJECTION BLOCKED - Legitimate access pattern 0x%x for %s (PID %d)", - // DesiredAccess, processName, ProcessId); - // return; - // } - // } + // Log the access pattern for analysis + if (DesiredAccess) { + BOOL bHighRisk = (DesiredAccess & MALICIOUS_FLAGS) != 0; + BOOL bAllAccess = (DesiredAccess == PROCESS_ALL_ACCESS); - // // Log the access pattern for analysis - // BOOL bHighRisk = (DesiredAccess & MALICIOUS_FLAGS) != 0; - // BOOL bAllAccess = (DesiredAccess == PROCESS_ALL_ACCESS); - - // if (bHighRisk || bAllAccess) { - // DebugOutput("ProcessMessage: INJECTION ALLOWED - Malicious access pattern 0x%x for %s (PID %d) (%s)", - // DesiredAccess, processName, ProcessId, bAllAccess ? "ALL_ACCESS" : "INJECTION_FLAGS"); - // } else { - // DebugOutput("ProcessMessage: INJECTION ALLOWED - Unknown access pattern 0x%x for %s (PID %d)", - // DesiredAccess, processName, ProcessId); - // } - // } else { - // // No access info available (process created, not opened) - // DebugOutput("ProcessMessage: INJECTION ALLOWED - Process created (not opened) %s (PID %d)", processName, ProcessId); - // } - } - - if (g_config.single_process) - { - DebugOutput("ProcessMessage: Skipping monitoring process %d as single-process mode set.", ProcessId); - return; + if (bHighRisk || bAllAccess) { + DebugOutput("ProcessMessage: INJECTION ALLOWED - Malicious access pattern 0x%x for PID %d (%s)", + DesiredAccess, ProcessId, bAllAccess ? "ALL_ACCESS" : "INJECTION_FLAGS"); + } else { + DebugOutput("ProcessMessage: INJECTION ALLOWED - Unknown access pattern 0x%x for PID %d", DesiredAccess, ProcessId); + } + } else { + // No access info available (process created, not opened) + DebugOutput("ProcessMessage: INJECTION ALLOWED - Process created (not opened) PID %d", ProcessId); + } } if (g_config.standalone) diff --git a/CAPE/Injection.h b/CAPE/Injection.h index ddd74397..23684e0a 100644 --- a/CAPE/Injection.h +++ b/CAPE/Injection.h @@ -45,6 +45,7 @@ typedef struct InjectionInfo { DWORD ProcessId; HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; DWORD InitialThreadId; DWORD_PTR ImageBase; DWORD_PTR EntryPoint; @@ -54,7 +55,6 @@ typedef struct InjectionInfo unsigned int BufferSizeOfImage; HANDLE SectionHandle; BOOL DontMonitor; - ACCESS_MASK DesiredAccess; // struct InjectionSectionView *SectionViewList; struct InjectionInfo *NextInjectionInfo; } INJECTIONINFO, *PINJECTIONINFO; From 3280f4e897fc4b30ccf7b584d95f35bcf85632d0 Mon Sep 17 00:00:00 2001 From: Mohannad Raafat <62453654+para0x0dise@users.noreply.github.com> Date: Wed, 9 Jul 2025 05:51:00 +0300 Subject: [PATCH 6/8] Filtering EXPLORER opened with specific access masks by MSOffice APPs --- CAPE/Injection.c | 77 ++++++++++++++++++++++-------------------------- CAPE/Injection.h | 2 +- config.c | 11 ++++--- config.h | 4 +-- hook_process.c | 6 ++++ hook_window.c | 39 ++++++++++++++++++------ 6 files changed, 81 insertions(+), 58 deletions(-) diff --git a/CAPE/Injection.c b/CAPE/Injection.c index e7e1af43..f6631528 100644 --- a/CAPE/Injection.c +++ b/CAPE/Injection.c @@ -31,7 +31,7 @@ along with this program.If not, see . #include "Shlwapi.h" #pragma comment(lib, "shlwapi.lib") -#pragma warning(push ) +#pragma warning(push) #pragma warning(disable : 4996) extern _NtMapViewOfSection pNtMapViewOfSection; @@ -46,6 +46,37 @@ extern char *our_process_name; extern void hook_disable(); extern void hook_enable(); +BOOL is_system_process(DWORD ProcessId) +{ + char processName[MAX_PATH] = {0}; + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, ProcessId); + if (hProcess) { + char processPath[MAX_PATH]; + if (GetProcessImageFileName(hProcess, processPath, MAX_PATH)) { + char *fileName = strrchr(processPath, '\\'); + if (fileName) { + strncpy(processName, fileName + 1, MAX_PATH - 1); + } + } + CloseHandle(hProcess); + } + + // Process name filtering - exclude system processes + const char *systemProcesses[] = { + "services.exe", "svchost.exe", "WmiPrvSE.exe", "wininit.exe", + "winlogon.exe", "lsass.exe", "csrss.exe", "smss.exe", + "explorer.exe", "dwm.exe", "conhost.exe", "audiodg.exe" + }; + + for (int i = 0; i < sizeof(systemProcesses) / sizeof(systemProcesses[0]); i++) { + if (!_stricmp(processName, systemProcesses[i])) { + return TRUE; + } + } + + return FALSE; +} + //************************************************************************************** PINJECTIONINFO GetInjectionInfo(DWORD ProcessId) //************************************************************************************** @@ -53,6 +84,7 @@ PINJECTIONINFO GetInjectionInfo(DWORD ProcessId) DWORD CurrentProcessId; PINJECTIONINFO CurrentInjectionInfo = InjectionInfoList; + while (CurrentInjectionInfo) { CurrentProcessId = CurrentInjectionInfo->ProcessId; @@ -685,6 +717,7 @@ PCHAR OpenProcessHandler(HANDLE ProcessHandle, DWORD Pid, ACCESS_MASK DesiredAcc if (Pid == GetCurrentProcessId()) return NULL; + CurrentInjectionInfo = GetInjectionInfo(Pid); @@ -694,7 +727,6 @@ PCHAR OpenProcessHandler(HANDLE ProcessHandle, DWORD Pid, ACCESS_MASK DesiredAcc if (CurrentInjectionInfo) { CurrentInjectionInfo->ProcessHandle = ProcessHandle; - CurrentInjectionInfo->DesiredAccess = DesiredAccess; CurrentInjectionInfo->EntryPoint = (DWORD_PTR)NULL; CurrentInjectionInfo->ImageDumped = FALSE; @@ -1127,52 +1159,13 @@ void ProcessMessage(DWORD ProcessId, DWORD ThreadId) DebugOutput("ProcessMessage: Skipping monitoring process %d", ProcessId); return; } - + if (g_config.single_process) { DebugOutput("ProcessMessage: Skipping monitoring process %d as single-process mode set.", ProcessId); return; } - // Add injection filtering logic here to prevent false positives - if (g_config.filter_system_injection) { - ACCESS_MASK DesiredAccess = 0; - - // Get the access flags used to open this process (reuse existing CurrentInjectionInfo) - if (CurrentInjectionInfo && CurrentInjectionInfo->DesiredAccess) { - DesiredAccess = CurrentInjectionInfo->DesiredAccess; - } - - // Define malicious injection access patterns - ACCESS_MASK MALICIOUS_FLAGS = PROCESS_CREATE_THREAD | PROCESS_VM_WRITE | PROCESS_VM_OPERATION; - ACCESS_MASK LEGITIMATE_FLAGS = PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION | - SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_VM_READ; - - // If process was opened with only legitimate flags, don't inject - if (DesiredAccess && !(DesiredAccess & MALICIOUS_FLAGS)) { - if (DesiredAccess & LEGITIMATE_FLAGS) { - DebugOutput("ProcessMessage: INJECTION BLOCKED - Legitimate access pattern 0x%x for PID %d", DesiredAccess, ProcessId); - return; - } - } - - // Log the access pattern for analysis - if (DesiredAccess) { - BOOL bHighRisk = (DesiredAccess & MALICIOUS_FLAGS) != 0; - BOOL bAllAccess = (DesiredAccess == PROCESS_ALL_ACCESS); - - if (bHighRisk || bAllAccess) { - DebugOutput("ProcessMessage: INJECTION ALLOWED - Malicious access pattern 0x%x for PID %d (%s)", - DesiredAccess, ProcessId, bAllAccess ? "ALL_ACCESS" : "INJECTION_FLAGS"); - } else { - DebugOutput("ProcessMessage: INJECTION ALLOWED - Unknown access pattern 0x%x for PID %d", DesiredAccess, ProcessId); - } - } else { - // No access info available (process created, not opened) - DebugOutput("ProcessMessage: INJECTION ALLOWED - Process created (not opened) PID %d", ProcessId); - } - } - if (g_config.standalone) { BOOL Wow64Process; diff --git a/CAPE/Injection.h b/CAPE/Injection.h index 23684e0a..03055511 100644 --- a/CAPE/Injection.h +++ b/CAPE/Injection.h @@ -45,7 +45,6 @@ typedef struct InjectionInfo { DWORD ProcessId; HANDLE ProcessHandle; - ACCESS_MASK DesiredAccess; DWORD InitialThreadId; DWORD_PTR ImageBase; DWORD_PTR EntryPoint; @@ -73,3 +72,4 @@ void MapSectionViewHandler(HANDLE ProcessHandle, HANDLE SectionHandle, PVOID Bas void UnmapSectionViewHandler(PVOID BaseAddress); void WriteMemoryHandler(HANDLE ProcessHandle, LPVOID BaseAddress, LPCVOID Buffer, SIZE_T NumberOfBytesWritten); void TerminateHandler(); +BOOL is_system_process(DWORD ProcessId); diff --git a/config.c b/config.c index 85c87b1b..63294ef6 100644 --- a/config.c +++ b/config.c @@ -1254,10 +1254,10 @@ void parse_config_line(char* line) if (g_config.injection) DebugOutput("Capture of injected payloads enabled.\n"); } - else if (!stricmp(key, "filter-system-injection")) { //When set to 1 this will enable filtering of system injection based on process access rights to reduce false positives + else if (!stricmp(key, "filter-system-injection")) { //When set to 1 this will enable filtering of system injection based on process names and access patterns g_config.filter_system_injection = value[0] == '1'; if (g_config.filter_system_injection) - DebugOutput("System injection filtering enabled - will filter based on process access rights.\n"); + DebugOutput("System injection filtering enabled.\n"); } else if (!stricmp(key, "dump-config-region")) { g_config.dump_config_region = value[0] == '1'; @@ -1410,7 +1410,10 @@ void read_config(void) g_config.dump_limit = DUMP_LIMIT; g_config.dropped_limit = 0; g_config.injection = 1; - g_config.filter_system_injection = 1; // Enable by default to prevent false positives + + g_config.filter_system_injection = 1; + g_config.filter_system_safe_process_pid = 0; + g_config.unpacker = 1; g_config.api_cap = 5000; g_config.api_rate_cap = 1; @@ -1681,4 +1684,4 @@ void read_config(void) } return; -} +} \ No newline at end of file diff --git a/config.h b/config.h index 43373cc3..9e11d85a 100644 --- a/config.h +++ b/config.h @@ -168,9 +168,9 @@ struct _g_config { int unpacker; int injection; - // filter system injection based on process access rights int filter_system_injection; - + int filter_system_safe_process_pid; + // should we dump each process on exit/analysis timeout? int procdump; int procmemdump; diff --git a/hook_process.c b/hook_process.c index dad7c957..fb679350 100644 --- a/hook_process.c +++ b/hook_process.c @@ -519,13 +519,19 @@ HOOKDEF(NTSTATUS, WINAPI, NtOpenProcess, ret = Old_NtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); + if (is_system_process(pid)) + g_config.filter_system_safe_process_pid = pid; + + if (NT_SUCCESS(ret) && g_config.injection) ProcessName = OpenProcessHandler(*ProcessHandle, pid, DesiredAccess); if (ProcessName) LOQ_ntstatus("process", "Phis", "ProcessHandle", ProcessHandle, "DesiredAccess", DesiredAccess, "ProcessIdentifier", pid, "ProcessName", ProcessName); + else LOQ_ntstatus("process", "Phi", "ProcessHandle", ProcessHandle, "DesiredAccess", DesiredAccess, "ProcessIdentifier", pid); + return ret; } diff --git a/hook_window.c b/hook_window.c index 8bf7b296..f528c4e1 100644 --- a/hook_window.c +++ b/hook_window.c @@ -23,10 +23,13 @@ along with this program. If not, see . #include "pipe.h" #include "log.h" + #define StringAtomSize 0x100 +extern void DebugOutput(_In_ LPCTSTR lpOutputString, ...); extern void ProcessMessage(DWORD ProcessId, DWORD ThreadId); extern void DumpSectionViewsForPid(DWORD Pid); +extern BOOL is_system_process(DWORD ProcessId); typedef DWORD (WINAPI * __GetWindowThreadProcessId)( __in HWND hWnd, @@ -189,6 +192,7 @@ HOOKDEF(BOOL, WINAPI, PostMessageW, return ret; } + HOOKDEF(BOOL, WINAPI, PostThreadMessageA, _In_ DWORD idThread, _In_ UINT Msg, @@ -198,17 +202,22 @@ HOOKDEF(BOOL, WINAPI, PostThreadMessageA, BOOL ret = Old_PostThreadMessageA(idThread, Msg, wParam, lParam); DWORD pid = GetThreadProcessId(idThread); + + LOQ_bool("windows", "iii", "ProcessId", pid, "ThreadId", idThread, "Message", Msg); if (pid && pid != GetCurrentProcessId()) { DumpSectionViewsForPid(pid); - ProcessMessage(pid, 0); + // ProcessMessage(pid, 0); } - - LOQ_bool("windows", "iii", "ProcessId", pid, "ThreadId", idThread, "Message", Msg); + if (g_config.filter_system_injection && is_system_process(pid) && pid == g_config.filter_system_safe_process_pid) { + return FALSE; + } + ProcessMessage(pid, 0); return ret; } + HOOKDEF(BOOL, WINAPI, PostThreadMessageW, _In_ DWORD idThread, _In_ UINT Msg, @@ -218,13 +227,17 @@ HOOKDEF(BOOL, WINAPI, PostThreadMessageW, BOOL ret = Old_PostThreadMessageW(idThread, Msg, wParam, lParam); DWORD pid = GetThreadProcessId(idThread); + LOQ_bool("windows", "iii", "ProcessId", pid, "ThreadId", idThread, "Message", Msg); + if (pid && pid != GetCurrentProcessId()) { DumpSectionViewsForPid(pid); - ProcessMessage(pid, 0); + // ProcessMessage(pid, 0); } - - LOQ_bool("windows", "iii", "ProcessId", pid, "ThreadId", idThread, "Message", Msg); + if (g_config.filter_system_injection && is_system_process(pid) && pid == g_config.filter_system_safe_process_pid) { + return FALSE; + } + ProcessMessage(pid, 0); return ret; } @@ -274,8 +287,12 @@ HOOKDEF(BOOL, WINAPI, SendNotifyMessageA, our_GetWindowThreadProcessId(hWnd, &pid); if (pid != GetCurrentProcessId()) { DumpSectionViewsForPid(pid); - ProcessMessage(pid, 0); + //ProcessMessage(pid, 0); + } + if (g_config.filter_system_injection && is_system_process(pid) && pid == g_config.filter_system_safe_process_pid) { + return FALSE; } + ProcessMessage(pid, 0); } set_lasterrors(&lasterror); @@ -301,8 +318,12 @@ HOOKDEF(BOOL, WINAPI, SendNotifyMessageW, our_GetWindowThreadProcessId(hWnd, &pid); if (pid != GetCurrentProcessId()) { DumpSectionViewsForPid(pid); - ProcessMessage(pid, 0); + // ProcessMessage(pid, 0); + } + if (g_config.filter_system_injection && is_system_process(pid) && pid == g_config.filter_system_safe_process_pid) { + return FALSE; } + ProcessMessage(pid, 0); } set_lasterrors(&lasterror); @@ -524,4 +545,4 @@ HOOKDEF(int, WINAPI, MessageBoxTimeoutW, else LOQ_zero("windows", "uui", "Text", lpszText, "Caption", lpszCaption, "Timeout", dwTimeout); return ret; -} +} \ No newline at end of file From 8cfc2d33a449ae318f87c9becaad9ef95f0305b2 Mon Sep 17 00:00:00 2001 From: Mohannad Raafat <62453654+para0x0dise@users.noreply.github.com> Date: Wed, 9 Jul 2025 12:34:10 +0300 Subject: [PATCH 7/8] Update hook_process.c --- hook_process.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/hook_process.c b/hook_process.c index fb679350..45d45b7f 100644 --- a/hook_process.c +++ b/hook_process.c @@ -518,9 +518,18 @@ HOOKDEF(NTSTATUS, WINAPI, NtOpenProcess, } ret = Old_NtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); - - if (is_system_process(pid)) - g_config.filter_system_safe_process_pid = pid; + + + if (g_config.filter_system_injection) { + ACCESS_MASK legitimate_flags = PROCESS_QUERY_INFORMATION | + PROCESS_QUERY_LIMITED_INFORMATION | + PROCESS_VM_READ | PROCESS_DUP_HANDLE | + SYNCHRONIZE; + + if ((DesiredAccess & ~legitimate_flags) == 0 && is_system_process(pid)) { + g_config.filter_system_safe_process_pid = pid; + } + } if (NT_SUCCESS(ret) && g_config.injection) From eb337d6c79f8f5af08b4e0022d403ed8f3d85216 Mon Sep 17 00:00:00 2001 From: Mohannad Raafat <62453654+para0x0dise@users.noreply.github.com> Date: Wed, 9 Jul 2025 13:23:31 +0300 Subject: [PATCH 8/8] Update hook_window.c --- hook_window.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hook_window.c b/hook_window.c index f528c4e1..db07884d 100644 --- a/hook_window.c +++ b/hook_window.c @@ -29,7 +29,6 @@ along with this program. If not, see . extern void DebugOutput(_In_ LPCTSTR lpOutputString, ...); extern void ProcessMessage(DWORD ProcessId, DWORD ThreadId); extern void DumpSectionViewsForPid(DWORD Pid); -extern BOOL is_system_process(DWORD ProcessId); typedef DWORD (WINAPI * __GetWindowThreadProcessId)( __in HWND hWnd, @@ -209,7 +208,7 @@ HOOKDEF(BOOL, WINAPI, PostThreadMessageA, DumpSectionViewsForPid(pid); // ProcessMessage(pid, 0); } - if (g_config.filter_system_injection && is_system_process(pid) && pid == g_config.filter_system_safe_process_pid) { + if (g_config.filter_system_injection && pid == g_config.filter_system_safe_process_pid) { return FALSE; } ProcessMessage(pid, 0); @@ -234,7 +233,7 @@ HOOKDEF(BOOL, WINAPI, PostThreadMessageW, DumpSectionViewsForPid(pid); // ProcessMessage(pid, 0); } - if (g_config.filter_system_injection && is_system_process(pid) && pid == g_config.filter_system_safe_process_pid) { + if (g_config.filter_system_injection && pid == g_config.filter_system_safe_process_pid) { return FALSE; } ProcessMessage(pid, 0); @@ -289,7 +288,7 @@ HOOKDEF(BOOL, WINAPI, SendNotifyMessageA, DumpSectionViewsForPid(pid); //ProcessMessage(pid, 0); } - if (g_config.filter_system_injection && is_system_process(pid) && pid == g_config.filter_system_safe_process_pid) { + if (g_config.filter_system_injection && pid == g_config.filter_system_safe_process_pid) { return FALSE; } ProcessMessage(pid, 0); @@ -320,7 +319,7 @@ HOOKDEF(BOOL, WINAPI, SendNotifyMessageW, DumpSectionViewsForPid(pid); // ProcessMessage(pid, 0); } - if (g_config.filter_system_injection && is_system_process(pid) && pid == g_config.filter_system_safe_process_pid) { + if (g_config.filter_system_injection && pid == g_config.filter_system_safe_process_pid) { return FALSE; } ProcessMessage(pid, 0);