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 ) ); }
RBOOL rpal_blob_remove ( rBlob blob, RU32 startOffset, RU32 size ) { RBOOL isSuccess = FALSE; _prBlob pBlob = (_prBlob)blob; if( NULL != pBlob && IS_WITHIN_BOUNDS( pBlob->pData + startOffset, size, pBlob->pData, pBlob->sizeUsed ) && rpal_memory_isValid( pBlob->pData ) ) { rpal_memory_memcpy( pBlob->pData + startOffset, pBlob->pData + startOffset + size, pBlob->sizeUsed - size - startOffset ); pBlob->sizeUsed -= size; if( rpal_memory_isValid( pBlob->pData ) ) { pBlob->pData = rpal_memory_realloc_from( pBlob->pData, pBlob->sizeUsed + sizeof( RWCHAR ), pBlob->from ); pBlob->currentSize = pBlob->sizeUsed; if( NULL != pBlob->pData ) { // We allocate WCHAR more than we need always to ensure that if the buffer contains a wide string it will be terminated rpal_memory_zero( pBlob->pData + pBlob->sizeUsed, sizeof( RWCHAR ) ); isSuccess = TRUE; } } } return isSuccess; }
static RVOID modKernelModeDiff ( rEvent isTimeToStop ) { RU32 i = 0; RU32 nScratch = 0; RU32 prev_nScratch = 0; KernelAcqModule new_from_kernel[ 200 ] = { 0 }; KernelAcqModule prev_from_kernel[ 200 ] = { 0 }; while( !rEvent_wait( isTimeToStop, 1000 ) ) { nScratch = ARRAY_N_ELEM( new_from_kernel ); rpal_memory_zero( new_from_kernel, sizeof( new_from_kernel ) ); if( !kAcq_getNewModules( new_from_kernel, &nScratch ) ) { rpal_debug_warning( "kernel acquisition for new modules failed" ); g_is_kernel_failure = TRUE; break; } for( i = 0; i < prev_nScratch; i++ ) { notifyOfKernelModule( &(prev_from_kernel[ i ]) ); } rpal_memory_memcpy( prev_from_kernel, new_from_kernel, sizeof( prev_from_kernel ) ); prev_nScratch = nScratch; } }
RBOOL rpal_blob_insert ( rBlob blob, RPVOID pData, RU32 size, RU32 offset ) { RBOOL isAdded = FALSE; _prBlob pBlob = (_prBlob)blob; if( rpal_memory_isValid( blob ) && NULL != pData && 0 != size ) { if( pBlob->currentSize - pBlob->sizeUsed < size ) { pBlob->currentSize += ( 0 != pBlob->growBy ? pBlob->growBy : size ); pBlob->pData = rpal_memory_realloc_from( pBlob->pData, pBlob->currentSize + sizeof( RWCHAR ), pBlob->from ); } if( rpal_memory_isValid( pBlob->pData ) ) { // Relocate existing data rpal_memory_memmove( pBlob->pData + offset + size, pBlob->pData + offset, pBlob->sizeUsed - offset ); rpal_memory_memcpy( pBlob->pData + offset, pData, size ); pBlob->sizeUsed += size; // We allocate WCHAR more than we need always to ensure that if the buffer contains a wide string it will be terminated rpal_memory_zero( pBlob->pData + pBlob->sizeUsed, sizeof( RWCHAR ) ); isAdded = TRUE; } } else if( NULL == pData || 0 == size ) { isAdded = TRUE; } if( isAdded ) { if( !rpal_memory_isValid( pBlob->pData ) ) { isAdded = FALSE; rpal_debug_break(); } } return isAdded; }
RBOOL rpal_blob_add ( rBlob blob, RPVOID pData, RU32 size ) { RBOOL isAdded = FALSE; if( rpal_memory_isValid( blob ) && NULL != pData && 0 != size ) { if( ((_prBlob)blob)->currentSize - ((_prBlob)blob)->sizeUsed < size ) { ((_prBlob)blob)->currentSize += ( ( 0 != ((_prBlob)blob)->growBy && size < ((_prBlob)blob)->growBy ) ? ((_prBlob)blob)->growBy : size ); ((_prBlob)blob)->pData = rpal_memory_realloc_from( ((_prBlob)blob)->pData, ((_prBlob)blob)->currentSize + sizeof( RWCHAR ), ((_prBlob)blob)->from ); } if( rpal_memory_isValid( ((_prBlob)blob)->pData ) ) { rpal_memory_memcpy( ((_prBlob)blob)->pData + ((_prBlob)blob)->sizeUsed, pData, size ); ((_prBlob)blob)->sizeUsed += size; // We allocate WCHAR more than we need always to ensure that if the buffer contains a wide string it will be terminated rpal_memory_zero( ((_prBlob)blob)->pData + ((_prBlob)blob)->sizeUsed, sizeof( RWCHAR ) ); isAdded = TRUE; } } else if( NULL == pData || 0 == size ) { isAdded = TRUE; } if( isAdded ) { if( !rpal_memory_isValid( ((_prBlob)blob)->pData ) ) { isAdded = FALSE; rpal_debug_break(); } } return isAdded; }
RBOOL addHitToNode ( PObsNode node, PObsSig sig ) { RBOOL isSuccess = FALSE; PObsSig* tmp = NULL; RU32 numHits = 0; if( rpal_memory_isValid( node ) && rpal_memory_isValid( sig ) ) { tmp = node->pSigsHit; if( NULL != tmp ) { while( NULL != *tmp ) { numHits++; tmp++; } } node->pSigsHit = rpal_memory_realloc( node->pSigsHit, ( ( numHits + 2 ) * sizeof( PObsSig ) ) ); tmp = node->pSigsHit; if( NULL != tmp ) { rpal_memory_zero( (RPU8)tmp + ( numHits * sizeof( PObsSig ) ), 2 * sizeof( PObsSig ) ); while( NULL != *tmp ) { tmp++; } *tmp = sig; isSuccess = TRUE; } } return isSuccess; }
RPRIVATE RVOID dnsKmDiffThread ( rEvent isTimeToStop ) { RU8 new_from_kernel[ DNS_KB_PACKET_BUFFER * 1024 ] = { 0 }; RU8 prev_from_kernel[ DNS_KB_PACKET_BUFFER * 1024 ] = { 0 }; RU32 sizeInNew = 0; RU32 sizeInPrev = 0; KernelAcqDnsPacket* pPacket = NULL; while( !rEvent_wait( isTimeToStop, 1000 ) ) { rpal_memory_zero( new_from_kernel, sizeof( new_from_kernel ) ); sizeInNew = sizeof( new_from_kernel ); if( !kAcq_getNewDnsPackets( (KernelAcqDnsPacket*)new_from_kernel, &sizeInNew ) ) { rpal_debug_warning( "kernel acquisition for new dns packets failed" ); break; } pPacket = (KernelAcqDnsPacket*)prev_from_kernel; while( IS_WITHIN_BOUNDS( pPacket, sizeof( *pPacket ), prev_from_kernel, sizeInPrev ) && 0 != pPacket->ts && IS_WITHIN_BOUNDS( pPacket, sizeof( *pPacket ) + pPacket->packetSize, prev_from_kernel, sizeInPrev ) ) { processDnsPacket( pPacket ); pPacket = (KernelAcqDnsPacket*)( (RPU8)pPacket + sizeof( *pPacket ) + pPacket->packetSize ); } rpal_memory_memcpy( prev_from_kernel, new_from_kernel, sizeInNew ); sizeInPrev = sizeInNew; } }
static RU32 _checkMemoryForStringSample ( HObs sample, RU32 pid, RPVOID moduleBase, RU64 moduleSize, rEvent isTimeToStop, LibOsPerformanceProfile* perfProfile ) { RPU8 pMem = NULL; RU8* sampleList = NULL; RPU8 sampleNumber = 0; RU32 nSamples = 0; RU32 nSamplesFound = (RU32)(-1); UNREFERENCED_PARAMETER( isTimeToStop ); if( NULL != sample && 0 != pid && NULL != moduleBase && 0 != moduleSize && _MIN_DISK_SAMPLE_SIZE <= ( nSamples = obsLib_getNumPatterns( sample ) ) ) { if( NULL != ( sampleList = rpal_memory_alloc( sizeof( RU8 ) * nSamples ) ) ) { rpal_memory_zero( sampleList, sizeof( RU8 ) * nSamples ); if( processLib_getProcessMemory( pid, moduleBase, moduleSize, (RPVOID*)&pMem, TRUE ) ) { if( obsLib_setTargetBuffer( sample, pMem, (RU32)moduleSize ) ) { while( !rEvent_wait( isTimeToStop, 0 ) && obsLib_nextHit( sample, (RPVOID*)&sampleNumber, NULL ) ) { libOs_timeoutWithProfile( perfProfile, TRUE, isTimeToStop ); if( sampleNumber < (RPU8)NUMBER_TO_PTR( nSamples ) && 0 == sampleList[ (RU32)PTR_TO_NUMBER( sampleNumber ) ] ) { sampleList[ (RU32)PTR_TO_NUMBER( sampleNumber ) ] = 1; nSamplesFound++; } } } rpal_memory_free( pMem ); } else { rpal_debug_info( "failed to get memory for %d: 0x%016X ( 0x%016X ) error %d", pid, moduleBase, moduleSize, rpal_error_getLast() ); } rpal_memory_free( sampleList ); } } return nSamplesFound; }
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; }
RPRIVATE RVOID processDnsPacket ( KernelAcqDnsPacket* pDns ) { rSequence notification = NULL; RU32 i = 0; DnsLabel* pLabel = NULL; DnsHeader* dnsHeader = NULL; DnsResponseInfo* pResponseInfo = NULL; RCHAR domain[ DNS_LABEL_MAX_SIZE ] = { 0 }; RU16 recordType = 0; RU64 timestamp = 0; Atom parentAtom = { 0 }; if( NULL == pDns ) { return; } dnsHeader = (DnsHeader*)( (RPU8)pDns + sizeof( *pDns ) ); pLabel = (DnsLabel*)dnsHeader->data; // We are parsing DNS packets coming from the kernel. They may: // 1- Be requests and not responses, check there are Answers. // 2- Be maliciously crafter packets so we need extra checking for sanity. if( 0 == dnsHeader->anCount || 0 == dnsHeader->qr || DNS_SANITY_MAX_RECORDS < rpal_ntoh16( dnsHeader->qdCount ) || DNS_SANITY_MAX_RECORDS < rpal_ntoh16( dnsHeader->anCount ) ) { return; } // We need to walk the Questions first to get to the Answers // but we don't really care to record them since they'll be repeated // in the Answers. for( i = 0; i < rpal_ntoh16( dnsHeader->qdCount ); i++ ) { DnsQuestionInfo* pQInfo = NULL; pLabel = dnsReadLabels( pLabel, NULL, (RPU8)dnsHeader, pDns->packetSize, 0, 0 ); pQInfo = (DnsQuestionInfo*)( pLabel ); if( !IS_WITHIN_BOUNDS( pQInfo, sizeof( *pQInfo ), dnsHeader, pDns->packetSize ) ) { rpal_debug_warning( "error parsing dns packet" ); break; } pLabel = (DnsLabel*)( (RPU8)pQInfo + sizeof( *pQInfo ) ); } if( !IS_WITHIN_BOUNDS( pLabel, sizeof( RU16 ), dnsHeader, pDns->packetSize ) ) { rpal_debug_warning( "error parsing dns packet" ); return; } // This is what we care about, the Answers (which also point to each Question). // We will emit one event per Answer so as to keep the DNS_REQUEST event flat and atomic. for( i = 0; i < rpal_ntoh16( dnsHeader->anCount ); i++ ) { pResponseInfo = NULL; // This was the Question for this answer. rpal_memory_zero( domain, sizeof( domain ) ); pLabel = dnsReadLabels( pLabel, domain, (RPU8)dnsHeader, pDns->packetSize, 0, 0 ); pResponseInfo = (DnsResponseInfo*)pLabel; pLabel = (DnsLabel*)( (RPU8)pResponseInfo + sizeof( *pResponseInfo ) + rpal_ntoh16( pResponseInfo->rDataLength ) ); if( !IS_WITHIN_BOUNDS( pResponseInfo, sizeof( *pResponseInfo ), dnsHeader, pDns->packetSize ) ) { rpal_debug_warning( "error parsing dns packet" ); break; } if( NULL == ( notification = rSequence_new() ) ) { rpal_debug_warning( "error parsing dns packet" ); break; } // This is a timestamp coming from the kernel so it is not globally adjusted. // We'll adjust it with the global offset. timestamp = pDns->ts; timestamp += MSEC_FROM_SEC( rpal_time_getGlobalFromLocal( 0 ) ); // Try to relate the DNS request to the owner process, this only works on OSX // at the moment (since the kernel does not expose the PID at the packet capture // stage), and even on OSX it's the DNSResolver process. So it's not super useful // but regardless we have the mechanism here as it's better than nothing and when // we add better resolving in the kernel it will work transparently. parentAtom.key.process.pid = pDns->pid; parentAtom.key.category = RP_TAGS_NOTIFICATION_NEW_PROCESS; if( atoms_query( &parentAtom, timestamp ) ) { HbsSetParentAtom( notification, parentAtom.id ); } rSequence_addTIMESTAMP( notification, RP_TAGS_TIMESTAMP, timestamp ); rSequence_addSTRINGA( notification, RP_TAGS_DOMAIN_NAME, domain ); rSequence_addRU32( notification, RP_TAGS_PROCESS_ID, pDns->pid ); recordType = rpal_ntoh16( pResponseInfo->recordType ); rSequence_addRU16( notification, RP_TAGS_MESSAGE_ID, rpal_ntoh16( dnsHeader->msgId ) ); rSequence_addRU16( notification, RP_TAGS_DNS_TYPE, recordType ); if( DNS_A_RECORD == recordType ) { rSequence_addIPV4( notification, RP_TAGS_IP_ADDRESS, *(RU32*)pResponseInfo->rData ); } else if( DNS_AAAA_RECORD == recordType ) { rSequence_addIPV6( notification, RP_TAGS_IP_ADDRESS, pResponseInfo->rData ); } else if( DNS_CNAME_RECORD == recordType ) { // CNAME records will have another label as a value and not an IP. rpal_memory_zero( domain, sizeof( domain ) ); dnsReadLabels( (DnsLabel*)pResponseInfo->rData, domain, (RPU8)dnsHeader, pDns->packetSize, 0, 0 ); rSequence_addSTRINGA( notification, RP_TAGS_CNAME, domain ); } else { // Right now we only care for A, CNAME and AAAA records. rSequence_free( notification ); notification = NULL; continue; } hbs_publish( RP_TAGS_NOTIFICATION_DNS_REQUEST, notification ); rSequence_free( notification ); notification = NULL; } }
static VOID WINAPI ServiceMain ( DWORD dwArgc, RPCHAR lpszArgv ) { RU32 memUsed = 0; RWCHAR svcName[] = { _SERVICE_NAME }; RU32 i = 0; UNREFERENCED_PARAMETER( dwArgc ); UNREFERENCED_PARAMETER( lpszArgv ); if( NULL == ( g_svc_status_handle = RegisterServiceCtrlHandlerW( svcName, SvcCtrlHandler ) ) ) { return; } rpal_memory_zero( &g_svc_status, sizeof( g_svc_status ) ); g_svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_svc_status.dwControlsAccepted = 0; g_svc_status.dwCurrentState = SERVICE_START_PENDING; g_svc_status.dwWin32ExitCode = 0; g_svc_status.dwServiceSpecificExitCode = 0; g_svc_status.dwCheckPoint = 0; SetServiceStatus( g_svc_status_handle, &g_svc_status ); if( NULL == ( g_timeToQuit = rEvent_create( TRUE ) ) ) { g_svc_status.dwControlsAccepted = 0; g_svc_status.dwCurrentState = SERVICE_STOPPED; g_svc_status.dwWin32ExitCode = GetLastError(); g_svc_status.dwCheckPoint = 1; SetServiceStatus( g_svc_status_handle, &g_svc_status ); return; } rpal_debug_info( "initialising rpHCP." ); if( !rpHostCommonPlatformLib_launch( g_svc_primary, g_svc_secondary ) ) { rpal_debug_warning( "error launching hcp." ); } for( i = 0; i < ARRAY_N_ELEM( g_manual_loads ); i++ ) { if( NULL != g_manual_loads[ i ].modPath ) { if( 0 != g_manual_loads[ i ].nMod ) { #ifdef HCP_EXE_ENABLE_MANUAL_LOAD rpHostCommonPlatformLib_load( g_manual_loads[ i ].modPath, g_manual_loads[ i ].nMod ); #endif } else { rpal_debug_error( "Mismatched number of -m modulePath and -n moduleId statements provided!" ); } rpal_memory_free( g_manual_loads[ i ].modPath ); g_manual_loads[ i ].modPath = NULL; } else { break; } } g_svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; g_svc_status.dwCurrentState = SERVICE_RUNNING; g_svc_status.dwWin32ExitCode = 0; g_svc_status.dwCheckPoint = 1; SetServiceStatus( g_svc_status_handle, &g_svc_status ); rpal_debug_info( "...running, waiting to exit..." ); rEvent_wait( g_timeToQuit, RINFINITE ); rEvent_free( g_timeToQuit ); rpal_debug_info( "...exiting..." ); rpal_Context_cleanup(); memUsed = rpal_memory_totalUsed(); if( 0 != memUsed ) { rpal_debug_critical( "Memory leak: %d bytes.\n", memUsed ); //rpal_memory_findMemory(); #ifdef RPAL_FEATURE_MEMORY_ACCOUNTING rpal_memory_printDetailedUsage(); #endif } g_svc_status.dwControlsAccepted = 0; g_svc_status.dwCurrentState = SERVICE_STOPPED; g_svc_status.dwWin32ExitCode = 0; g_svc_status.dwCheckPoint = 3; SetServiceStatus( g_svc_status_handle, &g_svc_status ); }
static RBOOL getSnapshot ( processEntry* toSnapshot ) { RBOOL isSuccess = FALSE; RU32 i = 0; if( NULL != toSnapshot ) { rpal_memory_zero( toSnapshot, sizeof( g_snapshot_1 ) ); } if( NULL != toSnapshot ) { #ifdef RPAL_PLATFORM_WINDOWS HANDLE hSnapshot = NULL; PROCESSENTRY32W procEntry = { 0 }; procEntry.dwSize = sizeof( procEntry ); if( INVALID_HANDLE_VALUE != ( hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ) ) ) { if( Process32FirstW( hSnapshot, &procEntry ) ) { isSuccess = TRUE; do { if( 0 == procEntry.th32ProcessID ) { continue; } toSnapshot[ i ].pid = procEntry.th32ProcessID; toSnapshot[ i ].ppid = procEntry.th32ParentProcessID; i++; } while( Process32NextW( hSnapshot, &procEntry ) && MAX_SNAPSHOT_SIZE > i ); } CloseHandle( hSnapshot ); } #elif defined( RPAL_PLATFORM_LINUX ) RWCHAR procDir[] = _WCH( "/proc/" ); rDir hProcDir = NULL; rFileInfo finfo = {0}; if( rDir_open( (RPWCHAR)&procDir, &hProcDir ) ) { isSuccess = TRUE; while( rDir_next( hProcDir, &finfo ) && MAX_SNAPSHOT_SIZE > i ) { if( rpal_string_wtoi( (RPWCHAR)finfo.fileName, &( toSnapshot[ i ].pid ) ) && 0 != toSnapshot[ i ].pid ) { i++; } } rDir_close( hProcDir ); } #elif defined( RPAL_PLATFORM_MACOSX ) int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; struct kinfo_proc* infos = NULL; size_t size = 0; int ret = 0; int j = 0; if( 0 == ( ret = sysctl( mib, ARRAY_N_ELEM( mib ), infos, &size, NULL, 0 ) ) ) { if( NULL != ( infos = rpal_memory_alloc( size ) ) ) { while( 0 != ( ret = sysctl( mib, ARRAY_N_ELEM( mib ), infos, &size, NULL, 0 ) ) && ENOMEM == errno ) { if( NULL == ( infos = rpal_memory_realloc( infos, size ) ) ) { break; } } } } if( 0 == ret && NULL != infos ) { isSuccess = TRUE; size = size / sizeof( struct kinfo_proc ); for( j = 0; j < size; j++ ) { toSnapshot[ i ].pid = infos[ j ].kp_proc.p_pid; toSnapshot[ i ].ppid = infos[ j ].kp_eproc.e_ppid; i++; } if( NULL != infos ) { rpal_memory_free( infos ); infos = NULL; } } #endif } return isSuccess; }
static RPVOID modUserModeDiff ( rEvent isTimeToStop ) { rBlob previousSnapshot = NULL; rBlob newSnapshot = NULL; _moduleHistEntry curModule = { 0 }; processLibProcEntry* processes = NULL; processLibProcEntry* curProc = NULL; rList modules = NULL; rSequence module = NULL; LibOsPerformanceProfile perfProfile = { 0 }; Atom parentAtom = { 0 }; RU64 curTime = 0; perfProfile.enforceOnceIn = 1; perfProfile.lastTimeoutValue = 10; perfProfile.sanityCeiling = MSEC_FROM_SEC( 10 ); perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = 1; while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) && ( !kAcq_isAvailable() || g_is_kernel_failure ) ) { if( NULL != ( processes = processLib_getProcessEntries( FALSE ) ) ) { if( NULL != ( newSnapshot = rpal_blob_create( 1000 * sizeof( _moduleHistEntry ), 1000 * sizeof( _moduleHistEntry ) ) ) ) { libOs_timeoutWithProfile( &perfProfile, FALSE, isTimeToStop ); curProc = processes; while( rpal_memory_isValid( isTimeToStop ) && #ifdef RPAL_PLATFORM_WINDOWS !rEvent_wait( isTimeToStop, 0 ) && #else // Module listing outside of !rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 1 ) ) && #endif 0 != curProc->pid ) { if( NULL != ( modules = processLib_getProcessModules( curProc->pid ) ) ) { curTime = rpal_time_getGlobalPreciseTime(); while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) && rList_getSEQUENCE( modules, RP_TAGS_DLL, &module ) ) { libOs_timeoutWithProfile( &perfProfile, TRUE, isTimeToStop ); if( rSequence_getPOINTER64( module, RP_TAGS_BASE_ADDRESS, &( curModule.baseAddr ) ) && rSequence_getRU64( module, RP_TAGS_MEMORY_SIZE, &(curModule.size) ) ) { curModule.procId = curProc->pid; rpal_blob_add( newSnapshot, &curModule, sizeof( curModule ) ); if( NULL != previousSnapshot && -1 == rpal_binsearch_array( rpal_blob_getBuffer( previousSnapshot ), rpal_blob_getSize( previousSnapshot ) / sizeof( _moduleHistEntry ), sizeof( _moduleHistEntry ), &curModule, (rpal_ordering_func)_cmpModule ) ) { hbs_timestampEvent( module, curTime ); parentAtom.key.category = RP_TAGS_NOTIFICATION_NEW_PROCESS; parentAtom.key.process.pid = curProc->pid; if( atoms_query( &parentAtom, curTime ) ) { HbsSetParentAtom( module, parentAtom.id ); } rpal_memory_zero( &parentAtom, sizeof( parentAtom ) ); hbs_publish( RP_TAGS_NOTIFICATION_MODULE_LOAD, module ); } } } rList_free( modules ); } curProc++; } if( !rpal_sort_array( rpal_blob_getBuffer( newSnapshot ), rpal_blob_getSize( newSnapshot ) / sizeof( _moduleHistEntry ), sizeof( _moduleHistEntry ), (rpal_ordering_func)_cmpModule ) ) { rpal_debug_warning( "error sorting modules" ); } } rpal_memory_free( processes ); } if( NULL != previousSnapshot ) { rpal_blob_free( previousSnapshot ); } previousSnapshot = newSnapshot; newSnapshot = NULL; } if( NULL != previousSnapshot ) { rpal_blob_free( previousSnapshot ); } return NULL; }
static RVOID kernelModeDiff ( rEvent isTimeToStop ) { RU32 i = 0; RU32 nScratch = 0; RU32 nProcessEntries = 0; KernelAcqProcess new_from_kernel[ 200 ] = { 0 }; processEntry tracking_user[ MAX_SNAPSHOT_SIZE ] = { 0 }; while( !rEvent_wait( isTimeToStop, 1000 ) ) { nScratch = ARRAY_N_ELEM( new_from_kernel ); rpal_memory_zero( new_from_kernel, sizeof( new_from_kernel ) ); if( !kAcq_getNewProcesses( new_from_kernel, &nScratch ) ) { rpal_debug_warning( "kernel acquisition for new processes failed" ); g_is_kernel_failure = TRUE; break; } for( i = 0; i < nScratch; i++ ) { notifyOfProcess( new_from_kernel[ i ].pid, new_from_kernel[ i ].ppid, TRUE, new_from_kernel[ i ].path, new_from_kernel[ i ].cmdline, new_from_kernel[ i ].uid, new_from_kernel[ i ].ts ); if( nProcessEntries >= ARRAY_N_ELEM( tracking_user ) - 1 ) { continue; } tracking_user[ nProcessEntries ].pid = new_from_kernel[ i ].pid; tracking_user[ nProcessEntries ].ppid = new_from_kernel[ i ].ppid; nProcessEntries++; } for( i = 0; i < nProcessEntries; i++ ) { if( !processLib_isPidInUse( tracking_user[ i ].pid ) ) { notifyOfProcess( tracking_user[ i ].pid, tracking_user[ i ].ppid, FALSE, NULL, NULL, KERNEL_ACQ_NO_USER_ID, 0 ); if( nProcessEntries != i + 1 ) { rpal_memory_memmove( &(tracking_user[ i ]), &(tracking_user[ i + 1 ]), nProcessEntries - i + 1 ); } nProcessEntries--; } } } }
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; }
PObsNode addTransition ( PObsNode parent, PObsNode node, PObsNode to, RU8 onValue ) { PObsNode retNode = NULL; RU32 currentNodeSize = 0; RU8 numElemToAdd = 0; RU8 indexToInsert = 0; PObsNode originalNode = node; RU32 i = 0; if( rpal_memory_isValid( node ) ) { currentNodeSize = sizeof( ObsNode ) + ( node->nElements * sizeof( RPVOID ) ); if( !IS_IN_RANGE( node, onValue ) ) { if( onValue >= node->startOffset + node->nElements ) { numElemToAdd = onValue - ( node->startOffset + node->nElements ) + 1; } else { numElemToAdd = node->startOffset - onValue; } if( node->nAllocated < node->nElements + numElemToAdd ) { node = rpal_memory_realloc( node, currentNodeSize + ( numElemToAdd * sizeof( RPVOID ) ) ); rpal_memory_zero( node->elements + node->nElements, numElemToAdd * sizeof( RPVOID ) ); node->nAllocated = node->nElements + numElemToAdd; } if( onValue < node->startOffset && 0 < node->nElements ) { rpal_memory_memmove( node->elements + numElemToAdd, node->elements, node->nElements * sizeof( RPVOID ) ); node->startOffset = node->startOffset - (RU8)numElemToAdd; } node->nElements += numElemToAdd; // The above realloc may have changed the pointer so we need // to update it in the parent, if it exists... if( NULL != parent && originalNode != node ) { for( i = 0; i < parent->nElements; i++ ) { if( originalNode == parent->elements[ i ] ) { parent->elements[ i ] = node; } } } } indexToInsert = EFFECTIVE_INDEX( node, onValue ); if( NULL == node->elements[ indexToInsert ] ) { node->elements[ indexToInsert ] = to; retNode = node; } } return retNode; }