/// <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; }
void Win32DllLoader::OverrideImports(const std::string &dll) { std::wstring strdllW; g_charsetConverter.utf8ToW(CSpecialProtocol::TranslatePath(dll), strdllW, false); BYTE* image_base = (BYTE*)GetModuleHandleW(strdllW.c_str()); if (!image_base) { CLog::Log(LOGERROR, "%s - unable to GetModuleHandle for dll %s", __FUNCTION__, dll.c_str()); return; } PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)image_base; PIMAGE_NT_HEADERS nt_header = (PIMAGE_NT_HEADERS)(image_base + dos_header->e_lfanew); // e_lfanew = value at 0x3c PIMAGE_IMPORT_DESCRIPTOR imp_desc = (PIMAGE_IMPORT_DESCRIPTOR)( image_base + nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); if (!imp_desc) { CLog::Log(LOGERROR, "%s - unable to get import directory for dll %s", __FUNCTION__, dll.c_str()); return; } // loop over all imported dlls for (int i = 0; imp_desc[i].Characteristics != 0; i++) { char *dllName = (char*)(image_base + imp_desc[i].Name); // check whether this is one of our dll's. if (NeedsHooking(dllName)) { // this will do a loadlibrary on it, which should effectively make sure that it's hooked // Note that the library has obviously already been loaded by the OS (as it's implicitly linked) // so all this will do is insert our hook and make sure our DllLoaderContainer knows about it HMODULE hModule = dllLoadLibraryA(dllName); if (hModule) m_referencedDlls.push_back(hModule); } PIMAGE_THUNK_DATA orig_first_thunk = (PIMAGE_THUNK_DATA)(image_base + imp_desc[i].OriginalFirstThunk); PIMAGE_THUNK_DATA first_thunk = (PIMAGE_THUNK_DATA)(image_base + imp_desc[i].FirstThunk); // and then loop over all imported functions for (int j = 0; orig_first_thunk[j].u1.Function != 0; j++) { void *fixup = NULL; if (orig_first_thunk[j].u1.Function & 0x80000000) ResolveOrdinal(dllName, (orig_first_thunk[j].u1.Ordinal & 0x7fffffff), &fixup); else { // resolve by name PIMAGE_IMPORT_BY_NAME orig_imports_by_name = (PIMAGE_IMPORT_BY_NAME)( image_base + orig_first_thunk[j].u1.AddressOfData); ResolveImport(dllName, (char*)orig_imports_by_name->Name, &fixup); }/* if (!fixup) { // create a dummy function for tracking purposes PIMAGE_IMPORT_BY_NAME orig_imports_by_name = (PIMAGE_IMPORT_BY_NAME)( image_base + orig_first_thunk[j].u1.AddressOfData); fixup = CreateDummyFunction(dllName, (char*)orig_imports_by_name->Name); }*/ if (fixup) { // save the old function Import import; import.table = &first_thunk[j].u1.Function; import.function = first_thunk[j].u1.Function; m_overriddenImports.push_back(import); DWORD old_prot = 0; // change to protection settings so we can write to memory area VirtualProtect((PVOID)&first_thunk[j].u1.Function, 4, PAGE_EXECUTE_READWRITE, &old_prot); // patch the address of function to point to our overridden version first_thunk[j].u1.Function = (DWORD)fixup; // reset to old settings VirtualProtect((PVOID)&first_thunk[j].u1.Function, 4, old_prot, &old_prot); } } } }
/// <summary> /// Get existing module or map it if absent /// </summary> /// <param name="path">Image path</param> /// <param name="flags">Mapping flags</param> /// <returns>Module info</returns> const ModuleData* MMap::FindOrMapModule( const std::wstring& path, int flags /*= NoFlags*/ ) { std::unique_ptr<ImageContext> pImage( new ImageContext() ); pImage->FilePath = path; pImage->FileName = Utils::StripPath( pImage->FilePath ); pImage->flags = static_cast<eLoadFlags>(flags); // Load and parse image if (!pImage->FileImage.Project( path ) || !pImage->PEImage.Parse( pImage->FileImage, pImage->FileImage.isPlainData() )) return nullptr; // Check if already loaded if (auto hMod = _process.modules().GetModule( path, LdrList, pImage->PEImage.mType() )) return hMod; // Try to map image in high memory range if (flags & MapInHighMem) { if (AllocateInHighMem( pImage->imgMem, pImage->PEImage.imageSize() ) == false) pImage->imgMem = _process.memory().Allocate( pImage->PEImage.imageSize( ), PAGE_EXECUTE_READWRITE, pImage->PEImage.imageBase() ); } // Try to map image at it's original ASRL-aware base else { pImage->imgMem = _process.memory().Allocate( pImage->PEImage.imageSize(), PAGE_EXECUTE_READWRITE, pImage->PEImage.imageBase() ); } if (!pImage->imgMem.valid()) return nullptr; // Create Activation context for SxS // .exe files usually contain manifest under id of 1 // .dll files have manifest under id of 2 if (!(flags & NoSxS)) CreateActx( path, pImage->FileImage.manifestID() ); // Manual Debug tests only /*if (!(flags & NoExceptions)) { MExcept::pImageBase = pImage->image.ptr<void*>( ); MExcept::imageSize = pImage->PEImage.imageSize( ); }*/ // Core image mapping operations if (!CopyImage( pImage.get() ) || !RelocateImage( pImage.get() )) return nullptr; auto mt = pImage->PEImage.mType(); 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 ))) { _process.modules().RemoveManualModule( pImage->FileName, mt ); return nullptr; } // Apply proper memory protection for sections ProtectImageMemory( pImage.get() ); // Make exception handling possible (C and C++) if (!(flags & NoExceptions) && !EnableExceptions( pImage.get() )) { _process.modules().RemoveManualModule( pImage->FileName, mt ); return nullptr; } // Unlink image from VAD list if (flags & UnlinkVAD) UnlinkVad( pImage->imgMem ); // Initialize security cookie if (!InitializeCookie( pImage.get() )) { _process.modules().RemoveManualModule( pImage->FileName, mt ); return nullptr; } // Create reference for native loader functions if (flags & CreateLdrRef) _process.nativeLdr().CreateNTReference( pImage->imgMem.ptr<HMODULE>(), pImage->PEImage.imageSize(), pImage->FilePath ); // Static TLS data if (!(flags & NoTLS) &&! InitStaticTLS( pImage.get( ) )) { _process.modules().RemoveManualModule( pImage->FileName, mt ); return nullptr; } // Fill TLS callbacks pImage->PEImage.GetTLSCallbacks( pImage->imgMem.ptr<ptr_t>(), pImage->tlsCallbacks ); // Get entry point pImage->EntryPoint = pImage->PEImage.entryPoint( pImage->imgMem.ptr<ptr_t>() ); // Unload local copy pImage->FileImage.Release(); // Release image pImage->imgMem.Release(); // Store image _images.emplace_back( std::move( pImage ) ); return pMod; }