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; }
/// <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 ); }
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); }
/// <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 ); }
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 }
/// <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; }