环境
msvc 2019 64位 Release
QT 5.15.1
源码
tsignal.h
#include <QMainWindow>
#include <QObject>
// 必须继承QObject才能使用信号和槽
class TsignalApp :public QMainWindow
{
public:
TsignalApp();
void slotFileNew();
Q_OBJECT
// 信号声明区
signals:
// 声明信号 mySignal()
void mySignal();
// 声明信号 mySignal(int)
void mySignal(int x);
// 声明信号 mySignalParam(int,int)
void mySignalParam(int x, int y);
// 槽声明区
public slots:
// 声明槽函数 mySlot()
void mySlot();
// 声明槽函数 mySlot(int)
void mySlot(int x);
// 声明槽函数 mySignalParam (int,int)
void mySlotParam(int x, int y);
};
tsignal.cpp
#include "tsignal.h"
#include <QMessageBox>
TsignalApp::TsignalApp()
{
// 将信号 mySignal() 与槽 mySlot() 相关联
connect(this, SIGNAL(mySignal()), SLOT(mySlot()));
// 将信号 mySignal(int) 与槽 mySlot(int) 相关联
connect(this, SIGNAL(mySignal(int)), SLOT(mySlot(int)));
// 将信号 mySignalParam(int,int) 与槽 mySlotParam(int,int) 相关联
connect(this, SIGNAL(mySignalParam(int, int)), SLOT(mySlotParam(int, int)));
}
// 定义槽函数 mySlot()
void TsignalApp::mySlot()
{
QMessageBox::about(this, "Tsignal", "This is a signal/slot sample withoutparameter.");
}
// 定义槽函数 mySlot(int)
void TsignalApp::mySlot(int x)
{
QMessageBox::about(this, "Tsignal", "This is a signal/slot sample with oneparameter.");
}
// 定义槽函数 mySlotParam(int,int)
void TsignalApp::mySlotParam(int x, int y)
{
char s[256];
sprintf(s, "x:%d y:%d", x, y);
QMessageBox::about(this, "Tsignal", s);
}
void TsignalApp::slotFileNew()
{
// 发射信号 mySignal()
emit mySignal();
// 发射信号 mySignal(int)
emit mySignal(5);
// 发射信号 mySignalParam(5,100)
emit mySignalParam(5, 100);
}
main.cpp
#include "tsignal.h"
#include <QApplication>
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
TsignalApp w;
w.slotFileNew();
return a.exec();
}
材料
用于分析的测试程序
https://wwmf.lanzout.com/iYx5G0haftbi
获取已知信息
我们使用IDA和x64dbg定位到 emit mySignal();信号发送的地方,看看我们已知的信息有哪些
void __fastcall sub_140001470(struct QObject *a1)
{
QMetaObject::activate(a1, (const struct QMetaObject *)&qword_140006100, 0, 0i64);
}
struct QObject *a1
是发送信号的对象
const struct QMetaObject qword_140006100
元数据对象
int local_signal_index
信号在信号发送类的本地索引
void **argv
传递的参数
后面我们所有的信息都是通过这几个数得到的
获取发送信号在类中的全局索引
信号全局索引(signal_index)是由元数据对象和local_signal_index得到的
元数据对象
struct { // private data
SuperData superdata; // 0x0 父类元数据对象的指针 由此可知这是一个链表结构
const QByteArrayData *stringdata;
const uint *data; //0x10 类的元数据 里面包含信号数量
typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
StaticMetacallFunction static_metacall;
const SuperData *relatedMetaObjects;
void *extradata; //reserved for future use
} d;
const uint *data
struct QMetaObjectPrivate
{
int revision;
int className;
int classInfoCount, classInfoData;
int methodCount, methodData;
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
int constructorCount, constructorData;
int flags;
int signalCount; //0x34 类的信号数量(不包含基类)
}
获取所有父类的信号数量
我们通过SuperData superdata;获取父类的元数据对象,然后通过data.signalCount获取父类的信号数量,不断重复,直到superdata值为0,说明没有父类了,把这些信号数量累积起来就可以得到所有基类的信号总数了
由上图可知,元数据对象的地址为0x0000000140021100,在内存窗口打开
由上图可知,父类的元数据对象的地址为0x00007FFF7C34EE08,在内存窗口中打开
由上图可知,由于data的偏移为0x10,故data的地址为0x00007FFF7C34EC20,在内存窗口中打开
由于 signalCount偏移为0x34 ,所以这个父类的signalCount为3
回到0x00007FFF7C34EE08
找到下一个父类的元数据对象地址 0x00007FFF7C4DD130
按照相同的办法找到signalCount 这里为4
继续找下一个父类的元数据对象地址 0x00007FFF7BDFB700
发现SuperData superdata;的值为0,说明没有父类了
这里的signalCount为3
所有父类的信号数量为3+4+3 = 10
获取本地信号索引(local_signal_index)
由上图可知,local_signal_index值为0
signal_index = local_signal_index + 所有父类的信号数量 = 10
标签:逆向,QT,mySignal,int,void,mySlot,发送,信号,父类 From: https://www.cnblogs.com/czlnb/p/16937572.html