RBOOL hbs_whenCpuBelow ( RU8 percent, RTIME timeoutSeconds, rEvent abortEvent ) { RBOOL isCpuIdle = FALSE; RTIME end = rpal_time_getLocal() + timeoutSeconds; do { if( libOs_getCpuUsage() <= percent ) { isCpuIdle = TRUE; break; } if( NULL == abortEvent ) { rpal_thread_sleep( MSEC_FROM_SEC( 1 ) ); } else { if( rEvent_wait( abortEvent, MSEC_FROM_SEC( 1 ) ) ) { break; } } } while( end > rpal_time_getLocal() ); return isCpuIdle; }
static VOID CreateProcessNotifyEx ( PEPROCESS Process, HANDLE ProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo ) { KLOCK_QUEUE_HANDLE hMutex = { 0 }; UNREFERENCED_PARAMETER( Process ); KeAcquireInStackQueuedSpinLock( &g_collector_1_mutex, &hMutex ); // We're only interested in starts for now, a non-NULL CreateInfo indicates this. if( NULL != CreateInfo ) { g_processes[ g_nextProcess ].pid = (RU32)ProcessId; g_processes[ g_nextProcess ].ppid = (RU32)CreateInfo->ParentProcessId; g_processes[ g_nextProcess ].ts = rpal_time_getLocal(); g_processes[ g_nextProcess ].uid = KERNEL_ACQ_NO_USER_ID; copyUnicodeStringToBuffer( CreateInfo->ImageFileName, g_processes[ g_nextProcess ].path ); copyUnicodeStringToBuffer( CreateInfo->CommandLine, g_processes[ g_nextProcess ].cmdline ); g_nextProcess++; if( g_nextProcess == _NUM_BUFFERED_PROCESSES ) { g_nextProcess = 0; } } KeReleaseInStackQueuedSpinLock( &hMutex ); }
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; }
#ifdef RPAL_PLATFORM_WINDOWS return _time64( NULL ); #elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX ) return time( NULL ); #endif } RPAL_DEFINE_API ( RU64, rpal_time_getGlobal, ) { RU64 time = 0; time = rpal_time_getLocal() + g_rpal_time_globalOffset; return time; } RPAL_DEFINE_API ( RU64, rpal_time_setGlobalOffset, RU64 offset ) { RU64 oldOffset = 0; oldOffset = g_rpal_time_globalOffset;
RBOOL processMessage ( rSequence seq ) { RBOOL isSuccess = FALSE; RU8 command = 0; rSequence idSeq = NULL; rpHCPId tmpId = { 0 }; rpHCPId emptyId = { 0 }; RU64 tmpTime = 0; rThread hQuitThread = 0; rpHCPIdentStore identStore = {0}; RPU8 token = NULL; RU32 tokenSize = 0; OBFUSCATIONLIB_DECLARE( store, RP_HCP_CONFIG_IDENT_STORE ); if( NULL != seq ) { if( rSequence_getRU8( seq, RP_TAGS_OPERATION, &command ) ) { rpal_debug_info( "Received command 0x%0X.", command ); switch( command ) { case RP_HCP_COMMAND_LOAD_MODULE: isSuccess = loadModule( &g_hcpContext, seq ); break; case RP_HCP_COMMAND_UNLOAD_MODULE: isSuccess = unloadModule( &g_hcpContext, seq ); break; case RP_HCP_COMMAND_SET_HCP_ID: if( rSequence_getSEQUENCE( seq, RP_TAGS_HCP_IDENT, &idSeq ) ) { tmpId = seqToHcpId( idSeq ); if( 0 != rpal_memory_memcmp( &emptyId, &tmpId, sizeof( emptyId ) ) ) { g_hcpContext.currentId = tmpId; OBFUSCATIONLIB_TOGGLE( store ); if( rSequence_getBUFFER( seq, RP_TAGS_HCP_ENROLLMENT_TOKEN, &token, &tokenSize ) ) { identStore.agentId = tmpId; if( saveHcpId( (RPNCHAR)store, &identStore, token, tokenSize ) ) { isSuccess = TRUE; } if( NULL != g_hcpContext.enrollmentToken ) { rpal_memory_free( g_hcpContext.enrollmentToken ); g_hcpContext.enrollmentToken = NULL; } if( NULL != ( g_hcpContext.enrollmentToken = rpal_memory_alloc( tokenSize ) ) ) { rpal_memory_memcpy( g_hcpContext.enrollmentToken, token, tokenSize ); g_hcpContext.enrollmentTokenSize = tokenSize; isSuccess = TRUE; } } else { rpal_debug_warning( "hcp id is missing token" ); } OBFUSCATIONLIB_TOGGLE( store ); } } break; case RP_HCP_COMMAND_SET_GLOBAL_TIME: if( rSequence_getTIMESTAMP( seq, RP_TAGS_TIMESTAMP, &tmpTime ) ) { rpal_time_setGlobalOffset( tmpTime - rpal_time_getLocal() ); isSuccess = TRUE; } break; case RP_HCP_COMMAND_QUIT: if( 0 != ( hQuitThread = rpal_thread_new( thread_quitAndCleanup, NULL ) ) ) { rpal_thread_free( hQuitThread ); isSuccess = TRUE; } break; case RP_HCP_COMMAND_UPGRADE: isSuccess = upgradeHcp( seq ); break; default: break; } if( isSuccess ) { rpal_debug_info( "Command was successful." ); } else { rpal_debug_warning( "Command was not successful." ); } } } return isSuccess; }
static int new_proc_listener ( kauth_cred_t cred, struct vnode *vp, struct vnode *scriptvp, struct label *vnodelabel, struct label *scriptlabel, struct label *execlabel, struct componentname *cnp, u_int *csflags, void *macpolicyattr, size_t macpolicyattrlen ) #endif { #ifdef _USE_KAUTH vnode_t prog = (vnode_t)arg0; const char* file_path = (const char*)arg1; #else int pathLen = sizeof( g_processes[ 0 ].path ); #endif pid_t pid = 0; pid_t ppid = 0; uid_t uid = 0; #ifdef _USE_KAUTH if( KAUTH_FILEOP_EXEC != action || ( NULL != prog && VREG != vnode_vtype( prog ) ) ) { return KAUTH_RESULT_DEFER; } #endif uid = kauth_getuid(); pid = proc_selfpid(); ppid = proc_selfppid(); // We skip a known false positive if( 0 == ppid && 1 == pid ) { #ifdef _USE_KAUTH return KAUTH_RESULT_DEFER; #else return 0; // Always allow #endif } if( NULL != file_path ) { // rpal_debug_info( "!!!!!! process start: %d/%d/%d %s", ppid, pid, uid, file_path ); } rpal_mutex_lock( g_collector_1_mutex ); #ifdef _USE_KAUTH if( NULL != file_path ) { strncpy( g_processes[ g_nextProcess ].path, file_path, sizeof( g_processes[ g_nextProcess ].path ) - 1 ); } #else vn_getpath( vp, g_processes[ g_nextProcess ].path, &pathLen ); #endif g_processes[ g_nextProcess ].pid = pid; g_processes[ g_nextProcess ].ppid = ppid; g_processes[ g_nextProcess ].uid = uid; g_processes[ g_nextProcess ].ts = rpal_time_getLocal(); g_nextProcess++; if( g_nextProcess == _NUM_BUFFERED_PROCESSES ) { g_nextProcess = 0; rpal_debug_warning( "overflow of the execution buffer" ); } // rpal_debug_info( "now %d processes in buffer", g_nextProcess ); rpal_mutex_unlock( g_collector_1_mutex ); #ifdef _USE_KAUTH return KAUTH_RESULT_DEFER; #else return 0; // Always allow #endif }
static FLT_POSTOP_CALLBACK_STATUS FileSetInfoFilterPostCallback ( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID CompletionContext, FLT_POST_OPERATION_FLAGS Flags ) { FLT_POSTOP_CALLBACK_STATUS status = FLT_POSTOP_FINISHED_PROCESSING; KLOCK_QUEUE_HANDLE hMutex = { 0 }; PFLT_FILE_NAME_INFORMATION fileInfoSrc = NULL; PFLT_FILE_NAME_INFORMATION fileInfoDst = NULL; RU32 pid = 0; RU64 ts = 0; RU32 createOptions = 0; RU32 createDispositions = 0; PFILE_RENAME_INFORMATION renameInfo = NULL; _fileContext* context = NULL; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); UNREFERENCED_PARAMETER( Flags ); // We only care about user mode for now. if( UserMode != Data->RequestorMode || STATUS_SUCCESS != Data->IoStatus.Status ) { return status; } if( FileRenameInformation == Data->Iopb->Parameters.SetFileInformation.FileInformationClass ) { if( NULL != ( fileInfoSrc = (PFLT_FILE_NAME_INFORMATION)CompletionContext ) ) { //rpal_debug_kernel( "MOVE OLD: %wZ", fileInfoSrc->Name ); } else { rpal_debug_kernel( "Failed to get src file name info" ); } renameInfo = (PFILE_RENAME_INFORMATION)Data->Iopb->Parameters.SetFileInformation.InfoBuffer; if( !NT_SUCCESS( FltGetDestinationFileNameInformation( FltObjects->Instance, FltObjects->FileObject, renameInfo->RootDirectory, renameInfo->FileName, renameInfo->FileNameLength, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &fileInfoDst ) ) ) { rpal_debug_kernel( "Failed to get dst file name info" ); } else { //rpal_debug_kernel( "MOVE TO: %wZ", fileInfoDst->Name ); } pid = (RU32)FltGetRequestorProcessId( Data ); ts = rpal_time_getLocal(); createOptions = Data->Iopb->Parameters.Create.Options & 0x00FFFFFF; createDispositions = ( Data->Iopb->Parameters.Create.Options & 0xFF000000 ) >> 24; KeAcquireInStackQueuedSpinLock( &g_collector_2_mutex, &hMutex ); g_files[ g_nextFile ].pid = pid; g_files[ g_nextFile ].ts = ts; g_files[ g_nextFile ].uid = KERNEL_ACQ_NO_USER_ID; // For compability with the user mode API we report file moves // as two different operations. // First we report the old file name. g_files[ g_nextFile ].action = KERNEL_ACQ_FILE_ACTION_RENAME_OLD; if( NULL != fileInfoSrc ) { copyUnicodeStringToBuffer( &fileInfoSrc->Name, g_files[ g_nextFile ].path ); FltReleaseFileNameInformation( fileInfoSrc ); } g_nextFile++; if( g_nextFile == _NUM_BUFFERED_FILES ) { g_nextFile = 0; } // Now report the new file name. g_files[ g_nextFile ].action = KERNEL_ACQ_FILE_ACTION_RENAME_NEW; if( NULL != fileInfoDst ) { copyUnicodeStringToBuffer( &fileInfoDst->Name, g_files[ g_nextFile ].path ); FltReleaseFileNameInformation( fileInfoDst ); } g_nextFile++; if( g_nextFile == _NUM_BUFFERED_FILES ) { g_nextFile = 0; } KeReleaseInStackQueuedSpinLock( &hMutex ); } else if( FileDispositionInformationEx == Data->Iopb->Parameters.SetFileInformation.FileInformationClass ||
static FLT_POSTOP_CALLBACK_STATUS FileCreateFilterPostCallback ( PFLT_CALLBACK_DATA Data, PCFLT_RELATED_OBJECTS FltObjects, PVOID CompletionContext, FLT_POST_OPERATION_FLAGS Flags ) { FLT_POSTOP_CALLBACK_STATUS status = FLT_POSTOP_FINISHED_PROCESSING; KLOCK_QUEUE_HANDLE hMutex = { 0 }; PFLT_FILE_NAME_INFORMATION fileInfo = NULL; RU32 pid = 0; RU64 ts = 0; RU32 createOptions = 0; RU32 createDispositions = 0; _fileContext* context = NULL; UNREFERENCED_PARAMETER( FltObjects ); UNREFERENCED_PARAMETER( CompletionContext ); UNREFERENCED_PARAMETER( Flags ); // We only care about user mode for now. if( UserMode != Data->RequestorMode || STATUS_SUCCESS != Data->IoStatus.Status ) { return status; } if( FILE_CREATED == Data->IoStatus.Information ) { pid = (RU32)FltGetRequestorProcessId( Data ); ts = rpal_time_getLocal(); if( !NT_SUCCESS( FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_ALWAYS_ALLOW_CACHE_LOOKUP, &fileInfo ) ) ) { rpal_debug_kernel( "Failed to get file name info" ); fileInfo = NULL; } else { //rpal_debug_kernel( "NEW: %wZ", fileInfo->Name ); } if( NULL != ( context = _getOrSetContext( Data ) ) ) { context->isNew = TRUE; FltReleaseContext( (PFLT_CONTEXT)context ); } KeAcquireInStackQueuedSpinLock( &g_collector_2_mutex, &hMutex ); g_files[ g_nextFile ].pid = pid; g_files[ g_nextFile ].ts = ts; g_files[ g_nextFile ].uid = KERNEL_ACQ_NO_USER_ID; g_files[ g_nextFile ].action = KERNEL_ACQ_FILE_ACTION_ADDED; if( NULL != fileInfo ) { copyUnicodeStringToBuffer( &fileInfo->Name, g_files[ g_nextFile ].path ); FltReleaseFileNameInformation( fileInfo ); } g_nextFile++; if( g_nextFile == _NUM_BUFFERED_FILES ) { g_nextFile = 0; } KeReleaseInStackQueuedSpinLock( &hMutex ); } createOptions = Data->Iopb->Parameters.Create.Options & 0x00FFFFFF; createDispositions = ( Data->Iopb->Parameters.Create.Options & 0xFF000000 ) >> 24; if( IS_FLAG_ENABLED( createOptions, FILE_DELETE_ON_CLOSE ) ) { if( NULL != ( context = _getOrSetContext( Data ) ) ) { context->isDelete = TRUE; FltReleaseContext( (PFLT_CONTEXT)context ); } } return status; }
RBOOL rpal_initialize ( rpal_PContext context, RU32 logicalIdentifier ) { RBOOL isSuccess = FALSE; rpal_private_module_context* tmpContext = NULL; rHandle hCurrentModule = RPAL_HANDLE_INIT; g_rpal_localContext.identifier = logicalIdentifier; rpal_srand( (RU32)rpal_time_getLocal() ); if( NULL == context ) { #ifdef RPAL_MODE_MASTER if( NULL == g_rpal_context ) { g_rpal_context = malloc( sizeof( *g_rpal_context ) ); if( NULL != g_rpal_context ) { g_rpal_is_root_context = TRUE; g_rpal_context->version = RPAL_VERSION_CURRENT; #ifdef RPAL_PLATFORM_WINDOWS g_heap = HeapCreate( 0, ( 1024 * 1024 * 10 ), 0 ); #endif // This is the core library. // Setup the Memory Management RPAL_API_REF( rpal_memory_allocEx ) = _rpal_memory_allocEx; RPAL_API_REF( rpal_memory_free ) = _rpal_memory_free; RPAL_API_REF( rpal_memory_isValid ) = _rpal_memory_isValid; RPAL_API_REF( rpal_memory_realloc ) = _rpal_memory_realloc; RPAL_API_REF( rpal_memory_totalUsed ) = _rpal_memory_totalUsed; RPAL_API_REF( rpal_time_getGlobal ) = _rpal_time_getGlobal; RPAL_API_REF( rpal_time_setGlobalOffset ) = _rpal_time_setGlobalOffset; RPAL_API_REF( rpal_handleManager_create_global ) = _rpal_handleManager_create_global; RPAL_API_REF( rpal_handleManager_open_global ) = _rpal_handleManager_open_global; RPAL_API_REF( rpal_handleManager_openEx_global ) = _rpal_handleManager_openEx_global; RPAL_API_REF( rpal_handleManager_close_global ) = _rpal_handleManager_close_global; RPAL_API_REF( rpal_handleManager_getValue_global ) = _rpal_handleManager_getValue_global; #ifdef RPAL_FEATURE_MEMORY_ACCOUNTING RPAL_API_REF( rpal_memory_printDetailedUsage ) = _rpal_memory_printDetailedUsage; #endif if( NULL != ( g_handleMajorLock = rRwLock_create() ) ) { rInterlocked_increment32( &g_rpal_nrecursiveInit ); isSuccess = TRUE; } else { free( g_rpal_context ); g_rpal_context = NULL; } } } else { rInterlocked_increment32( &g_rpal_nrecursiveInit ); isSuccess = TRUE; } #endif } #ifdef RPAL_MODE_SLAVE else if( RPAL_VERSION_CURRENT <= context->version ) { // We bind this instance to the core. g_rpal_context = context; isSuccess = TRUE; } #endif if( isSuccess ) { // If the local_handles is already create it means that // someone local already initialised rpal so no need to proceed... if( NULL == g_rpal_localContext.local_handles ) { // Let's setup the local context g_rpal_localContext.local_handles = rpal_btree_create( sizeof( rHandle ), (rpal_btree_comp_f)_findHandle, NULL ); if( NULL == g_rpal_localContext.local_handles ) { isSuccess = FALSE; } else { hCurrentModule.info.major = RPAL_HANDLES_MAJOR_MODULECONTEXT; hCurrentModule.info.minor = logicalIdentifier; // Let's register our local context // Is our component registered? if( rpal_handleManager_open( hCurrentModule, (RPVOID)&tmpContext ) ) { // Seems our component is registered, is it just a double-registration // or is it a different instance? if( tmpContext != &g_rpal_localContext ) { // Different instance, this is bad, bail out! isSuccess = FALSE; } else { // Double init... all good, ignore. } // Either way, release the handle rpal_handleManager_close( hCurrentModule, NULL ); } else { // Our component is not registered, do it. hCurrentModule = rpal_handleManager_create( RPAL_HANDLES_MAJOR_MODULECONTEXT, logicalIdentifier, &g_rpal_localContext, NULL ); if( RPAL_HANDLE_INVALID == hCurrentModule.h ) { // There was an error registering, bail out. isSuccess = FALSE; } else { g_rpal_localContext.hModule.h = hCurrentModule.h; } } } if( !isSuccess ) { if( NULL != g_rpal_localContext.local_handles ) { rpal_btree_destroy( g_rpal_localContext.local_handles, FALSE ); } if( g_rpal_is_root_context ) { free( g_rpal_context ); g_rpal_context = NULL; g_rpal_is_root_context = FALSE; } } } #ifdef RPAL_MODE_MASTER if( !isSuccess && g_rpal_is_root_context ) { rRwLock_free( g_handleMajorLock ); free( g_rpal_context ); g_rpal_context = NULL; } #endif } return isSuccess; }