Config file

_readsec(), hardnested(), _writeblk(), lockC(), setParameterC()
pull/33/head
wh201906 3 years ago
parent d0bc6808d0
commit 85ea3fd744

@ -78,6 +78,62 @@
}, },
"load sniff": { "load sniff": {
"cmd": "hf list mf -l <filename>" "cmd": "hf list mf -l <filename>"
},
"hardnested": {
"cmd": "hf mf hardnested <known key block> <known key type> <known key> <target key block> <target key type>",
"known key type": {
"A": "A",
"B": "B"
},
"target key type": {
"A": "A",
"B": "B"
}
},
"normal read sector": {
"cmd": "hf mf rdsc <sector> <key type> <key>",
"key type": {
"A": "A",
"B": "B"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read sector": {
"cmd": "hf mf cgetsc <sector>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"normal write block": {
"cmd": "hf mf wrbl <block> <key type> <key> <data>",
"key type": {
"A": "A",
"B": "B"
},
"failed flag": [
"isOk:00"
]
},
"Magic Card write block": {
"cmd": "hf mf csetblk <block> <data>",
"failed flag": [
"No chinese magic"
]
},
"emulator write block": {
"cmd": "hf mf eset <block> <data>"
},
"Magic Card lock": {
"cmd": "hf 14a raw ",
"sequence": [
"-pa -b7 40",
"-pa 43",
"-pa E0 00 39 F7",
"-pa E1 00 E1 EE",
"-pa 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47",
"-a 52"
]
},
"Magic Card set parameter": {
"cmd": "hf mf csetuid <uid> <atqa> <sak>"
} }
} }
} }

@ -78,6 +78,64 @@
"load sniff": { "load sniff": {
"cmd": "trace load -f <filename>", "cmd": "trace load -f <filename>",
"show cmd": "trace list --buffer -t mf" "show cmd": "trace list --buffer -t mf"
},
"hardnested": {
"cmd": "hf mf hardnested --blk <known key block> -<known key type> -k <known key> --tblk <target key block> --t<target key type>",
"known key type": {
"A": "a",
"B": "b"
},
"target key type": {
"A": "a",
"B": "b"
}
},
"normal read sector": {
"cmd": "hf mf rdsc --sec <sector> -<key type> -k <key>",
"key type": {
"A": "a",
"B": "b"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read sector": {
"cmd": "hf mf cgetsc --sec <sector>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"normal write block": {
"cmd": "hf mf wrbl --blk <block> -<key type> -k <key> -d <data>",
"key type": {
"A": "a",
"B": "b"
},
"failed flag": [
"fail",
"error"
]
},
"Magic Card write block": {
"cmd": "hf mf csetblk --blk <block> -d <data>",
"failed flag": [
"fail",
"error"
]
},
"emulator write block": {
"cmd": "hf mf esetblk --blk <block> -d <data>"
},
"Magic Card lock": {
"cmd": "hf 14a raw ",
"sequence": [
"-ak -b 7 40",
"-ak 43",
"-ak E0 00 39 F7",
"-ak E1 00 E1 EE",
"-ak 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47",
"-a 52"
]
},
"Magic Card set parameter": {
"cmd": "hf mf csetuid --uid <uid> --atqa <atqa> --sak <sak>"
} }
} }
} }

@ -1,4 +1,5 @@
#include "mifare.h" #include "mifare.h"
#include <QJsonArray>
const Mifare::CardType Mifare::card_mini = const Mifare::CardType Mifare::card_mini =
{ {
@ -246,7 +247,8 @@ void Mifare::nested(bool isStaticNested)
void Mifare::hardnested() void Mifare::hardnested()
{ {
MF_Attack_hardnestedDialog dialog(cardType.block_size); QVariantMap config = configMap["hardnested"].toMap();
MF_Attack_hardnestedDialog dialog(cardType.block_size, config);
connect(&dialog, &MF_Attack_hardnestedDialog::sendCMD, util, &Util::execCMD); connect(&dialog, &MF_Attack_hardnestedDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted) if(dialog.exec() == QDialog::Accepted)
Util::gotoRawTab(); Util::gotoRawTab();
@ -363,6 +365,7 @@ QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, Targe
QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key, TargetType targetType, int waitTime) QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key, TargetType targetType, int waitTime)
{ {
QVariantMap config;
QStringList data; QStringList data;
QString result, tmp; QString result, tmp;
QRegularExpressionMatch reMatch; QRegularExpressionMatch reMatch;
@ -373,83 +376,81 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
data.append(""); data.append("");
} }
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN) // try to read all blocks together
if(targetType == TARGET_MIFARE)
{ {
// try to read all blocks together if(!data_isKeyValid(key))
if(targetType == TARGET_MIFARE)
{
if(!data_isKeyValid(key))
{
return data;
}
result = util->execCMDWithOutput(
"hf mf rdsc "
+ QString::number(sectorId)
+ " "
+ (char)keyType
+ " "
+ key,
waitTime);
}
else if(targetType == TARGET_UID)
{
result = util->execCMDWithOutput(
"hf mf cgetsc "
+ QString::number(sectorId),
waitTime);
}
else if(targetType == TARGET_EMULATOR)
{ {
for(int i = 0; i < cardType.blk[sectorId]; i++)
data[i] = _readblk(cardType.blks[sectorId] + i, keyType, key, targetType, waitTime);
return data; return data;
} }
config = configMap["normal read sector"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<sector>", QString::number(sectorId));
cmd.replace("<key type>", config["key type"].toMap()[QString((char)keyType)].toString());
cmd.replace("<key>", key);
result = util->execCMDWithOutput(cmd, waitTime);
}
else if(targetType == TARGET_UID)
{
config = configMap["Magic Card read sector"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<sector>", QString::number(sectorId));
result = util->execCMDWithOutput(cmd, waitTime);
}
else if(targetType == TARGET_EMULATOR)
{
for(int i = 0; i < cardType.blk[sectorId]; i++)
data[i] = _readblk(cardType.blks[sectorId] + i, keyType, key, targetType, waitTime);
return data;
}
// for TARGET_MIFARE and TARGET_UID // for TARGET_MIFARE and TARGET_UID
reMatch = dataPattern->match(result); // if targetType == TARGET_EMULATOR, this function has returned
offset = reMatch.capturedStart(); QRegularExpression dataPattern = QRegularExpression(config["data pattern"].toString());
if(reMatch.hasMatch()) // read successful reMatch = dataPattern.match(result);
offset = reMatch.capturedStart();
if(reMatch.hasMatch()) // read successful
{
for(int i = 0; i < cardType.blk[sectorId]; i++)
{ {
for(int i = 0; i < cardType.blk[sectorId]; i++) reMatch = dataPattern.match(result, offset);
offset = reMatch.capturedStart();
if(reMatch.hasMatch())
{ {
reMatch = dataPattern->match(result, offset); tmp = reMatch.captured().toUpper();
offset = reMatch.capturedStart(); offset += tmp.length();
if(reMatch.hasMatch()) tmp.remove(" ");
{ data[i] = tmp;
tmp = reMatch.captured().toUpper();
offset += tmp.length();
tmp.remove(" ");
data[i] = tmp;
}
} }
} }
// when one of the block cannot be read, the rdsc will return nothing, so you need to read the rest of blocks manually }
// the following rdbl operation is not handled there, for better speed(rdsc_A->rdsc_B->rdbl0~3) // when one of the block cannot be read, the rdsc will return nothing, so you need to read the rest of blocks manually
else if(targetType == TARGET_UID) // treat as MIFARE // the following rdbl operation is not handled there, for better speed(rdsc_A->rdsc_B->rdbl0~3)
data = _readsec(sectorId, keyType, key, TARGET_MIFARE, waitTime); else if(targetType == TARGET_UID) // treat as MIFARE
data = _readsec(sectorId, keyType, key, TARGET_MIFARE, waitTime);
//process trailer(like _readblk()) //process trailer(like _readblk())
QString trailer = data[cardType.blk[sectorId] - 1]; QString trailer = data[cardType.blk[sectorId] - 1];
if(trailer != "" && targetType == TARGET_MIFARE) if(trailer != "" && targetType == TARGET_MIFARE)
{
if(keyType == KEY_A) // in this case, the Access Bits is always accessible
{ {
if(keyType == KEY_A) // in this case, the Access Bits is always accessible trailer.replace(0, 12, key);
QList<quint8> ACBits = data_getACBits(trailer.mid(12, 8));
if(ACBits[3] == 2 || ACBits[3] == 3 || ACBits[3] == 5 || ACBits[3] == 6 || ACBits[3] == 7) // in these cases, the KeyB cannot be read by KeyA
{ {
trailer.replace(0, 12, key); trailer.replace(20, 12, "????????????");
QList<quint8> ACBits = data_getACBits(trailer.mid(12, 8));
if(ACBits[3] == 2 || ACBits[3] == 3 || ACBits[3] == 5 || ACBits[3] == 6 || ACBits[3] == 7) // in these cases, the KeyB cannot be read by KeyA
{
trailer.replace(20, 12, "????????????");
}
} }
else if(keyType == KEY_B)
{
trailer.replace(20, 12, key);;
trailer.replace(0, 12, "????????????"); // fill the keyA part with ?
}
data[cardType.blk[sectorId] - 1] = trailer;
} }
else if(keyType == KEY_B)
{
trailer.replace(20, 12, key);;
trailer.replace(0, 12, "????????????"); // fill the keyA part with ?
}
data[cardType.blk[sectorId] - 1] = trailer;
} }
return data; return data;
} }
@ -578,45 +579,57 @@ bool Mifare::_writeblk(int blockId, KeyType keyType, const QString& key, const Q
if(data_isDataValid(input) != DATA_NOSPACE) if(data_isDataValid(input) != DATA_NOSPACE)
return false; return false;
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN) if(targetType == TARGET_MIFARE)
{ {
if(targetType == TARGET_MIFARE) if(!data_isKeyValid(key))
return false;
QVariantMap config = configMap["normal write block"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<block>", QString::number(blockId));
cmd.replace("<key type>", config["key type"].toMap()[QString((char)keyType)].toString());
cmd.replace("<key>", key);
cmd.replace("<data>", input);
result = util->execCMDWithOutput(cmd, waitTime);
if(result.isEmpty())
return false;
QVariantList failedFlag = config["failed flag"].toJsonArray().toVariantList();
for(auto flag = failedFlag.begin(); flag != failedFlag.end(); flag++)
{ {
if(!data_isKeyValid(key)) if(result.contains(flag->toString()))
return false; return false;
result = util->execCMDWithOutput(
"hf mf wrbl "
+ QString::number(blockId)
+ " "
+ (char)keyType
+ " "
+ key
+ " "
+ input,
waitTime);
return (result.indexOf("isOk:01") != -1);
} }
else if(targetType == TARGET_UID) return true;
{ }
result = util->execCMDWithOutput( else if(targetType == TARGET_UID)
"hf mf csetblk " {
+ QString::number(blockId) QVariantMap config = configMap["Magic Card write block"].toMap();
+ " " QString cmd = config["cmd"].toString();
+ input, cmd.replace("<block>", QString::number(blockId));
waitTime); cmd.replace("<data>", input);
return (result.indexOf("error") == -1); // failed flag result = util->execCMDWithOutput(cmd, waitTime);
} if(result.isEmpty())
else if(targetType == TARGET_EMULATOR) return false;
QVariantList failedFlag = config["failed flag"].toJsonArray().toVariantList();
for(auto flag = failedFlag.begin(); flag != failedFlag.end(); flag++)
{ {
util->execCMD( if(result.contains(flag->toString()))
"hf mf eset " return false;
+ QString::number(blockId)
+ " "
+ input);
util->delay(5);
return true;
} }
return true;
}
else if(targetType == TARGET_EMULATOR)
{
QVariantMap config = configMap["emulator write block"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<block>", QString::number(blockId));
cmd.replace("<data>", input);
util->execCMD(cmd);
util->delay(5);
return true;
} }
return false; return false;
} }
@ -754,6 +767,7 @@ void Mifare::wipeC()
void Mifare::setParameterC() void Mifare::setParameterC()
{ {
QVariantMap config = configMap["Magic Card set parameter"].toMap();
QMap<QString, QString> result = info(true); QMap<QString, QString> result = info(true);
if(result.isEmpty()) if(result.isEmpty())
{ {
@ -762,7 +776,7 @@ void Mifare::setParameterC()
} }
else else
{ {
MF_UID_parameterDialog dialog(result["UID"].toUpper(), result["ATQA"].toUpper(), result["SAK"].toUpper()); MF_UID_parameterDialog dialog(result["UID"].toUpper(), result["ATQA"].toUpper(), result["SAK"].toUpper(), config);
connect(&dialog, &MF_UID_parameterDialog::sendCMD, util, &Util::execCMD); connect(&dialog, &MF_UID_parameterDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted) if(dialog.exec() == QDialog::Accepted)
Util::gotoRawTab(); Util::gotoRawTab();
@ -771,23 +785,13 @@ void Mifare::setParameterC()
void Mifare::lockC() void Mifare::lockC()
{ {
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL) QVariantMap config = configMap["Magic Card lock"].toMap();
{ QString cmd = config["cmd"].toString();
util->execCMD("hf 14a raw -pa -b7 40"); QVariantList list = config["sequence"].toJsonArray().toVariantList();
util->execCMD("hf 14a raw -pa 43"); for(auto item = list.begin(); item != list.end(); item++)
util->execCMD("hf 14a raw -pa E0 00 39 F7");
util->execCMD("hf 14a raw -pa E1 00 E1 EE");
util->execCMD("hf 14a raw -pa 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47");
util->execCMD("hf 14a raw -a 52");
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{ {
util->execCMD("hf 14a raw -ak -b 7 40"); qDebug() << cmd + item->toString();
util->execCMD("hf 14a raw -ak 43"); util->execCMD(cmd + item->toString());
util->execCMD("hf 14a raw -ak E0 00 39 F7");
util->execCMD("hf 14a raw -ak E1 00 E1 EE");
util->execCMD("hf 14a raw -ak 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47");
util->execCMD("hf 14a raw -a 52");
} }
} }
@ -844,11 +848,11 @@ void Mifare::data_syncWithDataWidget(bool syncAll, int block)
tmp = ""; tmp = "";
if(dataList->at(i) != "") if(dataList->at(i) != "")
{ {
tmp += dataList->at(i).mid(0, 2); tmp += dataList->at(i).midRef(0, 2);
for(int j = 1; j < 16; j++) for(int j = 1; j < 16; j++)
{ {
tmp += " "; tmp += " ";
tmp += dataList->at(i).mid(j * 2, 2); tmp += dataList->at(i).midRef(j * 2, 2);
} }
} }
ui->MF_dataWidget->item(i, 2)->setText(tmp); ui->MF_dataWidget->item(i, 2)->setText(tmp);
@ -859,11 +863,11 @@ void Mifare::data_syncWithDataWidget(bool syncAll, int block)
tmp = ""; tmp = "";
if(dataList->at(block) != "") if(dataList->at(block) != "")
{ {
tmp += dataList->at(block).mid(0, 2); tmp += dataList->at(block).midRef(0, 2);
for(int j = 1; j < 16; j++) for(int j = 1; j < 16; j++)
{ {
tmp += " "; tmp += " ";
tmp += dataList->at(block).mid(j * 2, 2); tmp += dataList->at(block).midRef(j * 2, 2);
} }
} }
ui->MF_dataWidget->item(block, 2)->setText(tmp); ui->MF_dataWidget->item(block, 2)->setText(tmp);
@ -1217,7 +1221,7 @@ void Mifare::data_key2Data()
if(dataList->at(getTrailerBlockId(i)) == "") if(dataList->at(getTrailerBlockId(i)) == "")
tmp += "FF078069"; // default control bytes tmp += "FF078069"; // default control bytes
else else
tmp += dataList->at(getTrailerBlockId(i)).mid(12, 8); tmp += dataList->at(getTrailerBlockId(i)).midRef(12, 8);
if(data_isKeyValid(keyBList->at(i))) if(data_isKeyValid(keyBList->at(i)))
tmp += keyBList->at(i); tmp += keyBList->at(i);
@ -1332,6 +1336,7 @@ QString Mifare::data_getUID()
else else
return ""; return "";
} }
quint16 Mifare::getTrailerBlockId(quint8 sectorId, qint8 cardTypeId) quint16 Mifare::getTrailerBlockId(quint8 sectorId, qint8 cardTypeId)
{ {
if(cardTypeId == 0) if(cardTypeId == 0)

@ -1,16 +1,17 @@
#include "mf_attack_hardnesteddialog.h" #include "mf_attack_hardnesteddialog.h"
#include "ui_mf_attack_hardnesteddialog.h" #include "ui_mf_attack_hardnesteddialog.h"
MF_Attack_hardnestedDialog::MF_Attack_hardnestedDialog(int blocks, QWidget *parent) : MF_Attack_hardnestedDialog::MF_Attack_hardnestedDialog(int blocks, const QVariantMap& config, QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::MF_Attack_hardnestedDialog) ui(new Ui::MF_Attack_hardnestedDialog)
{ {
ui->setupUi(this); ui->setupUi(this);
for(int i = 0; i < blocks; i++) for(int i = 0; i < blocks; i++)
{ {
ui->knownKeySectorBox->addItem(QString::number(i)); ui->knownKeyBlockBox->addItem(QString::number(i));
ui->targetKeySectorBox->addItem(QString::number(i)); ui->targetKeyBlockBox->addItem(QString::number(i));
} }
this->config = config;
} }
@ -21,26 +22,11 @@ MF_Attack_hardnestedDialog::~MF_Attack_hardnestedDialog()
void MF_Attack_hardnestedDialog::on_buttonBox_accepted() void MF_Attack_hardnestedDialog::on_buttonBox_accepted()
{ {
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL) QString cmd = config["cmd"].toString();
emit sendCMD("hf mf hardnested " cmd.replace("<known key block>", ui->knownKeyBlockBox->currentText());
+ ui->knownKeySectorBox->currentText() cmd.replace("<known key type>", config["known key type"].toMap()[ui->knownKeyTypeBox->currentText()].toString());
+ " " cmd.replace("<known key>", ui->knownKeyBox->text());
+ ui->knownKeyTypeBox->currentText() cmd.replace("<target key block>", ui->targetKeyBlockBox->currentText());
+ " " cmd.replace("<target key type>", config["target key type"].toMap()[ui->targetKeyTypeBox->currentText()].toString());
+ ui->knownKeyBox->text() emit sendCMD(cmd);
+ " "
+ ui->targetKeySectorBox->currentText()
+ " "
+ ui->targetKeyTypeBox->currentText());
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN) // same format in v4.9237
emit sendCMD("hf mf hardnested "
+ ui->knownKeySectorBox->currentText()
+ " "
+ ui->knownKeyTypeBox->currentText()
+ " "
+ ui->knownKeyBox->text()
+ " "
+ ui->targetKeySectorBox->currentText()
+ " "
+ ui->targetKeyTypeBox->currentText());
} }

@ -14,12 +14,13 @@ class MF_Attack_hardnestedDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit MF_Attack_hardnestedDialog(int blocks, QWidget *parent = nullptr); explicit MF_Attack_hardnestedDialog(int blocks, const QVariantMap& config, QWidget *parent = nullptr);
~MF_Attack_hardnestedDialog(); ~MF_Attack_hardnestedDialog();
private: private:
Ui::MF_Attack_hardnestedDialog *ui; Ui::MF_Attack_hardnestedDialog *ui;
QVariantMap config;
signals: signals:
void sendCMD(const QString& cmd); void sendCMD(const QString& cmd);
private slots: private slots:

@ -31,7 +31,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QComboBox" name="knownKeySectorBox"> <widget class="QComboBox" name="knownKeyBlockBox">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>60</width> <width>60</width>
@ -106,7 +106,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QComboBox" name="targetKeySectorBox"> <widget class="QComboBox" name="targetKeyBlockBox">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>60</width> <width>60</width>

@ -1,7 +1,7 @@
#include "mf_uid_parameterdialog.h" #include "mf_uid_parameterdialog.h"
#include "ui_mf_uid_parameterdialog.h" #include "ui_mf_uid_parameterdialog.h"
MF_UID_parameterDialog::MF_UID_parameterDialog(const QString& uid, const QString& atqa, const QString& sak, QWidget *parent) : MF_UID_parameterDialog::MF_UID_parameterDialog(const QString& uid, const QString& atqa, const QString& sak, const QVariantMap& config, QWidget *parent) :
QDialog(parent), QDialog(parent),
ui(new Ui::MF_UID_parameterDialog) ui(new Ui::MF_UID_parameterDialog)
{ {
@ -9,6 +9,7 @@ MF_UID_parameterDialog::MF_UID_parameterDialog(const QString& uid, const QString
ui->UIDLineEdit->setText(uid); ui->UIDLineEdit->setText(uid);
ui->ATQALineEdit->setText(atqa); ui->ATQALineEdit->setText(atqa);
ui->SAKLineEdit->setText(sak); ui->SAKLineEdit->setText(sak);
this->config = config;
} }
MF_UID_parameterDialog::~MF_UID_parameterDialog() MF_UID_parameterDialog::~MF_UID_parameterDialog()
@ -18,18 +19,9 @@ MF_UID_parameterDialog::~MF_UID_parameterDialog()
void MF_UID_parameterDialog::on_buttonBox_accepted() void MF_UID_parameterDialog::on_buttonBox_accepted()
{ {
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL) QString cmd = config["cmd"].toString();
emit sendCMD("hf mf csetuid " cmd.replace("<uid>", ui->UIDLineEdit->text());
+ ui->UIDLineEdit->text() cmd.replace("<atqa>", ui->ATQALineEdit->text());
+ " " cmd.replace("<sak>", ui->SAKLineEdit->text());
+ ui->ATQALineEdit->text() emit sendCMD(cmd);
+ " "
+ ui->SAKLineEdit->text());
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN) // same format in v4.9237
emit sendCMD("hf mf csetuid "
+ ui->UIDLineEdit->text()
+ " "
+ ui->ATQALineEdit->text()
+ " "
+ ui->SAKLineEdit->text());
} }

@ -14,11 +14,12 @@ class MF_UID_parameterDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit MF_UID_parameterDialog(const QString& uid, const QString& atqa, const QString& sak, QWidget *parent = nullptr); explicit MF_UID_parameterDialog(const QString& uid, const QString& atqa, const QString& sak, const QVariantMap& config, QWidget *parent = nullptr);
~MF_UID_parameterDialog(); ~MF_UID_parameterDialog();
private: private:
Ui::MF_UID_parameterDialog *ui; Ui::MF_UID_parameterDialog *ui;
QVariantMap config;
signals: signals:
void sendCMD(const QString& cmd); void sendCMD(const QString& cmd);
private slots: private slots:

Loading…
Cancel
Save