#include #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"