From 6612803fea90fe8a19ab141153d5819b4a30891a Mon Sep 17 00:00:00 2001 From: bright Date: Tue, 10 Aug 2021 21:36:43 +0000 Subject: [PATCH] Upload New File --- example/lp.hpp | 700 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 700 insertions(+) create mode 100644 example/lp.hpp diff --git a/example/lp.hpp b/example/lp.hpp new file mode 100644 index 0000000..adc0ed3 --- /dev/null +++ b/example/lp.hpp @@ -0,0 +1,700 @@ +/* + * Copyright 2018-2020 Justas Masiulis + * + * 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. + */ + + // documentation is available at https://github.com/JustasMasiulis/lazy_importer + +#ifndef LAZY_IMPORTER_HPP +#define LAZY_IMPORTER_HPP + +#define LI_FN(name) \ + ::li::detail::lazy_function<::li::detail::khash(#name), decltype(&name)>() + +#define LI_FN_DEF(name) ::li::detail::lazy_function<::li::detail::khash(#name), name>() + +#define LI_MODULE(name) ::li::detail::lazy_module<::li::detail::khash(name)>() + +// NOTE only std::forward is used from this header. +// If there is a need to eliminate this dependency the function itself is very small. + +#include +#include +#include + +#ifndef LAZY_IMPORTER_NO_FORCEINLINE +#if defined(_MSC_VER) +#define LAZY_IMPORTER_FORCEINLINE __forceinline +#elif defined(__GNUC__) && __GNUC__ > 3 +#define LAZY_IMPORTER_FORCEINLINE inline __attribute__((__always_inline__)) +#else +#define LAZY_IMPORTER_FORCEINLINE inline +#endif +#else +#define LAZY_IMPORTER_FORCEINLINE inline +#endif + +#ifdef LAZY_IMPORTER_CASE_INSENSITIVE +#define LAZY_IMPORTER_TOLOWER(c) (c >= 'A' && c <= 'Z' ? (c | (1 << 5)) : c) +#else +#define LAZY_IMPORTER_TOLOWER(c) (c) +#endif + +namespace li { + namespace detail { + + template + struct pair { + First first; + Second second; + }; + + namespace win { + + struct LIST_ENTRY_T { + const char* Flink; + const char* Blink; + }; + + struct UNICODE_STRING_T { + unsigned short Length; + unsigned short MaximumLength; + wchar_t* Buffer; + }; + + struct PEB_LDR_DATA_T { + unsigned long Length; + unsigned long Initialized; + const char* SsHandle; + LIST_ENTRY_T InLoadOrderModuleList; + }; + + struct PEB_T { + unsigned char Reserved1[2]; + unsigned char BeingDebugged; + unsigned char Reserved2[1]; + const char* Reserved3[2]; + PEB_LDR_DATA_T* Ldr; + }; + + struct LDR_DATA_TABLE_ENTRY_T { + LIST_ENTRY_T InLoadOrderLinks; + LIST_ENTRY_T InMemoryOrderLinks; + LIST_ENTRY_T InInitializationOrderLinks; + const char* DllBase; + const char* EntryPoint; + union { + unsigned long SizeOfImage; + const char* _dummy; + }; + UNICODE_STRING_T FullDllName; + UNICODE_STRING_T BaseDllName; + + LAZY_IMPORTER_FORCEINLINE const LDR_DATA_TABLE_ENTRY_T* + load_order_next() const noexcept + { + return reinterpret_cast( + InLoadOrderLinks.Flink); + } + }; + + struct IMAGE_DOS_HEADER { // DOS .EXE header + unsigned short e_magic; // Magic number + unsigned short e_cblp; // Bytes on last page of file + unsigned short e_cp; // Pages in file + unsigned short e_crlc; // Relocations + unsigned short e_cparhdr; // Size of header in paragraphs + unsigned short e_minalloc; // Minimum extra paragraphs needed + unsigned short e_maxalloc; // Maximum extra paragraphs needed + unsigned short e_ss; // Initial (relative) SS value + unsigned short e_sp; // Initial SP value + unsigned short e_csum; // Checksum + unsigned short e_ip; // Initial IP value + unsigned short e_cs; // Initial (relative) CS value + unsigned short e_lfarlc; // File address of relocation table + unsigned short e_ovno; // Overlay number + unsigned short e_res[4]; // Reserved words + unsigned short e_oemid; // OEM identifier (for e_oeminfo) + unsigned short e_oeminfo; // OEM information; e_oemid specific + unsigned short e_res2[10]; // Reserved words + long e_lfanew; // File address of new exe header + }; + + struct IMAGE_FILE_HEADER { + unsigned short Machine; + unsigned short NumberOfSections; + unsigned long TimeDateStamp; + unsigned long PointerToSymbolTable; + unsigned long NumberOfSymbols; + unsigned short SizeOfOptionalHeader; + unsigned short Characteristics; + }; + + struct IMAGE_EXPORT_DIRECTORY { + unsigned long Characteristics; + unsigned long TimeDateStamp; + unsigned short MajorVersion; + unsigned short MinorVersion; + unsigned long Name; + unsigned long Base; + unsigned long NumberOfFunctions; + unsigned long NumberOfNames; + unsigned long AddressOfFunctions; // RVA from base of image + unsigned long AddressOfNames; // RVA from base of image + unsigned long AddressOfNameOrdinals; // RVA from base of image + }; + + struct IMAGE_DATA_DIRECTORY { + unsigned long VirtualAddress; + unsigned long Size; + }; + + struct IMAGE_OPTIONAL_HEADER64 { + unsigned short Magic; + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + unsigned long SizeOfCode; + unsigned long SizeOfInitializedData; + unsigned long SizeOfUninitializedData; + unsigned long AddressOfEntryPoint; + unsigned long BaseOfCode; + unsigned long long ImageBase; + unsigned long SectionAlignment; + unsigned long FileAlignment; + unsigned short MajorOperatingSystemVersion; + unsigned short MinorOperatingSystemVersion; + unsigned short MajorImageVersion; + unsigned short MinorImageVersion; + unsigned short MajorSubsystemVersion; + unsigned short MinorSubsystemVersion; + unsigned long Win32VersionValue; + unsigned long SizeOfImage; + unsigned long SizeOfHeaders; + unsigned long CheckSum; + unsigned short Subsystem; + unsigned short DllCharacteristics; + unsigned long long SizeOfStackReserve; + unsigned long long SizeOfStackCommit; + unsigned long long SizeOfHeapReserve; + unsigned long long SizeOfHeapCommit; + unsigned long LoaderFlags; + unsigned long NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; + }; + + struct IMAGE_OPTIONAL_HEADER32 { + unsigned short Magic; + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + unsigned long SizeOfCode; + unsigned long SizeOfInitializedData; + unsigned long SizeOfUninitializedData; + unsigned long AddressOfEntryPoint; + unsigned long BaseOfCode; + unsigned long BaseOfData; + unsigned long ImageBase; + unsigned long SectionAlignment; + unsigned long FileAlignment; + unsigned short MajorOperatingSystemVersion; + unsigned short MinorOperatingSystemVersion; + unsigned short MajorImageVersion; + unsigned short MinorImageVersion; + unsigned short MajorSubsystemVersion; + unsigned short MinorSubsystemVersion; + unsigned long Win32VersionValue; + unsigned long SizeOfImage; + unsigned long SizeOfHeaders; + unsigned long CheckSum; + unsigned short Subsystem; + unsigned short DllCharacteristics; + unsigned long SizeOfStackReserve; + unsigned long SizeOfStackCommit; + unsigned long SizeOfHeapReserve; + unsigned long SizeOfHeapCommit; + unsigned long LoaderFlags; + unsigned long NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[16]; + }; + + struct IMAGE_NT_HEADERS { + unsigned long Signature; + IMAGE_FILE_HEADER FileHeader; +#ifdef _WIN64 + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +#else + IMAGE_OPTIONAL_HEADER32 OptionalHeader; +#endif + }; + + } // namespace win + + // hashing stuff + struct hash_t { + using value_type = unsigned long; + constexpr static value_type offset = 2166136261; + constexpr static value_type prime = 16777619; + constexpr static unsigned long long prime64 = prime; + + LAZY_IMPORTER_FORCEINLINE constexpr static value_type single(value_type value, + char c) noexcept + { + return static_cast( + (value ^ LAZY_IMPORTER_TOLOWER(c)) * + static_cast(prime)); + } + }; + + template + LAZY_IMPORTER_FORCEINLINE constexpr hash_t::value_type + khash(const CharT* str, hash_t::value_type value = hash_t::offset) noexcept + { + return (*str ? khash(str + 1, hash_t::single(value, *str)) : value); + } + + template + LAZY_IMPORTER_FORCEINLINE hash_t::value_type hash(const CharT* str) noexcept + { + hash_t::value_type value = hash_t::offset; + + for (;;) { + char c = *str++; + if (!c) + return value; + value = hash_t::single(value, c); + } + } + + LAZY_IMPORTER_FORCEINLINE hash_t::value_type hash( + const win::UNICODE_STRING_T& str) noexcept + { + auto first = str.Buffer; + const auto last = first + (str.Length / sizeof(wchar_t)); + auto value = hash_t::offset; + for (; first != last; ++first) + value = hash_t::single(value, static_cast(*first)); + + return value; + } + + LAZY_IMPORTER_FORCEINLINE pair hash_forwarded( + const char* str) noexcept + { + pair module_and_function{ + hash_t::offset, hash_t::offset + }; + + for (; *str != '.'; ++str) + module_and_function.first = hash_t::single(module_and_function.first, *str); + + ++str; + + for (; *str; ++str) + module_and_function.second = hash_t::single(module_and_function.second, *str); + + return module_and_function; + } + + + // some helper functions + LAZY_IMPORTER_FORCEINLINE const win::PEB_T* peb() noexcept + { +#if defined(_M_X64) || defined(__amd64__) + return reinterpret_cast(__readgsqword(0x60)); +#elif defined(_M_IX86) || defined(__i386__) + return reinterpret_cast(__readfsdword(0x30)); +#elif defined(_M_ARM) || defined(__arm__) + return *reinterpret_cast(_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30); +#elif defined(_M_ARM64) || defined(__aarch64__) + return *reinterpret_cast(__getReg(18) + 0x60); +#elif defined(_M_IA64) || defined(__ia64__) + return *reinterpret_cast(static_cast(_rdteb()) + 0x60); +#else +#error Unsupported platform. Open an issue and I'll probably add support. +#endif + } + + LAZY_IMPORTER_FORCEINLINE const win::PEB_LDR_DATA_T* ldr() + { + return reinterpret_cast(peb()->Ldr); + } + + LAZY_IMPORTER_FORCEINLINE const win::IMAGE_NT_HEADERS* nt_headers( + const char* base) noexcept + { + return reinterpret_cast( + base + reinterpret_cast(base)->e_lfanew); + } + + LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* image_export_dir( + const char* base) noexcept + { + return reinterpret_cast( + base + nt_headers(base)->OptionalHeader.DataDirectory->VirtualAddress); + } + + LAZY_IMPORTER_FORCEINLINE const win::LDR_DATA_TABLE_ENTRY_T* ldr_data_entry() noexcept + { + return reinterpret_cast( + ldr()->InLoadOrderModuleList.Flink); + } + + struct exports_directory { + const char* _base; + const win::IMAGE_EXPORT_DIRECTORY* _ied; + unsigned long _ied_size; + + public: + using size_type = unsigned long; + + LAZY_IMPORTER_FORCEINLINE + exports_directory(const char* base) noexcept : _base(base) + { + const auto ied_data_dir = nt_headers(base)->OptionalHeader.DataDirectory[0]; + _ied = reinterpret_cast( + base + ied_data_dir.VirtualAddress); + _ied_size = ied_data_dir.Size; + } + + LAZY_IMPORTER_FORCEINLINE explicit operator bool() const noexcept + { + return reinterpret_cast(_ied) != _base; + } + + LAZY_IMPORTER_FORCEINLINE size_type size() const noexcept + { + return _ied->NumberOfNames; + } + + LAZY_IMPORTER_FORCEINLINE const char* base() const noexcept { return _base; } + LAZY_IMPORTER_FORCEINLINE const win::IMAGE_EXPORT_DIRECTORY* ied() const noexcept + { + return _ied; + } + + LAZY_IMPORTER_FORCEINLINE const char* name(size_type index) const noexcept + { + return reinterpret_cast( + _base + reinterpret_cast( + _base + _ied->AddressOfNames)[index]); + } + + LAZY_IMPORTER_FORCEINLINE const char* address(size_type index) const noexcept + { + const auto* const rva_table = + reinterpret_cast(_base + _ied->AddressOfFunctions); + + const auto* const ord_table = reinterpret_cast( + _base + _ied->AddressOfNameOrdinals); + + return _base + rva_table[ord_table[index]]; + } + + LAZY_IMPORTER_FORCEINLINE bool is_forwarded( + const char* export_address) const noexcept + { + const auto ui_ied = reinterpret_cast(_ied); + return (export_address > ui_ied && export_address < ui_ied + _ied_size); + } + }; + + struct safe_module_enumerator { + using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T; + value_type* value; + value_type* head; + + LAZY_IMPORTER_FORCEINLINE safe_module_enumerator() noexcept + : safe_module_enumerator(ldr_data_entry()) + {} + + LAZY_IMPORTER_FORCEINLINE + safe_module_enumerator(const detail::win::LDR_DATA_TABLE_ENTRY_T* ldr) noexcept + : value(ldr->load_order_next()), head(value) + {} + + LAZY_IMPORTER_FORCEINLINE void reset() noexcept + { + value = head->load_order_next(); + } + + LAZY_IMPORTER_FORCEINLINE bool next() noexcept + { + value = value->load_order_next(); + + return value != head && value->DllBase; + } + }; + + struct unsafe_module_enumerator { + using value_type = const detail::win::LDR_DATA_TABLE_ENTRY_T*; + value_type value; + + LAZY_IMPORTER_FORCEINLINE unsafe_module_enumerator() noexcept + : value(ldr_data_entry()) + {} + + LAZY_IMPORTER_FORCEINLINE void reset() noexcept { value = ldr_data_entry(); } + + LAZY_IMPORTER_FORCEINLINE bool next() noexcept + { + value = value->load_order_next(); + return true; + } + }; + + // provides the cached functions which use Derive classes methods + template + class lazy_base { + protected: + // This function is needed because every templated function + // with different args has its own static buffer + LAZY_IMPORTER_FORCEINLINE static void*& _cache() noexcept + { + static void* value = nullptr; + return value; + } + + public: + template + LAZY_IMPORTER_FORCEINLINE static T safe() noexcept + { + return Derived::template get(); + } + + template + LAZY_IMPORTER_FORCEINLINE static T cached() noexcept + { + auto& cached = _cache(); + if (!cached) + cached = Derived::template get(); + + return (T)(cached); + } + + template + LAZY_IMPORTER_FORCEINLINE static T get_safe() noexcept + { + return cached(); + } + }; + + template + struct lazy_module : lazy_base> { + template + LAZY_IMPORTER_FORCEINLINE static T get() noexcept + { + Enum e; + do { + if (hash(e.value->BaseDllName) == Hash) + return (T)(e.value->DllBase); + } while (e.next()); + return {}; + } + + template + LAZY_IMPORTER_FORCEINLINE static T in(Ldr ldr) noexcept + { + safe_module_enumerator e((const detail::win::LDR_DATA_TABLE_ENTRY_T*)(ldr)); + do { + if (hash(e.value->BaseDllName) == Hash) + return (T)(e.value->DllBase); + } while (e.next()); + return {}; + } + + template + LAZY_IMPORTER_FORCEINLINE static T in_cached(Ldr ldr) noexcept + { + auto& cached = lazy_base>::_cache(); + if (!cached) + cached = in(ldr); + + return (T)(cached); + } + }; + + template + struct lazy_function : lazy_base, T> { + using base_type = lazy_base, T>; + + template + LAZY_IMPORTER_FORCEINLINE decltype(auto) operator()(Args&&... args) const + { +#ifndef LAZY_IMPORTER_CACHE_OPERATOR_PARENS + return get()(std::forward(args)...); +#else + return this->cached()(std::forward(args)...); +#endif + } + + template + LAZY_IMPORTER_FORCEINLINE static F get() noexcept + { + // for backwards compatability. + // Before 2.0 it was only possible to resolve forwarded exports when + // this macro was enabled +#ifdef LAZY_IMPORTER_RESOLVE_FORWARDED_EXPORTS + return forwarded(); +#else + + Enum e; + + do { +#ifdef LAZY_IMPORTER_HARDENED_MODULE_CHECKS + if (!e.value->DllBase || !e.value->FullDllName.Length) + continue; +#endif + + const exports_directory exports(e.value->DllBase); + + if (exports) { + auto export_index = exports.size(); + while (export_index--) + if (hash(exports.name(export_index)) == Hash) + return (F)(exports.address(export_index)); + } + } while (e.next()); + return {}; +#endif + } + + template + LAZY_IMPORTER_FORCEINLINE static F forwarded() noexcept + { + detail::win::UNICODE_STRING_T name; + hash_t::value_type module_hash = 0; + auto function_hash = Hash; + + Enum e; + do { + name = e.value->BaseDllName; + name.Length -= 8; // get rid of .dll extension + + if (!module_hash || hash(name) == module_hash) { + const exports_directory exports(e.value->DllBase); + + if (exports) { + auto export_index = exports.size(); + while (export_index--) + if (hash(exports.name(export_index)) == function_hash) { + const auto addr = exports.address(export_index); + + if (exports.is_forwarded(addr)) { + auto hashes = hash_forwarded( + reinterpret_cast(addr)); + + function_hash = hashes.second; + module_hash = hashes.first; + + e.reset(); + break; + } + return (F)(addr); + } + } + } + } while (e.next()); + return {}; + } + + template + LAZY_IMPORTER_FORCEINLINE static F forwarded_safe() noexcept + { + return forwarded(); + } + + template + LAZY_IMPORTER_FORCEINLINE static F forwarded_cached() noexcept + { + auto& value = base_type::_cache(); + if (!value) + value = forwarded(); + return (F)(value); + } + + template + LAZY_IMPORTER_FORCEINLINE static F forwarded_safe_cached() noexcept + { + return forwarded_cached(); + } + + template + LAZY_IMPORTER_FORCEINLINE static F in(Module m) noexcept + { + if (IsSafe && !m) + return {}; + + const exports_directory exports((const char*)(m)); + if (IsSafe && !exports) + return {}; + + for (unsigned long i{};; ++i) { + if (IsSafe && i == exports.size()) + break; + + if (hash(exports.name(i)) == Hash) + return (F)(exports.address(i)); + } + return {}; + } + + template + LAZY_IMPORTER_FORCEINLINE static F in_safe(Module m) noexcept + { + return in(m); + } + + template + LAZY_IMPORTER_FORCEINLINE static F in_cached(Module m) noexcept + { + auto& value = base_type::_cache(); + if (!value) + value = in(m); + return (F)(value); + } + + template + LAZY_IMPORTER_FORCEINLINE static F in_safe_cached(Module m) noexcept + { + return in_cached(m); + } + + template + LAZY_IMPORTER_FORCEINLINE static F nt() noexcept + { + return in(ldr_data_entry()->load_order_next()->DllBase); + } + + template + LAZY_IMPORTER_FORCEINLINE static F nt_safe() noexcept + { + return in_safe(ldr_data_entry()->load_order_next()->DllBase); + } + + template + LAZY_IMPORTER_FORCEINLINE static F nt_cached() noexcept + { + return in_cached(ldr_data_entry()->load_order_next()->DllBase); + } + + template + LAZY_IMPORTER_FORCEINLINE static F nt_safe_cached() noexcept + { + return in_safe_cached(ldr_data_entry()->load_order_next()->DllBase); + } + }; + + } +} // namespace li::detail + +#endif // include guard \ No newline at end of file