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; }
void test_CreateAndDestroy(void) { HObs hObs = NULL; hObs = obsLib_new( 0, 0 ); CU_ASSERT_TRUE_FATAL( rpal_memory_isValid( hObs ) ); obsLib_free( hObs ); }
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 ); }
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; }
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; }
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 ); }