static RVOID processTerminateProcesses ( rpcm_tag notifType, rSequence event ) { RPU8 atomId = NULL; RU32 index = 0; UNREFERENCED_PARAMETER( notifType ); if( rMutex_lock( g_mutex ) ) { if( HbsGetParentAtom( event, &atomId ) ) { if( (RU32)-1 != ( index = rpal_binsearch_array( g_procContexts->elements, g_procContexts->nElements, sizeof( ProcExtInfo* ), &atomId, (rpal_ordering_func)_cmpContext ) ) ) { rpal_memory_free( ( (ProcExtInfo*)g_procContexts->elements[ index ] )->processPath ); rpal_memory_free( g_procContexts->elements[ index ] ); rpal_vector_remove( g_procContexts, index ); } } rMutex_unlock( g_mutex ); } }
RBOOL rRwLock_read_unlock ( rRwLock lock ) { RBOOL isSuccess = FALSE; _rRwLock* lck = (_rRwLock*)lock; if( rpal_memory_isValid( lock ) ) { if( rMutex_lock( lck->stateLock ) ) { lck->readCount--; if( 0 == lck->readCount ) { rEvent_set( lck->evtCanWrite ); } rMutex_unlock( lck->stateLock ); isSuccess = TRUE; } } return isSuccess; }
RBOOL rStack_atIndex ( rStack stack, RU32 i, RPVOID pOutElem ) { RBOOL isSuccess = FALSE; _prStack pStack = (_prStack)stack; RPVOID tmpElem = NULL; if( NULL != stack && NULL != pOutElem && 0 < pStack->nElements && i < pStack->nElements ) { if( rMutex_lock( pStack->lock ) ) { tmpElem = rpal_blob_arrElem( pStack->blob, pStack->elemSize, i ); if( NULL != tmpElem ) { rpal_memory_memcpy( pOutElem, tmpElem, pStack->elemSize ); isSuccess = TRUE; } rMutex_unlock( pStack->lock ); } } return isSuccess; }
RBOOL rStack_push ( rStack stack, RPVOID elem ) { RBOOL isSuccess = FALSE; _prStack pStack = (_prStack)stack; if( NULL != stack && NULL != elem ) { if( rMutex_lock( pStack->lock ) ) { isSuccess = rpal_blob_add( pStack->blob, elem, pStack->elemSize ); if( isSuccess ) { pStack->nElements++; } rMutex_unlock( pStack->lock ); } } return isSuccess; }
// Given an atom, check if it's on the deny list. RPRIVATE RBOOL isAtomDenied ( RPU8 atomId ) { RBOOL isDenied = FALSE; if( rMutex_lock( g_deniedMutex ) ) { if( ( -1 ) != rpal_binsearch_array( rpal_blob_getBuffer( g_denied ), rpal_blob_getSize( g_denied ) / HBS_ATOM_ID_SIZE, HBS_ATOM_ID_SIZE, atomId, (rpal_ordering_func)cmpAtoms ) ) { isDenied = TRUE; } rMutex_unlock( g_deniedMutex ); } return isDenied; }
// Receives new process notifications and check if they're on our // deny list, if so, kill. RPRIVATE RVOID denyNewProcesses ( rpcm_tag notifType, rSequence event ) { RPU8 atomId = NULL; RU32 pid = 0; UNREFERENCED_PARAMETER( notifType ); // We use the lastActivity check here as a cheap way of seeing if there is // anything at all in the denied tree. if( 0 != g_lastDenyActivity && HbsGetParentAtom( event, &atomId ) && isAtomDenied( atomId ) ) { // This atom is part of a tree that needs to be denied, so we do two things: // 1- Add its atom to the list of denied atoms. if( HbsGetThisAtom( event, &atomId ) ) { addAtomToDeny( atomId ); } // 2- As this is a process, we deny by killing it. if( rSequence_getRU32( event, RP_TAGS_PROCESS_ID, &pid ) ) { if( processLib_killProcess( pid ) ) { rpal_debug_info( "denied process id " RF_U32, pid ); } else { rpal_debug_warning( "failed to deny process id " RF_U32, pid ); } } } else if( 0 != g_lastDenyActivity && g_lastDenyActivity + DENY_TREE_CLEANUP_TIMEOUT < rpal_time_getGlobal() ) { // There has not been any positive activity on any denied trees, for the sake // of performance we'll reset the denied trees. if( rMutex_lock( g_deniedMutex ) ) { g_lastDenyActivity = 0; rpal_blob_free( g_denied ); g_denied = rpal_blob_create( 0, HBS_ATOM_ID_SIZE * 10 ); rMutex_unlock( g_deniedMutex ); } } }
RBOOL rStack_removeWith ( rStack stack, rStack_compareFunc compFunc, RPVOID ref, RPVOID pElem ) { RBOOL isRemoved = FALSE; _prStack pStack = (_prStack)stack; RU32 i = 0; RPVOID tmpElem = NULL; if( NULL != stack && NULL != compFunc ) { if( rMutex_lock( pStack->lock ) ) { for( i = 0; i < ( rpal_blob_getSize( pStack->blob ) / pStack->elemSize ); i++ ) { if( NULL != ( tmpElem = rpal_blob_arrElem( pStack->blob, pStack->elemSize, i ) ) ) { if( compFunc( tmpElem, ref ) ) { if( NULL != pElem ) { rpal_memory_memcpy( pElem, tmpElem, pStack->elemSize ); } if( rpal_blob_remove( pStack->blob, i * pStack->elemSize, pStack->elemSize ) ) { pStack->nElements--; isRemoved = TRUE; } break; } } } rMutex_unlock( pStack->lock ); } } return isRemoved; }
RBOOL rRefCount_release ( rRefCount ref, RBOOL* pIsReleased ) { RBOOL isSuccess = FALSE; RBOOL isReleased = FALSE; _rRefCount* pRef = NULL; if( rpal_memory_isValid( ref ) ) { pRef = (_rRefCount*)ref; if( rMutex_lock( pRef->mutex ) ) { if( 0 == --(pRef->count) ) { if( NULL != pRef->freeFunc ) { pRef->freeFunc( pRef->pElem, pRef->elemSize ); } rMutex_free( pRef->mutex ); rpal_memory_free( pRef ); isReleased = TRUE; } else { rMutex_unlock( pRef->mutex ); } if( NULL != pIsReleased ) { *pIsReleased = isReleased; } isSuccess = TRUE; } } return isSuccess; }
RBOOL rRwLock_write_unlock ( rRwLock lock ) { RBOOL isSuccess = FALSE; _rRwLock* lck = (_rRwLock*)lock; if( rpal_memory_isValid( lock ) ) { rEvent_set( lck->evtCanRead ); rMutex_unlock( lck->stateLock ); isSuccess = TRUE; } return isSuccess; }
// Add an atom to the deny list, which is just a sortled list // on which we do binary searches. RPRIVATE RVOID addAtomToDeny ( RPU8 atomId ) { if( rMutex_lock( g_deniedMutex ) ) { rpal_blob_add( g_denied, atomId, HBS_ATOM_ID_SIZE ); rpal_sort_array( rpal_blob_getBuffer( g_denied ), rpal_blob_getSize( g_denied ) / HBS_ATOM_ID_SIZE, HBS_ATOM_ID_SIZE, (rpal_ordering_func)cmpAtoms ); g_lastDenyActivity = rpal_time_getGlobal(); rMutex_unlock( g_deniedMutex ); } }
RBOOL collector_16_cleanup ( HbsState* hbsState, rSequence config ) { RBOOL isSuccess = FALSE; UNREFERENCED_PARAMETER( config ); if( NULL != hbsState ) { notifications_unsubscribe( RP_TAGS_NOTIFICATION_YARA_RULES_UPDATE, NULL, updateSignatures ); notifications_unsubscribe( RP_TAGS_NOTIFICATION_YARA_SCAN, NULL, doScan ); notifications_unsubscribe( RP_TAGS_NOTIFICATION_MODULE_LOAD, g_async_files_to_scan, NULL ); if( rMutex_lock( g_global_rules_mutex ) ) { if( NULL != g_global_rules ) { yr_rules_destroy( g_global_rules ); g_global_rules = NULL; } rMutex_unlock( g_global_rules_mutex ); } rQueue_free( g_async_files_to_scan ); g_async_files_to_scan = NULL; rMutex_free( g_global_rules_mutex ); g_global_rules_mutex = NULL; yr_finalize(); isSuccess = TRUE; } return isSuccess; }
RBOOL rRefCount_acquire ( rRefCount ref ) { RBOOL isSuccess = FALSE; if( rpal_memory_isValid( ref ) ) { if( rMutex_lock( ((_rRefCount*)ref)->mutex ) ) { ((_rRefCount*)ref)->count++; isSuccess = TRUE; rMutex_unlock( ((_rRefCount*)ref)->mutex ); } } return isSuccess; }
RU32 rStack_getSize ( rStack stack ) { RU32 size = 0; _prStack pStack = (_prStack)stack; if( NULL != stack ) { if( rMutex_lock( pStack->lock ) ) { size = pStack->nElements; rMutex_unlock( pStack->lock ); } } return size; }
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 ); } }
RBOOL rRwLock_read_lock ( rRwLock lock ) { RBOOL isSuccess = FALSE; _rRwLock* lck = (_rRwLock*)lock; RBOOL isReady = FALSE; if( rpal_memory_isValid( lock ) ) { // Wait to get permission to read atomically while( !isReady ) { if( rMutex_lock( lck->stateLock ) ) { if( rEvent_wait( lck->evtCanRead, 0 ) ) { isReady = TRUE; lck->readCount++; } rMutex_unlock( lck->stateLock ); isSuccess = TRUE; } if( !isReady ) { rEvent_wait( lck->evtCanRead, RINFINITE ); } } // Now we're safe to read } return isSuccess; }
RBOOL rRwLock_write_lock ( rRwLock lock ) { RBOOL isSuccess = FALSE; _rRwLock* lck = (_rRwLock*)lock; RBOOL isReady = FALSE; if( rpal_memory_isValid( lock ) ) { while( !isReady ) { if( rMutex_lock( lck->stateLock ) ) { if( 0 == lck->readCount ) { isReady = TRUE; rEvent_unset( lck->evtCanWrite ); } else { rEvent_unset( lck->evtCanRead ); rMutex_unlock( lck->stateLock ); } isSuccess = TRUE; } if( !isReady ) { rEvent_wait( lck->evtCanWrite, RINFINITE ); } } } return isSuccess; }
RBOOL rStack_pop ( rStack stack, RPVOID pOutElem ) { RBOOL isSuccess = FALSE; _prStack pStack = (_prStack)stack; RPVOID tmpElem = NULL; if( NULL != stack && NULL != pOutElem && 0 < pStack->nElements ) { if( rMutex_lock( pStack->lock ) ) { tmpElem = rpal_blob_arrElem( pStack->blob, pStack->elemSize, pStack->nElements - 1 ); if( NULL != tmpElem ) { rpal_memory_memcpy( pOutElem, tmpElem, pStack->elemSize ); if( rpal_blob_remove( pStack->blob, pStack->elemSize * ( pStack->nElements - 1 ), pStack->elemSize ) ) { isSuccess = TRUE; pStack->nElements--; } } rMutex_unlock( pStack->lock ); } } return isSuccess; }
RBOOL rRefCount_getElem ( rRefCount ref, RPVOID* pElem ) { RBOOL isSuccess = FALSE; if( rpal_memory_isValid( ref ) && NULL != pElem ) { if( rMutex_lock( ((_rRefCount*)ref)->mutex ) ) { *pElem = ((_rRefCount*)ref)->pElem; isSuccess = TRUE; rMutex_unlock( ((_rRefCount*)ref)->mutex ); } } return isSuccess; }
static RVOID updateSignatures ( rpcm_tag eventType, rSequence event ) { RPU8 buffer = NULL; RU32 bufferSize = 0; YR_RULES* rules = NULL; UNREFERENCED_PARAMETER( eventType ); if( rpal_memory_isValid( event ) ) { if( rSequence_getBUFFER( event, RP_TAGS_RULES, &buffer, &bufferSize ) ) { if( NULL != ( rules = loadYaraRules( buffer, bufferSize ) ) ) { if( rMutex_lock( g_global_rules_mutex ) ) { g_global_rules = rules; rMutex_unlock( g_global_rules_mutex ); } else { yr_rules_destroy( rules ); } } } } yr_finalize_thread(); }
RBOOL rStack_isEmpty ( rStack stack ) { RBOOL isEmpty = TRUE; _prStack pStack = (_prStack)stack; if( NULL != stack ) { if( rMutex_lock( pStack->lock ) ) { if( 0 != pStack->nElements ) { isEmpty = FALSE; } rMutex_unlock( pStack->lock ); } } return isEmpty; }
static RVOID processCodeIdentW ( RPWCHAR name, CryptoLib_Hash* pFileHash, RU64 codeSize, rSequence originalEvent ) { CodeIdent ident = { 0 }; rSequence notif = NULL; rSequence sig = NULL; RBOOL isSigned = FALSE; RBOOL isVerifiedLocal = FALSE; RBOOL isVerifiedGlobal = FALSE; ident.codeSize = codeSize; if( NULL != name ) { CryptoLib_hash( name, rpal_string_strlenw( name ) * sizeof( RWCHAR ), &ident.nameHash ); } if( NULL != pFileHash ) { rpal_memory_memcpy( &ident.fileHash, pFileHash, sizeof( *pFileHash ) ); } if( rMutex_lock( g_mutex ) ) { if( rpal_bloom_addIfNew( g_knownCode, &ident, sizeof( ident ) ) ) { rMutex_unlock( g_mutex ); if( NULL != ( notif = rSequence_new() ) ) { hbs_markAsRelated( originalEvent, notif ); if( ( rSequence_addSTRINGW( notif, RP_TAGS_FILE_PATH, name ) || rSequence_addSTRINGW( notif, RP_TAGS_DLL, name ) || rSequence_addSTRINGW( notif, RP_TAGS_EXECUTABLE, name ) ) && rSequence_addRU32( notif, RP_TAGS_MEMORY_SIZE, (RU32)codeSize ) && rSequence_addTIMESTAMP( notif, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() ) ) { if( NULL != pFileHash ) { rSequence_addBUFFER( notif, RP_TAGS_HASH, (RPU8)pFileHash, sizeof( *pFileHash ) ); } if( libOs_getSignature( name, &sig, ( OSLIB_SIGNCHECK_NO_NETWORK | OSLIB_SIGNCHECK_CHAIN_VERIFICATION ), &isSigned, &isVerifiedLocal, &isVerifiedGlobal ) ) { if( !rSequence_addSEQUENCE( notif, RP_TAGS_SIGNATURE, sig ) ) { rSequence_free( sig ); } } notifications_publish( RP_TAGS_NOTIFICATION_CODE_IDENTITY, notif ); } rSequence_free( notif ); } } else { rMutex_unlock( g_mutex ); } } }
static RPVOID continuousFileScan ( rEvent isTimeToStop, RPVOID ctx ) { rSequence event = NULL; RU32 timeout = 0; RPWCHAR strW = NULL; RPCHAR strA = NULL; YaraMatchContext matchContext = { 0 }; RU32 scanError = 0; rBloom knownFiles = NULL; UNREFERENCED_PARAMETER( ctx ); if( NULL == ( knownFiles = rpal_bloom_create( 100000, 0.00001 ) ) ) { return NULL; } while( !rEvent_wait( isTimeToStop, timeout ) ) { if( rQueue_remove( g_async_files_to_scan, (RPVOID*)&event, NULL, MSEC_FROM_SEC( 2 ) ) ) { if( rSequence_getSTRINGW( event, RP_TAGS_FILE_PATH, &strW ) ) { strA = rpal_string_wtoa( strW ); } else { rSequence_getSTRINGA( event, RP_TAGS_FILE_PATH, &strA ); } if( NULL != strA && rpal_bloom_addIfNew( knownFiles, strA, rpal_string_strlen( strA ) ) ) { rpal_debug_info( "yara scanning %s", strA ); matchContext.fileInfo = event; if( rMutex_lock( g_global_rules_mutex ) ) { if( NULL != g_global_rules ) { rpal_debug_info( "scanning continuous file with yara" ); if( ERROR_SUCCESS != ( scanError = yr_rules_scan_file( g_global_rules, strA, SCAN_FLAGS_FAST_MODE, _yaraFileMatchCallback, &matchContext, 60 ) ) ) { rpal_debug_warning( "Yara file scan error: %d", scanError ); } } rMutex_unlock( g_global_rules_mutex ); } } if( NULL != strA && NULL != strW ) { // If both are allocated it means we got a strW and converted to A // so we must free the strA version. rpal_memory_free( strA ); } strA = NULL; strW = NULL; rSequence_free( event ); timeout = _TIMEOUT_BETWEEN_FILE_SCANS; } else { timeout = 0; } } rpal_bloom_destroy( knownFiles ); yr_finalize_thread(); return NULL; }
static RPVOID continuousMemScan ( rEvent isTimeToStop, RPVOID ctx ) { processLibProcEntry* processes = NULL; processLibProcEntry* curProc = NULL; RU32 thisProcId = 0; YaraMatchContext matchContext = { 0 }; RU32 scanError = 0; UNREFERENCED_PARAMETER( ctx ); thisProcId = processLib_getCurrentPid(); while( !rEvent_wait( isTimeToStop, 0 ) ) { // Wait until we have global rules to look for. if( rMutex_lock( g_global_rules_mutex ) ) { if( NULL == g_global_rules ) { rMutex_unlock( g_global_rules_mutex ); rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 30 ) ); continue; } rMutex_unlock( g_global_rules_mutex ); } if( NULL != ( processes = processLib_getProcessEntries( TRUE ) ) ) { curProc = processes; while( 0 != curProc->pid ) { // We can't examine our own memory for the risk of tripping on the sigs themselves. if( curProc->pid == thisProcId ) continue; rpal_debug_info( "yara scanning pid %d", curProc->pid ); matchContext.pid = curProc->pid; matchContext.processInfo = NULL; matchContext.moduleInfo = NULL; scanError = _scanProcessWith( curProc->pid, &matchContext, NULL, isTimeToStop ); rSequence_free( matchContext.processInfo ); if( rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 30 ) ) ) { break; } curProc++; } rpal_memory_free( processes ); } } yr_finalize_thread(); return NULL; }
static RU32 _scanProcessWith ( RU32 pid, YaraMatchContext* matchContext, YR_RULES* rules, rEvent isTimeToStop ) { RU32 scanError = (RU32)(-1); rList modules = NULL; rSequence module = NULL; _MemRange* memRanges = NULL; RU32 i = 0; rList memoryMap = NULL; rSequence memoryRegion = NULL; RU8 memAccess = 0; RU64 mem = 0; RU64 memSize = 0; RPU8 buffer = NULL; // First pass is to scan known modules if( NULL != ( modules = processLib_getProcessModules( pid ) ) ) { rpal_debug_info( "scanning process %d module memory with yara", pid ); // We also generate an optimized list of module ranges for later if( NULL != ( memRanges = rpal_memory_alloc( sizeof( _MemRange ) * rList_getNumElements( modules ) ) ) ) { while( ( NULL == isTimeToStop || !rEvent_wait( isTimeToStop, MSEC_FROM_SEC( 5 ) ) ) && rList_getSEQUENCE( modules, RP_TAGS_DLL, &module ) ) { if( rSequence_getPOINTER64( module, RP_TAGS_BASE_ADDRESS, &mem ) && rSequence_getRU64( module, RP_TAGS_MEMORY_SIZE, &memSize ) ) { memRanges[ i ].base = mem; memRanges[ i ].size = memSize; i++; matchContext->regionBase = mem; matchContext->regionSize = memSize; matchContext->moduleInfo = module; if( processLib_getProcessMemory( pid, (RPVOID)NUMBER_TO_PTR( mem ), memSize, (RPVOID*)&buffer, TRUE ) ) { rpal_debug_info( "yara scanning module region of size 0x%lx", memSize ); if( NULL != rules || rMutex_lock( g_global_rules_mutex ) ) { if( ERROR_SUCCESS != ( scanError = yr_rules_scan_mem( NULL == rules ? g_global_rules : rules, buffer, (size_t)memSize, SCAN_FLAGS_FAST_MODE | SCAN_FLAGS_PROCESS_MEMORY, _yaraMemMatchCallback, matchContext, 60 ) ) ) { rpal_debug_warning( "Yara module scan error: %d 0x%lx 0x%lx: %d", pid, mem, memSize, scanError ); } if( NULL == rules ) { rMutex_unlock( g_global_rules_mutex ); } } rpal_memory_free( buffer ); rpal_debug_info( "finished region" ); } } } } rList_free( modules ); } // Optimize the memory ranges if( rpal_memory_isValid( memRanges ) && !rpal_sort_array( memRanges, i, sizeof( _MemRange ), (rpal_ordering_func)rpal_order_RU64 ) ) { rpal_memory_free( memRanges ); memRanges = NULL; } // Second pass is to go through executable non-module areas if( NULL != ( memoryMap = processLib_getProcessMemoryMap( pid ) ) ) { rpal_debug_info( "scanning process %d non-module memory with yara", pid ); while( ( NULL == isTimeToStop || !rEvent_wait(isTimeToStop, MSEC_FROM_SEC( 5 ) ) ) && rList_getSEQUENCE( memoryMap, RP_TAGS_MEMORY_REGION, &memoryRegion ) ) { if( rSequence_getPOINTER64( memoryRegion, RP_TAGS_BASE_ADDRESS, &mem ) && rSequence_getRU64( memoryRegion, RP_TAGS_MEMORY_SIZE, &memSize ) && rSequence_getRU8( memoryRegion, RP_TAGS_MEMORY_ACCESS, &memAccess ) && ( PROCESSLIB_MEM_ACCESS_EXECUTE == memAccess || PROCESSLIB_MEM_ACCESS_EXECUTE_READ == memAccess || PROCESSLIB_MEM_ACCESS_EXECUTE_READ_WRITE == memAccess || PROCESSLIB_MEM_ACCESS_EXECUTE_WRITE_COPY == memAccess ) ) { // If it's in a known module, skip if( (RU32)( -1 ) != rpal_binsearch_array_closest( memRanges, i, sizeof( _MemRange ), &mem, (rpal_ordering_func)rpal_order_RU64, TRUE ) ) { continue; } matchContext->regionBase = mem; matchContext->regionSize = memSize; matchContext->moduleInfo = NULL; if( processLib_getProcessMemory( pid, (RPVOID)NUMBER_TO_PTR(mem), memSize, (RPVOID*)&buffer, TRUE ) ) { rpal_debug_info( "yara scanning memory region of size 0x%lx", memSize ); if( NULL != rules || rMutex_lock( g_global_rules_mutex ) ) { if( ERROR_SUCCESS != ( scanError = yr_rules_scan_mem( NULL == rules ? g_global_rules : rules, buffer, (size_t)memSize, SCAN_FLAGS_FAST_MODE | SCAN_FLAGS_PROCESS_MEMORY, _yaraMemMatchCallback, matchContext, 60 ) ) ) { rpal_debug_warning( "Yara memory scan error: %d 0x%lx 0x%lx: %d", pid, mem, memSize, scanError ); } if( NULL == rules ) { rMutex_unlock( g_global_rules_mutex ); } } rpal_memory_free( buffer ); } } } rList_free( memoryMap ); } if( rpal_memory_isValid( memRanges ) ) { rpal_memory_free( memRanges ); } return scanError; }
static RVOID processFile ( rSequence notif ) { RPCHAR fileA = NULL; RPWCHAR fileW = NULL; RPU8 fileContent = NULL; RU32 fileSize = 0; CryptoLib_Hash hash = { 0 }; if( NULL != notif ) { obsLib_resetSearchState( matcherA ); obsLib_resetSearchState( matcherW ); if( ( rSequence_getSTRINGA( notif, RP_TAGS_FILE_PATH, &fileA ) && obsLib_setTargetBuffer( matcherA, fileA, ( rpal_string_strlen( fileA ) + 1 ) * sizeof( RCHAR ) ) && obsLib_nextHit( matcherA, NULL, NULL ) ) || ( rSequence_getSTRINGW( notif, RP_TAGS_FILE_PATH, &fileW ) && obsLib_setTargetBuffer( matcherW, fileW, ( rpal_string_strlenw( fileW ) + 1 ) * sizeof( RWCHAR ) ) && obsLib_nextHit( matcherW, NULL, NULL ) ) ) { // This means it's a file of interest. if( ( NULL != fileA && ( ( DOCUMENT_MAX_SIZE >= rpal_file_getSize( fileA, TRUE ) && rpal_file_read( fileA, (RPVOID*)&fileContent, &fileSize, TRUE ) && CryptoLib_hash( fileContent, fileSize, &hash ) ) || CryptoLib_hashFileA( fileA, &hash, TRUE ) ) ) || ( NULL != fileW && ( ( DOCUMENT_MAX_SIZE >= rpal_file_getSizew( fileW, TRUE ) && rpal_file_readw( fileW, (RPVOID*)&fileContent, &fileSize, TRUE ) && CryptoLib_hash( fileContent, fileSize, &hash ) ) || CryptoLib_hashFileW( fileW, &hash, TRUE ) ) ) ) { // We acquired the hash, either by reading the entire file in memory // which we will use for caching, or if it was too big by hashing it // sequentially on disk. rSequence_unTaintRead( notif ); rSequence_addBUFFER( notif, RP_TAGS_HASH, (RPU8)&hash, sizeof( hash ) ); notifications_publish( RP_TAGS_NOTIFICATION_NEW_DOCUMENT, notif ); } if( rMutex_lock( cacheMutex ) ) { if( NULL == fileContent || !rSequence_addBUFFER( notif, RP_TAGS_FILE_CONTENT, fileContent, fileSize ) || !HbsRingBuffer_add( documentCache, notif ) ) { rSequence_free( notif ); } rMutex_unlock( cacheMutex ); } else { rSequence_free( notif ); } if( NULL != fileContent ) { rpal_memory_free( fileContent ); } } else { rSequence_free( notif ); } } }
static RVOID getDocument ( rpcm_tag notifId, rSequence notif ) { rSequence tmp = NULL; DocSearchContext ctx = { 0 }; RU32 hashSize = 0; rList foundDocs = NULL; RBOOL isAAlloced = FALSE; RBOOL isWAlloced = FALSE; UNREFERENCED_PARAMETER( notifId ); if( NULL != notif ) { if( !rSequence_getSTRINGA( notif, RP_TAGS_STRING_PATTERN, &ctx.exprA ) ) { ctx.exprA = NULL; } if( !rSequence_getSTRINGW( notif, RP_TAGS_STRING_PATTERN, &ctx.exprW ) ) { ctx.exprW = NULL; } if( NULL != ctx.exprA && NULL == ctx.exprW ) { ctx.exprW = rpal_string_atow( ctx.exprA ); isWAlloced = TRUE; } if( NULL != ctx.exprW && NULL == ctx.exprA ) { ctx.exprA = rpal_string_wtoa( ctx.exprW ); isAAlloced = TRUE; } if( !rSequence_getBUFFER( notif, RP_TAGS_HASH, (RPU8*)&ctx.pHash, &hashSize ) || sizeof( *ctx.pHash ) != hashSize ) { // Unexpected hash size, let's not gamble ctx.pHash = NULL; } } if( rMutex_lock( cacheMutex ) ) { if( NULL != ( foundDocs = rList_new( RP_TAGS_FILE_INFO, RPCM_SEQUENCE ) ) ) { while( HbsRingBuffer_find( documentCache, (HbsRingBufferCompareFunc)findDoc, &ctx, &tmp ) ) { // TODO: optimize this since if we're dealing with large files // we will be temporarily using large amounts of duplicate memory. // We just need to do some shallow free of the datastructures // somehow. if( NULL != ( tmp = rSequence_duplicate( tmp ) ) ) { if( !rList_addSEQUENCE( foundDocs, tmp ) ) { rSequence_free( tmp ); } } } if( !rSequence_addLIST( notif, RP_TAGS_FILES, foundDocs ) ) { rList_free( foundDocs ); } } rMutex_unlock( cacheMutex ); notifications_publish( RP_TAGS_NOTIFICATION_GET_DOCUMENT_REP, notif ); } if( isAAlloced ) { rpal_memory_free( ctx.exprA ); } if( isWAlloced ) { rpal_memory_free( ctx.exprW ); } }
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 RU32 _krnlSendReceive ( RU32 op, RPU8 pArgs, RU32 argsSize, RPU8 pResult, RU32 resultSize, RU32* pSizeUsed ) { RU32 error = (RU32)(-1); RU32 nRetries = 1; // Check whether this particular function is available on // this platform via kernel. if( op >= KERNEL_ACQ_OP_COUNT || !g_platform_availability[ op ] ) { return error; } if( rMutex_lock( g_km_mutex ) ) { while( 0 != nRetries ) { #ifdef RPAL_PLATFORM_MACOSX KernelAcqCommand cmd = { 0 }; cmd.pArgs = pArgs; cmd.argsSize = argsSize; cmd.pResult = pResult; cmd.resultSize = resultSize; cmd.pSizeUsed = pSizeUsed; fd_set readset = { 0 }; struct timeval timeout = { 0 }; int waitVal = 0; error = setsockopt( g_km_socket, SYSPROTO_CONTROL, op, &cmd, sizeof( cmd ) ); #elif defined( RPAL_PLATFORM_WINDOWS ) RU32 ioBufferSize = sizeof( KernelAcqCommand ) + argsSize; RPU8 ioBuffer = NULL; KernelAcqCommand* pCmd = NULL; if( NULL != ( ioBuffer = rpal_memory_alloc( ioBufferSize ) ) ) { pCmd = (KernelAcqCommand*)ioBuffer; pCmd->op = op; pCmd->dataOffset = sizeof( KernelAcqCommand ); pCmd->argsSize = argsSize; if( NULL != pArgs && 0 != argsSize ) { rpal_memory_memcpy( pCmd->data, pArgs, argsSize ); } if( DeviceIoControl( g_km_handle, (DWORD)IOCTL_EXCHANGE_DATA, ioBuffer, ioBufferSize, pResult, resultSize, (LPDWORD)pSizeUsed, NULL ) ) { error = 0; } else { error = rpal_error_getLast(); } rpal_memory_free( ioBuffer ); } else { error = RPAL_ERROR_NOT_ENOUGH_MEMORY; } #else UNREFERENCED_PARAMETER( op ); UNREFERENCED_PARAMETER( pArgs ); UNREFERENCED_PARAMETER( argsSize ); UNREFERENCED_PARAMETER( pResult ); UNREFERENCED_PARAMETER( resultSize ); UNREFERENCED_PARAMETER( pSizeUsed ); break; #endif // Success, return in. if( 0 == error ) { break; } // Looks like we had a failure, this may be a sign from the kernel // that it must unload, so we'll give it a chance and toggle our // connection. _kAcq_deinit( FALSE ); if( !_kAcq_init( FALSE ) ) { break; } nRetries--; } rMutex_unlock( g_km_mutex ); } return error; }