Пример #1
0
RBOOL
    rpal_blob_remove
    (
        rBlob blob,
        RU32 startOffset,
        RU32 size
    )
{
    RBOOL isSuccess = FALSE;
    _prBlob pBlob = (_prBlob)blob;
    
    if( NULL != pBlob &&
        IS_WITHIN_BOUNDS( pBlob->pData + startOffset, size, pBlob->pData, pBlob->sizeUsed ) &&
        rpal_memory_isValid( pBlob->pData ) )
    {
        rpal_memory_memcpy( pBlob->pData + startOffset, pBlob->pData + startOffset + size, pBlob->sizeUsed - size - startOffset );
        pBlob->sizeUsed -= size;

        if( rpal_memory_isValid( pBlob->pData ) )
        {
            pBlob->pData = rpal_memory_realloc_from( pBlob->pData, pBlob->sizeUsed + sizeof( RWCHAR ), pBlob->from );
            pBlob->currentSize = pBlob->sizeUsed;

            if( NULL != pBlob->pData )
            {
                // We allocate WCHAR more than we need always to ensure that if the buffer contains a wide string it will be terminated
                rpal_memory_zero( pBlob->pData + pBlob->sizeUsed, sizeof( RWCHAR ) );
                isSuccess = TRUE;
            }
        }
    }

    return isSuccess;
}
static
RBOOL
    isMemInModule
    (
        RU64 memBase,
        RU64 memSize,
        _MemRange* memRanges,
        RU32 nRanges
    )
{
    RBOOL isInMod = FALSE;
    RU32 i = 0;

    if( NULL != memRanges )
    {
        i = rpal_binsearch_array_closest( memRanges, 
                                          nRanges, 
                                          sizeof( _MemRange ), 
                                          &memBase, 
                                          (rpal_ordering_func)rpal_order_RU64,
                                          TRUE );
        if( (RU32)(-1) != i )
        {
            if( IS_WITHIN_BOUNDS( NUMBER_TO_PTR( memBase ), 
                                  memSize, 
                                  NUMBER_TO_PTR( memRanges[ i ].base ), 
                                  memRanges[ i ].size ) )
            {
                isInMod = TRUE;
            }
        }
    }

    return isInMod;
}
Пример #3
0
RPVOID
    rpal_blob_arrElem
    (
        rBlob blob,
        RU32 elemSize,
        RU32 elemIndex
    )
{
    RPVOID pElem = NULL;
    _prBlob b = (_prBlob)blob;
    RU32 offset = 0;

    if( rpal_memory_isValid( b ) )
    {
        offset = elemSize * elemIndex;

        if( rpal_memory_isValid( b->pData ) &&
            IS_WITHIN_BOUNDS( b->pData + ( offset ), elemSize, b->pData, b->sizeUsed ) )
        {
            pElem = b->pData + offset;
        }
    }

    return pElem;
}
RPRIVATE
RVOID
    dnsKmDiffThread
    (
        rEvent isTimeToStop
    )
{
    RU8 new_from_kernel[ DNS_KB_PACKET_BUFFER * 1024 ] = { 0 };
    RU8 prev_from_kernel[ DNS_KB_PACKET_BUFFER * 1024 ] = { 0 };

    RU32 sizeInNew = 0;
    RU32 sizeInPrev = 0;

    KernelAcqDnsPacket* pPacket = NULL;

    while( !rEvent_wait( isTimeToStop, 1000 ) )
    {
        rpal_memory_zero( new_from_kernel, sizeof( new_from_kernel ) );
        sizeInNew = sizeof( new_from_kernel );

        if( !kAcq_getNewDnsPackets( (KernelAcqDnsPacket*)new_from_kernel, &sizeInNew ) )
        {
            rpal_debug_warning( "kernel acquisition for new dns packets failed" );
            break;
        }

        pPacket = (KernelAcqDnsPacket*)prev_from_kernel;
        while( IS_WITHIN_BOUNDS( pPacket, sizeof( *pPacket ), prev_from_kernel, sizeInPrev ) &&
               0 != pPacket->ts &&
               IS_WITHIN_BOUNDS( pPacket, sizeof( *pPacket ) + pPacket->packetSize, prev_from_kernel, sizeInPrev ) )
        {
            processDnsPacket( pPacket );

            pPacket = (KernelAcqDnsPacket*)( (RPU8)pPacket + sizeof( *pPacket ) + pPacket->packetSize );
        }

        rpal_memory_memcpy( prev_from_kernel, new_from_kernel, sizeInNew );
        sizeInPrev = sizeInNew;
    }
}
Пример #5
0
RBOOL
    rStack_free
    (
        rStack stack,
        rStack_freeFunc freeFunc
    )
{
    RBOOL isSuccess = FALSE;
    _prStack pStack = (_prStack)stack;
    RPVOID tmpElem = NULL;
    RPVOID tmpBuff = NULL;
    RU32 tmpSize = 0;
    RU32 i = 0;

    if( NULL != stack )
    {
        if( rMutex_lock( pStack->lock ) )
        {
            isSuccess = TRUE;

            tmpElem = rpal_blob_getBuffer( pStack->blob );
            tmpBuff = tmpElem;
            tmpSize = rpal_blob_getSize( pStack->blob );

            for( i = 0; i < pStack->nElements; i++ )
            {
                tmpElem = (RPU8)tmpElem + ( i * pStack->elemSize );

                if( IS_WITHIN_BOUNDS( tmpElem, pStack->elemSize, tmpBuff, tmpSize ) )
                {
                    if( NULL != freeFunc )
                    {
                        if( !freeFunc( tmpElem ) )
                        {
                            isSuccess = FALSE;
                        }
                    }
                }
            }

            rpal_blob_free( pStack->blob );

            rMutex_free( pStack->lock );
            rpal_memory_free( pStack );
        }
    }

    return isSuccess;
}
Пример #6
0
// TODO: Implement PMAP_CANFAIL logic
uint32_t pmap_enter(pmap_t *pmap, vaddr_t va, paddr_t pa, vm_prot_t vm_prot, pmap_flags_t pmap_flags) {
  // Must have a valid pmap
  kassert(pmap != NULL && pmap->pgd != NULL && IS_WITHIN_BOUNDS(pa) && IS_PAGE_ALIGNED(pa) && IS_PAGE_ALIGNED(va));

  // Encode the protection bits in the page table entry
  // Encode the protection and pmap flags in the page table entry 
  pte_t entry = PTE_CREATE(pa, PTE_AP0_BIT | PTE_S_BIT | PTE_ENCODE_PROTECTION(vm_prot, pmap_kernel()) | PTE_ENCODE_PMAP_FLAGS(pmap_flags));

  // First check if the page table for the given va exists within the page directory. If not create the page table
  uint32_t pgd_index = PGD_GET_INDEX(va);
  if(!PDE_PGT_EXISTS(pmap->pgd->pde[pgd_index])) {
    // TODO: To get pa of pgt -> TRUNC_PAGE(pgt) and search kernel pgd & pgt for entry
  }


  kassert(entry != 0);
  return 0;
}
static
RBOOL
    isMemInModule
    (
        RU64 memBase,
        RU64 memSize,
        rList modules
    )
{
    RBOOL isInMod = FALSE;
    rSequence mod = NULL;

    RU64 modBase = 0;
    RU64 modSize = 0;

    if( NULL != modules )
    {
        rList_resetIterator( modules );

        while( rList_getSEQUENCE( modules, RP_TAGS_DLL, &mod ) )
        {
            if( rSequence_getPOINTER64( mod, RP_TAGS_BASE_ADDRESS, &modBase ) &&
                rSequence_getRU64( mod, RP_TAGS_MEMORY_SIZE, &modSize ) )
            {
                if( IS_WITHIN_BOUNDS( NUMBER_TO_PTR( memBase ), memSize, NUMBER_TO_PTR( modBase ), modSize ) )
                {
                    isInMod = TRUE;
                    break;
                }
            }
        }

        rList_resetIterator( modules );
    }

    return isInMod;
}
RPRIVATE
RVOID
    processDnsPacket
    (
        KernelAcqDnsPacket* pDns
    )
{
    rSequence notification = NULL;
    RU32 i = 0;
    DnsLabel* pLabel = NULL;
    DnsHeader* dnsHeader = NULL;
    DnsResponseInfo* pResponseInfo = NULL;
    RCHAR domain[ DNS_LABEL_MAX_SIZE ] = { 0 };
    RU16 recordType = 0;
    RU64 timestamp = 0;
    Atom parentAtom = { 0 };

    if( NULL == pDns )
    {
        return;
    }

    dnsHeader = (DnsHeader*)( (RPU8)pDns + sizeof( *pDns ) );
    pLabel = (DnsLabel*)dnsHeader->data;

    // We are parsing DNS packets coming from the kernel. They may:
    // 1- Be requests and not responses, check there are Answers.
    // 2- Be maliciously crafter packets so we need extra checking for sanity.
    if( 0 == dnsHeader->anCount ||
        0 == dnsHeader->qr ||
        DNS_SANITY_MAX_RECORDS < rpal_ntoh16( dnsHeader->qdCount ) ||
        DNS_SANITY_MAX_RECORDS < rpal_ntoh16( dnsHeader->anCount ) )
    {
        return;
    }

    // We need to walk the Questions first to get to the Answers
    // but we don't really care to record them since they'll be repeated
    // in the Answers.
    for( i = 0; i < rpal_ntoh16( dnsHeader->qdCount ); i++ )
    {
        DnsQuestionInfo* pQInfo = NULL;

        pLabel = dnsReadLabels( pLabel, NULL, (RPU8)dnsHeader, pDns->packetSize, 0, 0 );

        pQInfo = (DnsQuestionInfo*)( pLabel );
        if( !IS_WITHIN_BOUNDS( pQInfo, sizeof( *pQInfo ), dnsHeader, pDns->packetSize ) )
        {
            rpal_debug_warning( "error parsing dns packet" );
            break;
        }

        pLabel = (DnsLabel*)( (RPU8)pQInfo + sizeof( *pQInfo ) );
    }

    if( !IS_WITHIN_BOUNDS( pLabel, sizeof( RU16 ), dnsHeader, pDns->packetSize ) )
    {
        rpal_debug_warning( "error parsing dns packet" );
        return;
    }

    // This is what we care about, the Answers (which also point to each Question).
    // We will emit one event per Answer so as to keep the DNS_REQUEST event flat and atomic.
    for( i = 0; i < rpal_ntoh16( dnsHeader->anCount ); i++ )
    {
        pResponseInfo = NULL;
            
        // This was the Question for this answer.
        rpal_memory_zero( domain, sizeof( domain ) );
        pLabel = dnsReadLabels( pLabel, domain, (RPU8)dnsHeader, pDns->packetSize, 0, 0 );

        pResponseInfo = (DnsResponseInfo*)pLabel;
        pLabel = (DnsLabel*)( (RPU8)pResponseInfo + sizeof( *pResponseInfo ) + rpal_ntoh16( pResponseInfo->rDataLength ) );

        if( !IS_WITHIN_BOUNDS( pResponseInfo, sizeof( *pResponseInfo ), dnsHeader, pDns->packetSize ) )
        {
            rpal_debug_warning( "error parsing dns packet" );
            break;
        }

        if( NULL == ( notification = rSequence_new() ) )
        {
            rpal_debug_warning( "error parsing dns packet" );
            break;
        }

        // This is a timestamp coming from the kernel so it is not globally adjusted.
        // We'll adjust it with the global offset.
        timestamp = pDns->ts;
        timestamp += MSEC_FROM_SEC( rpal_time_getGlobalFromLocal( 0 ) );

        // Try to relate the DNS request to the owner process, this only works on OSX
        // at the moment (since the kernel does not expose the PID at the packet capture
        // stage), and even on OSX it's the DNSResolver process. So it's not super useful
        // but regardless we have the mechanism here as it's better than nothing and when
        // we add better resolving in the kernel it will work transparently.
        parentAtom.key.process.pid = pDns->pid;
        parentAtom.key.category = RP_TAGS_NOTIFICATION_NEW_PROCESS;
        if( atoms_query( &parentAtom, timestamp ) )
        {
            HbsSetParentAtom( notification, parentAtom.id );
        }

        rSequence_addTIMESTAMP( notification, RP_TAGS_TIMESTAMP, timestamp );
        rSequence_addSTRINGA( notification, RP_TAGS_DOMAIN_NAME, domain );
        rSequence_addRU32( notification, RP_TAGS_PROCESS_ID, pDns->pid );

        recordType = rpal_ntoh16( pResponseInfo->recordType );

        rSequence_addRU16( notification, RP_TAGS_MESSAGE_ID, rpal_ntoh16( dnsHeader->msgId ) );
        rSequence_addRU16( notification, RP_TAGS_DNS_TYPE, recordType );

        if( DNS_A_RECORD == recordType )
        {
            rSequence_addIPV4( notification, RP_TAGS_IP_ADDRESS, *(RU32*)pResponseInfo->rData );
        }
        else if( DNS_AAAA_RECORD == recordType )
        {
            rSequence_addIPV6( notification, RP_TAGS_IP_ADDRESS, pResponseInfo->rData );
        }
        else if( DNS_CNAME_RECORD == recordType )
        {
            // CNAME records will have another label as a value and not an IP.
            rpal_memory_zero( domain, sizeof( domain ) );
            dnsReadLabels( (DnsLabel*)pResponseInfo->rData, domain, (RPU8)dnsHeader, pDns->packetSize, 0, 0 );
            rSequence_addSTRINGA( notification, RP_TAGS_CNAME, domain );
        }
        else
        {
            // Right now we only care for A, CNAME and AAAA records.
            rSequence_free( notification );
            notification = NULL;
            continue;
        }

        hbs_publish( RP_TAGS_NOTIFICATION_DNS_REQUEST, notification );
        rSequence_free( notification );
        notification = NULL;
    }
}
// Parses a label from a DNS packet and returns a pointer to the next byte after the label
// or label chain to be used to continue parsing the packet.
// If a human label is specified, will also assemble a human readable version of the labels
// in the buffer.
RPRIVATE
DnsLabel*
    dnsReadLabels
    (
        DnsLabel* pLabel,
        RCHAR humanLabel[ DNS_LABEL_MAX_SIZE ],
        RPU8 packetStart,
        RSIZET packetSize,
        RU32 labelOffset,
        RU32 recursiveDepth
    )
{
    RU32 copied = labelOffset;

    if( 3 < recursiveDepth )
    {
        return NULL;
    }

    if( NULL == pLabel )
    {
        return NULL;
    }

    while( IS_WITHIN_BOUNDS( pLabel, sizeof( *pLabel ), packetStart, packetSize ) &&
            ( DNS_LABEL_IS_OFFSET( pLabel ) ||
                ( IS_WITHIN_BOUNDS( pLabel, sizeof( *pLabel ) + pLabel->nChar, packetStart, packetSize ) &&
                0 != pLabel->nChar ) ) )
    {
        // It's possible for a pointer to be terminating a traditional label
        if( DNS_LABEL_IS_OFFSET( pLabel ) )
        {
            // Pointer to a label
            DnsLabel* tmpLabel = NULL;
            RU16 offset = DNS_LABEL_OFFSET( pLabel );

            if( !IS_WITHIN_BOUNDS( (RPU8)packetStart + offset, sizeof( RU16 ), packetStart, packetSize ) )
            {
                rpal_debug_warning( "error parsing dns packet" );
                return NULL;
            }

            tmpLabel = (DnsLabel*)( (RPU8)packetStart + offset );

            if( NULL == dnsReadLabels( tmpLabel, humanLabel, packetStart, packetSize, copied, recursiveDepth + 1 ) )
            {
                return NULL;
            }

            // Pointers are always terminating the label. So since there is
            // no 0 terminated label we don't need to skip an extra byte, we
            // just skip the current label pointer value.
            pLabel = (DnsLabel*)( (RPU8)pLabel + sizeof( RU16 ) );
            return pLabel;
        }
        else
        {
            if( DNS_LABEL_MAX_SIZE < copied + 1 + pLabel->nChar )
            {
                rpal_debug_warning( "error parsing dns packet" );
                return NULL;
            }

            if( NULL != humanLabel )
            {
                if( 0 != copied )
                {
                    humanLabel[ copied ] = '.';
                    copied++;
                }
                rpal_memory_memcpy( (RPU8)humanLabel + copied, pLabel->label, pLabel->nChar );
                copied += pLabel->nChar;
            }

            pLabel = (DnsLabel*)( (RPU8)pLabel + pLabel->nChar + 1 );
        }
    }

    // We do a last sanity check. A valid label parsing should end in a 0-val nChar within
    // the buffer, so we check it's all valid, otherwise we'll assume an error and will return an error.
    if( !IS_WITHIN_BOUNDS( pLabel, sizeof( *pLabel ), packetStart, packetSize ) ||
        0 != pLabel->nChar )
    {
        rpal_debug_warning( "error parsing dns packet" );
        return NULL;
    }

    // Get to the next valid byte, so we skip the 0-termination.
    pLabel = (DnsLabel*)( (RPU8)pLabel + 1 );

    return pLabel;
}
Пример #10
0
static
RPVOID
    lookForHiddenModulesIn
    (
        rEvent isTimeToStop,
        RU32 processId
    )
{
    rList mods = NULL;
    rList map = NULL;
    rSequence region = NULL;
    RU8 memType = 0;
    RU8 memProtect = 0;
    RU64 memBase = 0;
    RU64 memSize = 0;

    RPU8 pMem = NULL;

    RBOOL isPrefetched = FALSE;
    RBOOL isCurrentExec = FALSE;
    RBOOL isHidden = FALSE;

    rSequence procInfo = NULL;

#ifdef RPAL_PLATFORM_WINDOWS
    PIMAGE_DOS_HEADER pDos = NULL;
    PIMAGE_NT_HEADERS pNt = NULL;
#endif
    if( NULL != ( mods = processLib_getProcessModules( processId ) ) )
    {
        if( NULL != ( map = processLib_getProcessMemoryMap( processId ) ) )
        {
            // Now we got all the info needed for a single process, compare
            while( rpal_memory_isValid( isTimeToStop ) &&
                !rEvent_wait( isTimeToStop, 0 ) &&
                ( isPrefetched || rList_getSEQUENCE( map, RP_TAGS_MEMORY_REGION, &region ) ) )
            {
                if( isPrefetched )
                {
                    isPrefetched = FALSE;
                }

                if( rSequence_getRU8( region, RP_TAGS_MEMORY_TYPE, &memType ) &&
                    rSequence_getRU8( region, RP_TAGS_MEMORY_ACCESS, &memProtect ) &&
                    rSequence_getPOINTER64( region, RP_TAGS_BASE_ADDRESS, &memBase ) &&
                    rSequence_getRU64( region, RP_TAGS_MEMORY_SIZE, &memSize ) )
                {
                    if( PROCESSLIB_MEM_TYPE_PRIVATE == memType ||
                        PROCESSLIB_MEM_TYPE_MAPPED == memType )
                    {
                        if( PROCESSLIB_MEM_ACCESS_EXECUTE == memProtect ||
                            PROCESSLIB_MEM_ACCESS_EXECUTE_READ == memProtect ||
                            PROCESSLIB_MEM_ACCESS_EXECUTE_READ_WRITE == memProtect ||
                            PROCESSLIB_MEM_ACCESS_EXECUTE_WRITE_COPY == memProtect )
                        {
                            isCurrentExec = TRUE;
                        }
                        else
                        {
                            isCurrentExec = FALSE;
                        }

                        if( !isMemInModule( memBase, memSize, mods ) )
                        {
                            // Exec memory found outside of a region marked to belong to
                            // a module, keep looking in for module.
                            if( ( 1024 * 1024 * 10 ) >= memSize &&
                                processLib_getProcessMemory( processId, 
                                                             NUMBER_TO_PTR( memBase ), 
                                                             memSize, 
                                                             (RPVOID*)&pMem ) )
                            {
                                isHidden = FALSE;
#ifdef RPAL_PLATFORM_WINDOWS
                                // Let's just check for MZ and PE for now, we can get fancy later.
                                pDos = (PIMAGE_DOS_HEADER)pMem;
                                if( IS_WITHIN_BOUNDS( (RPU8)pMem, sizeof( IMAGE_DOS_HEADER ), pMem, memSize ) &&
                                    IMAGE_DOS_SIGNATURE == pDos->e_magic )
                                {
                                    pNt = (PIMAGE_NT_HEADERS)( (RPU8)pDos + pDos->e_lfanew );

                                    if( IS_WITHIN_BOUNDS( pNt, sizeof( *pNt ), pMem, memSize ) &&
                                        IMAGE_NT_SIGNATURE == pNt->Signature )
                                    {
                                        if( isCurrentExec )
                                        {
                                            // If the current region is exec, we've got a hidden module.
                                            isHidden = TRUE;
                                        }
                                        else
                                        {
                                            // We need to check if the next section in memory is
                                            // executable and outside of known modules since the PE
                                            // headers may have been marked read-only before the .text.
                                            if( rList_getSEQUENCE( map, RP_TAGS_MEMORY_REGION, &region ) )
                                            {
                                                isPrefetched = TRUE;

                                                if( ( PROCESSLIB_MEM_TYPE_PRIVATE == memType ||
                                                        PROCESSLIB_MEM_TYPE_MAPPED == memType ) &&
                                                    ( PROCESSLIB_MEM_ACCESS_EXECUTE == memProtect ||
                                                        PROCESSLIB_MEM_ACCESS_EXECUTE_READ == memProtect ||
                                                        PROCESSLIB_MEM_ACCESS_EXECUTE_READ_WRITE == memProtect ||
                                                        PROCESSLIB_MEM_ACCESS_EXECUTE_WRITE_COPY == memProtect ) )
                                                {
                                                    isHidden = TRUE;
                                                }
                                            }
                                        }
                                    }
                                }
#elif defined( RPAL_PLATFORM_LINUX ) || defined( RPAL_PLATFORM_MACOSX )
                                if( isCurrentExec &&
                                    0x7F == ( pMem )[ 0 ] &&
                                    'E' == ( pMem )[ 1 ] &&
                                    'L' == ( pMem )[ 2 ] &&
                                    'F' == ( pMem )[ 3 ] )
                                {
                                    isHidden = TRUE;
                                }
#endif

                                rpal_memory_free( pMem );

                                if( isHidden &&
                                    !rEvent_wait( isTimeToStop, 0 ) )
                                {
                                    rpal_debug_info( "found a hidden module in %d.", processId );

                                    if( NULL != ( procInfo = processLib_getProcessInfo( processId ) ) )
                                    {
                                        if( !rSequence_addSEQUENCE( region, RP_TAGS_PROCESS, procInfo ) )
                                        {
                                            rSequence_free( procInfo );
                                        }
                                    }

                                    rSequence_addTIMESTAMP( region, RP_TAGS_TIMESTAMP, rpal_time_getGlobal() );
                                    notifications_publish( RP_TAGS_NOTIFICATION_HIDDEN_MODULE_DETECTED, region );
                                    break;
                                }

                                rpal_thread_sleep( 10 );
                            }
                        }
                    }
                }
            }

            rList_free( map );
        }

        rList_free( mods );
    }

    return NULL;
}