Beispiel #1
0
	NTSTATUS MMap::AllocateInHighMem(MemBlock& imageMem, size_t size) {
		ptr_t ptr = 0;
		// Align on page boundary
		size = Align(size, 0x1000);
		//
		// Get random address 
		//
		bool found = true;
		static std::random_device rd;
		std::uniform_int_distribution<ptr_t> dist(0x100000, 0x7FFFFFFF);
		// Make sure address is unused
		for(ptr = dist(rd) * 0x1000; found; ptr = dist(rd) * 0x1000) {
			found = false;
			for(auto& entry : _usedBlocks) {
				if(ptr >= entry.first && ptr < entry.first + entry.second) {
					found = true;
					break;
				}
			}
		}
		// Not implemented yet
		NTSTATUS status = STATUS_NOT_IMPLEMENTED;
		// Change protection and save address
		if(NT_SUCCESS(status)) {
			_usedBlocks.emplace_back(std::make_pair(ptr, size));
			imageMem = MemBlock(&_process.Memory(), ptr, size, PAGE_READWRITE, false);
			_process.Memory().Protect(ptr, size, PAGE_READWRITE);
			return true;
		}
		return status;
	}
Beispiel #2
0
/// <summary>
/// Allocate new memory block
/// </summary>
/// <param name="process">Process memory routines</param>
/// <param name="size">Block size</param>
/// <param name="desired">Desired base address of new block</param>
/// <param name="protection">Memory protection</param>
/// <param name="own">false if caller will be responsible for block deallocation</param>
/// <returns>Memory block. If failed - returned block will be invalid</returns>
call_result_t<MemBlock> MemBlock::Allocate( ProcessMemory& process, size_t size, ptr_t desired /*= 0*/, DWORD protection /*= PAGE_EXECUTE_READWRITE */, bool own /*= true*/ )
{
    ptr_t desired64 = desired;
    DWORD newProt = CastProtection( protection, process.core().DEP() );
    
    NTSTATUS status = process.core().native()->VirtualAllocExT( desired64, size, MEM_COMMIT, newProt );
    if (!NT_SUCCESS( status ))
    {
        desired64 = 0;
        status = process.core().native()->VirtualAllocExT( desired64, size, MEM_COMMIT, newProt );
        if (NT_SUCCESS( status ))
            return call_result_t<MemBlock>( MemBlock( &process, desired64, size, protection, own ), STATUS_IMAGE_NOT_AT_BASE );
        else
            return status;
    }

    return MemBlock( &process, desired64, size, protection, own );
}
Beispiel #3
0
    void free(void* ptr) {
        if (ptr == NULL) {
            // Free does nothing on null pointers
            return;
        }

        debugAssert(isValidPointer(ptr));

        if (inTinyHeap(ptr)) {
            lock();
            tinyFree(ptr);
            unlock();
            return;
        }

        uint32 bytes = ((uint32*)ptr)[-1];

        lock();
        if (bytes <= smallBufferSize) {
            if (smallPoolSize < maxSmallBuffers) {
                smallPool[smallPoolSize] = MemBlock(ptr, bytes);
                ++smallPoolSize;
                unlock();
                return;
            }
        } else if (bytes <= medBufferSize) {
            if (medPoolSize < maxMedBuffers) {
                medPool[medPoolSize] = MemBlock(ptr, bytes);
                ++medPoolSize;
                unlock();
                return;
            }
        }
        bytesAllocated -= bytes + 4;
        unlock();

        // Free; the buffer pools are full or this is too big to store.
        ::free((uint8*)ptr - 4);
    }
Beispiel #4
0
/// <summary>
/// Allocates memory region beyond 4GB limit
/// </summary>
/// <param name="imageMem">Image data</param>
/// <param name="size">Block size</param>
/// <returns>true on success</returns>
bool MMap::AllocateInHighMem( MemBlock& imageMem, size_t size )
{
    HANDLE hFile = GetDriverHandle();

    if (hFile != INVALID_HANDLE_VALUE)
    {
        ptr_t ptr = 0;

        // Align on page boundary
        size = Align( size, 0x1000 );

        //
        // Get random address 
        //
        bool found = true;
        static std::random_device rd;
        std::uniform_int_distribution<ptr_t> dist( 0x100000, 0x7FFFFFFF );

        // Make sure address is unused
        for (ptr = dist( rd ) * 0x1000; found; ptr = dist( rd ) * 0x1000)
        {
            found = false;

            for (auto& entry : _usedBlocks)
                if (ptr >= entry.first && ptr < entry.first + entry.second)
                {
                    found = true;
                    break;
                }
        }

        PURGE_DATA data = { _process.core().pid(), 1, { ptr, size } };
        DWORD junk = 0;

        BOOL ret = DeviceIoControl( hFile, static_cast<DWORD>(IOCTL_VADPURGE_ENABLECHANGE), &data, sizeof(data), NULL, 0, &junk, NULL );
        CloseHandle( hFile );

        // Change protection and save address
        if(ret == TRUE)
        {
            _usedBlocks.emplace_back( std::make_pair( ptr, size ) );

            imageMem = MemBlock( &_process.memory(), ptr, size, PAGE_READWRITE, false );
            _process.memory( ).Protect( ptr, size, PAGE_READWRITE );
            return true;
        }
    }

    return false;
}
/// <summary>
/// Allocate new memory block
/// </summary>
/// <param name="process">Process memory routines</param>
/// <param name="size">Block size</param>
/// <param name="desired">Desired base address of new block</param>
/// <param name="protection">Memory protection</param>
/// <returns>Memory block. If failed - returned block will be invalid</returns>
MemBlock MemBlock::Allocate( ProcessMemory& process, size_t size, ptr_t desired /*= 0*/, DWORD protection /*= PAGE_EXECUTE_READWRITE */ )
{
    ptr_t desired64 = desired;
    DWORD newProt = CastProtection( protection, process.core().DEP() );
    
    if (process.core().native()->VirualAllocExT( desired64, size, MEM_COMMIT, newProt ) != STATUS_SUCCESS)
    {
        desired64 = 0;
        if (process.core().native()->VirualAllocExT( desired64, size, MEM_COMMIT, newProt ) == STATUS_SUCCESS)
            LastNtStatus( STATUS_IMAGE_NOT_AT_BASE );
        else
            desired64 = 0;
    }

    return MemBlock( &process, desired64, size, protection );
}
Beispiel #6
0
        void Vbo::resizeVbo(size_t newCapacity) {
            VboState oldState = m_state;
            
            unsigned char* temp = NULL;
            MemBlock::List memBlocks;
            if (m_vboId != 0 && m_freeCapacity < m_totalCapacity) {
                VboBlock* currentBlock = m_first;
                size_t totalLength = 0;
                
                while (currentBlock != NULL) {
                    while (currentBlock != NULL && currentBlock->free())
                        currentBlock = currentBlock->m_next;
                    if (currentBlock != NULL) {
                        size_t start = currentBlock->address();
                        size_t length = 0;
                        while (currentBlock != NULL && !currentBlock->free()) {
                            length += currentBlock->capacity();
                            currentBlock = currentBlock->m_next;
                        }
                        memBlocks.push_back(MemBlock(start, length));
                        totalLength += length;
                    }
                }
                
                if (m_state < VboActive)
                    activate();
                if (m_state < VboMapped)
                    map();

                temp = new unsigned char[totalLength];
                size_t offset = 0;
                MemBlock::List::const_iterator it, end;
                for (it = memBlocks.begin(), end = memBlocks.end(); it != end; ++it) {
                    const MemBlock& memBlock = *it;
                    memcpy(temp + offset, m_buffer + memBlock.start, memBlock.length);
                    offset += memBlock.length;
                }
            }
            
            size_t addedCapacity = newCapacity - m_totalCapacity;
            m_freeCapacity = newCapacity - (m_totalCapacity - m_freeCapacity);
            m_totalCapacity = newCapacity;
            
            if (m_last->free()) {
                resizeBlock(*m_last, m_last->capacity() + addedCapacity);
            } else {
                VboBlock* block = new VboBlock(*this, m_last->address() + m_last->capacity(), addedCapacity);
                block->insertBetween(m_last, NULL);
                insertFreeBlock(*block);
                m_last = block;
            }
            
            if (m_vboId != 0) {
                if (m_state == VboMapped)
                    unmap();
                if (m_state == VboActive)
                    deactivate();
                glDeleteBuffers(1, &m_vboId);
                m_vboId = 0;
            }
            
            if (temp != NULL) {
                assert(!memBlocks.empty());
                
                if (m_state < VboActive)
                    activate();
                if (m_state < VboMapped)
                    map();
                
                size_t offset = 0;
                MemBlock::List::const_iterator it, end;
                for (it = memBlocks.begin(), end = memBlocks.end(); it != end; ++it) {
                    const MemBlock& memBlock = *it;
                    memcpy(m_buffer + memBlock.start, temp + offset, memBlock.length);
                }
                
                delete [] temp;
                temp = NULL;
                memBlocks.clear();
                
                if (oldState < VboMapped)
                    unmap();
                if (oldState < VboActive)
                    deactivate();
            } else {
                if (oldState > VboInactive && m_state < VboActive)
                    activate();
                if (oldState > VboActive && m_state < VboMapped)
                    map();
            }
            
#ifdef _DEBUG_VBO
            checkBlockChain();
            checkFreeBlocks();
#endif
        }
Beispiel #7
0
	/// <summary>
	/// Get existing module or map it if absent
	/// </summary>
	/// <param name="path">Image path</param>
	/// <param name="buffer">Image data buffer</param>
	/// <param name="size">Buffer size.</param>
	/// <param name="asImage">If set to true - buffer has image memory layout</param>
	/// <param name="flags">Mapping flags</param>
	/// <returns>Module info</returns>
	const ModuleData* MMap::FindOrMapModule(
		const std::wstring& path,
		void* buffer, size_t size, bool asImage,
		eLoadFlags flags /*= NoFlags*/
		) {
		NTSTATUS status = STATUS_SUCCESS;
		std::unique_ptr<ImageContext> pImage(new ImageContext());
		pImage->FilePath = path;
		pImage->FileName = Utils::StripPath(pImage->FilePath);
		pImage->flags = flags;
		// Load and parse image
		status = buffer ? pImage->peImage.Load(buffer, size, !asImage) : pImage->peImage.Load(path, flags & NoSxS ? true : false);
		if(!NT_SUCCESS(status)) {
			BLACBONE_TRACE(L"ManualMap: Failed to load image '%ls'/0x%p. Status 0x%X", path.c_str(), buffer, status);
			pImage->peImage.Release();
			return nullptr;
		}
		// Check if already loaded
		if(auto hMod = _process.Modules().GetModule(path, LdrList, pImage->peImage.ImageType())) {
			pImage->peImage.Release();
			return hMod;
		}
		BLACBONE_TRACE(L"ManualMap: Loading new image '%ls'", path.c_str());
		// Try to map image in high (>4GB) memory range
		if(flags & MapInHighMem) {
			AllocateInHighMem(pImage->imgMem, pImage->peImage.ImageSize());
		}
		// Try to map image at it's original ASRL-aware base
		else if(flags & HideVAD) {
			ptr_t base = pImage->peImage.ImageBase();
			ptr_t isize = pImage->peImage.ImageSize();
			if(!NT_SUCCESS(Driver().EnsureLoaded())) {
				pImage->peImage.Release();
				return nullptr;
			}
			// Allocate as physical at desired base
			status = Driver().AllocateMem(_process.Id(), base, isize, MEM_COMMIT, PAGE_EXECUTE_READWRITE, true);
			// Allocate at any base
			if(!NT_SUCCESS(status)) {
				base = 0;
				size = pImage->peImage.ImageSize();
				status = Driver().AllocateMem(_process.Id(), base, isize, MEM_COMMIT, PAGE_EXECUTE_READWRITE, true);
			}
			// Store allocated region
			if(NT_SUCCESS(status)) {
				pImage->imgMem = MemBlock(&_process.Memory(), base, static_cast<size_t>(isize), PAGE_EXECUTE_READWRITE, true, true);
			}
			// Stop mapping
			else {
				//flags &= ~HideVAD;
				BLACBONE_TRACE(L"ManualMap: Failed to allocate physical memory for image, status 0x%d", status);
				pImage->peImage.Release();
				return nullptr;
			}
		}
		// Allocate normally if something went wrong
		if(pImage->imgMem == 0)
			pImage->imgMem = _process.Memory().Allocate(pImage->peImage.ImageSize(), PAGE_EXECUTE_READWRITE, pImage->peImage.ImageBase());
		BLACBONE_TRACE(L"ManualMap: Image base allocated at 0x%p", pImage->imgMem.Ptr<size_t>());
		if(!pImage->imgMem.Valid())
			return nullptr;
		// Create Activation context for SxS
		if(pImage->peImage.ManifestID() == 0)
			flags |= NoSxS;
		if(!(flags & NoSxS))
			CreateActx(pImage->peImage.ManifestFile(), pImage->peImage.ManifestID(), !pImage->peImage.NoPhysFile());
		// Core image mapping operations
		if(!CopyImage(pImage.get()) || !RelocateImage(pImage.get())) {
			pImage->peImage.Release();
			return nullptr;
		}
		auto mt = pImage->peImage.ImageType();
		auto pMod = _process.Modules().AddManualModule(pImage->FilePath, pImage->imgMem.Ptr<module_t>(), pImage->imgMem.Size(), mt);
		// Import tables
		if(!ResolveImport(pImage.get()) || (!(flags & NoDelayLoad) && !ResolveImport(pImage.get(), true))) {
			pImage->peImage.Release();
			_process.Modules().RemoveManualModule(pImage->FileName, mt);
			return nullptr;
		}
		// Apply proper memory protection for sections
		if(!(flags & HideVAD))
			ProtectImageMemory(pImage.get());
		// Make exception handling possible (C and C++)
		if(!(flags & NoExceptions)) {
			status = EnableExceptions(pImage.get());
			if(!NT_SUCCESS(status) && status != STATUS_NOT_FOUND) {
				BLACBONE_TRACE(L"ManualMap: Failed to enable exception handling for image %ls", pImage->FileName.c_str());
				pImage->peImage.Release();
				_process.Modules().RemoveManualModule(pImage->FileName, mt);
				return nullptr;
			}
		}
		// Unlink image from VAD list
		if(flags & HideVAD && !NT_SUCCESS(ConcealVad(pImage->imgMem))) {
			pImage->peImage.Release();
			_process.Modules().RemoveManualModule(pImage->FileName, mt);
			return nullptr;
		}
		// Initialize security cookie
		if(!InitializeCookie(pImage.get())) {
			pImage->peImage.Release();
			_process.Modules().RemoveManualModule(pImage->FileName, mt);
			return nullptr;
		}
		// Get entry point
		pImage->EntryPoint = pImage->peImage.EntryPoint(pImage->imgMem.Ptr<ptr_t>());
		// Create reference for native loader functions
		LdrRefFlags ldrFlags = flags & CreateLdrRef ? Ldr_All : Ldr_None;
		if(_mapCallback != nullptr) {
			auto mapData = _mapCallback(PostCallback, _userContext, _process, *pMod);
			ldrFlags = mapData.ldrFlags;
		}
		if(ldrFlags != Ldr_None) {
			_process.NativeLdr().CreateNTReference(
				pImage->imgMem.Ptr<HMODULE>(),
				pImage->peImage.ImageSize(),
				pImage->FilePath,
				static_cast<size_t>(pImage->EntryPoint),
				ldrFlags
				);
		}
		// Static TLS data
		if(!(flags & NoTLS) && !InitStaticTLS(pImage.get())) {
			pImage->peImage.Release();
			_process.Modules().RemoveManualModule(pImage->FileName, mt);
			return nullptr;
		}
		// Fill TLS callbacks
		pImage->peImage.GetTLSCallbacks(pImage->imgMem.Ptr<ptr_t>(), pImage->tlsCallbacks);
		// Unload local copy
		pImage->peImage.Release();
		// Release ownership of image memory block
		pImage->imgMem.Release();
		// Store image
		_images.emplace_back(std::move(pImage));
		return pMod;
	}