void test_modules ( void ) { processLibProcEntry* entries = NULL; RU32 entryIndex = 0; rList mods = NULL; rSequence mod = NULL; RPWCHAR path = NULL; entries = processLib_getProcessEntries( TRUE ); CU_ASSERT_PTR_NOT_EQUAL_FATAL( entries, NULL ); CU_ASSERT_NOT_EQUAL_FATAL( entries[ entryIndex ].pid, 0 ); mods = processLib_getProcessModules( entries[ entryIndex ].pid ); CU_ASSERT_PTR_NOT_EQUAL( mods, NULL ); CU_ASSERT_TRUE( rList_getSEQUENCE( mods, RP_TAGS_DLL, &mod ) ); CU_ASSERT_TRUE( rSequence_getSTRINGW( mod, RP_TAGS_FILE_PATH, &path ) ); CU_ASSERT_PTR_NOT_EQUAL( path, NULL ); CU_ASSERT_NOT_EQUAL( rpal_string_strlenw( path ), 0 ); rSequence_free( mods ); rpal_memory_free( entries ); }
static RPVOID lookForHiddenModules ( rEvent isTimeToStop, RPVOID ctx ) { processLibProcEntry* procs = NULL; processLibProcEntry* proc = NULL; UNREFERENCED_PARAMETER( ctx ); if( NULL != ( procs = processLib_getProcessEntries( TRUE ) ) ) { proc = procs; while( 0 != proc->pid && rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) ) { lookForHiddenModulesIn( isTimeToStop, proc->pid ); proc++; } rpal_memory_free( procs ); } return NULL; }
void test_processInfo ( void ) { processLibProcEntry* entries = NULL; RU32 entryIndex = 0; rSequence proc = NULL; RPWCHAR path = NULL; entries = processLib_getProcessEntries( TRUE ); CU_ASSERT_PTR_NOT_EQUAL_FATAL( entries, NULL ); CU_ASSERT_NOT_EQUAL_FATAL( entries[ entryIndex ].pid, 0 ); proc = processLib_getProcessInfo( entries[ entryIndex ].pid ); CU_ASSERT_PTR_NOT_EQUAL( proc, NULL ); CU_ASSERT_TRUE( rSequence_getSTRINGW( proc, RP_TAGS_FILE_PATH, &path ) ); CU_ASSERT_PTR_NOT_EQUAL( path, NULL ); CU_ASSERT_NOT_EQUAL( rpal_string_strlenw( path ), 0 ); rSequence_free( proc ); rpal_memory_free( entries ); }
void test_procEntries ( void ) { processLibProcEntry* entries = NULL; RU32 entryIndex = 0; RU32 nEntries = 0; entries = processLib_getProcessEntries( TRUE ); CU_ASSERT_PTR_NOT_EQUAL_FATAL( entries, NULL ); while( 0 != entries[ entryIndex ].pid ) { nEntries++; entryIndex++; } CU_ASSERT_TRUE( 5 < nEntries ); rpal_memory_free( entries ); entries = processLib_getProcessEntries( FALSE ); CU_ASSERT_PTR_NOT_EQUAL_FATAL( entries, NULL ); while( 0 != entries[ entryIndex ].pid ) { nEntries++; entryIndex++; } CU_ASSERT_TRUE( 5 < nEntries ); rpal_memory_free( entries ); }
static RPVOID lookForHiddenModulesConstantly ( rEvent isTimeToStop, RPVOID ctx ) { rSequence originalRequest = (rSequence)ctx; processLibProcEntry* procs = NULL; processLibProcEntry* proc = NULL; LibOsPerformanceProfile perfProfile = { 0 }; perfProfile.enforceOnceIn = 4; perfProfile.sanityCeiling = MSEC_FROM_SEC( 20 ); perfProfile.lastTimeoutValue = 200; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = 50; while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) ) { if( NULL != ( procs = processLib_getProcessEntries( TRUE ) ) ) { proc = procs; while( 0 != proc->pid && rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, _TIMEOUT_BETWEEN_CONSTANT_PROCESSS ) ) { if( hbs_whenCpuBelow( _CPU_WATERMARK, _MAX_CPU_WAIT, isTimeToStop ) ) { lookForHiddenModulesIn( isTimeToStop, proc->pid, originalRequest, &perfProfile ); } proc++; } rpal_memory_free( procs ); } } return NULL; }
void test_memmap ( void ) { processLibProcEntry* entries = NULL; RU32 entryIndex = 0; rList regions = NULL; rSequence region = NULL; RU32 nRegions = 0; RU8 type = 0; RU8 protect = 0; RU64 ptr = 0; RU64 size = 0; entries = processLib_getProcessEntries( TRUE ); CU_ASSERT_PTR_NOT_EQUAL_FATAL( entries, NULL ); CU_ASSERT_NOT_EQUAL_FATAL( entries[ entryIndex ].pid, 0 ); regions = processLib_getProcessMemoryMap( entries[ entryIndex ].pid ); CU_ASSERT_PTR_NOT_EQUAL( regions, NULL ); while( rList_getSEQUENCE( regions, RP_TAGS_MEMORY_REGION, ®ion ) ) { CU_ASSERT_TRUE( rSequence_getRU8( region, RP_TAGS_MEMORY_TYPE, &type ) ); CU_ASSERT_TRUE( rSequence_getRU8( region, RP_TAGS_MEMORY_ACCESS, &protect ) ); CU_ASSERT_TRUE( rSequence_getPOINTER64( region, RP_TAGS_BASE_ADDRESS, &ptr ) ); CU_ASSERT_TRUE( rSequence_getRU64( region, RP_TAGS_MEMORY_SIZE, &size ) ); nRegions++; } CU_ASSERT_TRUE( 2 < nRegions ); rSequence_free( regions ); rpal_memory_free( entries ); }
static RVOID doScan ( rpcm_tag eventType, rSequence event ) { RU32 pid = 0; RPWCHAR fileW = NULL; RPCHAR fileA = NULL; RPWCHAR procW = NULL; RPCHAR procA = NULL; RPU8 rulesBuffer = NULL; RU32 rulesBufferSize = 0; YR_RULES* rules = NULL; YaraMatchContext matchContext = { 0 }; processLibProcEntry* processes = NULL; processLibProcEntry* curProc = NULL; RU32 scanError = 0; rSequence processInfo = NULL; RPWCHAR tmpW = NULL; RPCHAR tmpA = NULL; UNREFERENCED_PARAMETER( eventType ); if( rpal_memory_isValid( event ) ) { rSequence_getRU32( event, RP_TAGS_PROCESS_ID, &pid ); rSequence_getSTRINGW( event, RP_TAGS_FILE_PATH, &fileW ); rSequence_getSTRINGA( event, RP_TAGS_FILE_PATH, &fileA ); rSequence_getSTRINGW( event, RP_TAGS_PROCESS, &procW ); rSequence_getSTRINGA( event, RP_TAGS_PROCESS, &procA ); if( rSequence_getBUFFER( event, RP_TAGS_RULES, &rulesBuffer, &rulesBufferSize ) ) { rules = loadYaraRules( rulesBuffer, rulesBufferSize ); } if( NULL != rules ) { if( NULL != fileW ) { fileA = rpal_string_wtoa( fileW ); } if( NULL != procW ) { procA = rpal_string_wtoa( procW ); } if( NULL != fileA ) { rpal_debug_info( "scanning file with yara" ); matchContext.fileInfo = event; // Scan this file if( ERROR_SUCCESS != ( scanError = yr_rules_scan_file( rules, fileA, SCAN_FLAGS_FAST_MODE, _yaraFileMatchCallback, &matchContext, 60 ) ) ) { rpal_debug_warning( "Yara file scan error: %d", scanError ); } } else if( NULL != procA ) { // Scan processes matching if( NULL != ( processes = processLib_getProcessEntries( TRUE ) ) ) { curProc = processes; while( 0 != curProc->pid ) { if( NULL != ( processInfo = processLib_getProcessInfo( curProc->pid, NULL ) ) ) { if( rSequence_getSTRINGW( processInfo, RP_TAGS_FILE_PATH, &tmpW ) || rSequence_getSTRINGA( processInfo, RP_TAGS_FILE_PATH, &tmpA ) ) { if( NULL != tmpW ) { tmpA = rpal_string_wtoa( tmpW ); } if( NULL != tmpA ) { if( rpal_string_match( procA, tmpA, RPAL_PLATFORM_FS_CASE_SENSITIVITY ) ) { matchContext.pid = curProc->pid; matchContext.processInfo = processInfo; scanError = _scanProcessWith( curProc->pid, &matchContext, rules, NULL ); } } if( NULL != tmpW && NULL != tmpA ) { // If both are allocated it means we got a strW and converted to A // so we must free the strA version. rpal_memory_free( tmpA ); } } rSequence_free( processInfo ); } curProc++; } rpal_memory_free( processes ); } } else if( 0 != pid ) { // Scan this process matchContext.pid = pid; scanError = _scanProcessWith( pid, &matchContext, rules, NULL ); rSequence_free( matchContext.processInfo ); } else { // Scan all processes if( NULL != ( processes = processLib_getProcessEntries( TRUE ) ) ) { curProc = processes; while( 0 != curProc->pid ) { matchContext.pid = curProc->pid; scanError = _scanProcessWith( curProc->pid, &matchContext, rules, NULL ); rSequence_free( matchContext.processInfo ); curProc++; } rpal_memory_free( processes ); } } if( NULL != fileW && NULL != fileA ) { // If both are allocated it means we got a strW and converted to A // so we must free the strA version. rpal_memory_free( fileA ); } if( NULL != procW && NULL != procA ) { // If both are allocated it means we got a strW and converted to A // so we must free the strA version. rpal_memory_free( procA ); } yr_rules_destroy( rules ); } else { rpal_debug_warning( "no rules in yara scan request" ); reportError( event, RPAL_ERROR_NOT_SUPPORTED, "yara rules do not parse" ); } } rpal_debug_info( "finished on demand yara scan" ); reportError( event, scanError, "done" ); yr_finalize_thread(); }
static RPVOID continuousMemScan ( rEvent isTimeToStop, RPVOID ctx ) { processLibProcEntry* processes = NULL; processLibProcEntry* curProc = NULL; RU32 thisProcId = 0; YaraMatchContext matchContext = { 0 }; RU32 scanError = 0; UNREFERENCED_PARAMETER( ctx ); thisProcId = processLib_getCurrentPid(); while( !rEvent_wait( isTimeToStop, 0 ) ) { // Wait until we have global rules to look for. if( rMutex_lock( g_global_rules_mutex ) ) { if( NULL == g_global_rules ) { rMutex_unlock( g_global_rules_mutex ); rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 30 ) ); continue; } rMutex_unlock( g_global_rules_mutex ); } if( NULL != ( processes = processLib_getProcessEntries( TRUE ) ) ) { curProc = processes; while( 0 != curProc->pid ) { // We can't examine our own memory for the risk of tripping on the sigs themselves. if( curProc->pid == thisProcId ) continue; rpal_debug_info( "yara scanning pid %d", curProc->pid ); matchContext.pid = curProc->pid; matchContext.processInfo = NULL; matchContext.moduleInfo = NULL; scanError = _scanProcessWith( curProc->pid, &matchContext, NULL, isTimeToStop ); rSequence_free( matchContext.processInfo ); if( rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 30 ) ) ) { break; } curProc++; } rpal_memory_free( processes ); } } yr_finalize_thread(); return NULL; }
static RPVOID spotCheckProcessConstantly ( rEvent isTimeToStop, RPVOID ctx ) { rSequence originalRequest = (rSequence)ctx; processLibProcEntry* procs = NULL; processLibProcEntry* proc = NULL; rList hollowedModules = NULL; rSequence processInfo = NULL; LibOsPerformanceProfile perfProfile = { 0 }; Atom parentAtom = { 0 }; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = _PROFILE_INCREMENT; perfProfile.enforceOnceIn = 1; perfProfile.lastTimeoutValue = _INITIAL_PROFILED_TIMEOUT; perfProfile.sanityCeiling = _SANITY_CEILING; while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) ) { libOs_timeoutWithProfile( &perfProfile, FALSE, isTimeToStop ); if( NULL != ( procs = processLib_getProcessEntries( TRUE ) ) ) { proc = procs; while( 0 != proc->pid && rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) ) { libOs_timeoutWithProfile( &perfProfile, TRUE, isTimeToStop ); if( NULL != ( hollowedModules = _spotCheckProcess( isTimeToStop, proc->pid, &perfProfile ) ) ) { if( NULL != ( processInfo = processLib_getProcessInfo( proc->pid, NULL ) ) || ( NULL != ( processInfo = rSequence_new() ) && rSequence_addRU32( processInfo, RP_TAGS_PROCESS_ID, proc->pid ) ) ) { if( !rSequence_addLIST( processInfo, RP_TAGS_MODULES, hollowedModules ) ) { rList_free( hollowedModules ); } else { parentAtom.key.category = RP_TAGS_NOTIFICATION_NEW_PROCESS; parentAtom.key.process.pid = proc->pid; if( atoms_query( &parentAtom, 0 ) ) { HbsSetParentAtom( processInfo, parentAtom.id ); } hbs_markAsRelated( originalRequest, processInfo ); hbs_publish( RP_TAGS_NOTIFICATION_MODULE_MEM_DISK_MISMATCH, processInfo ); } rSequence_free( processInfo ); } else { rList_free( hollowedModules ); } } proc++; } rpal_memory_free( procs ); } } return NULL; }
static RVOID injectIntoProcess ( ) { RNCHAR strSeDebug[] = _NC( "SeDebugPrivilege" ); processLibProcEntry* procIds = NULL; processLibProcEntry* tmpProcId = NULL; rSequence targetProc = NULL; RU32 targetPid = 0; RPWCHAR procName = NULL; RWCHAR targetProcName[] = _WCH( "EXPLORER.EXE" ); HANDLE hProc = NULL; RU32 selfSize = 0; RPVOID remoteDest = NULL; SIZE_T payloadSize = 0; RPU8 payloadBuff = NULL; rpal_debug_info( "getting debug privilege to inject..." ); if( !Get_Privilege( strSeDebug ) ) { rpal_debug_error( "could not get debug privilege, are we running as admin?" ); return; } rpal_debug_info( "getting process list to find explorer.exe" ); procIds = processLib_getProcessEntries( FALSE ); tmpProcId = procIds; while( NULL != tmpProcId ) { if( NULL != ( targetProc = processLib_getProcessInfo( tmpProcId->pid, NULL ) ) ) { if( rSequence_getSTRINGN( targetProc, RP_TAGS_FILE_PATH, &procName ) ) { rpal_string_toupper( procName ); if( NULL != rpal_string_strstr( procName, targetProcName ) ) { rpal_debug_info( "found the target process: %d", tmpProcId->pid ); targetPid = tmpProcId->pid; } else { rpal_debug_info( "not target process, next..." ); } } else { rpal_debug_warning( "process without file path, odd..." ); } rSequence_free( targetProc ); targetProc = NULL; if( 0 != targetPid ) { break; } } tmpProcId++; } rpal_memory_free( procIds ); if( 0 != targetPid ) { rpal_debug_info( "getting size of self..." ); if( (RU32)(-1) != ( selfSize = rpal_file_getSize( g_self_path, FALSE ) ) ) { rpal_debug_info( "opening target process with right privileges..." ); if( NULL != ( hProc = OpenProcess( PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, targetPid ) ) ) { rpal_debug_info( "allocating required memory in remote process..." ); if( NULL != ( remoteDest = VirtualAllocEx( hProc, NULL, selfSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE ) ) ) { rpal_debug_info( "reading payload to memory before writing it to remote." ); if( rpal_file_read( g_self_path, (RPVOID*)&payloadBuff, (RU32*)&payloadSize, FALSE ) ) { rpal_debug_info( "writing payload to remote process." ); if( WriteProcessMemory( hProc, remoteDest, payloadBuff, payloadSize, &payloadSize ) && payloadSize == selfSize ) { rpal_debug_info( "successfully written payload to remote process. This should look like an injected PE although no thread was started." ); } else { rpal_debug_error( "error writing payload to remote process." ); } rpal_memory_free( payloadBuff ); } else { rpal_debug_error( "error reading ourselves as payload." ); } } else { rpal_debug_error( "error allocating memory in remote process." ); } CloseHandle( hProc ); } else { rpal_debug_error( "error opening process with VM privilges." ); } } else { rpal_debug_error( "error getting size of self." ); } } }
//============================================================================= // PROFILERS //============================================================================= RPRIVATE RBOOL profile_processes ( ) { RBOOL isSuccess = FALSE; processLibProcEntry* processes = NULL; processLibProcEntry* process = NULL; rSequence processInfo = NULL; RPWCHAR processName = NULL; rList modules = NULL; rSequence module = NULL; RPWCHAR moduleName = NULL; _Profile profile = { 0 }; RBOOL isProfileReady = FALSE; RBOOL isChanged = FALSE; if( NULL != ( processes = processLib_getProcessEntries( FALSE ) ) ) { process = processes; while( 0 != process->pid ) { if( NULL != ( processInfo = processLib_getProcessInfo( process->pid, NULL ) ) ) { if( rSequence_getSTRINGW( processInfo, RP_TAGS_FILE_PATH, &processName ) ) { isProfileReady = FALSE; if( rpal_btree_search( g_profiles_process_module, &processName, &profile, FALSE ) ) { isProfileReady = TRUE; } else { if( _init_profile_strw_strw( g_profiles_process_module, processName ) ) { if( rpal_btree_add( g_profiles_process_module, &profile, FALSE ) ) { isProfileReady = TRUE; } else { _clean_profile( &profile ); } } } if( isProfileReady ) { if( NULL != ( modules = processLib_getProcessModules( process->pid ) ) ) { while( rList_getSEQUENCE( modules, RP_TAGS_DLL, &module ) ) { if( rSequence_getSTRINGW( module, RP_TAGS_FILE_PATH, &moduleName ) ) { if( !rpal_btree_search( profile.relations, &moduleName, NULL, FALSE ) && rpal_btree_add( profile.relations, &moduleName, FALSE ) ) { isChanged = TRUE; if( _isProfileStable( &profile ) ) { rpal_debug_info( "Stable profile change!" ); } } } } rList_free( modules ); } if( _recordGeneration( &profile, isChanged ) ) { rpal_btree_update( g_profiles_process_module, &profile, &profile, FALSE ); } } } rSequence_free( processInfo ); } process++; } rpal_memory_free( processes ); } return isSuccess; }
static RPVOID modUserModeDiff ( rEvent isTimeToStop ) { rBlob previousSnapshot = NULL; rBlob newSnapshot = NULL; _moduleHistEntry curModule = { 0 }; processLibProcEntry* processes = NULL; processLibProcEntry* curProc = NULL; rList modules = NULL; rSequence module = NULL; LibOsPerformanceProfile perfProfile = { 0 }; Atom parentAtom = { 0 }; RU64 curTime = 0; perfProfile.enforceOnceIn = 1; perfProfile.lastTimeoutValue = 10; perfProfile.sanityCeiling = MSEC_FROM_SEC( 10 ); perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = 1; while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) && ( !kAcq_isAvailable() || g_is_kernel_failure ) ) { if( NULL != ( processes = processLib_getProcessEntries( FALSE ) ) ) { if( NULL != ( newSnapshot = rpal_blob_create( 1000 * sizeof( _moduleHistEntry ), 1000 * sizeof( _moduleHistEntry ) ) ) ) { libOs_timeoutWithProfile( &perfProfile, FALSE, isTimeToStop ); curProc = processes; while( rpal_memory_isValid( isTimeToStop ) && #ifdef RPAL_PLATFORM_WINDOWS !rEvent_wait( isTimeToStop, 0 ) && #else // Module listing outside of !rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 1 ) ) && #endif 0 != curProc->pid ) { if( NULL != ( modules = processLib_getProcessModules( curProc->pid ) ) ) { curTime = rpal_time_getGlobalPreciseTime(); while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) && rList_getSEQUENCE( modules, RP_TAGS_DLL, &module ) ) { libOs_timeoutWithProfile( &perfProfile, TRUE, isTimeToStop ); if( rSequence_getPOINTER64( module, RP_TAGS_BASE_ADDRESS, &( curModule.baseAddr ) ) && rSequence_getRU64( module, RP_TAGS_MEMORY_SIZE, &(curModule.size) ) ) { curModule.procId = curProc->pid; rpal_blob_add( newSnapshot, &curModule, sizeof( curModule ) ); if( NULL != previousSnapshot && -1 == rpal_binsearch_array( rpal_blob_getBuffer( previousSnapshot ), rpal_blob_getSize( previousSnapshot ) / sizeof( _moduleHistEntry ), sizeof( _moduleHistEntry ), &curModule, (rpal_ordering_func)_cmpModule ) ) { hbs_timestampEvent( module, curTime ); parentAtom.key.category = RP_TAGS_NOTIFICATION_NEW_PROCESS; parentAtom.key.process.pid = curProc->pid; if( atoms_query( &parentAtom, curTime ) ) { HbsSetParentAtom( module, parentAtom.id ); } rpal_memory_zero( &parentAtom, sizeof( parentAtom ) ); hbs_publish( RP_TAGS_NOTIFICATION_MODULE_LOAD, module ); } } } rList_free( modules ); } curProc++; } if( !rpal_sort_array( rpal_blob_getBuffer( newSnapshot ), rpal_blob_getSize( newSnapshot ) / sizeof( _moduleHistEntry ), sizeof( _moduleHistEntry ), (rpal_ordering_func)_cmpModule ) ) { rpal_debug_warning( "error sorting modules" ); } } rpal_memory_free( processes ); } if( NULL != previousSnapshot ) { rpal_blob_free( previousSnapshot ); } previousSnapshot = newSnapshot; newSnapshot = NULL; } if( NULL != previousSnapshot ) { rpal_blob_free( previousSnapshot ); } return NULL; }
RPRIVATE RVOID mem_find_string ( rpcm_tag eventType, rSequence event ) { RU32 pid = 0; RU32 currentPid = 0; rList searchStrings = NULL; rList processes = NULL; rSequence process = NULL; processLibProcEntry* pids = NULL; RU32 nCurrent = 0; RU32 minLength = 5; RU32 maxLength = 128; RPU8 atom = NULL; RU32 atomSize = 0; UNREFERENCED_PARAMETER( eventType ); if( rpal_memory_isValid( event ) ) { if( ( rSequence_getRU32( event, RP_TAGS_PROCESS_ID, &pid ) || ( rSequence_getBUFFER( event, RP_TAGS_HBS_THIS_ATOM, &atom, &atomSize ) && HBS_ATOM_ID_SIZE == atomSize && 0 != ( pid = atoms_getPid( atom ) ) ) ) && rSequence_getLIST( event, RP_TAGS_STRINGSW, &searchStrings ) ) { currentPid = processLib_getCurrentPid(); if( NULL != ( processes = rList_new( RP_TAGS_PROCESS, RPCM_SEQUENCE ) ) ) { if( 0 != pid ) { if( NULL != ( process = _findStringsInProcess( pid, searchStrings, minLength, maxLength ) ) ) { if( !rList_addSEQUENCE( processes, process ) ) { rSequence_free( process ); } } } else { if( NULL != ( pids = processLib_getProcessEntries( TRUE ) ) ) { while( 0 != pids[ nCurrent ].pid ) { if( currentPid != pids[ nCurrent ].pid ) { if( NULL != ( process = _findStringsInProcess( pids[ nCurrent ].pid, searchStrings, minLength, maxLength ) ) ) { if( !rList_addSEQUENCE( processes, process ) ) { rSequence_free( process ); } } } nCurrent++; } rpal_memory_free( pids ); } } if( !rSequence_addLIST( event, RP_TAGS_PROCESSES, processes ) ) { rList_free( processes ); } } } hbs_timestampEvent( event, 0 ); hbs_publish( RP_TAGS_NOTIFICATION_MEM_FIND_STRING_REP, event ); } }