/* Copyright 2017 - 2026 R. Thomas * Copyright 2017 - 2026 Quarkslab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "LIEF/runtime/windows/Module.hpp" #include "LIEF/PE/Binary.hpp" #include "LIEF/PE/Parser.hpp" #include "LIEF/PE/ParserConfig.hpp" #include "logging.hpp" #include #include #include #include #include "LIEF/utils.hpp" namespace LIEF::runtime { namespace details { // The concrete implementation of a Linux module class Module { public: virtual uint64_t imagebase() const = 0; virtual std::string name() const = 0; virtual std::string path() const = 0; virtual size_t size() const = 0; virtual std::unique_ptr clone() const = 0; virtual void* handle() const { return nullptr; } virtual ~Module() = default; }; class ModuleIt { public: virtual bool eq(const ModuleIt& other) const = 0; virtual std::unique_ptr clone() const = 0; virtual std::unique_ptr get() const = 0; virtual void increment() = 0; virtual ~ModuleIt() = default; }; class DefaultModule : public Module { public: static std::unique_ptr create(HMODULE module, HANDLE current_proc) { std::array tmp_buffer{}; std::string path; std::string name; MODULEINFO module_info; std::memset(&module_info, 0, sizeof(MODULEINFO)); if (GetModuleFileNameW(module, tmp_buffer.data(), tmp_buffer.size()) != 0) { std::u16string u16 = reinterpret_cast(tmp_buffer.data()); path = u16tou8(u16); } else { LIEF_DEBUG("Error: {}:{} ({})", __FUNCTION__, __LINE__, (int)GetLastError()); } tmp_buffer.fill(0); if (GetModuleBaseNameW(current_proc, module, tmp_buffer.data(), tmp_buffer.size()) != 0) { std::u16string u16 = reinterpret_cast(tmp_buffer.data()); name = u16tou8(u16); } else { LIEF_DEBUG("Error: {}:{} ({})", __FUNCTION__, __LINE__, (int)GetLastError()); } if (GetModuleInformation(current_proc, module, &module_info, sizeof(MODULEINFO)) == 0) { LIEF_DEBUG("Error: {}:{} ({})", __FUNCTION__, __LINE__, (int)GetLastError()); } return std::make_unique(module, std::move(name), std::move(path), module_info); } DefaultModule() = default; DefaultModule(HMODULE M, std::string name, std::string path, const MODULEINFO& info) : impl_(M), info_(info), name_(std::move(name)), path_(std::move(path)) {} DefaultModule(const DefaultModule&) = default; DefaultModule& operator=(const DefaultModule&) = default; DefaultModule(DefaultModule&&) noexcept = default; DefaultModule& operator=(DefaultModule&&) noexcept = default; std::unique_ptr clone() const override { return std::make_unique(*this); } std::string name() const override { return name_; } std::string path() const override { return path_; } uint64_t imagebase() const override { return reinterpret_cast(info_.lpBaseOfDll); } size_t size() const override { return info_.SizeOfImage; } void* handle() const override { return impl_; } private: HMODULE impl_; MODULEINFO info_; std::string name_; std::string path_; }; using default_modules_t = std::vector>; class DefaultModuleIt : public ModuleIt { public: DefaultModuleIt() = delete; DefaultModuleIt(const DefaultModuleIt&) = default; DefaultModuleIt& operator=(const DefaultModuleIt&) = default; DefaultModuleIt(DefaultModuleIt&&) = default; DefaultModuleIt& operator=(DefaultModuleIt&&) = default; DefaultModuleIt(default_modules_t& modules, size_t pos) : pos_(pos), modules_(&modules) {} DefaultModuleIt(default_modules_t& modules) : DefaultModuleIt(modules, 0) {} bool eq(const ModuleIt& other) const override { return pos_ == static_cast(other).pos_; } std::unique_ptr clone() const override { return std::make_unique(*this); } std::unique_ptr get() const override { assert(pos_ < modules_->size()); return std::make_unique((*modules_)[pos_]->clone()); } void increment() override { ++pos_; } ~DefaultModuleIt() override = default; private: size_t pos_ = 0; default_modules_t* modules_ = nullptr; }; default_modules_t& default_modules() { static default_modules_t modules; modules.clear(); HANDLE hProcess = GetCurrentProcess(); HMODULE lphModule = nullptr; DWORD size = 0; if (!EnumProcessModules(hProcess, &lphModule, sizeof(HMODULE), &size)) { LIEF_DEBUG("Error: {}:{}", __FUNCTION__, __LINE__); return modules; } assert(size % sizeof(HMODULE) == 0); std::vector hModules; hModules.resize(size / sizeof(HMODULE)); if (!EnumProcessModules(hProcess, hModules.data(), size, &size)) { LIEF_DEBUG("Error: {}:{}", __FUNCTION__, __LINE__); return modules; } modules.reserve(hModules.size()); for (size_t i = 0; i < hModules.size(); ++i) { if (auto mod = DefaultModule::create(hModules[i], hProcess)) { modules.push_back(std::move(mod)); } } return modules; } } Module::Iterator::Iterator() = default; Module::Iterator::Iterator(const Iterator& other) : impl_(other.impl_->clone()) {} Module::Iterator& Module::Iterator::operator=(const Iterator& other) { if (this != &other) { impl_ = other.impl_->clone(); cached_.reset(); } return *this; } Module::Iterator::Iterator(Iterator&&) noexcept = default; Module::Iterator& Module::Iterator::operator=(Iterator&&) noexcept = default; Module::Iterator::Iterator(std::unique_ptr impl) : impl_(std::move(impl)) {} Module::Iterator::~Iterator() = default; bool operator==(const Module::Iterator& LHS, const Module::Iterator& RHS) { return LHS.impl_->eq(*RHS.impl_); } Module::Iterator& Module::Iterator::operator++() { impl_->increment(); cached_.reset(); return *this; } void Module::Iterator::load() const { if (cached_ == nullptr) { cached_ = impl_->get(); } } const Module& Module::Iterator::operator*() const { load(); return *cached_; } const Module* Module::Iterator::operator->() const { load(); return cached_.get(); } std::unique_ptr Module::Iterator::yield() { load(); return std::move(cached_); } Module::Module(std::unique_ptr impl) : impl_(std::move(impl)) {} Module::Module(Module&&) noexcept = default; Module& Module::operator=(Module&&) noexcept = default; Module::~Module() = default; std::unique_ptr Module::clone() const { return std::make_unique(impl_->clone()); } uint64_t Module::imagebase() const { return impl_->imagebase(); } uint64_t Module::size() const { return impl_->size(); } std::string Module::name() const { return impl_->name(); } std::string Module::path() const { return impl_->path(); } namespace windows { std::unique_ptr Module::from_handle(void* H) { HANDLE hProcess = GetCurrentProcess(); auto impl = details::DefaultModule::create(reinterpret_cast(H), hProcess); return std::make_unique(std::move(impl)); } std::unique_ptr Module::parse_from_path() const { return parse_from_path(PE::ParserConfig::default_conf()); } std::unique_ptr Module::parse_from_path(const PE::ParserConfig& config) const { const std::string& path = this->path(); if (path.empty()) { LIEF_ERR("Can't parse '{}': Path is empty", name()); return nullptr; } return PE::Parser::parse(path, config); } std::unique_ptr Module::parse_from_memory() const { return Module::parse_from_memory(PE::ParserConfig::default_conf()); } std::unique_ptr Module::parse_from_memory(const PE::ParserConfig& config) const { if (imagebase() == 0) { LIEF_ERR("Can't parse {}: imagebase is null", path()); return nullptr; } LIEF_DEBUG("Trying to parse {} from memory: [{:#010x}, {:#010x}]", path(), imagebase(), imagebase() + size()); return LIEF::PE::Parser::parse_from_memory(imagebase(), config); } void* Module::handle() const { return impl_->handle(); } std::unique_ptr dlopen(const std::string& name) { // HMODULE LoadLibraryExW( // [in] LPCWSTR lpLibFileName, // HANDLE hFile, // [in] DWORD dwFlags // ); std::u16string u16name = u8tou16(name).value_or(u""); if (u16name.empty()) { return nullptr; } HMODULE M = LoadLibraryExW(reinterpret_cast(u16name.c_str()), /*hFile=*/nullptr, /*dwFlags=*/0); if (M == nullptr) { return nullptr; } return Module::from_handle(M); } std::unique_ptr find_module(const std::string& name) { std::u16string u16name = u8tou16(name).value_or(u""); if (u16name.empty()) { return nullptr; } HMODULE M = GetModuleHandleW(reinterpret_cast(u16name.c_str())); if (M == nullptr) { return nullptr; } return Module::from_handle(M); } void* Module::dlsym(const std::string& name) const { return reinterpret_cast( GetProcAddress(reinterpret_cast(handle()), name.c_str()) ); } } std::string Module::to_string() const { return fmt::format("{:#010x}: {}", imagebase(), name()); } modules_t modules() { using namespace details; default_modules_t& default_mods = details::default_modules(); auto begin = runtime::Module::Iterator(std::make_unique(default_mods)); auto end = runtime::Module::Iterator( std::make_unique(default_mods, default_mods.size()) ); return make_range(std::move(begin), std::move(end)); } }