RPRIVATE RVOID _processSnapshot ( rList snapshot, CryptoLib_Hash** prevSnapshot, RU32* prevNumElem, rpcm_tag elemTag, rpcm_tag notifTag ) { CryptoLib_Hash hash = { 0 }; RU32 i = 0; CryptoLib_Hash* tmpSnap = NULL; rSequence elem = NULL; if( NULL == prevSnapshot || NULL == prevNumElem ) { return; } if( NULL != ( tmpSnap = rpal_memory_alloc( sizeof( hash ) * rList_getNumElements( snapshot ) ) ) ) { i = 0; while( rList_getSEQUENCE( snapshot, elemTag, &elem ) ) { _elemToHash( elem, &hash ); tmpSnap[ i ] = hash; if( NULL != *prevSnapshot ) { if( ( -1 ) == rpal_binsearch_array( *prevSnapshot, *prevNumElem, sizeof( hash ), &hash, (rpal_ordering_func)_cmpHashes ) ) { hbs_timestampEvent( elem, 0 ); hbs_publish( notifTag, elem ); } } i++; } FREE_AND_NULL( *prevSnapshot ); *prevSnapshot = tmpSnap; *prevNumElem = i; tmpSnap = NULL; rpal_sort_array( *prevSnapshot, *prevNumElem, sizeof( hash ), (rpal_ordering_func)_cmpHashes ); } }
static RBOOL assembleRanges ( rList mods, _MemRange** pRanges, RU32* pNRanges ) { RBOOL isSuccess = FALSE; _MemRange* memRanges = NULL; rSequence mod = NULL; RU64 base = 0; RU64 size = 0; RU32 i = 0; if( rpal_memory_isValid( mods ) && NULL != pRanges && NULL != pNRanges ) { if( NULL != ( memRanges = rpal_memory_alloc( sizeof( _MemRange ) * rList_getNumElements( mods ) ) ) ) { rList_resetIterator( mods ); while( rList_getSEQUENCE( mods, RP_TAGS_DLL, &mod ) ) { if( rSequence_getPOINTER64( mod, RP_TAGS_BASE_ADDRESS, &base ) && rSequence_getRU64( mod, RP_TAGS_MEMORY_SIZE, &size ) ) { memRanges[ i ].base = base; memRanges[ i ].size = size; i++; } } if( rpal_sort_array( memRanges, i, sizeof( _MemRange ), (rpal_ordering_func)rpal_order_RU64 ) ) { isSuccess = TRUE; *pRanges = memRanges; *pNRanges = i; } } } return isSuccess; }
static ProcExtInfo* getProcContext ( RPU8 atomId ) { ProcExtInfo* procInfo = NULL; RU32 index = 0; if( (RU32)-1 != ( index = rpal_binsearch_array( g_procContexts->elements, g_procContexts->nElements, sizeof( ProcExtInfo* ), &atomId, (rpal_ordering_func)_cmpContext ) ) ) { procInfo = g_procContexts->elements[ index ]; } else { if( NULL != ( procInfo = rpal_memory_alloc( sizeof( *procInfo ) ) ) ) { rpal_memory_memcpy( procInfo->atomId, atomId, sizeof( procInfo->atomId ) ); if( !rpal_vector_add( g_procContexts, procInfo ) ) { rpal_memory_free( procInfo ); rpal_debug_error( "error adding new process to history" ); procInfo = NULL; } else { rpal_sort_array( g_procContexts->elements, g_procContexts->nElements, sizeof( ProcExtInfo* ), (rpal_ordering_func)_cmpContext ); } } } return procInfo; }
// Add an atom to the deny list, which is just a sortled list // on which we do binary searches. RPRIVATE RVOID addAtomToDeny ( RPU8 atomId ) { if( rMutex_lock( g_deniedMutex ) ) { rpal_blob_add( g_denied, atomId, HBS_ATOM_ID_SIZE ); rpal_sort_array( rpal_blob_getBuffer( g_denied ), rpal_blob_getSize( g_denied ) / HBS_ATOM_ID_SIZE, HBS_ATOM_ID_SIZE, (rpal_ordering_func)cmpAtoms ); g_lastDenyActivity = rpal_time_getGlobal(); rMutex_unlock( g_deniedMutex ); } }
static RU32 _scanProcessWith ( RU32 pid, YaraMatchContext* matchContext, YR_RULES* rules, rEvent isTimeToStop ) { RU32 scanError = (RU32)(-1); rList modules = NULL; rSequence module = NULL; _MemRange* memRanges = NULL; RU32 i = 0; rList memoryMap = NULL; rSequence memoryRegion = NULL; RU8 memAccess = 0; RU64 mem = 0; RU64 memSize = 0; RPU8 buffer = NULL; // First pass is to scan known modules if( NULL != ( modules = processLib_getProcessModules( pid ) ) ) { rpal_debug_info( "scanning process %d module memory with yara", pid ); // We also generate an optimized list of module ranges for later if( NULL != ( memRanges = rpal_memory_alloc( sizeof( _MemRange ) * rList_getNumElements( modules ) ) ) ) { while( ( NULL == isTimeToStop || !rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 5 ) ) ) && rList_getSEQUENCE( modules, RP_TAGS_DLL, &module ) ) { if( rSequence_getPOINTER64( module, RP_TAGS_BASE_ADDRESS, &mem ) && rSequence_getRU64( module, RP_TAGS_MEMORY_SIZE, &memSize ) ) { memRanges[ i ].base = mem; memRanges[ i ].size = memSize; i++; matchContext->regionBase = mem; matchContext->regionSize = memSize; matchContext->moduleInfo = module; if( processLib_getProcessMemory( pid, (RPVOID)NUMBER_TO_PTR( mem ), memSize, (RPVOID*)&buffer, TRUE ) ) { rpal_debug_info( "yara scanning module region of size 0x%lx", memSize ); if( NULL != rules || rMutex_lock( g_global_rules_mutex ) ) { if( ERROR_SUCCESS != ( scanError = yr_rules_scan_mem( NULL == rules ? g_global_rules : rules, buffer, (size_t)memSize, SCAN_FLAGS_FAST_MODE | SCAN_FLAGS_PROCESS_MEMORY, _yaraMemMatchCallback, matchContext, 60 ) ) ) { rpal_debug_warning( "Yara module scan error: %d 0x%lx 0x%lx: %d", pid, mem, memSize, scanError ); } if( NULL == rules ) { rMutex_unlock( g_global_rules_mutex ); } } rpal_memory_free( buffer ); rpal_debug_info( "finished region" ); } } } } rList_free( modules ); } // Optimize the memory ranges if( rpal_memory_isValid( memRanges ) && !rpal_sort_array( memRanges, i, sizeof( _MemRange ), (rpal_ordering_func)rpal_order_RU64 ) ) { rpal_memory_free( memRanges ); memRanges = NULL; } // Second pass is to go through executable non-module areas if( NULL != ( memoryMap = processLib_getProcessMemoryMap( pid ) ) ) { rpal_debug_info( "scanning process %d non-module memory with yara", pid ); while( ( NULL == isTimeToStop || !rEvent_wait(isTimeToStop, MSEC_FROM_SEC( 5 ) ) ) && rList_getSEQUENCE( memoryMap, RP_TAGS_MEMORY_REGION, &memoryRegion ) ) { if( rSequence_getPOINTER64( memoryRegion, RP_TAGS_BASE_ADDRESS, &mem ) && rSequence_getRU64( memoryRegion, RP_TAGS_MEMORY_SIZE, &memSize ) && rSequence_getRU8( memoryRegion, RP_TAGS_MEMORY_ACCESS, &memAccess ) && ( PROCESSLIB_MEM_ACCESS_EXECUTE == memAccess || PROCESSLIB_MEM_ACCESS_EXECUTE_READ == memAccess || PROCESSLIB_MEM_ACCESS_EXECUTE_READ_WRITE == memAccess || PROCESSLIB_MEM_ACCESS_EXECUTE_WRITE_COPY == memAccess ) ) { // If it's in a known module, skip if( (RU32)( -1 ) != rpal_binsearch_array_closest( memRanges, i, sizeof( _MemRange ), &mem, (rpal_ordering_func)rpal_order_RU64, TRUE ) ) { continue; } matchContext->regionBase = mem; matchContext->regionSize = memSize; matchContext->moduleInfo = NULL; if( processLib_getProcessMemory( pid, (RPVOID)NUMBER_TO_PTR(mem), memSize, (RPVOID*)&buffer, TRUE ) ) { rpal_debug_info( "yara scanning memory region of size 0x%lx", memSize ); if( NULL != rules || rMutex_lock( g_global_rules_mutex ) ) { if( ERROR_SUCCESS != ( scanError = yr_rules_scan_mem( NULL == rules ? g_global_rules : rules, buffer, (size_t)memSize, SCAN_FLAGS_FAST_MODE | SCAN_FLAGS_PROCESS_MEMORY, _yaraMemMatchCallback, matchContext, 60 ) ) ) { rpal_debug_warning( "Yara memory scan error: %d 0x%lx 0x%lx: %d", pid, mem, memSize, scanError ); } if( NULL == rules ) { rMutex_unlock( g_global_rules_mutex ); } } rpal_memory_free( buffer ); } } } rList_free( memoryMap ); } if( rpal_memory_isValid( memRanges ) ) { rpal_memory_free( memRanges ); } return scanError; }
RPRIVATE RVOID dnsUmDiffThread ( rEvent isTimeToStop ) { rSequence notif = NULL; rBlob snapCur = NULL; rBlob snapPrev = NULL; _dnsRecord rec = { 0 }; _dnsRecord* pCurRec = NULL; RU32 i = 0; LibOsPerformanceProfile perfProfile = { 0 }; #ifdef RPAL_PLATFORM_WINDOWS PDNSCACHEENTRY pDnsEntry = NULL; PDNSCACHEENTRY pPrevDnsEntry = NULL; #endif perfProfile.enforceOnceIn = 1; perfProfile.sanityCeiling = MSEC_FROM_SEC( 10 ); perfProfile.lastTimeoutValue = 100; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = 1; while( !rEvent_wait( isTimeToStop, 0 ) ) { if( kAcq_isAvailable() ) { // If kernel acquisition becomes available, try kernel again. return; } libOs_timeoutWithProfile( &perfProfile, FALSE, isTimeToStop ); if( NULL != ( snapCur = rpal_blob_create( 0, 10 * sizeof( rec ) ) ) ) { #ifdef RPAL_PLATFORM_WINDOWS if( TRUE == getCache( &pDnsEntry ) ) { while( NULL != pDnsEntry ) { rec.flags = pDnsEntry->dwFlags; rec.type = pDnsEntry->wType; if( NULL != ( rec.name = rpal_string_strdup( pDnsEntry->pszName ) ) ) { rpal_blob_add( snapCur, &rec, sizeof( rec ) ); } pPrevDnsEntry = pDnsEntry; pDnsEntry = pDnsEntry->pNext; freeCacheEntry( pPrevDnsEntry->pszName, DnsFreeFlat ); freeCacheEntry( pPrevDnsEntry, DnsFreeFlat ); } rpal_sort_array( rpal_blob_getBuffer( snapCur ), rpal_blob_getSize( snapCur ) / sizeof( rec ), sizeof( rec ), _cmpDns ); } #elif defined( RPAL_PLATFORM_MACOSX ) rpal_thread_sleep( MSEC_FROM_SEC( 2 ) ); #endif // Do a general diff of the snapshots to find new entries. if( NULL != snapPrev ) { i = 0; while( !rEvent_wait( isTimeToStop, 0 ) && NULL != ( pCurRec = rpal_blob_arrElem( snapCur, sizeof( rec ), i++ ) ) ) { if( -1 == rpal_binsearch_array( rpal_blob_getBuffer( snapPrev ), rpal_blob_getSize( snapPrev ) / sizeof( rec ), sizeof( rec ), pCurRec, (rpal_ordering_func)_cmpDns ) ) { if( NULL != ( notif = rSequence_new() ) ) { rSequence_addSTRINGN( notif, RP_TAGS_DOMAIN_NAME, pCurRec->name ); rSequence_addRU16( notif, RP_TAGS_DNS_TYPE, pCurRec->type ); rSequence_addRU32( notif, RP_TAGS_DNS_FLAGS, pCurRec->flags ); hbs_timestampEvent( notif, 0 ); hbs_publish( RP_TAGS_NOTIFICATION_DNS_REQUEST, notif ); rSequence_free( notif ); } } } } } if( NULL != snapPrev ) { _freeRecords( snapPrev ); rpal_blob_free( snapPrev ); snapPrev = NULL; } snapPrev = snapCur; snapCur = NULL; libOs_timeoutWithProfile( &perfProfile, TRUE, isTimeToStop ); } if( NULL != snapPrev ) { _freeRecords( snapPrev ); rpal_blob_free( snapPrev ); snapPrev = NULL; } }
static RPVOID trackerDiffThread ( rEvent isTimeToStop, RPVOID ctx ) { _volEntry* prevVolumes = NULL; RU32 nVolumes = 0; rList snapshot = NULL; rList prevSnapshot = NULL; _volEntry* newVolumes = NULL; RU32 nNewVolumes = 0; rSequence volume = NULL; rBlob serial = NULL; RU32 i = 0; LibOsPerformanceProfile perfProfile = { 0 }; UNREFERENCED_PARAMETER( ctx ); perfProfile.enforceOnceIn = 1; perfProfile.sanityCeiling = MSEC_FROM_SEC( 10 ); perfProfile.lastTimeoutValue = 10; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = 1; while( !rEvent_wait( isTimeToStop, 0 ) ) { libOs_timeoutWithProfile( &perfProfile, FALSE ); if( NULL != ( snapshot = libOs_getVolumes() ) ) { if( NULL != ( newVolumes = rpal_memory_alloc( sizeof( *newVolumes ) * rList_getNumElements( snapshot ) ) ) ) { nNewVolumes = 0; while( !rEvent_wait( isTimeToStop, 0 ) && rList_getSEQUENCE( snapshot, RP_TAGS_VOLUME, &volume ) ) { libOs_timeoutWithProfile( &perfProfile, TRUE ); if( NULL != ( serial = rpal_blob_create( 0, 0 ) ) ) { if( rSequence_serialise( volume, serial ) && CryptoLib_hash( rpal_blob_getBuffer( serial ), rpal_blob_getSize( serial ), &( newVolumes[ nNewVolumes ].hash ) ) ) { newVolumes[ nNewVolumes ].volume = volume; if( NULL != prevVolumes && ( -1 ) == rpal_binsearch_array( prevVolumes, nVolumes, sizeof( *prevVolumes ), &( newVolumes[ nNewVolumes ] ), (rpal_ordering_func)_cmpHashes ) ) { notifications_publish( RP_TAGS_NOTIFICATION_VOLUME_MOUNT, volume ); rpal_debug_info( "new volume mounted" ); } nNewVolumes++; } rpal_blob_free( serial ); } } if( !rEvent_wait( isTimeToStop, 0 ) ) { rpal_sort_array( newVolumes, nNewVolumes, sizeof( *newVolumes ), (rpal_ordering_func)_cmpHashes ); for( i = 0; i < nVolumes; i++ ) { libOs_timeoutWithProfile( &perfProfile, TRUE ); if( ( -1 ) == rpal_binsearch_array( newVolumes, nNewVolumes, sizeof( *newVolumes ), &( prevVolumes[ i ].hash ), (rpal_ordering_func)_cmpHashes ) ) { notifications_publish( RP_TAGS_NOTIFICATION_VOLUME_UNMOUNT, prevVolumes[ i ].volume ); rpal_debug_info( "volume unmounted" ); } } } } if( NULL != prevSnapshot ) { rList_free( prevSnapshot ); } prevSnapshot = snapshot; if( NULL != prevVolumes ) { rpal_memory_free( prevVolumes ); } prevVolumes = newVolumes; nVolumes = nNewVolumes; } } if( NULL != prevSnapshot ) { rList_free( prevSnapshot ); } if( NULL != prevVolumes ) { rpal_memory_free( prevVolumes ); } return NULL; }
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; }
static RBOOL getSnapshot ( processEntry* toSnapshot, RU32* nElem ) { RBOOL isSuccess = FALSE; RU32 i = 0; if( NULL != toSnapshot ) { rpal_memory_zero( toSnapshot, sizeof( processEntry ) * MAX_SNAPSHOT_SIZE ); } if( NULL != toSnapshot && NULL != nElem ) { #ifdef RPAL_PLATFORM_WINDOWS HANDLE hSnapshot = NULL; PROCESSENTRY32W procEntry = { 0 }; procEntry.dwSize = sizeof( procEntry ); if( INVALID_HANDLE_VALUE != ( hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ) ) ) { if( Process32FirstW( hSnapshot, &procEntry ) ) { isSuccess = TRUE; do { if( 0 == procEntry.th32ProcessID ) { continue; } toSnapshot[ i ].pid = procEntry.th32ProcessID; toSnapshot[ i ].ppid = procEntry.th32ParentProcessID; i++; } while( Process32NextW( hSnapshot, &procEntry ) && MAX_SNAPSHOT_SIZE > i ); } CloseHandle( hSnapshot ); } #elif defined( RPAL_PLATFORM_LINUX ) RWCHAR procDir[] = _WCH( "/proc/" ); rDir hProcDir = NULL; rFileInfo finfo = {0}; if( rDir_open( (RPWCHAR)&procDir, &hProcDir ) ) { isSuccess = TRUE; while( rDir_next( hProcDir, &finfo ) && MAX_SNAPSHOT_SIZE > i ) { if( rpal_string_wtoi( (RPWCHAR)finfo.fileName, &( toSnapshot[ i ].pid ) ) && 0 != toSnapshot[ i ].pid ) { i++; } } rDir_close( hProcDir ); } #elif defined( RPAL_PLATFORM_MACOSX ) int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; struct kinfo_proc* infos = NULL; size_t size = 0; int ret = 0; if( 0 == ( ret = sysctl( mib, ARRAY_N_ELEM( mib ), infos, &size, NULL, 0 ) ) ) { if( NULL != ( infos = rpal_memory_alloc( size ) ) ) { while( 0 != ( ret = sysctl( mib, ARRAY_N_ELEM( mib ), infos, &size, NULL, 0 ) ) && ENOMEM == errno ) { if( NULL == ( infos = rpal_memory_realloc( infos, size ) ) ) { break; } } } } if( 0 == ret && NULL != infos ) { isSuccess = TRUE; size = size / sizeof( struct kinfo_proc ); for( i = 0; i < size && MAX_SNAPSHOT_SIZE > i; i++ ) { toSnapshot[ i ].pid = infos[ i ].kp_proc.p_pid; toSnapshot[ i ].ppid = infos[ i ].kp_eproc.e_ppid; } if( NULL != infos ) { rpal_memory_free( infos ); infos = NULL; } } #endif rpal_sort_array( toSnapshot, i, sizeof( processEntry ), (rpal_ordering_func)rpal_order_RU32 ); *nElem = i; } return isSuccess; }