From aa92e7c9032f2b70594b9fbde5829746bd318e9e Mon Sep 17 00:00:00 2001 From: ws <> Date: Sun, 12 Nov 2023 12:24:23 +1300 Subject: [PATCH] Add dlinfo --- metamod/AMBuilder | 1 + metamod/CMakeLists.txt | 2 + metamod/src/core/dlinfo.cpp | 115 ++++++++++++++++++++++++++++++++++++ metamod/src/core/dlinfo.h | 21 +++++++ metamod/src/core/module.h | 20 +++---- 5 files changed, 146 insertions(+), 13 deletions(-) create mode 100644 metamod/src/core/dlinfo.cpp create mode 100644 metamod/src/core/dlinfo.h diff --git a/metamod/AMBuilder b/metamod/AMBuilder index 468b028..0b3fccc 100644 --- a/metamod/AMBuilder +++ b/metamod/AMBuilder @@ -46,6 +46,7 @@ for sdk_name in MMSPlugin.sdks: 'src/autoupdater.cpp', 'src/core/schemasystem.cpp', 'src/core/whereami.cpp', + 'src/core/dlinfo.cpp' ] if sdk_name in ['dota', 'cs2']: diff --git a/metamod/CMakeLists.txt b/metamod/CMakeLists.txt index c161f3e..411e262 100644 --- a/metamod/CMakeLists.txt +++ b/metamod/CMakeLists.txt @@ -36,6 +36,8 @@ add_executable(wst src/script_or_zone_file.cpp src/script_or_zone_file.h src/core/common.h + src/core/dlinfo.cpp + src/core/dlinfo.h ) # Dummy target to integrate custom build script diff --git a/metamod/src/core/dlinfo.cpp b/metamod/src/core/dlinfo.cpp new file mode 100644 index 0000000..5b34dcc --- /dev/null +++ b/metamod/src/core/dlinfo.cpp @@ -0,0 +1,115 @@ +#include "dlinfo.h" + +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif + + +#ifdef WIN32 + +int dlinfo(HINSTANCE handle, dlinfo_t* out) +{ + // https://learn.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-moduleinfo + _MODULEINFO module_info{}; + if (!GetModuleInformation(GetCurrentProcess(), handle, &module_info, sizeof(_MODULEINFO))) + { + return 1; + } + + out->address = module_info.lpBaseOfDll; + out->size = module_info.SizeOfImage; + return 0; +} + +#else + + // https://github.com/Source2ZE/CS2Fixes/blob/db679357c84e61c979623b15b1454537c128cf56/src/utils/plat_unix.cpp +// https://github.com/alliedmodders/sourcemod/blob/master/core/logic/MemoryUtils.cpp#L502-L587 + +#define PAGE_SIZE 4096 +#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) + +int dlinfo(HINSTANCE hModule, dlinfo_t* out) +{ + struct link_map* dlmap = (struct link_map*)hModule; + Dl_info info; + Elf64_Ehdr* file; + Elf64_Phdr* phdr; + uint16_t phdrCount; + + if (!dladdr((void*)dlmap->l_addr, &info)) + { + return 1; + } + + if (!info.dli_fbase || !info.dli_fname) + { + return 2; + } + + /* This is for our insane sanity checks :o */ + uintptr_t baseAddr = reinterpret_cast(info.dli_fbase); + file = reinterpret_cast(baseAddr); + + /* Check ELF magic */ + if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) + { + return 3; + } + + /* Check ELF version */ + if (file->e_ident[EI_VERSION] != EV_CURRENT) + { + return 4; + } + + /* Check ELF endianness */ + if (file->e_ident[EI_DATA] != ELFDATA2LSB) + { + return 5; + } + + /* Check ELF architecture */ + if (file->e_ident[EI_CLASS] != ELFCLASS64 || file->e_machine != EM_X86_64) + { + return 6; + } + + /* For our purposes, this must be a dynamic library/shared object */ + if (file->e_type != ET_DYN) + { + return 7; + } + + phdrCount = file->e_phnum; + phdr = reinterpret_cast(baseAddr + file->e_phoff); + + for (uint16_t i = 0; i < phdrCount; i++) + { + Elf64_Phdr& hdr = phdr[i]; + + /* We only really care about the segment with executable code */ + if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X | PF_R)) + { + /* From glibc, elf/dl-load.c: + * c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1) + * & ~(GLRO(dl_pagesize) - 1)); + * + * In glibc, the segment file size is aligned up to the nearest page size and + * added to the virtual address of the segment. We just want the size here. + */ + out->address = (void*)(baseAddr + hdr.p_paddr); + out->size = PAGE_ALIGN_UP(hdr.p_filesz); + break; + } + } + + return 0; +} +#endif \ No newline at end of file diff --git a/metamod/src/core/dlinfo.h b/metamod/src/core/dlinfo.h new file mode 100644 index 0000000..037f752 --- /dev/null +++ b/metamod/src/core/dlinfo.h @@ -0,0 +1,21 @@ +// +// Created by RTX 3090 Gamer on 12/11/2023. +// + +#ifndef WST_DLINFO_H +#define WST_DLINFO_H + +#pragma once + +#include + +struct dlinfo_t +{ + void* address{nullptr}; + size_t size{0}; +}; + +int dlinfo(HINSTANCE module, dlinfo_t* info); + + +#endif //WST_DLINFO_H diff --git a/metamod/src/core/module.h b/metamod/src/core/module.h index 44bbf11..caf02d9 100644 --- a/metamod/src/core/module.h +++ b/metamod/src/core/module.h @@ -7,10 +7,7 @@ #include "interface.h" #include "strtools.h" #include "metamod_oslink.h" - -#ifdef _WIN32 -#include -#endif +#include "dlinfo.h" #ifdef _WIN32 @@ -44,16 +41,13 @@ class CModule if (!m_hModule) Error("Could not find %s\n", szModule); -#ifdef _WIN32 - MODULEINFO m_hModuleInfo; - GetModuleInformation(GetCurrentProcess(), m_hModule, &m_hModuleInfo, sizeof(m_hModuleInfo)); + dlinfo_t info; + int error = dlinfo(m_hModule, &info); + if (error != 0) + Error("Could not get info for %s\n", szModule); - m_base = (void *)m_hModuleInfo.lpBaseOfDll; - m_size = m_hModuleInfo.SizeOfImage; -#else - if (int e = GetModuleInformation(szModule, &m_base, &m_size)) - Error("Failed to get module info for %s, error %d\n", szModule, e); -#endif + m_base = info.address; + m_size = info.size; } void *FindSignature(const byte *pData, size_t length)