static rList _spotCheckProcess ( rEvent isTimeToStop, RU32 pid, LibOsPerformanceProfile* perfProfile ) { rList hollowedModules = NULL; rList modules = NULL; rSequence module = NULL; RPNCHAR modulePath = NULL; RU32 fileSize = 0; RU64 moduleBase = 0; RU64 moduleSize = 0; HObs diskSample = NULL; rSequence hollowedModule = NULL; RU32 lastScratchIndex = 0; RU32 nSamplesFound = 0; RU32 nSamplesTotal = 0; RU32 tmpSamplesFound = 0; RU32 tmpSamplesSize = 0; RTIME runTime = 0; rpal_debug_info( "spot checking process %d", pid ); if( NULL != ( modules = processLib_getProcessModules( pid ) ) ) { while( !rEvent_wait( isTimeToStop, 0 ) && rList_getSEQUENCE( modules, RP_TAGS_DLL, &module ) ) { libOs_timeoutWithProfile( perfProfile, FALSE, isTimeToStop ); runTime = rpal_time_getLocal(); modulePath = NULL; lastScratchIndex = 0; if( ( rSequence_getSTRINGN( module, RP_TAGS_FILE_PATH, &modulePath ) ) && rSequence_getPOINTER64( module, RP_TAGS_BASE_ADDRESS, &moduleBase ) && rSequence_getRU64( module, RP_TAGS_MEMORY_SIZE, &moduleSize ) ) { if( 0 != ( fileSize = rpal_file_getSize( modulePath, TRUE ) ) ) { nSamplesFound = 0; nSamplesTotal = 0; tmpSamplesFound = (RU32)( -1 ); while( !rEvent_wait( isTimeToStop, 0 ) && NULL != ( diskSample = _getModuleDiskStringSample( modulePath, &lastScratchIndex, isTimeToStop, perfProfile ) ) ) { libOs_timeoutWithProfile( perfProfile, TRUE, isTimeToStop ); tmpSamplesSize = obsLib_getNumPatterns( diskSample ); if( 0 != tmpSamplesSize ) { tmpSamplesFound = _checkMemoryForStringSample( diskSample, pid, NUMBER_TO_PTR( moduleBase ), moduleSize, isTimeToStop, perfProfile ); obsLib_free( diskSample ); if( (RU32)( -1 ) == tmpSamplesFound ) { break; } nSamplesFound += tmpSamplesFound; nSamplesTotal += tmpSamplesSize; if( _MIN_DISK_SAMPLE_SIZE <= nSamplesTotal && ( _MIN_SAMPLE_MATCH_PERCENT < ( (RFLOAT)nSamplesFound / nSamplesTotal ) * 100 ) && _MIN_DISK_BIN_COVERAGE_PERCENT <= (RFLOAT)( ( lastScratchIndex * _SCRATCH_SIZE ) / fileSize ) * 100 ) { break; } } else { obsLib_free( diskSample ); } } } else { rpal_debug_info( "could not get file information, not checking" ); } rpal_debug_info( "process hollowing check found a match in %d ( %d / %d ) from %d passes in %d sec", pid, nSamplesFound, nSamplesTotal, lastScratchIndex, rpal_time_getLocal() - runTime ); if( !rEvent_wait( isTimeToStop, 0 ) && (RU32)(-1) != tmpSamplesFound && _MIN_DISK_SAMPLE_SIZE <= nSamplesTotal && ( ( (RFLOAT)nSamplesFound / nSamplesTotal ) * 100 ) < _MIN_SAMPLE_MATCH_PERCENT ) { rpal_debug_info( "sign of process hollowing found in process %d", pid ); if( NULL != ( hollowedModule = rSequence_duplicate( module ) ) ) { if( !rList_addSEQUENCE( hollowedModules, hollowedModule ) ) { rSequence_free( hollowedModule ); } } } } else { rpal_debug_info( "module missing characteristic" ); } } rList_free( modules ); } else { rpal_debug_info( "failed to get process modules, might be dead" ); } return hollowedModules; }
static RPVOID spotCheckProcessConstantly ( rEvent isTimeToStop, RPVOID ctx ) { rSequence originalRequest = (rSequence)ctx; processLibProcEntry* procs = NULL; processLibProcEntry* proc = NULL; rList hollowedModules = NULL; rSequence processInfo = NULL; LibOsPerformanceProfile perfProfile = { 0 }; Atom parentAtom = { 0 }; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = _PROFILE_INCREMENT; perfProfile.enforceOnceIn = 1; perfProfile.lastTimeoutValue = _INITIAL_PROFILED_TIMEOUT; perfProfile.sanityCeiling = _SANITY_CEILING; while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) ) { libOs_timeoutWithProfile( &perfProfile, FALSE, isTimeToStop ); if( NULL != ( procs = processLib_getProcessEntries( TRUE ) ) ) { proc = procs; while( 0 != proc->pid && rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) ) { libOs_timeoutWithProfile( &perfProfile, TRUE, isTimeToStop ); if( NULL != ( hollowedModules = _spotCheckProcess( isTimeToStop, proc->pid, &perfProfile ) ) ) { if( NULL != ( processInfo = processLib_getProcessInfo( proc->pid, NULL ) ) || ( NULL != ( processInfo = rSequence_new() ) && rSequence_addRU32( processInfo, RP_TAGS_PROCESS_ID, proc->pid ) ) ) { if( !rSequence_addLIST( processInfo, RP_TAGS_MODULES, hollowedModules ) ) { rList_free( hollowedModules ); } else { parentAtom.key.category = RP_TAGS_NOTIFICATION_NEW_PROCESS; parentAtom.key.process.pid = proc->pid; if( atoms_query( &parentAtom, 0 ) ) { HbsSetParentAtom( processInfo, parentAtom.id ); } hbs_markAsRelated( originalRequest, processInfo ); hbs_publish( RP_TAGS_NOTIFICATION_MODULE_MEM_DISK_MISMATCH, processInfo ); } rSequence_free( processInfo ); } else { rList_free( hollowedModules ); } } proc++; } rpal_memory_free( procs ); } } return NULL; }
static HObs _getModuleDiskStringSample ( RPNCHAR modulePath, RU32* pLastScratch, rEvent isTimeToStop, LibOsPerformanceProfile* perfProfile ) { HObs sample = NULL; RPU8 scratch = NULL; rFile hFile = NULL; RU32 read = 0; RPU8 start = NULL; RPU8 end = NULL; RU32 toSkip = 0; RU32 longestLength = 0; RBOOL isUnicode = FALSE; RPU8 sampleNumber = 0; rBloom stringsSeen = NULL; RU64 readOffset = 0; UNREFERENCED_PARAMETER( isTimeToStop ); if( NULL != modulePath && NULL != pLastScratch ) { readOffset = *pLastScratch * _SCRATCH_SIZE; if( NULL != ( stringsSeen = rpal_bloom_create( _MAX_DISK_SAMPLE_SIZE, 0.0001 ) ) ) { if( NULL != ( scratch = rpal_memory_alloc( _SCRATCH_SIZE ) ) ) { if( rFile_open( modulePath, &hFile, RPAL_FILE_OPEN_EXISTING | RPAL_FILE_OPEN_READ ) ) { if( readOffset == rFile_seek( hFile, readOffset, rFileSeek_SET ) && 0 != ( read = rFile_readUpTo( hFile, _SCRATCH_SIZE, scratch ) ) ) { if( NULL != ( sample = obsLib_new( _MAX_DISK_SAMPLE_SIZE, 0 ) ) ) { ( *pLastScratch )++; start = scratch; end = scratch + read; // We parse for strings up to 'read', we don't care about the // memory boundary, we might truncate some strings but we're // sampling anyway. while( !rEvent_wait( isTimeToStop, 0 ) && ( start >= scratch ) && ( start >= scratch ) && ( start + _MIN_SAMPLE_STR_LEN ) < ( scratch + read ) && _MAX_DISK_SAMPLE_SIZE >= PTR_TO_NUMBER( sampleNumber ) ) { libOs_timeoutWithProfile( perfProfile, TRUE, isTimeToStop ); isUnicode = FALSE; if( _longestString( (RPCHAR)start, (RU32)( end - start ), &toSkip, &longestLength, &isUnicode ) && _MIN_SAMPLE_STR_LEN <= longestLength && _MAX_SAMPLE_STR_LEN >= longestLength ) { if( rpal_bloom_addIfNew( stringsSeen, start, longestLength ) ) { if( obsLib_addPattern( sample, start, longestLength, sampleNumber ) ) { sampleNumber++; } } } start += toSkip; } } } rFile_close( hFile ); } rpal_memory_free( scratch ); } rpal_bloom_destroy( stringsSeen ); } } return sample; }
static 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 RVOID dnsUmDiffThread ( rEvent isTimeToStop ) { rSequence notif = NULL; rBlob snapCur = NULL; rBlob snapPrev = NULL; _dnsRecord rec = { 0 }; _dnsRecord* pCurRec = NULL; RU32 i = 0; LibOsPerformanceProfile perfProfile = { 0 }; #ifdef RPAL_PLATFORM_WINDOWS PDNSCACHEENTRY pDnsEntry = NULL; PDNSCACHEENTRY pPrevDnsEntry = NULL; #endif perfProfile.enforceOnceIn = 1; perfProfile.sanityCeiling = MSEC_FROM_SEC( 10 ); perfProfile.lastTimeoutValue = 100; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = 1; while( !rEvent_wait( isTimeToStop, 0 ) ) { if( kAcq_isAvailable() ) { // If kernel acquisition becomes available, try kernel again. return; } libOs_timeoutWithProfile( &perfProfile, FALSE, isTimeToStop ); if( NULL != ( snapCur = rpal_blob_create( 0, 10 * sizeof( rec ) ) ) ) { #ifdef RPAL_PLATFORM_WINDOWS if( TRUE == getCache( &pDnsEntry ) ) { while( NULL != pDnsEntry ) { rec.flags = pDnsEntry->dwFlags; rec.type = pDnsEntry->wType; if( NULL != ( rec.name = rpal_string_strdup( pDnsEntry->pszName ) ) ) { rpal_blob_add( snapCur, &rec, sizeof( rec ) ); } pPrevDnsEntry = pDnsEntry; pDnsEntry = pDnsEntry->pNext; freeCacheEntry( pPrevDnsEntry->pszName, DnsFreeFlat ); freeCacheEntry( pPrevDnsEntry, DnsFreeFlat ); } rpal_sort_array( rpal_blob_getBuffer( snapCur ), rpal_blob_getSize( snapCur ) / sizeof( rec ), sizeof( rec ), _cmpDns ); } #elif defined( RPAL_PLATFORM_MACOSX ) rpal_thread_sleep( MSEC_FROM_SEC( 2 ) ); #endif // Do a general diff of the snapshots to find new entries. if( NULL != snapPrev ) { i = 0; while( !rEvent_wait( isTimeToStop, 0 ) && NULL != ( pCurRec = rpal_blob_arrElem( snapCur, sizeof( rec ), i++ ) ) ) { if( -1 == rpal_binsearch_array( rpal_blob_getBuffer( snapPrev ), rpal_blob_getSize( snapPrev ) / sizeof( rec ), sizeof( rec ), pCurRec, (rpal_ordering_func)_cmpDns ) ) { if( NULL != ( notif = rSequence_new() ) ) { rSequence_addSTRINGN( notif, RP_TAGS_DOMAIN_NAME, pCurRec->name ); rSequence_addRU16( notif, RP_TAGS_DNS_TYPE, pCurRec->type ); rSequence_addRU32( notif, RP_TAGS_DNS_FLAGS, pCurRec->flags ); hbs_timestampEvent( notif, 0 ); hbs_publish( RP_TAGS_NOTIFICATION_DNS_REQUEST, notif ); rSequence_free( notif ); } } } } } if( NULL != snapPrev ) { _freeRecords( snapPrev ); rpal_blob_free( snapPrev ); snapPrev = NULL; } snapPrev = snapCur; snapCur = NULL; libOs_timeoutWithProfile( &perfProfile, TRUE, isTimeToStop ); } if( NULL != snapPrev ) { _freeRecords( snapPrev ); rpal_blob_free( snapPrev ); snapPrev = NULL; } }
static RPVOID trackerDiffThread ( rEvent isTimeToStop, RPVOID ctx ) { _volEntry* prevVolumes = NULL; RU32 nVolumes = 0; rList snapshot = NULL; rList prevSnapshot = NULL; _volEntry* newVolumes = NULL; RU32 nNewVolumes = 0; rSequence volume = NULL; rBlob serial = NULL; RU32 i = 0; LibOsPerformanceProfile perfProfile = { 0 }; UNREFERENCED_PARAMETER( ctx ); perfProfile.enforceOnceIn = 1; perfProfile.sanityCeiling = MSEC_FROM_SEC( 10 ); perfProfile.lastTimeoutValue = 10; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = 1; while( !rEvent_wait( isTimeToStop, 0 ) ) { libOs_timeoutWithProfile( &perfProfile, FALSE ); if( NULL != ( snapshot = libOs_getVolumes() ) ) { if( NULL != ( newVolumes = rpal_memory_alloc( sizeof( *newVolumes ) * rList_getNumElements( snapshot ) ) ) ) { nNewVolumes = 0; while( !rEvent_wait( isTimeToStop, 0 ) && rList_getSEQUENCE( snapshot, RP_TAGS_VOLUME, &volume ) ) { libOs_timeoutWithProfile( &perfProfile, TRUE ); if( NULL != ( serial = rpal_blob_create( 0, 0 ) ) ) { if( rSequence_serialise( volume, serial ) && CryptoLib_hash( rpal_blob_getBuffer( serial ), rpal_blob_getSize( serial ), &( newVolumes[ nNewVolumes ].hash ) ) ) { newVolumes[ nNewVolumes ].volume = volume; if( NULL != prevVolumes && ( -1 ) == rpal_binsearch_array( prevVolumes, nVolumes, sizeof( *prevVolumes ), &( newVolumes[ nNewVolumes ] ), (rpal_ordering_func)_cmpHashes ) ) { notifications_publish( RP_TAGS_NOTIFICATION_VOLUME_MOUNT, volume ); rpal_debug_info( "new volume mounted" ); } nNewVolumes++; } rpal_blob_free( serial ); } } if( !rEvent_wait( isTimeToStop, 0 ) ) { rpal_sort_array( newVolumes, nNewVolumes, sizeof( *newVolumes ), (rpal_ordering_func)_cmpHashes ); for( i = 0; i < nVolumes; i++ ) { libOs_timeoutWithProfile( &perfProfile, TRUE ); if( ( -1 ) == rpal_binsearch_array( newVolumes, nNewVolumes, sizeof( *newVolumes ), &( prevVolumes[ i ].hash ), (rpal_ordering_func)_cmpHashes ) ) { notifications_publish( RP_TAGS_NOTIFICATION_VOLUME_UNMOUNT, prevVolumes[ i ].volume ); rpal_debug_info( "volume unmounted" ); } } } } if( NULL != prevSnapshot ) { rList_free( prevSnapshot ); } prevSnapshot = snapshot; if( NULL != prevVolumes ) { rpal_memory_free( prevVolumes ); } prevVolumes = newVolumes; nVolumes = nNewVolumes; } } if( NULL != prevSnapshot ) { rList_free( prevSnapshot ); } if( NULL != prevVolumes ) { rpal_memory_free( prevVolumes ); } return NULL; }
static RPVOID 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 userModeDiff ( rEvent isTimeToStop ) { processEntry snapshot_1[ MAX_SNAPSHOT_SIZE ] = { 0 }; processEntry snapshot_2[ MAX_SNAPSHOT_SIZE ] = { 0 }; processEntry* currentSnapshot = snapshot_1; processEntry* previousSnapshot = snapshot_2; processEntry* tmpSnapshot = NULL; RBOOL isFirstSnapshots = TRUE; RU32 i = 0; RBOOL isFound = FALSE; RU32 nTmpElem = 0; RU32 nCurElem = 0; RU32 nPrevElem = 0; LibOsPerformanceProfile perfProfile = { 0 }; perfProfile.enforceOnceIn = 1; perfProfile.sanityCeiling = MSEC_FROM_SEC( 10 ); perfProfile.lastTimeoutValue = 100; perfProfile.targetCpuPerformance = 0; perfProfile.globalTargetCpuPerformance = GLOBAL_CPU_USAGE_TARGET; perfProfile.timeoutIncrementPerSec = 10; while( !rEvent_wait( isTimeToStop, 0 ) && ( !kAcq_isAvailable() || g_is_kernel_failure ) ) { libOs_timeoutWithProfile( &perfProfile, FALSE ); tmpSnapshot = currentSnapshot; currentSnapshot = previousSnapshot; previousSnapshot = tmpSnapshot; nTmpElem = nCurElem; nCurElem = nPrevElem; nPrevElem = nTmpElem; if( getSnapshot( currentSnapshot, &nCurElem ) ) { if( isFirstSnapshots ) { isFirstSnapshots = FALSE; continue; } // Diff to find new processes for( i = 0; i < nCurElem; i++ ) { isFound = FALSE; if( (RU32)( -1 ) != rpal_binsearch_array( previousSnapshot, nPrevElem, sizeof( processEntry ), &(currentSnapshot[ i ].pid), (rpal_ordering_func)rpal_order_RU32 ) ) { isFound = TRUE; } if( !isFound ) { if( !notifyOfProcess( currentSnapshot[ i ].pid, currentSnapshot[ i ].ppid, TRUE, NULL, NULL, KERNEL_ACQ_NO_USER_ID, 0 ) ) { rpal_debug_warning( "error reporting new process: %d", currentSnapshot[ i ].pid ); } } } // Diff to find terminated processes for( i = 0; i < nPrevElem; i++ ) { isFound = FALSE; if( (RU32)( -1 ) != rpal_binsearch_array( currentSnapshot, nCurElem, sizeof( processEntry ), &(previousSnapshot[ i ].pid), (rpal_ordering_func)rpal_order_RU32 ) ) { isFound = TRUE; } if( !isFound ) { if( !notifyOfProcess( previousSnapshot[ i ].pid, previousSnapshot[ i ].ppid, FALSE, NULL, NULL, KERNEL_ACQ_NO_USER_ID, 0 ) ) { rpal_debug_warning( "error reporting terminated process: %d", previousSnapshot[ i ].pid ); } } } } libOs_timeoutWithProfile( &perfProfile, TRUE ); } }
static RPVOID lookForHiddenModulesIn ( rEvent isTimeToStop, RU32 processId, rSequence originalRequest, LibOsPerformanceProfile* perfProfile ) { rList mods = NULL; _MemRange* memRanges = NULL; RU32 nRanges = 0; rList map = NULL; rSequence region = NULL; RU8 memType = 0; RU8 memProtect = 0; RU64 memBase = 0; RU64 memSize = 0; RPU8 pMem = NULL; RBOOL isPrefetched = FALSE; RBOOL isCurrentExec = FALSE; RBOOL isHidden = FALSE; rSequence procInfo = NULL; #ifdef RPAL_PLATFORM_WINDOWS PIMAGE_DOS_HEADER pDos = NULL; PIMAGE_NT_HEADERS pNt = NULL; #endif rpal_debug_info( "looking for hidden modules in process %d.", processId ); if( NULL != ( mods = processLib_getProcessModules( processId ) ) ) { if( assembleRanges( mods, &memRanges, &nRanges ) ) { if( NULL != ( map = processLib_getProcessMemoryMap( processId ) ) ) { // Now we got all the info needed for a single process, compare while( rpal_memory_isValid( isTimeToStop ) && !rEvent_wait( isTimeToStop, 0 ) && ( isPrefetched || rList_getSEQUENCE( map, RP_TAGS_MEMORY_REGION, ®ion ) ) ) { libOs_timeoutWithProfile( perfProfile, FALSE ); if( isPrefetched ) { isPrefetched = FALSE; } if( rSequence_getRU8( region, RP_TAGS_MEMORY_TYPE, &memType ) && rSequence_getRU8( region, RP_TAGS_MEMORY_ACCESS, &memProtect ) && rSequence_getPOINTER64( region, RP_TAGS_BASE_ADDRESS, &memBase ) && rSequence_getRU64( region, RP_TAGS_MEMORY_SIZE, &memSize ) ) { if( PROCESSLIB_MEM_TYPE_PRIVATE == memType || PROCESSLIB_MEM_TYPE_MAPPED == memType ) { if( PROCESSLIB_MEM_ACCESS_EXECUTE == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_READ == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_READ_WRITE == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_WRITE_COPY == memProtect ) { isCurrentExec = TRUE; } else { isCurrentExec = FALSE; } // This check is somewhat redundant since it the memory // regions are already filtered by not allowing TYPE_IMAGE. // It's now not that expensive so running it in parallel // might catch some edge case.(?) if( !isMemInModule( memBase, memSize, memRanges, nRanges ) ) { // Exec memory found outside of a region marked to belong to // a module, keep looking in for module. if( ( 1024 * 1024 * 10 ) >= memSize && processLib_getProcessMemory( processId, NUMBER_TO_PTR( memBase ), memSize, (RPVOID*)&pMem, TRUE ) ) { isHidden = FALSE; #ifdef RPAL_PLATFORM_WINDOWS // Let's just check for MZ and PE for now, we can get fancy later. pDos = (PIMAGE_DOS_HEADER)pMem; if( IS_WITHIN_BOUNDS( (RPU8)pMem, sizeof( IMAGE_DOS_HEADER ), pMem, memSize ) && IMAGE_DOS_SIGNATURE == pDos->e_magic ) { pNt = (PIMAGE_NT_HEADERS)( (RPU8)pDos + pDos->e_lfanew ); if( IS_WITHIN_BOUNDS( pNt, sizeof( *pNt ), pMem, memSize ) && IMAGE_NT_SIGNATURE == pNt->Signature ) { if( isCurrentExec ) { // If the current region is exec, we've got a hidden module. isHidden = TRUE; } else { // We need to check if the next section in memory is // executable and outside of known modules since the PE // headers may have been marked read-only before the .text. if( rList_getSEQUENCE( map, RP_TAGS_MEMORY_REGION, ®ion ) ) { isPrefetched = TRUE; if( ( PROCESSLIB_MEM_TYPE_PRIVATE == memType || PROCESSLIB_MEM_TYPE_MAPPED == memType ) && ( PROCESSLIB_MEM_ACCESS_EXECUTE == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_READ == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_READ_WRITE == memProtect || PROCESSLIB_MEM_ACCESS_EXECUTE_WRITE_COPY == memProtect ) ) { isHidden = TRUE; } } } } } #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) if( isCurrentExec && 0x7F == ( pMem )[ 0 ] && 'E' == ( pMem )[ 1 ] && 'L' == ( pMem )[ 2 ] && 'F' == ( pMem )[ 3 ] ) { isHidden = TRUE; } #endif rpal_memory_free( pMem ); if( isHidden && !rEvent_wait( isTimeToStop, 0 ) ) { rpal_debug_info( "found a hidden module in %d.", processId ); if( NULL != ( procInfo = processLib_getProcessInfo( processId, NULL ) ) ) { if( !rSequence_addSEQUENCE( region, RP_TAGS_PROCESS, procInfo ) ) { rSequence_free( procInfo ); } } rSequence_addTIMESTAMP( region, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ); hbs_markAsRelated( originalRequest, region ); notifications_publish( RP_TAGS_NOTIFICATION_HIDDEN_MODULE_DETECTED, region ); break; } libOs_timeoutWithProfile( perfProfile, TRUE ); } } } } } rList_free( map ); } rpal_memory_free( memRanges ); } rList_free( mods ); } return NULL; }