我的代码将自身注入到闭源 Qt5 应用程序中。在启动过程中,应用程序创建了一些我想要访问的全局对象。这些对象始终在
QApplication
和 QQmlApplicationEngine
之间的同一内存区域中创建(Gammaray 屏幕截图)。
条目之间的偏移量和顺序不一致,但内存位置始终相同。它们没有父级 (
QObject(0x0)
),因此没有简单的方法来访问它们。 GammaRay 通过使用 LD_PRELOAD 挂钩对象创建来获取此信息,这是不可取的。
这是我的想法:以 4 字节间隔遍历
qApp
和 QQmlApplicationEngine
之间的内存,并检查该地址是否是有效的 QObject:
auto b = qmlEngine(someQmlEntity);
auto qAppEngine = (char *) qobject_cast<QQmlApplicationEngine *>(b);
char *p = (char *) qApp;
while (p < qAppEngine) {
QObject *obj;
obj = (QObject *) (void *) p;
printf("class name %s\n", obj->metaObject()->className());
p = p + 4;
}
此代码在第一次迭代后失败,因为
(char*)qApp + 4
不是有效的 QObject
。将 obj->metaObject()
包装到 try-catch 块中也会导致应用程序崩溃。
有没有一种方法可以很好地恢复这些对象?我是不是选错了?
有一个未记录的 API 旨在允许挂钩对象创建。像这样使用它:
#include <QtCore/private/qhooks_p.h>
void addCallback(QObject* obj)
{
std::printf("Created object at %p\n", obj);
}
int main(int argc, char** argv)
{
qtHookData[QHooks::AddQObject] = reinterpret_cast<quintptr>(&addCallback);
QApplication app(argc, argv);
...
}
请注意,无法以线程安全的方式删除或更改回调,至少按照 C++ 标准的字母,但实际上,如果您只需将值设置回零以禁用挂钩,它应该可以工作。
如果您使用 CMake,请像这样链接以使挂钩的私有标头可见:
target_link_libraries(your_app Qt::CorePrivate ...)