mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
127 lines
5.5 KiB
C++
127 lines
5.5 KiB
C++
#include "SceTypes.hpp"
|
|
#include "tests/GuestUnwindModuleInfoFixture.hpp"
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <windows.h>
|
|
#include <psapi.h>
|
|
|
|
extern "C" int APS5_VABI sceKernelGetModuleInfoForUnwind(uint64_t addr, int flags, ModuleInfoForUnwind* info);
|
|
extern "C" void* APS5_VABI dlopen_nid_postfix(const char*, int);
|
|
extern "C" void* APS5_VABI dlsym_nid_postfix(void*, const char*);
|
|
extern "C" int APS5_VABI dlclose_nid_postfix(void*);
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
static bool Throws(std::uint64_t address) {
|
|
ModuleInfoForUnwind info{};
|
|
try {
|
|
sceKernelGetModuleInfoForUnwind(address, 0, &info);
|
|
} catch (const std::runtime_error&) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
struct FixtureCopy {
|
|
void* handle;
|
|
UnwindFixture* fixture;
|
|
std::uint64_t address;
|
|
};
|
|
|
|
static std::string FixtureCopyPath() {
|
|
HMODULE linked = nullptr;
|
|
Require(GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
|
reinterpret_cast<LPCWSTR>(GetUnwindFixture()), &linked));
|
|
wchar_t original[MAX_PATH] = {};
|
|
Require(GetModuleFileNameW(linked, original, MAX_PATH) != 0);
|
|
const auto copy = std::filesystem::path(original).replace_filename("unwind_fixture_copy.dll");
|
|
std::filesystem::copy_file(original, copy, std::filesystem::copy_options::overwrite_existing);
|
|
return copy.string();
|
|
}
|
|
|
|
static FixtureCopy LoadFixtureCopy(const std::string& path) {
|
|
void* handle = dlopen_nid_postfix(path.c_str(), 2);
|
|
Require(handle != nullptr);
|
|
const auto get = reinterpret_cast<UnwindFixture* (*)()>(dlsym_nid_postfix(handle, "GetUnwindFixture_nid_no_patch"));
|
|
Require(get != nullptr);
|
|
auto* fixture = get();
|
|
return {handle, fixture, reinterpret_cast<std::uint64_t>(fixture)};
|
|
}
|
|
|
|
template <typename Edit>
|
|
static void LookupOfEditedCopy(const std::string& path, Edit edit, bool throws) {
|
|
const auto copy = LoadFixtureCopy(path);
|
|
edit(*copy.fixture);
|
|
Require(Throws(copy.address) == throws);
|
|
Require(dlclose_nid_postfix(copy.handle) == 0);
|
|
}
|
|
|
|
static void ReloadedModuleIsRead(const std::string& path) {
|
|
for (int round = 0; round < 2; ++round) {
|
|
const auto copy = LoadFixtureCopy(path);
|
|
if (round == 0) {
|
|
copy.fixture->frames.terminator = 12;
|
|
copy.fixture->frames.spare[0] = 1;
|
|
}
|
|
ModuleInfoForUnwind info{};
|
|
Require(sceKernelGetModuleInfoForUnwind(copy.address, 0, &info) == 0);
|
|
Require(info.eh_frame_size == (round == 0 ? 4 + 12 + 4 + 12 : 4 + 12));
|
|
Require(dlclose_nid_postfix(copy.handle) == 0);
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
auto* fixture = GetUnwindFixture();
|
|
Require(fixture != nullptr);
|
|
const auto address = reinterpret_cast<std::uint64_t>(fixture);
|
|
MEMORY_BASIC_INFORMATION memory{};
|
|
Require(VirtualQuery(reinterpret_cast<LPCVOID>(address), &memory, sizeof(memory)) != 0);
|
|
const auto base = reinterpret_cast<std::uint64_t>(memory.AllocationBase);
|
|
Require(base != reinterpret_cast<std::uint64_t>(GetModuleHandleW(nullptr)));
|
|
|
|
ModuleInfoForUnwind info{};
|
|
Require(sceKernelGetModuleInfoForUnwind(address, 0, &info) == 0);
|
|
Require(info.st_size == sizeof(ModuleInfoForUnwind));
|
|
Require(info.eh_frame_hdr_addr == reinterpret_cast<std::uint64_t>(&fixture->header));
|
|
Require(info.eh_frame_addr == reinterpret_cast<std::uint64_t>(&fixture->frames));
|
|
Require(info.eh_frame_size == 4 + 12);
|
|
Require(info.seg0_addr == base);
|
|
const auto* dos = reinterpret_cast<const IMAGE_DOS_HEADER*>(base);
|
|
const auto* nt = reinterpret_cast<const IMAGE_NT_HEADERS64*>(base + dos->e_lfanew);
|
|
Require(info.seg0_size == nt->OptionalHeader.SizeOfImage);
|
|
char mapped[4096] = {};
|
|
Require(GetMappedFileNameA(GetCurrentProcess(), memory.BaseAddress, mapped, sizeof(mapped) - 1) != 0);
|
|
Require(std::strncmp(info.name, mapped, sizeof(info.name) - 1) == 0);
|
|
for (const auto* inside : {static_cast<const void*>(&fixture->header), static_cast<const void*>(&fixture->frames)}) {
|
|
ModuleInfoForUnwind other{};
|
|
Require(sceKernelGetModuleInfoForUnwind(reinterpret_cast<std::uint64_t>(inside), 0, &other) == 0);
|
|
Require(std::memcmp(&other, &info, sizeof(info)) == 0);
|
|
}
|
|
for (int repeat = 0; repeat < 3; ++repeat) {
|
|
ModuleInfoForUnwind again{};
|
|
Require(sceKernelGetModuleInfoForUnwind(address, 0, &again) == 0);
|
|
Require(std::memcmp(&again, &info, sizeof(info)) == 0);
|
|
}
|
|
|
|
const auto path = FixtureCopyPath();
|
|
LookupOfEditedCopy(path, [](UnwindFixture& edited) { edited.header.version = 2; }, true);
|
|
for (const std::uint8_t encoding : {0x3b, 0x9b, 0x0f, 0xff}) {
|
|
LookupOfEditedCopy(path, [encoding](UnwindFixture& edited) { edited.header.framePointerEncoding = encoding; }, true);
|
|
}
|
|
LookupOfEditedCopy(path, [](UnwindFixture& edited) { edited.frames.cieLength = 0xffffffffu; }, true);
|
|
LookupOfEditedCopy(path, [](UnwindFixture&) {}, false);
|
|
ReloadedModuleIsRead(path);
|
|
std::filesystem::remove(path);
|
|
|
|
ModuleInfoForUnwind host{};
|
|
Require(sceKernelGetModuleInfoForUnwind(reinterpret_cast<std::uint64_t>(&GetModuleHandleW), 0, &host) == 0);
|
|
Require(host.eh_frame_hdr_addr == 0 && host.eh_frame_addr == 0 && host.eh_frame_size == 0);
|
|
ModuleInfoForUnwind hostAgain{};
|
|
Require(sceKernelGetModuleInfoForUnwind(reinterpret_cast<std::uint64_t>(&GetModuleHandleW), 0, &hostAgain) == 0);
|
|
Require(std::memcmp(&hostAgain, &host, sizeof(host)) == 0);
|
|
}
|