mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
- KernelMemory plugin: kernel-mode process/physical memory R/W via IOCTL driver - rcxdrv.sys: MmCopyMemory for reads, MDL mapping with correct cache types (MmCached for RAM, MmNonCached for MMIO only — fixes cache corruption BSOD) - Driver reconnect: ensureDriverLoaded tries device handle first, no auto stop+delete cycle. Manual unload closes handle only, service stays running. - Unified source menu: ProviderRegistry::populateSourceMenu() shared by both main window Data Source menu and RcxEditor inline picker (icons + dll names) - IProviderPlugin::populatePluginMenu() for conditional plugin actions (e.g. "Unload Kernel Driver" only when loaded) - Physical memory mode removed from selectTarget (access via context menu only) - requestOpenProviderTab sets base address from provider after template load - Address parser: vtop(), cr3(), physRead() callbacks for kernel paging expressions
141 lines
4.8 KiB
C++
141 lines
4.8 KiB
C++
#pragma once
|
|
#include <QByteArray>
|
|
#include <QString>
|
|
#include <QVector>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
|
|
namespace rcx {
|
|
|
|
struct MemoryRegion {
|
|
uint64_t base = 0;
|
|
uint64_t size = 0;
|
|
bool readable = true;
|
|
bool writable = false;
|
|
bool executable = false;
|
|
QString moduleName;
|
|
};
|
|
|
|
struct VtopResult {
|
|
uint64_t physical = 0;
|
|
uint64_t pml4e = 0, pdpte = 0, pde = 0, pte = 0;
|
|
uint8_t pageSize = 0; // 0=4KB, 1=2MB, 2=1GB
|
|
bool valid = false;
|
|
};
|
|
|
|
class Provider {
|
|
public:
|
|
virtual ~Provider() = default;
|
|
|
|
// --- Subclasses MUST implement these two ---
|
|
virtual bool read(uint64_t addr, void* buf, int len) const = 0;
|
|
virtual int size() const = 0;
|
|
|
|
// --- Optional overrides ---
|
|
virtual bool write(uint64_t addr, const void* buf, int len) {
|
|
Q_UNUSED(addr); Q_UNUSED(buf); Q_UNUSED(len);
|
|
return false;
|
|
}
|
|
virtual bool isWritable() const { return false; }
|
|
|
|
// Human-readable label for this source.
|
|
// Examples: "notepad.exe", "dump.bin", "tcp://10.0.0.1:1337"
|
|
virtual QString name() const { return {}; }
|
|
|
|
// Whether data can change externally (e.g. live process, network socket).
|
|
// Auto-refresh is only active for live providers.
|
|
virtual bool isLive() const { return false; }
|
|
|
|
// Category tag for the command row Source span.
|
|
// Examples: "File", "Process", "Socket"
|
|
virtual QString kind() const { return QStringLiteral("File"); }
|
|
|
|
// Native pointer size of the target (4 for 32-bit, 8 for 64-bit).
|
|
// Providers should override this to report the target's architecture.
|
|
virtual int pointerSize() const { return 8; }
|
|
|
|
// Initial base address discovered by the provider (e.g. main module base).
|
|
// Used by the controller to set tree.baseAddress on first attach.
|
|
// For file/buffer providers this is always 0.
|
|
virtual uint64_t base() const { return 0; }
|
|
|
|
// Resolve an absolute address to a symbol name.
|
|
// Returns empty string if no symbol is known.
|
|
// Example: "ntdll.dll+0x1A30"
|
|
// BufferProvider: "" (no symbols in flat files)
|
|
virtual QString getSymbol(uint64_t addr) const {
|
|
Q_UNUSED(addr);
|
|
return {};
|
|
}
|
|
|
|
// Resolve a module/symbol name to its address (reverse of getSymbol).
|
|
// Returns 0 if the name is not found.
|
|
virtual uint64_t symbolToAddress(const QString& name) const {
|
|
Q_UNUSED(name);
|
|
return 0;
|
|
}
|
|
|
|
// Enumerate committed/readable memory regions.
|
|
// Used by the scan engine to know what address ranges to scan.
|
|
// Default: returns empty (scan engine falls back to [0, size())).
|
|
virtual QVector<MemoryRegion> enumerateRegions() const { return {}; }
|
|
|
|
// Process Environment Block address (x64 PEB VA in target process).
|
|
// Only meaningful for live process providers. Returns 0 if unavailable.
|
|
virtual uint64_t peb() const { return 0; }
|
|
|
|
struct ThreadInfo { uint64_t tebAddress; uint32_t threadId; };
|
|
virtual QVector<ThreadInfo> tebs() const { return {}; }
|
|
|
|
// --- Kernel paging capabilities (override in kernel providers) ---
|
|
virtual bool hasKernelPaging() const { return false; }
|
|
virtual uint64_t getCr3() const { return 0; }
|
|
virtual VtopResult translateAddress(uint64_t va) const {
|
|
Q_UNUSED(va); return {};
|
|
}
|
|
virtual QVector<uint64_t> readPageTable(uint64_t physAddr,
|
|
int startIdx = 0,
|
|
int count = 512) const {
|
|
Q_UNUSED(physAddr); Q_UNUSED(startIdx); Q_UNUSED(count);
|
|
return {};
|
|
}
|
|
|
|
// --- Derived convenience (non-virtual, never override) ---
|
|
|
|
bool isValid() const { return size() > 0; }
|
|
|
|
virtual bool isReadable(uint64_t addr, int len) const {
|
|
if (len <= 0) return (len == 0);
|
|
uint64_t ulen = (uint64_t)len;
|
|
return addr <= (uint64_t)size() && ulen <= (uint64_t)size() - addr;
|
|
}
|
|
|
|
template<typename T>
|
|
T readAs(uint64_t addr) const {
|
|
T v{};
|
|
read(addr, &v, sizeof(T));
|
|
return v;
|
|
}
|
|
|
|
uint8_t readU8 (uint64_t a) const { return readAs<uint8_t>(a); }
|
|
uint16_t readU16(uint64_t a) const { return readAs<uint16_t>(a); }
|
|
uint32_t readU32(uint64_t a) const { return readAs<uint32_t>(a); }
|
|
uint64_t readU64(uint64_t a) const { return readAs<uint64_t>(a); }
|
|
float readF32(uint64_t a) const { return readAs<float>(a); }
|
|
double readF64(uint64_t a) const { return readAs<double>(a); }
|
|
|
|
QByteArray readBytes(uint64_t addr, int len) const {
|
|
if (len <= 0) return {};
|
|
QByteArray buf(len, Qt::Uninitialized);
|
|
if (!read(addr, buf.data(), len))
|
|
buf.fill('\0');
|
|
return buf;
|
|
}
|
|
|
|
bool writeBytes(uint64_t addr, const QByteArray& d) {
|
|
return write(addr, d.constData(), d.size());
|
|
}
|
|
};
|
|
|
|
} // namespace rcx
|