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:
@@ -80,15 +80,19 @@ static const struct { int xmlType; NodeKind kind; } kTypeMap2013[] = {
|
||||
{ 30, NodeKind::Array }, // ClassPointerArray
|
||||
};
|
||||
|
||||
static NodeKind lookupKind(int xmlType, XmlVersion ver) {
|
||||
static NodeKind lookupKind(int xmlType, XmlVersion ver, int ptrSize = 8) {
|
||||
NodeKind k = NodeKind::Hex8;
|
||||
if (ver == XmlVersion::V2016) {
|
||||
for (const auto& e : kTypeMap2016)
|
||||
if (e.xmlType == xmlType) return e.kind;
|
||||
if (e.xmlType == xmlType) { k = e.kind; break; }
|
||||
} else {
|
||||
for (const auto& e : kTypeMap2013)
|
||||
if (e.xmlType == xmlType) return e.kind;
|
||||
if (e.xmlType == xmlType) { k = e.kind; break; }
|
||||
}
|
||||
return NodeKind::Hex8; // fallback
|
||||
// Remap pointer types for 32-bit targets
|
||||
if (ptrSize < 8 && k == NodeKind::Pointer64)
|
||||
k = NodeKind::Pointer32;
|
||||
return k;
|
||||
}
|
||||
|
||||
// Is this XML type a pointer-like type that uses the "Pointer" attribute?
|
||||
@@ -135,7 +139,7 @@ struct PendingRef {
|
||||
QString className;
|
||||
};
|
||||
|
||||
NodeTree importReclassXml(const QString& filePath, QString* errorMsg) {
|
||||
NodeTree importReclassXml(const QString& filePath, QString* errorMsg, int pointerSize) {
|
||||
qDebug() << "[ImportXML] Opening file:" << filePath;
|
||||
|
||||
QFile file(filePath);
|
||||
@@ -152,6 +156,7 @@ NodeTree importReclassXml(const QString& filePath, QString* errorMsg) {
|
||||
|
||||
NodeTree tree;
|
||||
tree.baseAddress = 0x00400000;
|
||||
tree.pointerSize = pointerSize;
|
||||
|
||||
// Class name → struct node ID (for pointer resolution)
|
||||
QHash<QString, uint64_t> classIds;
|
||||
@@ -249,7 +254,7 @@ NodeTree importReclassXml(const QString& filePath, QString* errorMsg) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NodeKind kind = lookupKind(xmlType, version);
|
||||
NodeKind kind = lookupKind(xmlType, version, pointerSize);
|
||||
|
||||
// Handle ClassInstanceArray: read child <Array> element
|
||||
if (isClassInstanceArrayType(xmlType, version)) {
|
||||
|
||||
@@ -5,7 +5,9 @@ namespace rcx {
|
||||
|
||||
// Import a ReClass XML file (.reclass, .MemeCls, etc.) into a NodeTree.
|
||||
// Supports ReClassEx, MemeClsEx, ReClass 2011/2013/2016 XML formats.
|
||||
// pointerSize: 4 for 32-bit targets, 8 for 64-bit (default).
|
||||
// Returns an empty NodeTree on failure; populates errorMsg if non-null.
|
||||
NodeTree importReclassXml(const QString& filePath, QString* errorMsg = nullptr);
|
||||
NodeTree importReclassXml(const QString& filePath, QString* errorMsg = nullptr,
|
||||
int pointerSize = 8);
|
||||
|
||||
} // namespace rcx
|
||||
|
||||
@@ -14,8 +14,12 @@ struct TypeInfo {
|
||||
int size; // bytes (0 = dynamic/pointer)
|
||||
};
|
||||
|
||||
static QHash<QString, TypeInfo> buildTypeTable() {
|
||||
static QHash<QString, TypeInfo> buildTypeTable(int ptrSize = 8) {
|
||||
QHash<QString, TypeInfo> t;
|
||||
// Pointer/size_t kinds depend on target architecture
|
||||
NodeKind ptrKind = (ptrSize >= 8) ? NodeKind::Pointer64 : NodeKind::Pointer32;
|
||||
NodeKind uintpKind = (ptrSize >= 8) ? NodeKind::UInt64 : NodeKind::UInt32;
|
||||
NodeKind intpKind = (ptrSize >= 8) ? NodeKind::Int64 : NodeKind::Int32;
|
||||
|
||||
// stdint.h
|
||||
t[QStringLiteral("uint8_t")] = {NodeKind::UInt8, 1};
|
||||
@@ -85,35 +89,35 @@ static QHash<QString, TypeInfo> buildTypeTable() {
|
||||
t[QStringLiteral("LONG64")] = {NodeKind::Int64, 8};
|
||||
t[QStringLiteral("INT64")] = {NodeKind::Int64, 8};
|
||||
|
||||
// Platform pointer-size types
|
||||
t[QStringLiteral("PVOID")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("LPVOID")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("HANDLE")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("HMODULE")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("HWND")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("HINSTANCE")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("SIZE_T")] = {NodeKind::UInt64, 8};
|
||||
t[QStringLiteral("ULONG_PTR")] = {NodeKind::UInt64, 8};
|
||||
t[QStringLiteral("UINT_PTR")] = {NodeKind::UInt64, 8};
|
||||
t[QStringLiteral("DWORD_PTR")] = {NodeKind::UInt64, 8};
|
||||
t[QStringLiteral("LONG_PTR")] = {NodeKind::Int64, 8};
|
||||
t[QStringLiteral("INT_PTR")] = {NodeKind::Int64, 8};
|
||||
t[QStringLiteral("SSIZE_T")] = {NodeKind::Int64, 8};
|
||||
t[QStringLiteral("uintptr_t")] = {NodeKind::UInt64, 8};
|
||||
t[QStringLiteral("intptr_t")] = {NodeKind::Int64, 8};
|
||||
t[QStringLiteral("size_t")] = {NodeKind::UInt64, 8};
|
||||
t[QStringLiteral("ptrdiff_t")] = {NodeKind::Int64, 8};
|
||||
t[QStringLiteral("ssize_t")] = {NodeKind::Int64, 8};
|
||||
// Platform pointer-size types (depend on target architecture)
|
||||
t[QStringLiteral("PVOID")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("LPVOID")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("HANDLE")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("HMODULE")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("HWND")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("HINSTANCE")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("SIZE_T")] = {uintpKind, ptrSize};
|
||||
t[QStringLiteral("ULONG_PTR")] = {uintpKind, ptrSize};
|
||||
t[QStringLiteral("UINT_PTR")] = {uintpKind, ptrSize};
|
||||
t[QStringLiteral("DWORD_PTR")] = {uintpKind, ptrSize};
|
||||
t[QStringLiteral("LONG_PTR")] = {intpKind, ptrSize};
|
||||
t[QStringLiteral("INT_PTR")] = {intpKind, ptrSize};
|
||||
t[QStringLiteral("SSIZE_T")] = {intpKind, ptrSize};
|
||||
t[QStringLiteral("uintptr_t")] = {uintpKind, ptrSize};
|
||||
t[QStringLiteral("intptr_t")] = {intpKind, ptrSize};
|
||||
t[QStringLiteral("size_t")] = {uintpKind, ptrSize};
|
||||
t[QStringLiteral("ptrdiff_t")] = {intpKind, ptrSize};
|
||||
t[QStringLiteral("ssize_t")] = {intpKind, ptrSize};
|
||||
|
||||
// Pointer type aliases
|
||||
t[QStringLiteral("PCHAR")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("LPSTR")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("LPCSTR")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("PCSTR")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("PWSTR")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("LPWSTR")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("LPCWSTR")]= {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("PCWSTR")] = {NodeKind::Pointer64, 8};
|
||||
t[QStringLiteral("PCHAR")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("LPSTR")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("LPCSTR")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("PCSTR")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("PWSTR")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("LPWSTR")] = {ptrKind, ptrSize};
|
||||
t[QStringLiteral("LPCWSTR")]= {ptrKind, ptrSize};
|
||||
t[QStringLiteral("PCWSTR")] = {ptrKind, ptrSize};
|
||||
|
||||
return t;
|
||||
}
|
||||
@@ -940,6 +944,7 @@ struct BuildContext {
|
||||
QVector<PendingRef>& pendingRefs;
|
||||
bool useCommentOffsets;
|
||||
QSet<QString> enumNames; // enum type names (emit as UInt32 + refId)
|
||||
int ptrSize = 8; // target pointer size (4 or 8)
|
||||
};
|
||||
|
||||
static void buildFields(BuildContext& ctx, uint64_t parentId, int baseOffset,
|
||||
@@ -1018,7 +1023,7 @@ static void buildFields(BuildContext& ctx, uint64_t parentId, int baseOffset,
|
||||
// Pointer field
|
||||
if (field.isPointer) {
|
||||
Node n;
|
||||
n.kind = NodeKind::Pointer64;
|
||||
n.kind = (ctx.ptrSize >= 8) ? NodeKind::Pointer64 : NodeKind::Pointer32;
|
||||
n.name = field.name;
|
||||
n.parentId = parentId;
|
||||
n.offset = fieldOffset;
|
||||
@@ -1032,7 +1037,7 @@ static void buildFields(BuildContext& ctx, uint64_t parentId, int baseOffset,
|
||||
ctx.pendingRefs.append({nodeId, field.pointerTarget});
|
||||
}
|
||||
|
||||
computedOffset = fieldOffset + 8;
|
||||
computedOffset = fieldOffset + ctx.ptrSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1217,7 +1222,7 @@ static bool hasAnyCommentOffset(const QVector<ParsedField>& fields) {
|
||||
|
||||
// ── NodeTree builder ──
|
||||
|
||||
NodeTree importFromSource(const QString& sourceCode, QString* errorMsg) {
|
||||
NodeTree importFromSource(const QString& sourceCode, QString* errorMsg, int pointerSize) {
|
||||
if (sourceCode.trimmed().isEmpty()) {
|
||||
if (errorMsg) *errorMsg = QStringLiteral("Empty source code");
|
||||
return {};
|
||||
@@ -1236,8 +1241,8 @@ NodeTree importFromSource(const QString& sourceCode, QString* errorMsg) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Build type table
|
||||
QHash<QString, TypeInfo> typeTable = buildTypeTable();
|
||||
// Build type table (pointer-size types depend on target architecture)
|
||||
QHash<QString, TypeInfo> typeTable = buildTypeTable(pointerSize);
|
||||
|
||||
// Register typedefs into type table
|
||||
for (auto it = parser.typedefs.begin(); it != parser.typedefs.end(); ++it) {
|
||||
@@ -1248,6 +1253,7 @@ NodeTree importFromSource(const QString& sourceCode, QString* errorMsg) {
|
||||
|
||||
NodeTree tree;
|
||||
tree.baseAddress = 0x00400000;
|
||||
tree.pointerSize = pointerSize;
|
||||
|
||||
QHash<QString, uint64_t> classIds;
|
||||
QVector<PendingRef> pendingRefs;
|
||||
@@ -1265,7 +1271,7 @@ NodeTree importFromSource(const QString& sourceCode, QString* errorMsg) {
|
||||
enumNames.insert(ps.name);
|
||||
}
|
||||
|
||||
BuildContext ctx{tree, typeTable, classIds, pendingRefs, useCommentOffsets, enumNames};
|
||||
BuildContext ctx{tree, typeTable, classIds, pendingRefs, useCommentOffsets, enumNames, pointerSize};
|
||||
|
||||
// Build nodes for each struct/enum
|
||||
for (const auto& ps : parser.structs) {
|
||||
|
||||
@@ -7,7 +7,9 @@ namespace rcx {
|
||||
// Supports two modes (auto-detected):
|
||||
// 1. With comment offsets (// 0xNN) - trusts the offset values
|
||||
// 2. Without comment offsets - computes offsets from type sizes
|
||||
// pointerSize: 4 for 32-bit targets, 8 for 64-bit (default).
|
||||
// Returns an empty NodeTree on failure; populates errorMsg if non-null.
|
||||
NodeTree importFromSource(const QString& sourceCode, QString* errorMsg = nullptr);
|
||||
NodeTree importFromSource(const QString& sourceCode, QString* errorMsg = nullptr,
|
||||
int pointerSize = 8);
|
||||
|
||||
} // namespace rcx
|
||||
|
||||
Reference in New Issue
Block a user