RPRIVATE RPVOID dnsDiffThread ( rEvent isTimeToStop, RPVOID ctx ) { UNREFERENCED_PARAMETER( ctx ); while( !rEvent_wait( isTimeToStop, 0 ) ) { if( kAcq_isAvailable() ) { rpal_debug_info( "running kernelmode acquisition dns notification" ); dnsKmDiffThread( isTimeToStop ); } else if( !rEvent_wait( isTimeToStop, 0 ) ) { rpal_debug_info( "running usermode acquisition dns notification" ); dnsUmDiffThread( isTimeToStop ); } } return NULL; }
static RPVOID moduleDiffThread ( rEvent isTimeToStop, RPVOID ctx ) { UNREFERENCED_PARAMETER( ctx ); while( !rEvent_wait( isTimeToStop, 0 ) ) { if( kAcq_isAvailable() && !g_is_kernel_failure ) { // We first attempt to get new modules through // the kernel mode acquisition driver rpal_debug_info( "running kernel acquisition module notification" ); modKernelModeDiff( isTimeToStop ); } // If the kernel mode fails, or is not available, try // to revert to user mode else if( !rEvent_wait( isTimeToStop, 0 ) ) { rpal_debug_info( "running usermode acquisition module notification" ); modUserModeDiff( isTimeToStop ); } } return NULL; }
static RVOID shutdownCollectors ( ) { RU32 i = 0; if( !rEvent_wait( g_hbs_state.isTimeToStop, 0 ) ) { rpal_debug_info( "signaling to collectors to stop." ); rEvent_set( g_hbs_state.isTimeToStop ); if( NULL != g_hbs_state.hThreadPool ) { rpal_debug_info( "destroying collector thread pool." ); rThreadPool_destroy( g_hbs_state.hThreadPool, TRUE ); g_hbs_state.hThreadPool = NULL; for( i = 0; i < ARRAY_N_ELEM( g_collectors ); i++ ) { if( g_collectors[ i ].isEnabled ) { rpal_debug_info( "cleaning up collector %d.", i ); g_collectors[ i ].cleanup( &g_hbs_state, g_collectors[ i ].conf ); rSequence_free( g_collectors[ i ].conf ); g_collectors[ i ].conf = NULL; } } } } }
static RVOID modKernelModeDiff ( rEvent isTimeToStop ) { RU32 i = 0; RU32 nScratch = 0; RU32 prev_nScratch = 0; KernelAcqModule new_from_kernel[ 200 ] = { 0 }; KernelAcqModule prev_from_kernel[ 200 ] = { 0 }; while( !rEvent_wait( isTimeToStop, 1000 ) ) { nScratch = ARRAY_N_ELEM( new_from_kernel ); rpal_memory_zero( new_from_kernel, sizeof( new_from_kernel ) ); if( !kAcq_getNewModules( new_from_kernel, &nScratch ) ) { rpal_debug_warning( "kernel acquisition for new modules failed" ); g_is_kernel_failure = TRUE; break; } for( i = 0; i < prev_nScratch; i++ ) { notifyOfKernelModule( &(prev_from_kernel[ i ]) ); } rpal_memory_memcpy( prev_from_kernel, new_from_kernel, sizeof( prev_from_kernel ) ); prev_nScratch = nScratch; } }
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; }
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; }
RBOOL rRwLock_read_lock ( rRwLock lock ) { RBOOL isSuccess = FALSE; _rRwLock* lck = (_rRwLock*)lock; RBOOL isReady = FALSE; if( rpal_memory_isValid( lock ) ) { // Wait to get permission to read atomically while( !isReady ) { if( rMutex_lock( lck->stateLock ) ) { if( rEvent_wait( lck->evtCanRead, 0 ) ) { isReady = TRUE; lck->readCount++; } rMutex_unlock( lck->stateLock ); isSuccess = TRUE; } if( !isReady ) { rEvent_wait( lck->evtCanRead, RINFINITE ); } } // Now we're safe to read } return isSuccess; }
RU32 RPAL_THREAD_FUNC RpHcpI_mainThread ( rEvent isTimeToStop ) { RU32 ret = 0; FORCE_LINK_THAT(HCP_IFACE); while( !rEvent_wait( isTimeToStop, (10*1000) ) ) { rpal_debug_info("RP HCP Test Module Running...\n"); } return ret; }
RPRIVATE RVOID dnsKmDiffThread ( rEvent isTimeToStop ) { RU8 new_from_kernel[ DNS_KB_PACKET_BUFFER * 1024 ] = { 0 }; RU8 prev_from_kernel[ DNS_KB_PACKET_BUFFER * 1024 ] = { 0 }; RU32 sizeInNew = 0; RU32 sizeInPrev = 0; KernelAcqDnsPacket* pPacket = NULL; while( !rEvent_wait( isTimeToStop, 1000 ) ) { rpal_memory_zero( new_from_kernel, sizeof( new_from_kernel ) ); sizeInNew = sizeof( new_from_kernel ); if( !kAcq_getNewDnsPackets( (KernelAcqDnsPacket*)new_from_kernel, &sizeInNew ) ) { rpal_debug_warning( "kernel acquisition for new dns packets failed" ); break; } pPacket = (KernelAcqDnsPacket*)prev_from_kernel; while( IS_WITHIN_BOUNDS( pPacket, sizeof( *pPacket ), prev_from_kernel, sizeInPrev ) && 0 != pPacket->ts && IS_WITHIN_BOUNDS( pPacket, sizeof( *pPacket ) + pPacket->packetSize, prev_from_kernel, sizeInPrev ) ) { processDnsPacket( pPacket ); pPacket = (KernelAcqDnsPacket*)( (RPU8)pPacket + sizeof( *pPacket ) + pPacket->packetSize ); } rpal_memory_memcpy( prev_from_kernel, new_from_kernel, sizeInNew ); sizeInPrev = sizeInNew; } }
RBOOL rRwLock_write_lock ( rRwLock lock ) { RBOOL isSuccess = FALSE; _rRwLock* lck = (_rRwLock*)lock; RBOOL isReady = FALSE; if( rpal_memory_isValid( lock ) ) { while( !isReady ) { if( rMutex_lock( lck->stateLock ) ) { if( 0 == lck->readCount ) { isReady = TRUE; rEvent_unset( lck->evtCanWrite ); } else { rEvent_unset( lck->evtCanRead ); rMutex_unlock( lck->stateLock ); } isSuccess = TRUE; } if( !isReady ) { rEvent_wait( lck->evtCanWrite, RINFINITE ); } } } return isSuccess; }
static RPVOID parseDocuments ( rEvent isTimeToStop, RPVOID ctx ) { rSequence createEvt = NULL; UNREFERENCED_PARAMETER( ctx ); while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) ) { if( rQueue_remove( createQueue, &createEvt, NULL, MSEC_FROM_SEC( 1 ) ) ) { processFile( createEvt ); } } return NULL; }
RBOOL hbs_whenCpuBelow ( RU8 percent, RTIME timeoutSeconds, rEvent abortEvent ) { RBOOL isCpuIdle = FALSE; RTIME end = rpal_time_getLocal() + timeoutSeconds; do { if( libOs_getCpuUsage() <= percent ) { isCpuIdle = TRUE; break; } if( NULL == abortEvent ) { rpal_thread_sleep( MSEC_FROM_SEC( 1 ) ); } else { if( rEvent_wait( abortEvent, MSEC_FROM_SEC( 1 ) ) ) { break; } } } while( end > rpal_time_getLocal() ); return isCpuIdle; }
static HObs _getModuleDiskStringSample ( RPNCHAR modulePath, RU32* pLastScratch, rEvent isTimeToStop, LibOsPerformanceProfile* perfProfile ) { HObs sample = NULL; RPU8 scratch = NULL; rFile hFile = NULL; RU32 read = 0; RPU8 start = NULL; RPU8 end = NULL; RU32 toSkip = 0; RU32 longestLength = 0; RBOOL isUnicode = FALSE; RPU8 sampleNumber = 0; rBloom stringsSeen = NULL; RU64 readOffset = 0; UNREFERENCED_PARAMETER( isTimeToStop ); if( NULL != modulePath && NULL != pLastScratch ) { readOffset = *pLastScratch * _SCRATCH_SIZE; if( NULL != ( stringsSeen = rpal_bloom_create( _MAX_DISK_SAMPLE_SIZE, 0.0001 ) ) ) { if( NULL != ( scratch = rpal_memory_alloc( _SCRATCH_SIZE ) ) ) { if( rFile_open( modulePath, &hFile, RPAL_FILE_OPEN_EXISTING | RPAL_FILE_OPEN_READ ) ) { if( readOffset == rFile_seek( hFile, readOffset, rFileSeek_SET ) && 0 != ( read = rFile_readUpTo( hFile, _SCRATCH_SIZE, scratch ) ) ) { if( NULL != ( sample = obsLib_new( _MAX_DISK_SAMPLE_SIZE, 0 ) ) ) { ( *pLastScratch )++; start = scratch; end = scratch + read; // We parse for strings up to 'read', we don't care about the // memory boundary, we might truncate some strings but we're // sampling anyway. while( !rEvent_wait( isTimeToStop, 0 ) && ( start >= scratch ) && ( start >= scratch ) && ( start + _MIN_SAMPLE_STR_LEN ) < ( scratch + read ) && _MAX_DISK_SAMPLE_SIZE >= PTR_TO_NUMBER( sampleNumber ) ) { libOs_timeoutWithProfile( perfProfile, TRUE, isTimeToStop ); isUnicode = FALSE; if( _longestString( (RPCHAR)start, (RU32)( end - start ), &toSkip, &longestLength, &isUnicode ) && _MIN_SAMPLE_STR_LEN <= longestLength && _MAX_SAMPLE_STR_LEN >= longestLength ) { if( rpal_bloom_addIfNew( stringsSeen, start, longestLength ) ) { if( obsLib_addPattern( sample, start, longestLength, sampleNumber ) ) { sampleNumber++; } } } start += toSkip; } } } rFile_close( hFile ); } rpal_memory_free( scratch ); } rpal_bloom_destroy( stringsSeen ); } } return sample; }
static RPVOID lookForHiddenModulesIn ( rEvent isTimeToStop, RU32 processId ) { rList mods = NULL; rList map = NULL; rSequence region = NULL; RU8 memType = 0; RU8 memProtect = 0; RU64 memBase = 0; RU64 memSize = 0; RPU8 pMem = NULL; RBOOL isPrefetched = FALSE; RBOOL isCurrentExec = FALSE; RBOOL isHidden = FALSE; rSequence procInfo = NULL; #ifdef RPAL_PLATFORM_WINDOWS PIMAGE_DOS_HEADER pDos = NULL; PIMAGE_NT_HEADERS pNt = NULL; #endif if( NULL != ( mods = processLib_getProcessModules( processId ) ) ) { if( NULL != ( map = processLib_getProcessMemoryMap( processId ) ) ) { // Now we got all the info needed for a single process, compare while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) && ( isPrefetched || rList_getSEQUENCE( map, RP_TAGS_MEMORY_REGION, ®ion ) ) ) { if( isPrefetched ) { isPrefetched = FALSE; } if( rSequence_getRU8( region, RP_TAGS_MEMORY_TYPE, &memType ) && rSequence_getRU8( region, RP_TAGS_MEMORY_ACCESS, &memProtect ) && rSequence_getPOINTER64( region, RP_TAGS_BASE_ADDRESS, &memBase ) && rSequence_getRU64( region, RP_TAGS_MEMORY_SIZE, &memSize ) ) { if( PROCESSLIB_MEM_TYPE_PRIVATE == memType || PROCESSLIB_MEM_TYPE_MAPPED == memType ) { if( PROCESSLIB_MEM_ACCESS_EXECUTE == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_READ == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_READ_WRITE == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_WRITE_COPY == memProtect ) { isCurrentExec = TRUE; } else { isCurrentExec = FALSE; } if( !isMemInModule( memBase, memSize, mods ) ) { // Exec memory found outside of a region marked to belong to // a module, keep looking in for module. if( ( 1024 * 1024 * 10 ) >= memSize && processLib_getProcessMemory( processId, NUMBER_TO_PTR( memBase ), memSize, (RPVOID*)&pMem ) ) { isHidden = FALSE; #ifdef RPAL_PLATFORM_WINDOWS // Let's just check for MZ and PE for now, we can get fancy later. pDos = (PIMAGE_DOS_HEADER)pMem; if( IS_WITHIN_BOUNDS( (RPU8)pMem, sizeof( IMAGE_DOS_HEADER ), pMem, memSize ) && IMAGE_DOS_SIGNATURE == pDos->e_magic ) { pNt = (PIMAGE_NT_HEADERS)( (RPU8)pDos + pDos->e_lfanew ); if( IS_WITHIN_BOUNDS( pNt, sizeof( *pNt ), pMem, memSize ) && IMAGE_NT_SIGNATURE == pNt->Signature ) { if( isCurrentExec ) { // If the current region is exec, we've got a hidden module. isHidden = TRUE; } else { // We need to check if the next section in memory is // executable and outside of known modules since the PE // headers may have been marked read-only before the .text. if( rList_getSEQUENCE( map, RP_TAGS_MEMORY_REGION, ®ion ) ) { isPrefetched = TRUE; if( ( PROCESSLIB_MEM_TYPE_PRIVATE == memType || PROCESSLIB_MEM_TYPE_MAPPED == memType ) && ( PROCESSLIB_MEM_ACCESS_EXECUTE == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_READ == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_READ_WRITE == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_WRITE_COPY == memProtect ) ) { isHidden = TRUE; } } } } } #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) if( isCurrentExec && 0x7F == ( pMem )[ 0 ] && 'E' == ( pMem )[ 1 ] && 'L' == ( pMem )[ 2 ] && 'F' == ( pMem )[ 3 ] ) { isHidden = TRUE; } #endif rpal_memory_free( pMem ); if( isHidden && !rEvent_wait( isTimeToStop, 0 ) ) { rpal_debug_info( "found a hidden module in %d.", processId ); if( NULL != ( procInfo = processLib_getProcessInfo( processId ) ) ) { if( !rSequence_addSEQUENCE( region, RP_TAGS_PROCESS, procInfo ) ) { rSequence_free( procInfo ); } } rSequence_addTIMESTAMP( region, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ); notifications_publish( RP_TAGS_NOTIFICATION_HIDDEN_MODULE_DETECTED, region ); break; } rpal_thread_sleep( 10 ); } } } } } rList_free( map ); } rList_free( mods ); } return NULL; }
//============================================================================= // Entry Point //============================================================================= RU32 RPAL_THREAD_FUNC RpHcpI_mainThread ( rEvent isTimeToStop ) { RU32 ret = 0; RU64 nextBeaconTime = 0; rList cloudMessages = NULL; rSequence msg = NULL; rList newConfigurations = NULL; rList newNotifications = NULL; RPU8 newConfigurationHash = NULL; RU32 newHashSize = 0; rSequence staticConfig = NULL; RU8* tmpBuffer = NULL; RU32 tmpSize = 0; FORCE_LINK_THAT( HCP_IFACE ); CryptoLib_init(); getPrivileges(); // This is the event for the collectors, it is different than the // hbs proper event so that we can restart the collectors without // signaling hbs as a whole. if( NULL == ( g_hbs_state.isTimeToStop = rEvent_create( TRUE ) ) ) { return (RU32)-1; } // By default, no collectors are running rEvent_set( g_hbs_state.isTimeToStop ); // We attempt to load some initial config from the serialized // rSequence that can be patched in this binary. if( NULL != ( staticConfig = getStaticConfig() ) ) { if( rSequence_getBUFFER( staticConfig, RP_TAGS_HBS_ROOT_PUBLIC_KEY, &tmpBuffer, &tmpSize ) ) { hbs_cloud_pub_key = rpal_memory_duplicate( tmpBuffer, tmpSize ); if( NULL == hbs_cloud_pub_key ) { hbs_cloud_pub_key = hbs_cloud_default_pub_key; } rpal_debug_info( "loading hbs root public key from static config" ); } if( rSequence_getRU32( staticConfig, RP_TAGS_MAX_QUEUE_SIZE, &g_hbs_state.maxQueueNum ) ) { rpal_debug_info( "loading max queue size from static config" ); } else { g_hbs_state.maxQueueNum = HBS_EXFIL_QUEUE_MAX_NUM; } if( rSequence_getRU32( staticConfig, RP_TAGS_MAX_SIZE, &g_hbs_state.maxQueueSize ) ) { rpal_debug_info( "loading max queue num from static config" ); } else { g_hbs_state.maxQueueSize = HBS_EXFIL_QUEUE_MAX_SIZE; } rSequence_free( staticConfig ); } else { hbs_cloud_pub_key = hbs_cloud_default_pub_key; g_hbs_state.maxQueueNum = HBS_EXFIL_QUEUE_MAX_NUM; g_hbs_state.maxQueueSize = HBS_EXFIL_QUEUE_MAX_SIZE; } if( !rQueue_create( &g_hbs_state.outQueue, freeExfilEvent, g_hbs_state.maxQueueNum ) ) { rEvent_free( g_hbs_state.isTimeToStop ); return (RU32)-1; } // We simply enqueue a message to let the cloud know we're starting sendStartupEvent(); while( !rEvent_wait( isTimeToStop, (RU32)nextBeaconTime ) ) { nextBeaconTime = MSEC_FROM_SEC( HBS_DEFAULT_BEACON_TIMEOUT + ( rpal_rand() % HBS_DEFAULT_BEACON_TIMEOUT_FUZZ ) ); if( NULL != ( cloudMessages = beaconHome() ) ) { while( rList_getSEQUENCE( cloudMessages, RP_TAGS_MESSAGE, &msg ) ) { // Cloud message indicating next requested beacon time, as a Seconds delta if( rSequence_getTIMEDELTA( msg, RP_TAGS_TIMEDELTA, &nextBeaconTime ) ) { nextBeaconTime = MSEC_FROM_SEC( nextBeaconTime ); rpal_debug_info( "received set_next_beacon" ); } if( NULL == newConfigurations && rSequence_getLIST( msg, RP_TAGS_HBS_CONFIGURATIONS, &newConfigurations ) ) { rpal_debug_info( "received a new profile" ); if( rSequence_getBUFFER( msg, RP_TAGS_HASH, &newConfigurationHash, &newHashSize ) && newHashSize == CRYPTOLIB_HASH_SIZE ) { newConfigurations = rList_duplicate( newConfigurations ); rpal_memory_memcpy( &( g_hbs_state.currentConfigHash ), newConfigurationHash, CRYPTOLIB_HASH_SIZE ); g_hbs_state.isProfilePresent = TRUE; } else { newConfigurations = NULL; rpal_debug_error( "profile hash received is invalid" ); } } if( NULL == newNotifications && rSequence_getLIST( msg, RP_TAGS_HBS_CLOUD_NOTIFICATIONS, &newNotifications ) ) { rpal_debug_info( "received cloud events" ); newNotifications = rList_duplicate( newNotifications ); } } rList_free( cloudMessages ); } // If this is the initial boot and we have no profile yet, we'll load a dummy // blank profile and use our defaults. if( NULL == newConfigurations && !g_hbs_state.isProfilePresent && !rEvent_wait( isTimeToStop, 0 ) ) { newConfigurations = rList_new( RP_TAGS_HCP_MODULES, RPCM_SEQUENCE ); rpal_debug_info( "setting empty profile" ); } if( NULL != newConfigurations ) { // We try to be as responsive as possible when asked to quit // so if we happen to have received the signal during a beacon // we will action the quit instead of the config change. if( !rEvent_wait( isTimeToStop, 0 ) ) { rpal_debug_info( "begining sensor update on new profile" ); shutdownCollectors(); updateCollectorConfigs( newConfigurations ); rList_free( newConfigurations ); newConfigurations = NULL; startCollectors(); } else { rList_free( newConfigurations ); } newConfigurations = NULL; } if( NULL != newNotifications ) { if( !rEvent_wait( isTimeToStop, 0 ) ) { publishCloudNotifications( newNotifications ); } rList_free( newNotifications ); newNotifications = NULL; } } // We issue one last beacon indicating we are stopping sendShutdownEvent(); // Shutdown everything shutdownCollectors(); // Cleanup the last few resources rEvent_free( g_hbs_state.isTimeToStop ); rQueue_free( g_hbs_state.outQueue ); CryptoLib_deinit(); if( hbs_cloud_default_pub_key != hbs_cloud_pub_key && NULL != hbs_cloud_pub_key ) { rpal_memory_free( hbs_cloud_pub_key ); hbs_cloud_pub_key = NULL; } return ret; }
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 RPVOID spotCheckNewProcesses ( rEvent isTimeToStop, RPVOID ctx ) { RU32 pid = 0; RTIME timestamp = 0; RTIME timeToWait = 0; RTIME now = 0; rSequence newProcess = NULL; rList hollowedModules = NULL; LibOsPerformanceProfile perfProfile = { 0 }; UNREFERENCED_PARAMETER( ctx ); perfProfile.sanityCeiling = _SANITY_CEILING; perfProfile.lastTimeoutValue = _INITIAL_PROFILED_TIMEOUT; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.enforceOnceIn = 7; perfProfile.timeoutIncrementPerSec = _PROFILE_INCREMENT; while( !rEvent_wait( isTimeToStop, 0 ) ) { if( rQueue_remove( g_newProcessNotifications, &newProcess, NULL, MSEC_FROM_SEC( 5 ) ) ) { if( rSequence_getRU32( newProcess, RP_TAGS_PROCESS_ID, &pid ) && rSequence_getTIMESTAMP( newProcess, RP_TAGS_TIMESTAMP, ×tamp ) ) { timeToWait = timestamp + _CHECK_SEC_AFTER_PROCESS_CREATION; now = rpal_time_getGlobalPreciseTime(); if( now < timeToWait ) { timeToWait = timeToWait - now; if( _CHECK_SEC_AFTER_PROCESS_CREATION < timeToWait ) { // Sanity check timeToWait = _CHECK_SEC_AFTER_PROCESS_CREATION; } rpal_thread_sleep( (RU32)timeToWait ); } if( NULL != ( hollowedModules = _spotCheckProcess( isTimeToStop, pid, &perfProfile ) ) ) { if( !rSequence_addLIST( newProcess, RP_TAGS_MODULES, hollowedModules ) ) { rList_free( hollowedModules ); } else { hbs_publish( RP_TAGS_NOTIFICATION_MODULE_MEM_DISK_MISMATCH, newProcess ); } } } rSequence_free( newProcess ); } } 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 rList _spotCheckProcess ( rEvent isTimeToStop, RU32 pid, LibOsPerformanceProfile* perfProfile ) { rList hollowedModules = NULL; rList modules = NULL; rSequence module = NULL; RPNCHAR modulePath = NULL; RU32 fileSize = 0; RU64 moduleBase = 0; RU64 moduleSize = 0; HObs diskSample = NULL; rSequence hollowedModule = NULL; RU32 lastScratchIndex = 0; RU32 nSamplesFound = 0; RU32 nSamplesTotal = 0; RU32 tmpSamplesFound = 0; RU32 tmpSamplesSize = 0; RTIME runTime = 0; rpal_debug_info( "spot checking process %d", pid ); if( NULL != ( modules = processLib_getProcessModules( pid ) ) ) { while( !rEvent_wait( isTimeToStop, 0 ) && rList_getSEQUENCE( modules, RP_TAGS_DLL, &module ) ) { libOs_timeoutWithProfile( perfProfile, FALSE, isTimeToStop ); runTime = rpal_time_getLocal(); modulePath = NULL; lastScratchIndex = 0; if( ( rSequence_getSTRINGN( module, RP_TAGS_FILE_PATH, &modulePath ) ) && rSequence_getPOINTER64( module, RP_TAGS_BASE_ADDRESS, &moduleBase ) && rSequence_getRU64( module, RP_TAGS_MEMORY_SIZE, &moduleSize ) ) { if( 0 != ( fileSize = rpal_file_getSize( modulePath, TRUE ) ) ) { nSamplesFound = 0; nSamplesTotal = 0; tmpSamplesFound = (RU32)( -1 ); while( !rEvent_wait( isTimeToStop, 0 ) && NULL != ( diskSample = _getModuleDiskStringSample( modulePath, &lastScratchIndex, isTimeToStop, perfProfile ) ) ) { libOs_timeoutWithProfile( perfProfile, TRUE, isTimeToStop ); tmpSamplesSize = obsLib_getNumPatterns( diskSample ); if( 0 != tmpSamplesSize ) { tmpSamplesFound = _checkMemoryForStringSample( diskSample, pid, NUMBER_TO_PTR( moduleBase ), moduleSize, isTimeToStop, perfProfile ); obsLib_free( diskSample ); if( (RU32)( -1 ) == tmpSamplesFound ) { break; } nSamplesFound += tmpSamplesFound; nSamplesTotal += tmpSamplesSize; if( _MIN_DISK_SAMPLE_SIZE <= nSamplesTotal && ( _MIN_SAMPLE_MATCH_PERCENT < ( (RFLOAT)nSamplesFound / nSamplesTotal ) * 100 ) && _MIN_DISK_BIN_COVERAGE_PERCENT <= (RFLOAT)( ( lastScratchIndex * _SCRATCH_SIZE ) / fileSize ) * 100 ) { break; } } else { obsLib_free( diskSample ); } } } else { rpal_debug_info( "could not get file information, not checking" ); } rpal_debug_info( "process hollowing check found a match in %d ( %d / %d ) from %d passes in %d sec", pid, nSamplesFound, nSamplesTotal, lastScratchIndex, rpal_time_getLocal() - runTime ); if( !rEvent_wait( isTimeToStop, 0 ) && (RU32)(-1) != tmpSamplesFound && _MIN_DISK_SAMPLE_SIZE <= nSamplesTotal && ( ( (RFLOAT)nSamplesFound / nSamplesTotal ) * 100 ) < _MIN_SAMPLE_MATCH_PERCENT ) { rpal_debug_info( "sign of process hollowing found in process %d", pid ); if( NULL != ( hollowedModule = rSequence_duplicate( module ) ) ) { if( !rList_addSEQUENCE( hollowedModules, hollowedModule ) ) { rSequence_free( hollowedModule ); } } } } else { rpal_debug_info( "module missing characteristic" ); } } rList_free( modules ); } else { rpal_debug_info( "failed to get process modules, might be dead" ); } return hollowedModules; }
static RPVOID processDiffThread ( rEvent isTimeToStop, RPVOID ctx ) { processEntry* currentSnapshot = g_snapshot_1; processEntry* previousSnapshot = g_snapshot_2; processEntry* tmpSnapshot = NULL; RBOOL isFirstSnapshots = TRUE; RU32 i = 0; RU32 j = 0; RBOOL isFound = FALSE; RU32 nThLoop = 0; RU32 currentTimeout = 0; UNREFERENCED_PARAMETER( ctx ); while( !rEvent_wait( isTimeToStop, currentTimeout ) ) { tmpSnapshot = currentSnapshot; currentSnapshot = previousSnapshot; previousSnapshot = tmpSnapshot; if( getSnapshot( currentSnapshot ) ) { if( isFirstSnapshots ) { isFirstSnapshots = FALSE; continue; } // Diff to find new processes for( i = 0; i < MAX_SNAPSHOT_SIZE; i++ ) { isFound = FALSE; if( 0 == currentSnapshot[ i ].pid ) { break; } for( j = 0; j < MAX_SNAPSHOT_SIZE; j++ ) { if( 0 == previousSnapshot[ j ].pid ) { break; } if( previousSnapshot[ j ].pid == currentSnapshot[ i ].pid ) { isFound = TRUE; break; } } if( !isFound ) { if( !notifyOfProcess( currentSnapshot[ i ].pid, currentSnapshot[ i ].ppid, TRUE ) ) { rpal_debug_warning( "error reporting new process: %d", currentSnapshot[ i ].pid ); } } } // Diff to find terminated processes for( i = 0; i < MAX_SNAPSHOT_SIZE; i++ ) { isFound = FALSE; if( 0 == previousSnapshot[ i ].pid ) { break; } for( j = 0; j < MAX_SNAPSHOT_SIZE; j++ ) { if( 0 == currentSnapshot[ j ].pid ) { break; } if( previousSnapshot[ i ].pid == currentSnapshot[ j ].pid ) { isFound = TRUE; break; } } if( !isFound ) { if( !notifyOfProcess( previousSnapshot[ i ].pid, previousSnapshot[ i ].ppid, FALSE ) ) { rpal_debug_warning( "error reporting terminated process: %d", previousSnapshot[ i ].pid ); } } } } nThLoop++; if( 0 == nThLoop % 20 ) { #ifdef RPAL_PLATFORM_WINDOWS // The Windows API is much more efficient than on Nix so we can affort // going faster between our diffs. currentTimeout = libOs_getUsageProportionalTimeout( 500 ) + 100; #else currentTimeout = libOs_getUsageProportionalTimeout( 800 ) + 200; #endif } } return NULL; }
static RPVOID continuousFileScan ( rEvent isTimeToStop, RPVOID ctx ) { rSequence event = NULL; RU32 timeout = 0; RPWCHAR strW = NULL; RPCHAR strA = NULL; YaraMatchContext matchContext = { 0 }; RU32 scanError = 0; rBloom knownFiles = NULL; UNREFERENCED_PARAMETER( ctx ); if( NULL == ( knownFiles = rpal_bloom_create( 100000, 0.00001 ) ) ) { return NULL; } while( !rEvent_wait( isTimeToStop, timeout ) ) { if( rQueue_remove( g_async_files_to_scan, (RPVOID*)&event, NULL, MSEC_FROM_SEC( 2 ) ) ) { if( rSequence_getSTRINGW( event, RP_TAGS_FILE_PATH, &strW ) ) { strA = rpal_string_wtoa( strW ); } else { rSequence_getSTRINGA( event, RP_TAGS_FILE_PATH, &strA ); } if( NULL != strA && rpal_bloom_addIfNew( knownFiles, strA, rpal_string_strlen( strA ) ) ) { rpal_debug_info( "yara scanning %s", strA ); matchContext.fileInfo = event; if( rMutex_lock( g_global_rules_mutex ) ) { if( NULL != g_global_rules ) { rpal_debug_info( "scanning continuous file with yara" ); if( ERROR_SUCCESS != ( scanError = yr_rules_scan_file( g_global_rules, strA, SCAN_FLAGS_FAST_MODE, _yaraFileMatchCallback, &matchContext, 60 ) ) ) { rpal_debug_warning( "Yara file scan error: %d", scanError ); } } rMutex_unlock( g_global_rules_mutex ); } } if( NULL != strA && NULL != strW ) { // If both are allocated it means we got a strW and converted to A // so we must free the strA version. rpal_memory_free( strA ); } strA = NULL; strW = NULL; rSequence_free( event ); timeout = _TIMEOUT_BETWEEN_FILE_SCANS; } else { timeout = 0; } } rpal_bloom_destroy( knownFiles ); yr_finalize_thread(); return NULL; }
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; }
static RPVOID dnsDiffThread ( rEvent isTimeToStop, RPVOID ctx ) { RU32 nThLoop = 0; RU32 currentTimeout = 0; rSequence notif = NULL; rBlob snapCur = NULL; rBlob snapPrev = NULL; _dnsRecord rec = { 0 }; _dnsRecord* pCurRec = NULL; _dnsRecord* pPrevRec = NULL; RU32 i = 0; RU32 j = 0; RBOOL isNew = FALSE; #ifdef RPAL_PLATFORM_WINDOWS PDNSCACHEENTRY pDnsEntry = NULL; PDNSCACHEENTRY pPrevDnsEntry = NULL; #endif UNREFERENCED_PARAMETER( ctx ); while( !rEvent_wait( isTimeToStop, currentTimeout ) ) { 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_strdupw( pDnsEntry->pszName ) ) ) { rpal_blob_add( snapCur, &rec, sizeof( rec ) ); } pPrevDnsEntry = pDnsEntry; pDnsEntry = pDnsEntry->pNext; freeCacheEntry( pPrevDnsEntry->pszName, DnsFreeFlat ); freeCacheEntry( pPrevDnsEntry, DnsFreeFlat ); } } #endif // Do a general diff of the snapshots to find new entries. if( NULL != snapPrev ) { i = 0; while( NULL != ( pCurRec = rpal_blob_arrElem( snapCur, sizeof( rec ), i++ ) ) ) { isNew = TRUE; j = 0; while( NULL != ( pPrevRec = rpal_blob_arrElem( snapPrev, sizeof( rec ), j++ ) ) ) { if( pCurRec->flags == pPrevRec->flags && pCurRec->type == pPrevRec->type && 0 == rpal_string_strcmpw( pCurRec->name, pPrevRec->name ) ) { isNew = FALSE; break; } } if( isNew && !rEvent_wait( isTimeToStop, 0 ) ) { if( NULL != ( notif = rSequence_new() ) ) { rSequence_addSTRINGW( 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 ); rSequence_addTIMESTAMP( notif, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ); notifications_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; nThLoop++; if( 0 == nThLoop % 20 ) { currentTimeout = libOs_getUsageProportionalTimeout( MSEC_FROM_SEC( 10 ) ) + MSEC_FROM_SEC( 5 ); } rpal_thread_sleep( currentTimeout ); } if( NULL != snapPrev ) { _freeRecords( snapPrev ); rpal_blob_free( snapPrev ); snapPrev = NULL; } return NULL; }
static VOID WINAPI ServiceMain ( DWORD dwArgc, RPCHAR lpszArgv ) { RU32 memUsed = 0; RWCHAR svcName[] = { _SERVICE_NAME }; RU32 i = 0; UNREFERENCED_PARAMETER( dwArgc ); UNREFERENCED_PARAMETER( lpszArgv ); if( NULL == ( g_svc_status_handle = RegisterServiceCtrlHandlerW( svcName, SvcCtrlHandler ) ) ) { return; } rpal_memory_zero( &g_svc_status, sizeof( g_svc_status ) ); g_svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_svc_status.dwControlsAccepted = 0; g_svc_status.dwCurrentState = SERVICE_START_PENDING; g_svc_status.dwWin32ExitCode = 0; g_svc_status.dwServiceSpecificExitCode = 0; g_svc_status.dwCheckPoint = 0; SetServiceStatus( g_svc_status_handle, &g_svc_status ); if( NULL == ( g_timeToQuit = rEvent_create( TRUE ) ) ) { g_svc_status.dwControlsAccepted = 0; g_svc_status.dwCurrentState = SERVICE_STOPPED; g_svc_status.dwWin32ExitCode = GetLastError(); g_svc_status.dwCheckPoint = 1; SetServiceStatus( g_svc_status_handle, &g_svc_status ); return; } rpal_debug_info( "initialising rpHCP." ); if( !rpHostCommonPlatformLib_launch( g_svc_primary, g_svc_secondary ) ) { rpal_debug_warning( "error launching hcp." ); } for( i = 0; i < ARRAY_N_ELEM( g_manual_loads ); i++ ) { if( NULL != g_manual_loads[ i ].modPath ) { if( 0 != g_manual_loads[ i ].nMod ) { #ifdef HCP_EXE_ENABLE_MANUAL_LOAD rpHostCommonPlatformLib_load( g_manual_loads[ i ].modPath, g_manual_loads[ i ].nMod ); #endif } else { rpal_debug_error( "Mismatched number of -m modulePath and -n moduleId statements provided!" ); } rpal_memory_free( g_manual_loads[ i ].modPath ); g_manual_loads[ i ].modPath = NULL; } else { break; } } g_svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; g_svc_status.dwCurrentState = SERVICE_RUNNING; g_svc_status.dwWin32ExitCode = 0; g_svc_status.dwCheckPoint = 1; SetServiceStatus( g_svc_status_handle, &g_svc_status ); rpal_debug_info( "...running, waiting to exit..." ); rEvent_wait( g_timeToQuit, RINFINITE ); rEvent_free( g_timeToQuit ); rpal_debug_info( "...exiting..." ); rpal_Context_cleanup(); memUsed = rpal_memory_totalUsed(); if( 0 != memUsed ) { rpal_debug_critical( "Memory leak: %d bytes.\n", memUsed ); //rpal_memory_findMemory(); #ifdef RPAL_FEATURE_MEMORY_ACCOUNTING rpal_memory_printDetailedUsage(); #endif } g_svc_status.dwControlsAccepted = 0; g_svc_status.dwCurrentState = SERVICE_STOPPED; g_svc_status.dwWin32ExitCode = 0; g_svc_status.dwCheckPoint = 3; SetServiceStatus( g_svc_status_handle, &g_svc_status ); }
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 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 RU32 _checkMemoryForStringSample ( HObs sample, RU32 pid, RPVOID moduleBase, RU64 moduleSize, rEvent isTimeToStop, LibOsPerformanceProfile* perfProfile ) { RPU8 pMem = NULL; RU8* sampleList = NULL; RPU8 sampleNumber = 0; RU32 nSamples = 0; RU32 nSamplesFound = (RU32)(-1); UNREFERENCED_PARAMETER( isTimeToStop ); if( NULL != sample && 0 != pid && NULL != moduleBase && 0 != moduleSize && _MIN_DISK_SAMPLE_SIZE <= ( nSamples = obsLib_getNumPatterns( sample ) ) ) { if( NULL != ( sampleList = rpal_memory_alloc( sizeof( RU8 ) * nSamples ) ) ) { rpal_memory_zero( sampleList, sizeof( RU8 ) * nSamples ); if( processLib_getProcessMemory( pid, moduleBase, moduleSize, (RPVOID*)&pMem, TRUE ) ) { if( obsLib_setTargetBuffer( sample, pMem, (RU32)moduleSize ) ) { while( !rEvent_wait( isTimeToStop, 0 ) && obsLib_nextHit( sample, (RPVOID*)&sampleNumber, NULL ) ) { libOs_timeoutWithProfile( perfProfile, TRUE, isTimeToStop ); if( sampleNumber < (RPU8)NUMBER_TO_PTR( nSamples ) && 0 == sampleList[ (RU32)PTR_TO_NUMBER( sampleNumber ) ] ) { sampleList[ (RU32)PTR_TO_NUMBER( sampleNumber ) ] = 1; nSamplesFound++; } } } rpal_memory_free( pMem ); } else { rpal_debug_info( "failed to get memory for %d: 0x%016X ( 0x%016X ) error %d", pid, moduleBase, moduleSize, rpal_error_getLast() ); } rpal_memory_free( sampleList ); } } return nSamplesFound; }
static RPVOID osTrackerDiffThread ( rEvent isTimeToStop, RPVOID ctx ) { CryptoLib_Hash* prevServices = NULL; RU32 prevNServices = 0; CryptoLib_Hash* prevDrivers = NULL; RU32 prevNDrivers = 0; CryptoLib_Hash* prevAutoruns = NULL; RU32 prevNAutoruns = 0; rList snapshot = NULL; UNREFERENCED_PARAMETER( ctx ); while( !rEvent_wait( isTimeToStop, g_diff_timeout ) ) { rpal_debug_info( "looking for changes in os snapshots" ); if( NULL != ( snapshot = libOs_getServices( TRUE ) ) ) { _processSnapshot( snapshot, &prevServices, &prevNServices, RP_TAGS_SVC, RP_TAGS_NOTIFICATION_SERVICE_CHANGE ); rList_free( snapshot ); } if( rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 5 ) ) ) { break; } if( NULL != ( snapshot = libOs_getDrivers( TRUE ) ) ) { _processSnapshot( snapshot, &prevDrivers, &prevNDrivers, RP_TAGS_SVC, RP_TAGS_NOTIFICATION_DRIVER_CHANGE ); rList_free( snapshot ); } if( rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 5 ) ) ) { break; } if( NULL != ( snapshot = libOs_getAutoruns( TRUE ) ) ) { _processSnapshot( snapshot, &prevAutoruns, &prevNAutoruns, RP_TAGS_SVC, RP_TAGS_NOTIFICATION_AUTORUN_CHANGE ); rList_free( snapshot ); } rpal_debug_info( "finished updating snapshots" ); } FREE_AND_NULL( prevServices ); FREE_AND_NULL( prevDrivers ); FREE_AND_NULL( prevAutoruns ); return NULL; }
static RPVOID networkDiffThread ( rEvent isTimeToStop, RPVOID ctx ) { NetLib_Tcp4Table* currentTcp4Table = NULL; NetLib_Tcp4Table* oldTcp4Table = NULL; NetLib_UdpTable* currentUdpTable = NULL; NetLib_UdpTable* oldUdpTable = NULL; RU32 i = 0; RU32 j = 0; RBOOL isFound = FALSE; rSequence notif = NULL; rSequence comp = NULL; RU32 timeout = 100; RU32 nThLoop = 0; UNREFERENCED_PARAMETER( ctx ); while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) ) { if( NULL != oldTcp4Table ) { rpal_memory_free( oldTcp4Table ); oldTcp4Table = NULL; } if( NULL != oldUdpTable ) { rpal_memory_free( oldUdpTable ); oldUdpTable = NULL; } // Swap the old snapshot for the (prev) new one oldTcp4Table = currentTcp4Table; oldUdpTable = currentUdpTable; currentTcp4Table = NULL; currentUdpTable = NULL; // Generate new tables currentTcp4Table = NetLib_getTcp4Table(); currentUdpTable = NetLib_getUdpTable(); // Diff TCP snapshots for new entries if( rpal_memory_isValid( currentTcp4Table ) && rpal_memory_isValid( oldTcp4Table ) ) { for( i = 0; i < currentTcp4Table->nRows; i++ ) { isFound = FALSE; if( rEvent_wait( isTimeToStop, 0 ) ) { break; } for( j = 0; j < oldTcp4Table->nRows; j++ ) { if( isTcpEqual( ¤tTcp4Table->rows[ i ], &oldTcp4Table->rows[ j ] ) ) { isFound = TRUE; break; } } if( !isFound ) { if( NULL != ( notif = rSequence_new() ) ) { if( rSequence_addRU32( notif, RP_TAGS_STATE, currentTcp4Table->rows[ i ].state ) && rSequence_addRU32( notif, RP_TAGS_PROCESS_ID, currentTcp4Table->rows[ i ].pid ) && rSequence_addTIMESTAMP( notif, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ) ) { if( NULL != ( comp = rSequence_new() ) ) { // Add the destination components if( !rSequence_addIPV4( comp, RP_TAGS_IP_ADDRESS, currentTcp4Table->rows[ i ].destIp ) || !rSequence_addRU16( comp, RP_TAGS_PORT, rpal_ntoh16( (RU16)currentTcp4Table->rows[ i ].destPort ) ) || !rSequence_addSEQUENCE( notif, RP_TAGS_DESTINATION, comp ) ) { rSequence_free( comp ); comp = NULL; } } if( NULL != ( comp = rSequence_new() ) ) { // Add the source components if( !rSequence_addIPV4( comp, RP_TAGS_IP_ADDRESS, currentTcp4Table->rows[ i ].sourceIp ) || !rSequence_addRU16( comp, RP_TAGS_PORT, rpal_ntoh16( (RU16)currentTcp4Table->rows[ i ].sourcePort ) ) || !rSequence_addSEQUENCE( notif, RP_TAGS_SOURCE, comp ) ) { rSequence_free( comp ); comp = NULL; } } rpal_debug_info( "new tcp connection: 0x%08X = 0x%08X:0x%04X ---> 0x%08X:0x%04X -- 0x%08X.", currentTcp4Table->rows[ i ].state, currentTcp4Table->rows[ i ].sourceIp, currentTcp4Table->rows[ i ].sourcePort, currentTcp4Table->rows[ i ].destIp, currentTcp4Table->rows[ i ].destPort, currentTcp4Table->rows[ i ].pid ); notifications_publish( RP_TAGS_NOTIFICATION_NEW_TCP4_CONNECTION, notif ); } rSequence_free( notif ); } } } } else if( 0 != nThLoop ) { rpal_debug_warning( "could not get tcp connections table." ); } // Diff TCP snapshots for new entries if( NULL != currentUdpTable && NULL != oldUdpTable ) { for( i = 0; i < currentUdpTable->nRows; i++ ) { isFound = FALSE; if( rEvent_wait( isTimeToStop, 0 ) ) { break; } for( j = 0; j < oldUdpTable->nRows; j++ ) { if( isUdpEqual( ¤tUdpTable->rows[ i ], &oldUdpTable->rows[ j ] ) ) { isFound = TRUE; break; } } if( !isFound ) { if( NULL != ( notif = rSequence_new() ) ) { if( !rSequence_addIPV4( notif, RP_TAGS_IP_ADDRESS, currentUdpTable->rows[ i ].localIp ) || !rSequence_addRU16( notif, RP_TAGS_PORT, rpal_ntoh16( (RU16)currentUdpTable->rows[ i ].localPort ) ) || !rSequence_addRU32( notif, RP_TAGS_PROCESS_ID, currentUdpTable->rows[ i ].pid ) || !rSequence_addTIMESTAMP( notif, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ) ) { notif = NULL; } else { rpal_debug_info( "new udp connection: 0x%08X:0x%04X -- 0x%08X.", currentUdpTable->rows[ i ].localIp, currentUdpTable->rows[ i ].localPort, currentUdpTable->rows[ i ].pid ); notifications_publish( RP_TAGS_NOTIFICATION_NEW_UDP4_CONNECTION, notif ); } rSequence_free( notif ); } } } } else if( 0 != nThLoop ) { rpal_debug_warning( "could not get udp connections table." ); } nThLoop++; if( 0 == nThLoop % 10 ) { timeout = libOs_getUsageProportionalTimeout( 1000 ) + 500; } rpal_thread_sleep( timeout ); } rpal_memory_free( currentTcp4Table ); rpal_memory_free( currentUdpTable ); rpal_memory_free( oldTcp4Table ); rpal_memory_free( oldUdpTable ); return NULL; }