Files
archived-Reclass/tests/test_provider_getSymbol.cpp
2026-02-10 23:06:55 +01:00

98 lines
3.3 KiB
C++

#include <QTest>
#ifdef _WIN32
#include "providers/process_provider.h"
using namespace rcx;
#endif
class TestProcessProviderSymbol : public QObject {
Q_OBJECT
private slots:
#ifdef _WIN32
void getSymbol_selfProcess() {
// Attach to our own process for testing
HANDLE self = GetCurrentProcess();
// DuplicateHandle to get a real handle we can pass
HANDLE hReal = nullptr;
DuplicateHandle(self, self, self, &hReal, 0, FALSE, DUPLICATE_SAME_ACCESS);
HMODULE hMod = nullptr;
DWORD needed = 0;
EnumProcessModulesEx(hReal, &hMod, sizeof(hMod), &needed, LIST_MODULES_ALL);
MODULEINFO mi{};
GetModuleInformation(hReal, hMod, &mi, sizeof(mi));
uint64_t base = (uint64_t)mi.lpBaseOfDll;
int regionSize = (int)mi.SizeOfImage;
// ProcessProvider takes ownership of the handle
ProcessProvider prov(hReal, base, regionSize, "self_test");
QCOMPARE(prov.kind(), QStringLiteral("Process"));
QCOMPARE(prov.name(), QStringLiteral("self_test"));
QVERIFY(prov.isValid());
QVERIFY(prov.size() > 0);
// getSymbol for our own base address should resolve to our exe name
QString sym = prov.getSymbol(base);
QVERIFY(!sym.isEmpty());
// Should contain +0x
QVERIFY(sym.contains("+0x"));
// getSymbol for a bogus address should return empty
QString bogus = prov.getSymbol(0xDEAD);
QVERIFY(bogus.isEmpty());
// Read our own PE signature as a sanity check
// (first two bytes of any PE are 'MZ')
uint16_t mz = prov.readU16(0);
QCOMPARE(mz, (uint16_t)0x5A4D); // 'MZ' in little-endian
}
void getSymbol_ntdllResolvable() {
// ntdll is loaded in every process
HANDLE self = GetCurrentProcess();
HANDLE hReal = nullptr;
DuplicateHandle(self, self, self, &hReal, 0, FALSE, DUPLICATE_SAME_ACCESS);
HMODULE mods[256];
DWORD needed = 0;
EnumProcessModulesEx(hReal, mods, sizeof(mods), &needed, LIST_MODULES_ALL);
// Find ntdll
uint64_t ntdllBase = 0;
int count = (int)(needed / sizeof(HMODULE));
for (int i = 0; i < count; ++i) {
WCHAR name[MAX_PATH];
if (GetModuleBaseNameW(hReal, mods[i], name, MAX_PATH)) {
if (QString::fromWCharArray(name).toLower() == "ntdll.dll") {
MODULEINFO mi{};
GetModuleInformation(hReal, mods[i], &mi, sizeof(mi));
ntdllBase = (uint64_t)mi.lpBaseOfDll;
break;
}
}
}
QVERIFY(ntdllBase != 0);
// Use main module as the "base" for the provider
MODULEINFO mainMi{};
GetModuleInformation(hReal, mods[0], &mainMi, sizeof(mainMi));
ProcessProvider prov(hReal, (uint64_t)mainMi.lpBaseOfDll,
(int)mainMi.SizeOfImage, "self_test");
// Resolve ntdll base -- should return "ntdll.dll+0x0"
QString sym = prov.getSymbol(ntdllBase);
QVERIFY(sym.toLower().startsWith("ntdll.dll+0x"));
}
#else
void skip() { QSKIP("ProcessProvider tests are Windows-only"); }
#endif
};
QTEST_MAIN(TestProcessProviderSymbol)
#include "test_provider_getSymbol.moc"