예제 #1
0
RBOOL
    collector_18_cleanup
    (
        HbsState* hbsState,
        rSequence config
    )
{
    RBOOL isSuccess = FALSE;

    UNREFERENCED_PARAMETER( config );

    if( NULL != hbsState )
    {
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_CREATE, createQueue, NULL );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_GET_DOCUMENT_REQ, NULL, getDocument );
        rQueue_free( createQueue );
        createQueue = NULL;

        obsLib_free( matcherA );
        obsLib_free( matcherW );
        HbsRingBuffer_free( documentCache );
        matcherA = NULL;
        matcherW = NULL;
        documentCache = NULL;

        rMutex_free( cacheMutex );
        cacheMutex = NULL;

        isSuccess = TRUE;
    }

    return isSuccess;
}
예제 #2
0
파일: main.c 프로젝트: certego/limacharlie
void test_CreateAndDestroy(void)
{
    HObs hObs = NULL;

    hObs = obsLib_new( 0, 0 );

    CU_ASSERT_TRUE_FATAL( rpal_memory_isValid( hObs ) );

    obsLib_free( hObs );
}
예제 #3
0
파일: main.c 프로젝트: certego/limacharlie
void test_addPattern(void)
{
    HObs hObs = NULL;
    RU8 pattern[] = { 0x01, 0x02, 0x03, 0x04 };
    RU32 context = 0;

    hObs = obsLib_new( 0, 0 );

    CU_ASSERT_TRUE_FATAL( rpal_memory_isValid( hObs ) );

    CU_ASSERT_TRUE_FATAL( obsLib_addPattern( hObs, (RPU8)&pattern, sizeof( pattern ), &context ) );

    obsLib_free( hObs );
}
예제 #4
0
파일: main.c 프로젝트: certego/limacharlie
void test_singlePattern(void)
{
    HObs hObs = NULL;
    RU8 pattern[] = { 0x01, 0x02, 0x03, 0x04 };
    RU8 buffer1[] = { 0x02, 0x04, 0xFF, 0xEF, 0x01, 0x02, 0x03, 0x04 };
    RU8 buffer2[] = { 0x02, 0x04, 0xFF, 0xEF, 0x01, 0x02, 0x03, 0x04, 0xEE, 0x6F };
    RU8 buffer3[] = { 0x02, 0x04, 0xFF, 0xEF, 0x01, 0x02, 0x01, 0x04, 0xEE, 0x6F };
    RU8 buffer4[] = { 0x02, 0x04, 0xFF, 0xEF, 0x01, 0x02, 0x03, 0x04, 0xEE, 0x6F, 0x01, 0x02, 0x03, 0x04 };
    RU32 context = 0;
    PVOID hitCtx = NULL;
    RU8* hitLoc = NULL;

    hObs = obsLib_new( 0, 0 );

    CU_ASSERT_TRUE_FATAL( rpal_memory_isValid( hObs ) );

    CU_ASSERT_TRUE_FATAL( obsLib_addPattern( hObs, (RPU8)&pattern, sizeof( pattern ), &context ) );

    // 1 pattern found end of buffer
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer1, sizeof( buffer1 ) ) );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context );
    CU_ASSERT_EQUAL( hitLoc, buffer1 + sizeof( buffer1 ) - 4 );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    // 1 pattern found middle of buffer
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer2, sizeof( buffer2 ) ) );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context );
    CU_ASSERT_EQUAL( hitLoc, buffer2 + sizeof( buffer2 ) - 6 );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    // 0 pattern found
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer3, sizeof( buffer3 ) ) );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    // 2 pattern found end and middle of buffer
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer4, sizeof( buffer4 ) ) );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context );
    CU_ASSERT_EQUAL( hitLoc, buffer4 + sizeof( buffer4 ) - 10 );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context );
    CU_ASSERT_EQUAL( hitLoc, buffer4 + sizeof( buffer4 ) - 4 );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    obsLib_free( hObs );
}
RBOOL
    collector_22_cleanup
    (
        HbsState* hbsState,
        rSequence config
    )
{
    RBOOL isSuccess = FALSE;
    RU32 i = 0;

    UNREFERENCED_PARAMETER( config );

    if( NULL != hbsState )
    {
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_CREATE, NULL, processFileIo );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_DELETE, NULL, processFileIo );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_MODIFIED, NULL, processFileIo );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_READ, NULL, processFileIo );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_NEW_PROCESS, NULL, processNewProcesses );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_EXISTING_PROCESS, NULL, processNewProcesses );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_TERMINATE_PROCESS, NULL, processTerminateProcesses );
        obsLib_free( g_extensions );
        g_extensions = NULL;
        if( NULL != g_procContexts )
        {
            for( i = 0; i < g_procContexts->nElements; i++ )
            {
                rpal_memory_free( ( (ProcExtInfo*)g_procContexts->elements[ i ] )->processPath );
                rpal_memory_free( g_procContexts->elements[ i ] );
            }
        }
        rpal_vector_free( g_procContexts );
        g_procContexts = NULL;
        rMutex_free( g_mutex );
        g_mutex = NULL;

        isSuccess = TRUE;
    }

    return isSuccess;
}
예제 #6
0
RBOOL
    collector_18_init
    (
        HbsState* hbsState,
        rSequence config
    )
{
    RBOOL isSuccess = FALSE;

    rList extensions = NULL;
    rList patterns = NULL;
    RPCHAR strA = NULL;
    RPCHAR tmpA = NULL;
    RPWCHAR strW = NULL;
    RPWCHAR tmpW = NULL;
    RU32 maxSize = 0;
    RBOOL isCaseInsensitive = FALSE;

    if( NULL != hbsState )
    {
#ifdef RPAL_PLATFORM_WINDOWS
        // On Windows files and paths are not case sensitive.
        isCaseInsensitive = TRUE;
#endif

        if( NULL == config ||
            rSequence_getLIST( config, RP_TAGS_EXTENSIONS, &extensions ) ||
            rSequence_getLIST( config, RP_TAGS_PATTERNS, &patterns ) )
        {
            if( NULL != ( cacheMutex = rMutex_create() ) &&
                NULL != ( matcherA = obsLib_new( 0, 0 ) ) &&
                NULL != ( matcherW = obsLib_new( 0, 0 ) ) )
            {
                cacheSize = 0;
                if( NULL != config &&
                    rSequence_getRU32( config, RP_TAGS_MAX_SIZE, &maxSize ) )
                {
                    cacheMaxSize = maxSize;
                }
                else
                {
                    cacheMaxSize = MAX_CACHE_SIZE;
                }
                
                if( NULL != ( documentCache = HbsRingBuffer_new( 0, cacheMaxSize ) ) )
                {
                    if( NULL == config )
                    {
                        // As a default we'll cache all new files
                        obsLib_addPattern( matcherA, (RPU8)"", sizeof( RCHAR ), NULL );
                        obsLib_addPattern( matcherW, (RPU8)_WCH(""), sizeof( RWCHAR ), NULL );
                    }
                    else
                    {
                        // If a config was provided we'll cache only certain extensions
                        // specified.
                        while( rList_getSTRINGA( extensions, RP_TAGS_EXTENSION, &strA ) )
                        {
                            if( rpal_string_expand( strA, &tmpA ) )
                            {
                                obsLib_addStringPatternA( matcherA, tmpA, TRUE, isCaseInsensitive, NULL );
                                rpal_memory_free( tmpA );
                            }
                            if( NULL != ( strW = rpal_string_atow( strA ) ) )
                            {
                                if( rpal_string_expandw( strW, &tmpW ) )
                                {
                                    obsLib_addStringPatternW( matcherW, tmpW, TRUE, isCaseInsensitive, NULL );
                                    rpal_memory_free( tmpW );
                                }
                                rpal_memory_free( strW );
                            }
                        }

                        while( rList_getSTRINGW( extensions, RP_TAGS_EXTENSION, &strW ) )
                        {
                            if( rpal_string_expandw( strW, &tmpW ) )
                            {
                                obsLib_addStringPatternW( matcherW, tmpW, TRUE, isCaseInsensitive, NULL );
                                rpal_memory_free( tmpW );
                            }
                            if( NULL != ( strA = rpal_string_wtoa( strW ) ) )
                            {
                                if( rpal_string_expand( strA, &tmpA ) )
                                {
                                    obsLib_addStringPatternA( matcherA, tmpA, TRUE, isCaseInsensitive, NULL );
                                    rpal_memory_free( tmpA );
                                }
                                rpal_memory_free( strA );
                            }
                        }

                        while( rList_getSTRINGA( patterns, RP_TAGS_STRING_PATTERN, &strA ) )
                        {
                            if( rpal_string_expand( strA, &tmpA ) )
                            {
                                obsLib_addStringPatternA( matcherA, tmpA, FALSE, isCaseInsensitive, NULL );
                                rpal_memory_free( tmpA );
                            }
                            if( NULL != ( strW = rpal_string_atow( strA ) ) )
                            {
                                if( rpal_string_expandw( strW, &tmpW ) )
                                {
                                    obsLib_addStringPatternW( matcherW, tmpW, FALSE, isCaseInsensitive, NULL );
                                    rpal_memory_free( tmpW );
                                }
                                rpal_memory_free( strW );
                            }
                        }

                        while( rList_getSTRINGW( patterns, RP_TAGS_STRING_PATTERN, &strW ) )
                        {
                            if( rpal_string_expandw( strW, &tmpW ) )
                            {
                                obsLib_addStringPatternW( matcherW, tmpW, FALSE, isCaseInsensitive, NULL );
                                rpal_memory_free( tmpW );
                            }
                            if( NULL != ( strA = rpal_string_wtoa( strW ) ) )
                            {
                                if( rpal_string_expand( strA, &tmpA ) )
                                {
                                    obsLib_addStringPatternA( matcherA, tmpA, FALSE, isCaseInsensitive, NULL );
                                    rpal_memory_free( tmpA );
                                }
                                rpal_memory_free( strA );
                            }
                        }
                    }

                    if( rQueue_create( &createQueue, _freeEvt, 200 ) &&
                        notifications_subscribe( RP_TAGS_NOTIFICATION_FILE_CREATE, NULL, 0, createQueue, NULL ) &&
                        notifications_subscribe( RP_TAGS_NOTIFICATION_GET_DOCUMENT_REQ, NULL, 0, NULL, getDocument ) &&
                        rThreadPool_task( hbsState->hThreadPool, parseDocuments, NULL ) )
                    {
                        isSuccess = TRUE;
                    }
                }
            }

            if( !isSuccess )
            {
                notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_CREATE, createQueue, NULL );
                notifications_unsubscribe( RP_TAGS_NOTIFICATION_GET_DOCUMENT_REQ, NULL, getDocument );
                rQueue_free( createQueue );
                createQueue = NULL;

                obsLib_free( matcherA );
                obsLib_free( matcherW );
                HbsRingBuffer_free( documentCache );
                matcherA = NULL;
                matcherW = NULL;
                documentCache = NULL;

                rMutex_free( cacheMutex );
                cacheMutex = NULL;
            }
        }
    }

    return isSuccess;
}
RBOOL
    collector_22_init
    (
        HbsState* hbsState,
        rSequence config
    )
{
    RBOOL isSuccess = FALSE;
    rList patterns = NULL;
    rSequence pattern = NULL;
    RPCHAR strA = NULL;
    RPWCHAR strW = NULL;
    RPNCHAR tmpN = NULL;
    RU8 patternId = 0;
    RU32 i = 0;

    if( NULL != hbsState &&
        NULL != ( g_extensions = obsLib_new( 0, 0 ) ) )
    {
        if( rSequence_getLIST( config, RP_TAGS_PATTERNS, &patterns ) )
        {
            while( rList_getSEQUENCE( patterns, RP_TAGS_RULE, &pattern ) )
            {
                if( rSequence_getRU8( pattern, RP_TAGS_RULE_NAME, &patternId ) )
                {
                    if( 64 < patternId || 0 == patternId )
                    {
                        rpal_debug_critical( "rule id must be below 64 and 1-based." );
                        continue;
                    }

                    // Base the pattern id to 0
                    patternId--;

                    if( rSequence_getSTRINGA( pattern, RP_TAGS_EXTENSION, &strA ) &&
                        NULL != ( tmpN = rpal_string_aton( strA ) ) )
                    {
                        _addPattern( g_extensions, tmpN, TRUE, NUMBER_TO_PTR( patternId ) );
                        rpal_memory_free( tmpN );
                    }

                    if( rSequence_getSTRINGW( pattern, RP_TAGS_EXTENSION, &strW ) &&
                        NULL != ( tmpN = rpal_string_wton( strW ) ) )
                    {
                        _addPattern( g_extensions, tmpN, TRUE, NUMBER_TO_PTR( patternId ) );
                        rpal_memory_free( tmpN );
                    }

                    if( rSequence_getSTRINGA( pattern, RP_TAGS_STRING_PATTERN, &strA ) &&
                        NULL != ( tmpN = rpal_string_aton( strA ) ) )
                    {
                        _addPattern( g_extensions, tmpN, FALSE, NUMBER_TO_PTR( patternId ) );
                        rpal_memory_free( tmpN );
                    }

                    if( rSequence_getSTRINGW( pattern, RP_TAGS_STRING_PATTERN, &strW ) &&
                        NULL != ( tmpN = rpal_string_wton( strW ) ) )
                    {
                        _addPattern( g_extensions, tmpN, FALSE, NUMBER_TO_PTR( patternId ) );
                        rpal_memory_free( tmpN );
                    }
                }
            }

            if( NULL != ( g_mutex = rMutex_create() ) &&
                NULL != ( g_procContexts = rpal_vector_new() ) &&
                notifications_subscribe( RP_TAGS_NOTIFICATION_FILE_CREATE, NULL, 0, NULL, processFileIo ) &&
                notifications_subscribe( RP_TAGS_NOTIFICATION_FILE_DELETE, NULL, 0, NULL, processFileIo ) &&
                notifications_subscribe( RP_TAGS_NOTIFICATION_FILE_MODIFIED, NULL, 0, NULL, processFileIo ) &&
                notifications_subscribe( RP_TAGS_NOTIFICATION_FILE_READ, NULL, 0, NULL, processFileIo ) &&
                notifications_subscribe( RP_TAGS_NOTIFICATION_NEW_PROCESS, NULL, 0, NULL, processNewProcesses ) &&
                notifications_subscribe( RP_TAGS_NOTIFICATION_EXISTING_PROCESS, NULL, 0, NULL, processNewProcesses ) &&
                notifications_subscribe( RP_TAGS_NOTIFICATION_TERMINATE_PROCESS, NULL, 0, NULL, processTerminateProcesses ) )
            {
                isSuccess = TRUE;
            }
        }
    }

    if( !isSuccess )
    {
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_CREATE, NULL, processFileIo );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_DELETE, NULL, processFileIo );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_MODIFIED, NULL, processFileIo );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_FILE_READ, NULL, processFileIo );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_NEW_PROCESS, NULL, processNewProcesses );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_EXISTING_PROCESS, NULL, processNewProcesses );
        notifications_unsubscribe( RP_TAGS_NOTIFICATION_TERMINATE_PROCESS, NULL, processTerminateProcesses );
        obsLib_free( g_extensions );
        g_extensions = NULL;
        if( NULL != g_procContexts )
        {
            for( i = 0; i < g_procContexts->nElements; i++ )
            {
                rpal_memory_free( ( (ProcExtInfo*)g_procContexts->elements[ i ] )->processPath );
                rpal_memory_free( g_procContexts->elements[ i ] );
            }
        }
        rpal_vector_free( g_procContexts );
        g_procContexts = NULL;
        rMutex_free( g_mutex );
        g_mutex = NULL;
    }

    return isSuccess;
}
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;
}
예제 #9
0
파일: main.c 프로젝트: certego/limacharlie
void test_multiPattern(void)
{
    HObs hObs = NULL;
    RU8 pattern1[] = { 0x01, 0x02, 0x03, 0x04 };
    RU8 pattern2[] = { 0x01, 0x02, 0x03, 0x06 };
    RU8 pattern3[] = { 0x01, 0x02, 0x06, 0x04 };
    RU8 pattern4[] = { 0xEF, 0x02, 0x03, 0x04 };
    RU8 buffer1[] = { 0x02, 0x04, 0xFF, 0xEF, 
                      0x01, 0x02, 0x03, 0x04 };
    RU8 buffer2[] = { 0x02, 0x04, 0xFF, 0xEF,
                      0x01, 0x02, 0x03, 0x04, 0xEE, 0x6F };
    RU8 buffer3[] = { 0x02, 0x04, 0xFF, 0xEF,
                      0x01, 0x02, 0x01, 0x04, 0xEE, 0x6F };
    RU8 buffer4[] = { 0x02, 0x04, 0xFF, 0xEF, 0x01, 
                      0x02, 0x03, 0x04, 0xEE, 0x6F,
                      0x01, 0x02, 0x03, 0x04 };
    RU8 buffer5[] = { 0x02, 0x04, 0xFF, 0xEF, 
                      0x02, 0x03, 0x04, 0x04, 
                      0xEE, 0x6F, 0x01, 0x02, 0x03, 0x04 };
    RU8 buffer6[] = { 0x02, 0x04, 0xFF, 0xEF,
                      0x02, 0x03, 0x04, 0x04, 
                      0xEE, 0x6F, 0x01, 0x02, 
                      0x03, 0x04, 0x01, 0x02, 0x06, 0x04 };
    RU32 context1 = 0;
    RU32 context2 = 0;
    RU32 context3 = 0;
    RU32 context4 = 0;
    PVOID hitCtx = NULL;
    RU8* hitLoc = NULL;

    hObs = obsLib_new( 0, 0 );

    CU_ASSERT_TRUE_FATAL( rpal_memory_isValid( hObs ) );

    CU_ASSERT_TRUE_FATAL( obsLib_addPattern( hObs, (RPU8)&pattern1, sizeof( pattern1 ), &context1 ) );
    CU_ASSERT_TRUE_FATAL( obsLib_addPattern( hObs, (RPU8)&pattern2, sizeof( pattern2 ), &context2 ) );
    CU_ASSERT_TRUE_FATAL( obsLib_addPattern( hObs, (RPU8)&pattern3, sizeof( pattern3 ), &context3 ) );
    CU_ASSERT_TRUE_FATAL( obsLib_addPattern( hObs, (RPU8)&pattern4, sizeof( pattern4 ), &context4 ) );

    // 1 pattern found end of buffer
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer1, sizeof( buffer1 ) ) );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context1 );
    CU_ASSERT_EQUAL( hitLoc, buffer1 + sizeof( buffer1 ) - 4 );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    // 1 pattern found middle of buffer
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer2, sizeof( buffer2 ) ) );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context1 );
    CU_ASSERT_EQUAL( hitLoc, buffer2 + sizeof( buffer2 ) - 6 );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    // 0 pattern found
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer3, sizeof( buffer3 ) ) );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    // 2 pattern found end and middle of buffer
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer4, sizeof( buffer4 ) ) );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context1 );
    CU_ASSERT_EQUAL( hitLoc, buffer4 + sizeof( buffer4 ) - 10 );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context1 );
    CU_ASSERT_EQUAL( hitLoc, buffer4 + sizeof( buffer4 ) - 4 );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    // Multi 1
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer5, sizeof( buffer5 ) ) );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context4 );
    CU_ASSERT_EQUAL( hitLoc, buffer5 + 3 );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context1 );
    CU_ASSERT_EQUAL( hitLoc, buffer5 + sizeof( buffer5 ) - 4 );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    // Multi 2
    CU_ASSERT_TRUE_FATAL( obsLib_setTargetBuffer( hObs, buffer6, sizeof( buffer6 ) ) );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context4 );
    CU_ASSERT_EQUAL( hitLoc, buffer6 + 3 );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context1 );
    CU_ASSERT_EQUAL( hitLoc, buffer6 + sizeof( buffer6 ) - 8 );
    CU_ASSERT_TRUE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );
    CU_ASSERT_EQUAL( hitCtx, &context3 );
    CU_ASSERT_EQUAL( hitLoc, buffer6 + sizeof( buffer6 ) - 4 );
    CU_ASSERT_FALSE( obsLib_nextHit( hObs, &hitCtx, &hitLoc ) );

    obsLib_free( hObs );
}