/// <summary> /// Return existing or load missing dependency /// </summary> /// <param name="pImage">Currently napped image data</param> /// <param name="path">Dependency path</param> /// <returns></returns> const ModuleData* MMap::FindOrMapDependency( ImageContext* pImage, std::wstring& path ) { // For win32 one exception handler is enough // For amd64 each image must have it's own handler to resolve C++ exceptions properly #ifdef _M_AMD64 eLoadFlags newFlags = static_cast<eLoadFlags>(pImage->flags | NoSxS | NoDelayLoad); #else eLoadFlags newFlags = static_cast<eLoadFlags>(pImage->flags | NoSxS | NoDelayLoad | PartialExcept); #endif // Already loaded auto hMod = _process.modules().GetModule( path, LdrList, pImage->PEImage.mType(), pImage->FileName.c_str() ); if (hMod) return hMod; NameResolve::Instance().ResolvePath( path, pImage->FileName, Utils::GetParent( pImage->FilePath ), NameResolve::EnsureFullPath, _process.pid(), pImage->FileImage.actx() ); // Loading method if (pImage->flags & ManualImports) return FindOrMapModule( path, newFlags ); else return _process.modules().Inject( path ); };
/// <summary> /// Manually map PE image into underlying target process /// </summary> /// <param name="path">Image path</param> /// <param name="flags">Image mapping flags</param> /// <returns>Mapped image info</returns> const ModuleData* MMap::MapImage( const std::wstring& path, int flags /*= NoFlags*/ ) { // Already loaded if (auto hMod = _process.modules().GetModule( path )) return hMod; // Prepare target process if (_process.remote().CreateRPCEnvironment() != STATUS_SUCCESS) return nullptr; // No need to support exceptions if DEP is disabled if (_process.core().DEP() == false) flags |= NoExceptions; // Ignore MapInHighMem for native x64 process if (!_process.core().isWow64()) flags &= ~MapInHighMem; // Map module and all dependencies auto mod = FindOrMapModule( path, flags ); if (mod == nullptr) return nullptr; // Change process base module address if needed if (flags & RebaseProcess && !_images.empty() && _images.rbegin()->get()->PEImage.IsExe()) _process.memory().Write( _process.core().peb() + 2 * WordSize, _images.rbegin()->get()->imgMem.ptr<size_t>() ); // Run initializers for (auto& img : _images) { // Init once if (!img->initialized) { if (!RunModuleInitializers( img.get(), DLL_PROCESS_ATTACH )) return nullptr; // Wipe header if (img->flags & WipeHeader) img->imgMem.Free( img->PEImage.headersSize() ); img->initialized = true; } } return mod; }
const ModuleData* MMap::FindOrMapDependency(ImageContext* pImage, std::wstring& path) { // Already loaded auto hMod = _process.Modules().GetModule(path, LdrList, pImage->peImage.ImageType(), pImage->FileName.c_str()); if(hMod) return hMod; BLACBONE_TRACE(L"ManualMap: Loading new dependency '%ls'", path.c_str()); auto basedir = pImage->peImage.NoPhysFile() ? Utils::GetExeDirectory() : Utils::GetParent(pImage->FilePath); auto status = NameResolve::Instance().ResolvePath(path, pImage->FileName, basedir, NameResolve::EnsureFullPath, _process.Id(), pImage->peImage.ActCtx()); if(!NT_SUCCESS(status)) { BLACBONE_TRACE(L"ManualMap: Failed to resolve dependency path '%ls'", path.c_str()); return nullptr; } BLACBONE_TRACE(L"ManualMap: Dependency path resolved to '%ls'", path.c_str()); LoadData data; if(_mapCallback != nullptr) { ModuleData tmpData; tmpData.baseAddress = 0; tmpData.manual = ((pImage->flags & ManualImports) != 0); tmpData.fullPath = path; tmpData.name = Utils::StripPath(path); tmpData.size = 0; tmpData.type = mt_unknown; data = _mapCallback(PreCallback, _userContext, _process, tmpData); } // Loading method if(data.mtype == MT_Manual || (data.mtype == MT_Default && pImage->flags & ManualImports)) { return FindOrMapModule(path, nullptr, 0, false, pImage->flags | NoSxS | NoDelayLoad | PartialExcept); } else if(data.mtype != MT_None) { return _process.Modules().Inject(path); } // Aborted by user else { LastNtStatus(STATUS_REQUEST_CANCELED); return nullptr; } };
const ModuleData* MMap::MapImageInternal( const std::wstring& path, void* buffer, size_t size, bool asImage /*= false*/, eLoadFlags flags /*= NoFlags*/, MapCallback mapCallback /*= nullptr*/, void* context /*= nullptr*/ ) { // Already loaded if(auto hMod = _process.Modules().GetModule(path)) return hMod; // Prepare target process if(!NT_SUCCESS(_process.Remote().CreateRPCEnvironment())) { Cleanup(); return nullptr; } // No need to support exceptions if DEP is disabled if(_process.Core().DEP() == false) flags |= NoExceptions; // Ignore MapInHighMem for native x64 process if(!_process.Core().IsWOW64()) flags &= ~MapInHighMem; // Set native loader callback _mapCallback = mapCallback; _userContext = context; BLACBONE_TRACE(L"ManualMap: Mapping image '%ls' with flags 0x%x", path.c_str(), flags); // Map module and all dependencies auto mod = FindOrMapModule(path, buffer, size, asImage, flags); if(mod == nullptr) { Cleanup(); return nullptr; } // Change process base module address if needed if(flags & RebaseProcess && !_images.empty() && _images.rbegin()->get()->peImage.IsExecutable()) { BLACBONE_TRACE(L"ManualMap: Rebasing process to address 0x%p", static_cast<size_t>(mod->baseAddress)); // Managed path fix if(_images.rbegin()->get()->peImage.PureIL() && !path.empty()) FixManagedPath(_process.Memory().Read<size_t>(_process.Core().GetPEB() + 2 * WordSize), path); _process.Memory().Write(_process.Core().GetPEB() + 2 * WordSize, WordSize, &mod->baseAddress); } auto wipeMemory = [](Process& proc, ImageContext* img, size_t offset, size_t size) { size = Align(size, 0x1000); std::unique_ptr<uint8_t[]> zeroBuf(new uint8_t[size]()); if(img->flags & HideVAD) { Driver().WriteMem(proc.Id(), img->imgMem.Ptr() + offset, size, zeroBuf.get()); } else { img->imgMem.Write(offset, size, zeroBuf.get()); if(!NT_SUCCESS(proc.Memory().Free(img->imgMem.Ptr() + offset, size))) proc.Memory().Protect(img->imgMem.Ptr() + offset, size, PAGE_NOACCESS); } }; // Run initializers for(auto& img : _images) { // Init once if(!img->initialized) { // Hack for IL dlls if(!img->peImage.IsExecutable() && img->peImage.PureIL()) { DWORD flOld = 0; auto flg = img->imgMem.Read(img->peImage.ILFlagOffset(), 0); img->imgMem.Protect(PAGE_EXECUTE_READWRITE, img->peImage.ILFlagOffset(), sizeof(flg), &flOld); img->imgMem.Write(img->peImage.ILFlagOffset(), flg & ~COMIMAGE_FLAGS_ILONLY); img->imgMem.Protect(flOld, img->peImage.ILFlagOffset(), sizeof(flg), &flOld); } if(!RunModuleInitializers(img.get(), DLL_PROCESS_ATTACH)) return nullptr; // Wipe header if(img->flags & WipeHeader) wipeMemory(_process, img.get(), 0, img->peImage.HeadersSize()); // Wipe discardable sections for non pure IL images for(auto& sec : img->peImage.Sections()) if(sec.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) wipeMemory(_process, img.get(), sec.VirtualAddress, sec.Misc.VirtualSize); img->initialized = true; } } Cleanup(); return mod; }