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;
}
示例#3
0
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;
}
示例#4
0
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 );
        }
    }
}
示例#7
0
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 );
    }
}
示例#11
0
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;
}
示例#13
0
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;
}
示例#17
0
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;
}
示例#19
0
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();
}
示例#20
0
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 );
        }
    }
}
示例#22
0
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;
}
示例#23
0
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;
}
示例#24
0
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;
}