mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
feat: 32-bit process support, scanner rescan filtering, suppress flash on navigate
- Add pointerSize() to Provider base; WoW64/ELF detection in ProcessMemory, WinDbg, and RemoteProcessMemory plugins - Wire pointer size through NodeTree, source/XML imports, C++ generator, controller, compose, address parser, and RPC protocol header - Add is32Bit to PluginProcessInfo and ProcessInfo; show (32-bit) in picker - Scanner rescan now filters results against the current input value - Go-to-address from scanner resets change tracking to prevent false flashing
This commit is contained in:
@@ -56,8 +56,13 @@ ProcessMemoryProvider::ProcessMemoryProvider(uint32_t pid, const QString& proces
|
||||
m_writable = false;
|
||||
}
|
||||
|
||||
if (m_handle)
|
||||
if (m_handle) {
|
||||
// Detect 32-bit (WoW64) process
|
||||
BOOL isWow64 = FALSE;
|
||||
if (IsWow64Process(m_handle, &isWow64) && isWow64)
|
||||
m_pointerSize = 4;
|
||||
cacheModules();
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessMemoryProvider::read(uint64_t addr, void* buf, int len) const
|
||||
@@ -192,9 +197,20 @@ ProcessMemoryProvider::ProcessMemoryProvider(uint32_t pid, const QString& proces
|
||||
m_writable = false;
|
||||
}
|
||||
|
||||
if (m_fd >= 0)
|
||||
if (m_fd >= 0) {
|
||||
// Detect 32-bit ELF process
|
||||
QString exePath = QStringLiteral("/proc/%1/exe").arg(pid);
|
||||
QByteArray exePathUtf8 = exePath.toUtf8();
|
||||
int exeFd = ::open(exePathUtf8.constData(), O_RDONLY);
|
||||
if (exeFd >= 0) {
|
||||
unsigned char elfClass = 0;
|
||||
// ELF e_ident[EI_CLASS] is at offset 4
|
||||
if (::pread(exeFd, &elfClass, 1, 4) == 1 && elfClass == 1) // ELFCLASS32
|
||||
m_pointerSize = 4;
|
||||
::close(exeFd);
|
||||
}
|
||||
cacheModules();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool ProcessMemoryProvider::read(uint64_t addr, void* buf, int len) const
|
||||
@@ -525,6 +541,7 @@ bool ProcessMemoryPlugin::selectTarget(QWidget* parent, QString* target)
|
||||
info.name = pinfo.name;
|
||||
info.path = pinfo.path;
|
||||
info.icon = pinfo.icon;
|
||||
info.is32Bit = pinfo.is32Bit;
|
||||
processes.append(info);
|
||||
}
|
||||
|
||||
@@ -586,6 +603,11 @@ QVector<PluginProcessInfo> ProcessMemoryPlugin::enumerateProcesses()
|
||||
}
|
||||
}
|
||||
|
||||
// Detect 32-bit (WoW64) process
|
||||
BOOL isWow64 = FALSE;
|
||||
if (IsWow64Process(hProcess, &isWow64) && isWow64)
|
||||
info.is32Bit = true;
|
||||
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
|
||||
@@ -632,6 +654,16 @@ QVector<PluginProcessInfo> ProcessMemoryPlugin::enumerateProcesses()
|
||||
info.name = procName;
|
||||
info.path = resolvedPath;
|
||||
info.icon = defaultIcon;
|
||||
|
||||
// Detect 32-bit ELF process
|
||||
int exeFd = ::open(exePath.toUtf8().constData(), O_RDONLY);
|
||||
if (exeFd >= 0) {
|
||||
unsigned char elfClass = 0;
|
||||
if (::pread(exeFd, &elfClass, 1, 4) == 1 && elfClass == 1) // ELFCLASS32
|
||||
info.is32Bit = true;
|
||||
::close(exeFd);
|
||||
}
|
||||
|
||||
processes.append(info);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
|
||||
bool isLive() const override { return true; }
|
||||
uint64_t base() const override { return m_base; }
|
||||
int pointerSize() const override { return m_pointerSize; }
|
||||
QVector<rcx::MemoryRegion> enumerateRegions() const override;
|
||||
bool isReadable(uint64_t, int len) const override {
|
||||
#ifdef _WIN32
|
||||
@@ -54,6 +55,7 @@ private:
|
||||
QString m_processName;
|
||||
bool m_writable;
|
||||
uint64_t m_base;
|
||||
int m_pointerSize = 8;
|
||||
|
||||
struct ModuleInfo {
|
||||
QString name;
|
||||
|
||||
@@ -59,6 +59,10 @@ struct IpcClient {
|
||||
QMutex mutex;
|
||||
bool connected = false;
|
||||
|
||||
RcxRpcHeader* header() const {
|
||||
return mappedView ? reinterpret_cast<RcxRpcHeader*>(mappedView) : nullptr;
|
||||
}
|
||||
|
||||
~IpcClient() { disconnect(); }
|
||||
|
||||
/* ── connect / disconnect ──────────────────────────────────────── */
|
||||
@@ -285,8 +289,16 @@ RemoteProcessProvider::RemoteProcessProvider(
|
||||
, m_base(0)
|
||||
, m_ipc(std::move(ipc))
|
||||
{
|
||||
if (m_connected)
|
||||
if (m_connected) {
|
||||
cacheModules();
|
||||
// Read pointer size from payload's SHM header (0 means not set → default 8)
|
||||
auto* hdr = m_ipc ? m_ipc->header() : nullptr;
|
||||
if (hdr) {
|
||||
uint32_t ps = hdr->pointerSize;
|
||||
if (ps == 4 || ps == 8)
|
||||
m_pointerSize = (int)ps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RemoteProcessProvider::~RemoteProcessProvider() = default;
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
QString kind() const override { return QStringLiteral("RemoteProcess"); }
|
||||
bool isLive() const override { return true; }
|
||||
uint64_t base() const override { return m_base; }
|
||||
int pointerSize() const override { return m_pointerSize; }
|
||||
bool isReadable(uint64_t, int len) const override { return m_connected && len >= 0; }
|
||||
QString getSymbol(uint64_t addr) const override;
|
||||
uint64_t symbolToAddress(const QString& n) const override;
|
||||
@@ -45,6 +46,7 @@ private:
|
||||
QString m_processName;
|
||||
bool m_connected;
|
||||
uint64_t m_base;
|
||||
int m_pointerSize = 8;
|
||||
mutable std::shared_ptr<IpcClient> m_ipc;
|
||||
QVector<ModuleInfo> m_modules;
|
||||
};
|
||||
|
||||
@@ -66,7 +66,8 @@ struct RcxRpcModuleEntry {
|
||||
* 32 responseCount (4)
|
||||
* 36 totalDataUsed (4)
|
||||
* 40 imageBase (8) -- main module base from PEB / procfs
|
||||
* 48 _pad[4048]
|
||||
* 48 pointerSize (4) -- 4 for 32-bit, 8 for 64-bit payload
|
||||
* 52 _pad[4044]
|
||||
*/
|
||||
struct RcxRpcHeader {
|
||||
uint32_t version;
|
||||
@@ -79,7 +80,8 @@ struct RcxRpcHeader {
|
||||
uint32_t responseCount;
|
||||
uint32_t totalDataUsed;
|
||||
uint64_t imageBase; /* main module base (PEB on Win, /proc on Linux) */
|
||||
uint8_t _pad[RCX_RPC_HEADER_SIZE - 48];
|
||||
uint32_t pointerSize; /* 4 for 32-bit, 8 for 64-bit payload */
|
||||
uint8_t _pad[RCX_RPC_HEADER_SIZE - 52];
|
||||
};
|
||||
|
||||
/* ── name formatting helpers (PID-only, no nonce) ─────────────────── */
|
||||
|
||||
@@ -201,6 +201,19 @@ void WinDbgMemoryProvider::querySessionInfo()
|
||||
}
|
||||
}
|
||||
|
||||
// Query effective processor type for pointer size detection
|
||||
if (m_control) {
|
||||
ULONG procType = 0;
|
||||
hr = m_control->GetEffectiveProcessorType(&procType);
|
||||
if (SUCCEEDED(hr)) {
|
||||
// IMAGE_FILE_MACHINE_I386 = 0x014C
|
||||
if (procType == 0x014C)
|
||||
m_pointerSize = 4;
|
||||
qDebug() << "[WinDbg] EffectiveProcessorType=" << Qt::hex << procType
|
||||
<< "pointerSize=" << m_pointerSize;
|
||||
}
|
||||
}
|
||||
|
||||
// WinDbg provides access to the entire virtual address space.
|
||||
// Do NOT auto-select a module as base — let the user set their
|
||||
// own base address. m_base stays 0 so the controller won't
|
||||
|
||||
@@ -64,6 +64,7 @@ public:
|
||||
|
||||
bool isLive() const override { return m_isLive; }
|
||||
uint64_t base() const override { return m_base; }
|
||||
int pointerSize() const override { return m_pointerSize; }
|
||||
|
||||
private:
|
||||
void initInterfaces(); // get IDebugDataSpaces/Control/Symbols from client
|
||||
@@ -85,6 +86,7 @@ private:
|
||||
uint64_t m_base = 0;
|
||||
bool m_isLive = false;
|
||||
bool m_writable = false;
|
||||
int m_pointerSize = 8;
|
||||
bool m_isRemote = false; // true when connected via DebugConnect (tcp/npipe)
|
||||
mutable int m_readFailCount = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user