#pragma once #include "../Config.h" #include "../Include/Winheaders.h" #include "../Include/Macro.h" #include "../PE/PEImage.h" #include "../Process/MemBlock.h" #include "../ManualMap/Native/NtLoader.h" #include "MExcept.h" #include #include #include #include namespace blackbone { class CustomArgs_t { public: void push_back( const void* ptr, size_t size ) { append( ptr, size ); } template void push_back( const T* ptr ) { append( ptr, sizeof( T ) ); } template void push_back( const std::basic_string& str ) { append( str.data(), str.size() * sizeof( T ) ); } template void push_back( const std::vector& cVec ) { append( cVec.data(), cVec.size() * sizeof( T ) ); } template void push_back( const std::array& arr ) { append( arr.data(), arr.size() * sizeof( T ) ); } #if _MSC_VER >= 1900 template void push_back( const std::tuple& tpl ) { tuple_detail::copyTuple( tpl, _buffer ); } #endif /// /// Get raw data size /// /// inline size_t size() const { return _buffer.size(); } /// /// Get raw data /// /// Data ptr inline uint8_t* data() { return _buffer.data(); } inline const uint8_t* data() const { return _buffer.data(); } private: /// /// Append buffer from raw memory /// /// Raw pointer /// Data size void append( const void* ptr, size_t size ) { if (ptr) { const auto offset = _buffer.size(); _buffer.resize( offset + size ); memcpy( _buffer.data() + offset, ptr, size ); } } private: std::vector _buffer; }; // Loader flags enum eLoadFlags { NoFlags = 0x00, // No flags ManualImports = 0x01, // Manually map import libraries CreateLdrRef = 0x02, // Create module references for native loader WipeHeader = 0x04, // Wipe image PE headers HideVAD = 0x10, // Make image appear as PAGE_NOACESS region MapInHighMem = 0x20, // Try to map image in address space beyond 4GB limit RebaseProcess = 0x40, // If target image is an .exe file, process base address will be replaced with mapped module value NoThreads = 0x80, // Don't create new threads, use hijacking ForceRemap = 0x100, // Force remapping module even if it's already loaded NoExceptions = 0x01000, // Do not create custom exception handler PartialExcept = 0x02000, // Only create Inverted function table, without VEH NoDelayLoad = 0x04000, // Do not resolve delay import NoSxS = 0x08000, // Do not apply SxS activation context NoTLS = 0x10000, // Skip TLS initialization and don't execute TLS callbacks IsDependency = 0x20000, // Module is a dependency }; ENUM_OPS( eLoadFlags ) // Image mapping type enum MappingType { MT_Default, // Use eLoadFlags value MT_Native, // Use native loader MT_Manual, // Manually map MT_None, // Don't load }; struct LoadData { MappingType mtype = MT_Default; enum LdrRefFlags ldrFlags = static_cast(0); LoadData() = default; LoadData( MappingType mtype_, enum LdrRefFlags ldrFlags_ ) : mtype( mtype_ ) , ldrFlags( ldrFlags_ ) { } }; // Image mapping callback enum CallbackType { PreCallback, // Called before loading. Loading type is decided here PostCallback // Called after manual mapping, but before entry point invocation. Loader flags are decided here }; using MapCallback = LoadData( *)(CallbackType type, void* context, Process& process, const ModuleData& modInfo); /// /// Image data /// struct ImageContext { using vecPtr = std::vector; pe::PEImage peImage; // PE image data MemBlock imgMem; // Target image memory region NtLdrEntry ldrEntry; // Native loader module information vecPtr tlsCallbacks; // TLS callback routines ptr_t pExpTableAddr = 0; // Exception table address (amd64 only) eLoadFlags flags = NoFlags; // Image loader flags bool initialized = false; // Image entry point was called }; using ImageContextPtr = std::shared_ptr; using vecImageCtx = std::vector; /// /// Manual image mapper /// class MMap { public: BLACKBONE_API MMap( class Process& proc ); BLACKBONE_API ~MMap( void ); /// /// Manually map PE image into underlying target process /// /// Image path /// Image mapping flags /// Mapping callback. Triggers for each mapped module /// User-supplied callback context /// Mapped image info BLACKBONE_API call_result_t MapImage( const std::wstring& path, eLoadFlags flags = NoFlags, MapCallback mapCallback = nullptr, void* context = nullptr, CustomArgs_t* pCustomArgs_t = nullptr ); /// ///Manually map PE image into underlying target process /// /// Image data buffer /// Buffer size. /// If set to true - buffer has image memory layout /// Image mapping flags /// Mapping callback. Triggers for each mapped module /// User-supplied callback context /// Mapped image info BLACKBONE_API call_result_t MapImage( size_t size, void* buffer, bool asImage = false, eLoadFlags flags = NoFlags, MapCallback mapCallback = nullptr, void* context = nullptr, CustomArgs_t* pCustomArgs_t = nullptr ); /// /// Unmap all manually mapped modules /// /// Status code BLACKBONE_API NTSTATUS UnmapAllModules(); /// /// Remove any traces from remote process /// /// BLACKBONE_API void Cleanup(); /// /// Reset local data /// BLACKBONE_API inline void reset() { _images.clear(); _pAContext.Reset(); _usedBlocks.clear(); } private: /// /// Manually map PE image into underlying target process /// /// Image path /// Image data buffer /// Buffer size. /// If set to true - buffer has image memory layout /// Image mapping flags /// Mapping callback. Triggers for each mapped module /// User-supplied callback context /// Mapped image info call_result_t MapImageInternal( const std::wstring& path, void* buffer, size_t size, bool asImage = false, eLoadFlags flags = NoFlags, MapCallback ldrCallback = nullptr, void* ldrContext = nullptr, CustomArgs_t* pCustomArgs_t = nullptr ); /// /// Fix image path for pure managed mapping /// /// Image base /// New image path template void FixManagedPath( ptr_t base, const std::wstring &path ); /// /// Get existing module or map it if absent /// /// Image path /// Mapping flags /// Module info call_result_t FindOrMapModule( const std::wstring& path, void* buffer, size_t size, bool asImage, eLoadFlags flags = NoFlags ); /// /// Run module initializers(TLS and entry point). /// /// Image data /// one of the following: /// DLL_PROCESS_ATTACH /// DLL_THREAD_ATTACH /// DLL_PROCESS_DETACH /// DLL_THREAD_DETTACH /// /// DllMain result call_result_t RunModuleInitializers( ImageContextPtr pImage, DWORD dwReason, CustomArgs_t* pCustomArgs_t = nullptr ); /// /// Copies image into target process /// /// Image data /// Status code NTSTATUS CopyImage( ImageContextPtr pImage ); /// /// Adjust image memory protection /// /// image data /// Status code NTSTATUS ProtectImageMemory( ImageContextPtr pImage ); /// /// Fix relocations if image wasn't loaded at base address /// /// image data /// true on success NTSTATUS RelocateImage( ImageContextPtr pImage ); /// /// Resolves image import or delayed image import /// /// Image data /// Resolve delayed import instead /// Status code NTSTATUS ResolveImport( ImageContextPtr pImage, bool useDelayed = false ); /// /// Resolve static TLS storage /// /// image data /// Status code NTSTATUS InitStaticTLS( ImageContextPtr pImage ); /// /// Set custom exception handler to bypass SafeSEH under DEP /// /// image data /// Status code NTSTATUS EnableExceptions( ImageContextPtr pImage ); /// /// Remove custom exception handler /// /// image data /// true on success NTSTATUS DisableExceptions( ImageContextPtr pImage ); /// /// Calculate and set security cookie /// /// image data /// Status code NTSTATUS InitializeCookie( ImageContextPtr pImage ); /// /// Return existing or load missing dependency /// /// Currently mapped image data /// Dependency path /// call_result_t FindOrMapDependency( ImageContextPtr pImage, std::wstring& path ); /// /// Create activation context /// Target memory layout: /// ----------------------------- /// | hCtx | ACTCTX | file_path | /// ----------------------------- /// /// Manifest container path /// Manifest resource id /// if true - 'path' points to a valid PE file, otherwise - 'path' points to separate manifest file /// true on success NTSTATUS CreateActx( const pe::PEImage& image ); /// /// Do SxS path probing in the target process /// /// Path to probe /// Status code NTSTATUS ProbeRemoteSxS( std::wstring& path ); /// /// Hide memory VAD node /// /// Image to purge /// Status code NTSTATUS ConcealVad( const MemBlock& imageMem ); /// /// Allocates memory region beyond 4GB limit /// /// Image data /// Block size /// Status code NTSTATUS AllocateInHighMem( MemBlock& imageMem, size_t size ); /// /// Transform section characteristics into memory protection flags /// /// Section characteristics /// Memory protection value DWORD GetSectionProt( DWORD characteristics ); private: class Process& _process; // Target process manager MExcept _expMgr; // Exception handler manager vecImageCtx _images; // Mapped images MemBlock _pAContext; // SxS activation context memory address MapCallback _mapCallback = nullptr; // Loader callback for adding image into loader lists void* _userContext = nullptr; // user context for _ldrCallback std::vector> _usedBlocks; // Used memory blocks }; }