static RBOOL _reportEvents ( StatefulMachine* machine ) { RBOOL isSuccess = FALSE; rSequence wrapper = NULL; rList events = NULL; rSequence event = NULL; RU32 i = 0; if( NULL != machine ) { if( NULL != ( wrapper = rSequence_new() ) ) { if( NULL != ( events = rList_new( RP_TAGS_EVENT, RPCM_SEQUENCE ) ) ) { for( i = 0; i < machine->history->nElements; i++ ) { event = ( (StatefulEvent*)machine->history->elements[ i ] )->data; rList_addSEQUENCE( events, rSequence_duplicate( event ) ); } if( !rSequence_addLIST( wrapper, RP_TAGS_EVENTS, events ) ) { rList_free( events ); } else { hbs_timestampEvent( wrapper, 0 ); isSuccess = hbs_publish( machine->desc->reportEventType, wrapper ); } } rSequence_free( wrapper ); } } return isSuccess; }
static RVOID getDocument ( rpcm_tag notifId, rSequence notif ) { rSequence tmp = NULL; DocSearchContext ctx = { 0 }; RU32 hashSize = 0; rList foundDocs = NULL; RBOOL isAAlloced = FALSE; RBOOL isWAlloced = FALSE; UNREFERENCED_PARAMETER( notifId ); if( NULL != notif ) { if( !rSequence_getSTRINGA( notif, RP_TAGS_STRING_PATTERN, &ctx.exprA ) ) { ctx.exprA = NULL; } if( !rSequence_getSTRINGW( notif, RP_TAGS_STRING_PATTERN, &ctx.exprW ) ) { ctx.exprW = NULL; } if( NULL != ctx.exprA && NULL == ctx.exprW ) { ctx.exprW = rpal_string_atow( ctx.exprA ); isWAlloced = TRUE; } if( NULL != ctx.exprW && NULL == ctx.exprA ) { ctx.exprA = rpal_string_wtoa( ctx.exprW ); isAAlloced = TRUE; } if( !rSequence_getBUFFER( notif, RP_TAGS_HASH, (RPU8*)&ctx.pHash, &hashSize ) || sizeof( *ctx.pHash ) != hashSize ) { // Unexpected hash size, let's not gamble ctx.pHash = NULL; } } if( rMutex_lock( cacheMutex ) ) { if( NULL != ( foundDocs = rList_new( RP_TAGS_FILE_INFO, RPCM_SEQUENCE ) ) ) { while( HbsRingBuffer_find( documentCache, (HbsRingBufferCompareFunc)findDoc, &ctx, &tmp ) ) { // TODO: optimize this since if we're dealing with large files // we will be temporarily using large amounts of duplicate memory. // We just need to do some shallow free of the datastructures // somehow. if( NULL != ( tmp = rSequence_duplicate( tmp ) ) ) { if( !rList_addSEQUENCE( foundDocs, tmp ) ) { rSequence_free( tmp ); } } } if( !rSequence_addLIST( notif, RP_TAGS_FILES, foundDocs ) ) { rList_free( foundDocs ); } } rMutex_unlock( cacheMutex ); notifications_publish( RP_TAGS_NOTIFICATION_GET_DOCUMENT_REP, notif ); } if( isAAlloced ) { rpal_memory_free( ctx.exprA ); } if( isWAlloced ) { rpal_memory_free( ctx.exprW ); } }
//============================================================================= // 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 rList beaconHome ( ) { rList response = NULL; rList exfil = NULL; rSequence msg = NULL; RU32 nExfilMsg = 0; rSequence tmpMessage = NULL; if( NULL != ( exfil = rList_new( RP_TAGS_MESSAGE, RPCM_SEQUENCE ) ) ) { if( NULL != ( msg = rSequence_new() ) ) { if( rSequence_addBUFFER( msg, RP_TAGS_HASH, g_hbs_state.currentConfigHash, CRYPTOLIB_HASH_SIZE ) ) { if( !rList_addSEQUENCE( exfil, msg ) ) { rSequence_free( msg ); msg = NULL; } tmpMessage = msg; } else { rSequence_free( msg ); msg = NULL; } } while( rQueue_remove( g_hbs_state.outQueue, &msg, NULL, 0 ) ) { nExfilMsg++; if( !rList_addSEQUENCE( exfil, msg ) ) { rSequence_free( msg ); } } rpal_debug_info( "%d messages ready for exfil.", nExfilMsg ); if( rpHcpI_beaconHome( exfil, &response ) ) { rpal_debug_info( "%d messages received from cloud.", rList_getNumElements( response ) ); } else if( g_hbs_state.maxQueueSize > rList_getEstimateSize( exfil ) ) { rpal_debug_info( "beacon failed, re-adding %d messages.", rList_getNumElements( exfil ) ); // We will attempt to re-add the existing messages back in the queue since this failed rList_resetIterator( exfil ); while( rList_getSEQUENCE( exfil, RP_TAGS_MESSAGE, &msg ) ) { // Ignore message we generate temporarily for the beacon if( tmpMessage == msg ) { rSequence_free( msg ); continue; } if( !rQueue_add( g_hbs_state.outQueue, msg, 0 ) ) { rSequence_free( msg ); } } rList_shallowFree( exfil ); exfil = NULL; } else { rpal_debug_warning( "beacon failed but discarded exfil because of its size." ); } if( NULL != exfil ) { rList_free( exfil ); } } return response; }
static rList assembleRequest ( RPU8 optCrashCtx, RU32 optCrashCtxSize ) { rSequence req = NULL; RU32 moduleIndex = 0; rList msgList = NULL; rList modList = NULL; rSequence modEntry = NULL; if( NULL != ( req = rSequence_new() ) ) { // Add some basic info rSequence_addRU32( req, RP_TAGS_MEMORY_USAGE, rpal_memory_totalUsed() ); rSequence_addTIMESTAMP( req, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ); // If we have a crash context to report if( NULL != optCrashCtx ) { if( !rSequence_addBUFFER( req, RP_TAGS_HCP_CRASH_CONTEXT, optCrashCtx, optCrashCtxSize ) ) { rpal_debug_error( "error adding crash context of size %d to hcp beacon", optCrashCtxSize ); } else { rpal_debug_info( "crash context is being bundled in hcp beacon" ); } } // List of loaded modules if( NULL != ( modList = rList_new( RP_TAGS_HCP_MODULE, RPCM_SEQUENCE ) ) ) { for( moduleIndex = 0; moduleIndex < RP_HCP_CONTEXT_MAX_MODULES; moduleIndex++ ) { if( NULL != g_hcpContext.modules[ moduleIndex ].hModule ) { if( NULL != ( modEntry = rSequence_new() ) ) { if( !rSequence_addBUFFER( modEntry, RP_TAGS_HASH, g_hcpContext.modules[ moduleIndex ].hash, sizeof( g_hcpContext.modules[ moduleIndex ].hash ) ) || !rSequence_addRU8( modEntry, RP_TAGS_HCP_MODULE_ID, g_hcpContext.modules[ moduleIndex ].id ) || !rList_addSEQUENCE( modList, modEntry ) ) { break; } // We take the opportunity to cleanup the list of modules... if( rpal_thread_wait( g_hcpContext.modules[ moduleIndex ].hThread, 0 ) ) { // This thread has exited, which is our signal that the module // has stopped executing... rEvent_free( g_hcpContext.modules[ moduleIndex ].isTimeToStop ); rpal_thread_free( g_hcpContext.modules[ moduleIndex ].hThread ); rpal_memory_zero( &(g_hcpContext.modules[ moduleIndex ]), sizeof( g_hcpContext.modules[ moduleIndex ] ) ); if( !rSequence_addRU8( modEntry, RP_TAGS_HCP_MODULE_TERMINATED, 1 ) ) { break; } } } } } if( !rSequence_addLIST( req, RP_TAGS_HCP_MODULES, modList ) ) { rList_free( modList ); } } if( NULL != ( msgList = rList_new( RP_TAGS_MESSAGE, RPCM_SEQUENCE ) ) ) { if( !rList_addSEQUENCE( msgList, req ) ) { rList_free( msgList ); rSequence_free( req ); msgList = NULL; } } else { rSequence_free( req ); } } return msgList; }
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 ); } }
RPRIVATE RVOID mem_strings ( rpcm_tag eventType, rSequence event ) { RU32 pid = 0; rList memMapList = NULL; rSequence region = NULL; RU64 memBase = 0; RU64 memSize = 0; RPU8 pRegion = NULL; rList stringsAList = NULL; rList stringsWList = NULL; 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 ) ) ) ) { if( NULL != ( memMapList = processLib_getProcessMemoryMap( pid ) ) && ( NULL != ( stringsAList = rList_new( RP_TAGS_STRINGSA, RPCM_STRINGA ) ) ) && ( NULL != ( stringsWList = rList_new( RP_TAGS_STRINGSW, RPCM_STRINGW ) ) ) ) { while( rList_getSEQUENCE( memMapList, RP_TAGS_MEMORY_REGION, ®ion ) ) { if( rSequence_getPOINTER64( region, RP_TAGS_BASE_ADDRESS, &memBase ) && rSequence_getRU64( region, RP_TAGS_MEMORY_SIZE, &memSize ) ) { if( processLib_getProcessMemory( pid, (RPVOID)rpal_ULongToPtr( memBase ), memSize, (RPVOID*)&pRegion, TRUE ) ) { // now search for strings inside this region _getStringsList( stringsAList, stringsWList, pRegion, memSize, minLength, maxLength ); rpal_memory_free( pRegion ); } } } if( !rSequence_addLIST( event, RP_TAGS_STRINGSA, stringsAList ) ) { rList_free( stringsAList ); } if( !rSequence_addLIST( event, RP_TAGS_STRINGSW, stringsWList ) ) { rList_free( stringsWList ); } } else { rSequence_addRU32( event, RP_TAGS_ERROR, rpal_error_getLast() ); } if( NULL != memMapList ) { rList_free( memMapList ); } } hbs_timestampEvent( event, 0 ); hbs_publish( RP_TAGS_NOTIFICATION_MEM_STRINGS_REP, event ); } }
RPRIVATE rSequence _findStringsInProcess ( RU32 pid, rList searchStrings, RU32 minLength, RU32 maxLength ) { rSequence info = NULL; rList memMapList = NULL; rSequence region = NULL; RU64 memBase = 0; RU64 memSize = 0; RPU8 pRegion = NULL; rList stringsFound = NULL; if( NULL != searchStrings ) { if( NULL != ( info = rSequence_new() ) ) { rSequence_addRU32( info, RP_TAGS_PROCESS_ID, pid ); if( NULL != ( memMapList = processLib_getProcessMemoryMap( pid ) ) && ( NULL != ( stringsFound = rList_new( RP_TAGS_STRINGSW, RPCM_SEQUENCE ) ) ) ) { while( rList_getSEQUENCE( memMapList, RP_TAGS_MEMORY_REGION, ®ion ) ) { if( rSequence_getPOINTER64( region, RP_TAGS_BASE_ADDRESS, &memBase ) && rSequence_getRU64( region, RP_TAGS_MEMORY_SIZE, &memSize ) ) { if( processLib_getProcessMemory( pid, (RPVOID)rpal_ULongToPtr( memBase ), memSize, (RPVOID*)&pRegion, TRUE ) ) { // now search for strings inside this region _searchForStrings( stringsFound, searchStrings, pRegion, memSize, memBase, minLength, maxLength); rpal_memory_free( pRegion ); } } } if( !rSequence_addLIST( info, RP_TAGS_STRINGS_FOUND, stringsFound ) ) { rList_free( stringsFound ); } } else { rSequence_addRU32( info, RP_TAGS_ERROR, rpal_error_getLast() ); } if( NULL != memMapList ) { rList_free( memMapList ); } } } return info; }