#include "pe_parser.hpp" #include "../common/hashes.hpp" #include namespace PeParser { Peb* GetPeb() { #ifdef _WIN64 return reinterpret_cast(__readgsqword(0x60)); #else return reinterpret_cast(__readfsdword(0x30)); #endif } bool WideToLowerAscii(const PeUnicodeString& name, char* out, size_t outCap) { if (!name.Buffer || name.Length == 0 || outCap == 0) { return false; } const int wcharCount = name.Length / sizeof(WCHAR); int written = WideCharToMultiByte( CP_ACP, 0, name.Buffer, wcharCount, out, static_cast(outCap - 1), nullptr, nullptr); if (written <= 0) { return false; } out[written] = '\0'; CharLowerA(out); return true; } HMODULE GetModuleByHash(std::uint32_t moduleHash) { auto* peb = GetPeb(); if (!peb || !peb->Ldr) { return nullptr; } auto* head = &peb->Ldr->InMemoryOrderModuleList; for (auto* link = head->Flink; link != head; link = link->Flink) { auto* entry = reinterpret_cast( reinterpret_cast(link) - offsetof(LdrDataTableEntry, InMemoryOrderLinks)); if (!entry->BaseDllName.Buffer) { continue; } char narrow[MAX_PATH] = {}; if (!WideToLowerAscii(entry->BaseDllName, narrow, sizeof(narrow))) { continue; } // Match precomputed hash (api_hash constants) or runtime djb2 lowercase. if (Hashes::Djb2(narrow) == moduleHash || Hashes::Djb2Lower(narrow) == moduleHash) { return reinterpret_cast(entry->DllBase); } } return nullptr; } HMODULE GetModuleByIndex(unsigned index) { auto* peb = GetPeb(); if (!peb || !peb->Ldr) { return nullptr; } auto* head = &peb->Ldr->InMemoryOrderModuleList; unsigned i = 0; for (auto* link = head->Flink; link != head; link = link->Flink, ++i) { if (i == index) { auto* entry = reinterpret_cast( reinterpret_cast(link) - offsetof(LdrDataTableEntry, InMemoryOrderLinks)); return reinterpret_cast(entry->DllBase); } } return nullptr; } PIMAGE_NT_HEADERS GetNtHeaders(HMODULE module) { if (!module) { return nullptr; } auto* base = reinterpret_cast(module); auto* dos = reinterpret_cast(base); if (dos->e_magic != IMAGE_DOS_SIGNATURE) { return nullptr; } auto* nt = reinterpret_cast(base + dos->e_lfanew); if (nt->Signature != IMAGE_NT_SIGNATURE) { return nullptr; } return nt; } FARPROC GetExportByHash(HMODULE module, std::uint32_t exportHash) { if (!module) { return nullptr; } auto* base = reinterpret_cast(module); auto* nt = GetNtHeaders(module); if (!nt) { return nullptr; } const auto& dir = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; if (dir.VirtualAddress == 0 || dir.Size == 0) { return nullptr; } auto* exp = reinterpret_cast(base + dir.VirtualAddress); auto* names = reinterpret_cast(base + exp->AddressOfNames); auto* ords = reinterpret_cast(base + exp->AddressOfNameOrdinals); auto* funcs = reinterpret_cast(base + exp->AddressOfFunctions); for (DWORD i = 0; i < exp->NumberOfNames; ++i) { const char* exportName = reinterpret_cast(base + names[i]); if (Hashes::Djb2(exportName) != exportHash) { continue; } return reinterpret_cast(base + funcs[ords[i]]); } return nullptr; } } // namespace PeParser