Support read/write data in emulator

pull/3/head
wh201906 5 years ago
parent 5f1df6782a
commit b44488fbed

@ -1,6 +1,7 @@
#include "mifare.h" #include "mifare.h"
Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent) : QObject(parent) Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent)
: QObject(parent)
{ {
this->parent = parent; this->parent = parent;
util = addr; util = addr;
@ -9,27 +10,26 @@ Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent) : QObject(parent
keyAList = new QStringList(); keyAList = new QStringList();
keyBList = new QStringList(); keyBList = new QStringList();
dataList = new QStringList(); dataList = new QStringList();
data_clearKey(); // fill with blank Qstring data_clearKey(); // fill with blank Qstring
data_clearData(); // fill with blank Qstring data_clearData(); // fill with blank Qstring
dataPattern = new QRegExp("([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"); dataPattern = new QRegExp("([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}");
chkKeyPattern = new QRegExp("\\|\\d{3}\\|.+\\|.+\\|"); chkKeyPattern = new QRegExp("\\|\\d{3}\\|.+\\|.+\\|");
nestedKeyPattern = new QRegExp("\\|\\d{3}\\|.+\\|.+\\|.+\\|.+\\|"); nestedKeyPattern = new QRegExp("\\|\\d{3}\\|.+\\|.+\\|.+\\|.+\\|");
} }
QString Mifare::info(bool isRequiringOutput) QString Mifare::info(bool isRequiringOutput)
{ {
if(isRequiringOutput) if (isRequiringOutput)
{ {
QString result = util->execCMDWithOutput("hf 14a info", 500); QString result = util->execCMDWithOutput("hf 14a info", 500);
qDebug() << result << result.indexOf(QRegExp(ui->MF_RW_dataEdit->text()), 0); qDebug() << result
<< result.indexOf(QRegExp(ui->MF_RW_dataEdit->text()), 0);
result.replace("UID :", "|"); result.replace("UID :", "|");
result.replace("ATQA :", "|"); result.replace("ATQA :", "|");
result.replace("SAK :", "|"); result.replace("SAK :", "|");
result.replace("TYPE :", "|"); result.replace("TYPE :", "|");
QStringList lis = result.split("|"); QStringList lis = result.split("|");
if(lis.length() > 4) if (lis.length() > 4)
{ {
qDebug() << lis[1] + lis[2] + lis[3]; qDebug() << lis[1] + lis[2] + lis[3];
return lis[1] + lis[2] + lis[3]; return lis[1] + lis[2] + lis[3];
@ -47,22 +47,25 @@ QString Mifare::info(bool isRequiringOutput)
void Mifare::chk() void Mifare::chk()
{ {
QString result = util->execCMDWithOutput("hf mf chk *" + QString::number(cardType.type) + " ?", 1000 + cardType.type * 1000); QString result = util->execCMDWithOutput(
"hf mf chk *" + QString::number(cardType.type) + " ?",
1000 + cardType.type * 1000);
qDebug() << result; qDebug() << result;
int offset = 0; int offset = 0;
QString tmp, tmp2; QString tmp, tmp2;
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
offset = result.indexOf(*chkKeyPattern, offset); offset = chkKeyPattern->indexIn(result, offset);
// offset = result.indexOf(*chkKeyPattern, offset);
tmp = result.mid(offset, 39).toUpper(); tmp = result.mid(offset, 39).toUpper();
offset += 39; offset += 39;
qDebug() << tmp << offset; qDebug() << tmp << offset;
tmp2 = tmp.mid(7, 12).trimmed(); tmp2 = tmp.mid(7, 12).trimmed();
if(tmp2 != "?") if (tmp2 != "?")
keyAList->replace(i, tmp2); keyAList->replace(i, tmp2);
tmp2 = tmp.mid(24, 12).trimmed(); tmp2 = tmp.mid(24, 12).trimmed();
if(tmp2 != "?") if (tmp2 != "?")
keyBList->replace(i, tmp2); keyBList->replace(i, tmp2);
} }
data_syncWithKeyWidget(); data_syncWithKeyWidget();
@ -70,18 +73,20 @@ void Mifare::chk()
void Mifare::nested() void Mifare::nested()
{ {
QString result = util->execCMDWithOutput("hf mf nested " + QString::number(cardType.type) + " *"); QString result = util->execCMDWithOutput(
"hf mf nested " + QString::number(cardType.type) + " *");
int offset = 0; int offset = 0;
QString tmp; QString tmp;
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
offset = result.indexOf(*nestedKeyPattern, offset); offset = nestedKeyPattern->indexIn(result, offset);
// offset = result.indexOf(*nestedKeyPattern, offset);
tmp = result.mid(offset, 47).toUpper(); tmp = result.mid(offset, 47).toUpper();
offset += 47; offset += 47;
if(tmp.at(23) == '1') if (tmp.at(23) == '1')
keyAList->replace(i, tmp.mid(7, 12).trimmed()); keyAList->replace(i, tmp.mid(7, 12).trimmed());
if(tmp.at(44) == '1') if (tmp.at(44) == '1')
keyBList->replace(i, tmp.mid(28, 12).trimmed()); keyBList->replace(i, tmp.mid(28, 12).trimmed());
} }
data_syncWithKeyWidget(); data_syncWithKeyWidget();
@ -91,7 +96,7 @@ void Mifare::hardnested()
{ {
MF_Attack_hardnestedDialog dialog(cardType.blocks); MF_Attack_hardnestedDialog dialog(cardType.blocks);
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)
ui->funcTab->setCurrentIndex(1); ui->funcTab->setCurrentIndex(1);
} }
@ -111,30 +116,30 @@ void Mifare::read()
{ {
int waitTime = 300; int waitTime = 300;
int currblk = ui->MF_RW_blockBox->currentText().toInt(); int currblk = ui->MF_RW_blockBox->currentText().toInt();
QString result = util->execCMDWithOutput("hf mf rdbl " QString result = util->execCMDWithOutput(
+ QString::number(currblk) "hf mf rdbl " + QString::number(currblk) + " " +
+ " " ui->MF_RW_keyTypeBox->currentText() + " " + ui->MF_RW_keyEdit->text(),
+ ui->MF_RW_keyTypeBox->currentText() waitTime);
+ " " if (result.indexOf("isOk:01") != -1)
+ ui->MF_RW_keyEdit->text(), waitTime); {
if(result.indexOf("isOk:01") != -1) result = result.mid(dataPattern->indexIn(result), 47).toUpper();
{ if ((currblk < 128 && ((currblk + 1) % 4 == 0)) ||
result = result.mid(result.indexOf(*dataPattern, 0), 47).toUpper(); ((currblk + 1) % 8 == 0)) // process key block
if((currblk < 128 && ((currblk + 1) % 4 == 0)) || ((currblk + 1) % 8 == 0)) // process key block
{ {
if(ui->MF_RW_keyTypeBox->currentText() == "A") if (ui->MF_RW_keyTypeBox->currentText() == "A")
{ {
for(int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
result = result.replace(i * 3, 2, ui->MF_RW_keyEdit->text().mid(i * 2, 2)); result =
result.replace(i * 3, 2, ui->MF_RW_keyEdit->text().mid(i * 2, 2));
} }
ui->MF_RW_dataEdit->setText(result); ui->MF_RW_dataEdit->setText(result);
QString tmpKey = result.right(18).replace(" ", ""); QString tmpKey = result.right(18).replace(" ", "");
result = util->execCMDWithOutput("hf mf rdbl " result = util->execCMDWithOutput(
+ ui->MF_RW_keyTypeBox->currentText() "hf mf rdbl " + ui->MF_RW_keyTypeBox->currentText() + " B " +
+ " B " tmpKey,
+ tmpKey, waitTime); waitTime);
if(result.indexOf("isOk:01") == -1) if (result.indexOf("isOk:01") == -1)
{ {
result = ui->MF_RW_dataEdit->text(); result = ui->MF_RW_dataEdit->text();
result = result.replace(30, 17, "?? ?? ?? ?? ?? ??"); result = result.replace(30, 17, "?? ?? ?? ?? ?? ??");
@ -143,9 +148,10 @@ void Mifare::read()
} }
else else
{ {
for(int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
result = result.replace(30 + i * 3, 2, ui->MF_RW_keyEdit->text().mid(i * 2, 2)); result = result.replace(30 + i * 3, 2,
ui->MF_RW_keyEdit->text().mid(i * 2, 2));
} }
result = result.replace(0, 18, "?? ?? ?? ?? ?? ?? "); result = result.replace(0, 18, "?? ?? ?? ?? ?? ?? ");
ui->MF_RW_dataEdit->setText(result); ui->MF_RW_dataEdit->setText(result);
@ -167,27 +173,27 @@ void Mifare::readAll()
QString tmp; QString tmp;
int offset = 0; int offset = 0;
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
result = ""; result = "";
isKeyAValid = false; isKeyAValid = false;
isKeyBValid = false; isKeyBValid = false;
// check keys and read the first block of each sector // check keys and read the first block of each sector
if(data_isKeyValid(keyAList->at(i))) if (data_isKeyValid(keyAList->at(i)))
{ {
result = util->execCMDWithOutput("hf mf rdsc " result = util->execCMDWithOutput("hf mf rdsc " + QString::number(i) +
+ QString::number(i) " A " + keyAList->at(i),
+ " A " waitTime);
+ keyAList->at(i), waitTime);
qDebug() << result; qDebug() << result;
offset = result.indexOf("isOk:01"); offset = result.indexOf("isOk:01");
if(offset != -1) if (offset != -1)
{ {
isKeyAValid = true; isKeyAValid = true;
for(int j = 0; j < cardType.blk[i]; j++) for (int j = 0; j < cardType.blk[i]; j++)
{ {
offset = result.indexOf(*dataPattern, offset); offset = dataPattern->indexIn(result, offset);
// offset = result.indexOf(*dataPattern, offset);
tmp = result.mid(offset, 47).toUpper(); tmp = result.mid(offset, 47).toUpper();
offset += 47; offset += 47;
qDebug() << tmp; qDebug() << tmp;
@ -197,20 +203,20 @@ void Mifare::readAll()
} }
} }
} }
if(data_isKeyValid(keyBList->at(i))) if (data_isKeyValid(keyBList->at(i)))
{ {
result = util->execCMDWithOutput("hf mf rdsc " result = util->execCMDWithOutput("hf mf rdsc " + QString::number(i) +
+ QString::number(i) " B " + keyBList->at(i),
+ " B " waitTime);
+ keyBList->at(i), waitTime);
qDebug() << result; qDebug() << result;
offset = result.indexOf("isOk:01"); offset = result.indexOf("isOk:01");
if(offset != -1) if (offset != -1)
{ {
isKeyBValid = true; isKeyBValid = true;
for(int j = 0; j < cardType.blk[i]; j++) for (int j = 0; j < cardType.blk[i]; j++)
{ {
offset = result.indexOf(*dataPattern, offset); offset = dataPattern->indexIn(result, offset);
// offset = result.indexOf(*dataPattern, offset);
tmp = result.mid(offset, 47).toUpper(); tmp = result.mid(offset, 47).toUpper();
offset += 47; offset += 47;
qDebug() << tmp; qDebug() << tmp;
@ -221,18 +227,19 @@ void Mifare::readAll()
} }
} }
if(isKeyAValid || isKeyBValid) if (isKeyAValid || isKeyBValid)
{ {
// fill the MF_dataWidget with the known valid key // fill the MF_dataWidget with the known valid key
// //
// check whether the MF_dataWidget contains the valid key, // check whether the MF_dataWidget contains the valid key,
// and fill MF_keyWidget(when you only have KeyA but the ReadBlock output contains the KeyB) // and fill MF_keyWidget(when you only have KeyA but the ReadBlock output
// contains the KeyB)
// //
// the structure is not symmetric, since you cannot get KeyA from output // the structure is not symmetric, since you cannot get KeyA from output
// this program will only process the provided KeyA(in MF_keyWidget) // this program will only process the provided KeyA(in MF_keyWidget)
result = dataList->at(cardType.blks[i] + cardType.blk[i] - 1); result = dataList->at(cardType.blks[i] + cardType.blk[i] - 1);
if(isKeyAValid) if (isKeyAValid)
{ {
result.replace(0, 12, keyAList->at(i)); result.replace(0, 12, keyAList->at(i));
} }
@ -242,20 +249,22 @@ void Mifare::readAll()
} }
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result); dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
if(isKeyBValid) if (isKeyBValid)
{ {
result.replace(20, 12, keyBList->at(i)); result.replace(20, 12, keyBList->at(i));
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result); dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
data_syncWithDataWidget(false, cardType.blks[i] + cardType.blk[i] - 1); data_syncWithDataWidget(false, cardType.blks[i] + cardType.blk[i] - 1);
} }
else // now isKeyAValid == true, the output might contains the KeyB else // now isKeyAValid == true, the output might contains the KeyB
{ {
QString tmpKey = dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12); QString tmpKey =
result = util->execCMDWithOutput("hf mf rdbl " dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12);
+ QString::number(cardType.blks[i] + cardType.blk[i] - 1) result = util->execCMDWithOutput(
+ " B " "hf mf rdbl " +
+ tmpKey, waitTime); QString::number(cardType.blks[i] + cardType.blk[i] - 1) +
if(result.indexOf("isOk:01") != -1) " B " + tmpKey,
waitTime);
if (result.indexOf("isOk:01") != -1)
{ {
keyBList->replace(i, tmpKey); keyBList->replace(i, tmpKey);
data_syncWithKeyWidget(false, i, false); data_syncWithKeyWidget(false, i, false);
@ -265,7 +274,6 @@ void Mifare::readAll()
result = dataList->at(cardType.blks[i] + cardType.blk[i] - 1); result = dataList->at(cardType.blks[i] + cardType.blk[i] - 1);
result = result.replace(20, 12, "????????????"); result = result.replace(20, 12, "????????????");
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result); dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
} }
} }
data_syncWithDataWidget(false, cardType.blks[i] + cardType.blk[i] - 1); data_syncWithDataWidget(false, cardType.blks[i] + cardType.blk[i] - 1);
@ -276,15 +284,13 @@ void Mifare::readAll()
void Mifare::write() void Mifare::write()
{ {
int waitTime = 300; int waitTime = 300;
QString result = util->execCMDWithOutput("hf mf wrbl " QString result = util->execCMDWithOutput(
+ ui->MF_RW_blockBox->currentText() "hf mf wrbl " + ui->MF_RW_blockBox->currentText() + " " +
+ " " ui->MF_RW_keyTypeBox->currentText() + " " +
+ ui->MF_RW_keyTypeBox->currentText() ui->MF_RW_keyEdit->text() + " " +
+ " " ui->MF_RW_dataEdit->text().replace(" ", ""),
+ ui->MF_RW_keyEdit->text() waitTime);
+ " " if (result.indexOf("isOk:01") != -1)
+ ui->MF_RW_dataEdit->text().replace(" ", ""), waitTime);
if(result.indexOf("isOk:01") != -1)
{ {
QMessageBox::information(parent, tr("Info"), tr("Success!")); QMessageBox::information(parent, tr("Info"), tr("Success!"));
} }
@ -298,31 +304,31 @@ void Mifare::writeAll()
{ {
const int waitTime = 300; const int waitTime = 300;
QString result; QString result;
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
for(int j = 0; j < cardType.blk[i]; j++) for (int j = 0; j < cardType.blk[i]; j++)
{ {
result = ""; // if the KeyA is invalid and the result is not empty, the KeyB will not be tested. result = ""; // if the KeyA is invalid and the result is not empty, the
if(data_isDataValid(dataList->at(cardType.blks[i] + j)) != DATA_NOSPACE || dataList->at(cardType.blks[i] + j).contains('?')) // KeyB will not be tested.
if (data_isDataValid(dataList->at(cardType.blks[i] + j)) !=
DATA_NOSPACE ||
dataList->at(cardType.blks[i] + j).contains('?'))
continue; continue;
if(data_isKeyValid(keyAList->at(i))) if (data_isKeyValid(keyAList->at(i)))
{ {
result = util->execCMDWithOutput("hf mf wrbl " result = util->execCMDWithOutput(
+ QString::number(cardType.blks[i] + j) "hf mf wrbl " + QString::number(cardType.blks[i] + j) + " A " +
+ " A " keyAList->at(i) + " " + dataList->at(cardType.blks[i] + j),
+ keyAList->at(i) waitTime);
+ " "
+ dataList->at(cardType.blks[i] + j), waitTime);
} }
qDebug() << i << j << result.indexOf("isOk:01") << data_isKeyValid(keyBList->at(i)); qDebug() << i << j << result.indexOf("isOk:01")
if(result.indexOf("isOk:01") == -1 && data_isKeyValid(keyBList->at(i))) << data_isKeyValid(keyBList->at(i));
if (result.indexOf("isOk:01") == -1 && data_isKeyValid(keyBList->at(i)))
{ {
result = util->execCMDWithOutput("hf mf wrbl " result = util->execCMDWithOutput(
+ QString::number(cardType.blks[i] + j) "hf mf wrbl " + QString::number(cardType.blks[i] + j) + " B " +
+ " B " keyBList->at(i) + " " + dataList->at(cardType.blks[i] + j),
+ keyBList->at(i) waitTime);
+ " "
+ dataList->at(cardType.blks[i] + j), waitTime);
} }
} }
} }
@ -332,11 +338,11 @@ void Mifare::readC()
{ {
int waitTime = 300; int waitTime = 300;
int currblk = ui->MF_RW_blockBox->currentText().toInt(); int currblk = ui->MF_RW_blockBox->currentText().toInt();
QString result = util->execCMDWithOutput("hf mf cgetblk " QString result = util->execCMDWithOutput(
+ QString::number(currblk), waitTime); "hf mf cgetblk " + QString::number(currblk), waitTime);
if(result.indexOf("No chinese") == -1) if (result.indexOf("No chinese") == -1)
{ {
result = result.mid(result.indexOf(*dataPattern, 0), 47).toUpper(); result = result.mid(dataPattern->indexIn(result), 47).toUpper();
ui->MF_RW_dataEdit->setText(result); ui->MF_RW_dataEdit->setText(result);
} }
} }
@ -348,17 +354,17 @@ void Mifare::readAllC()
QString tmp; QString tmp;
int offset = 0; int offset = 0;
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
result = util->execCMDWithOutput("hf mf cgetsc " result = util->execCMDWithOutput("hf mf cgetsc " + QString::number(i), waitTime);
+ QString::number(i), waitTime);
qDebug() << result; qDebug() << result;
if(result.indexOf("No chinese") == -1) if (result.indexOf("No chinese") == -1)
{ {
offset = 0; offset = 0;
for(int j = 0; j < cardType.blk[i]; j++) for (int j = 0; j < cardType.blk[i]; j++)
{ {
offset = result.indexOf(*dataPattern, offset); offset = dataPattern->indexIn(result, offset);
// offset = result.indexOf(*dataPattern, offset);
tmp = result.mid(offset, 47).toUpper(); tmp = result.mid(offset, 47).toUpper();
offset += 47; offset += 47;
qDebug() << tmp; qDebug() << tmp;
@ -366,8 +372,10 @@ void Mifare::readAllC()
dataList->replace(cardType.blks[i] + j, tmp); dataList->replace(cardType.blks[i] + j, tmp);
data_syncWithDataWidget(false, cardType.blks[i] + j); data_syncWithDataWidget(false, cardType.blks[i] + j);
} }
keyAList->replace(i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).left(12)); keyAList->replace(
keyBList->replace(i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12)); i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).left(12));
keyBList->replace(
i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12));
data_syncWithKeyWidget(false, i, true); data_syncWithKeyWidget(false, i, true);
data_syncWithKeyWidget(false, i, false); data_syncWithKeyWidget(false, i, false);
} }
@ -377,11 +385,11 @@ void Mifare::readAllC()
void Mifare::writeC() void Mifare::writeC()
{ {
int waitTime = 150; int waitTime = 150;
QString result = util->execCMDWithOutput("hf mf csetblk " QString result = util->execCMDWithOutput(
+ ui->MF_RW_blockBox->currentText() "hf mf csetblk " + ui->MF_RW_blockBox->currentText() + " " +
+ " " ui->MF_RW_dataEdit->text().replace(" ", ""),
+ ui->MF_RW_dataEdit->text().replace(" ", ""), waitTime); waitTime);
if(result.indexOf("No chinese") == -1) if (result.indexOf("No chinese") == -1)
{ {
QMessageBox::information(parent, tr("Info"), tr("Success!")); QMessageBox::information(parent, tr("Info"), tr("Success!"));
} }
@ -395,33 +403,32 @@ void Mifare::writeAllC()
{ {
const int waitTime = 150; const int waitTime = 150;
QString result; QString result;
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
for(int j = 0; j < cardType.blk[i]; j++) for (int j = 0; j < cardType.blk[i]; j++)
{ {
result = ""; // if the KeyA is invalid and the result is not empty, the KeyB will not be tested. result = "";
if(data_isDataValid(dataList->at(cardType.blks[i] + j)) != DATA_NOSPACE || dataList->at(cardType.blks[i] + j).contains('?')) if (data_isDataValid(dataList->at(cardType.blks[i] + j)) != DATA_NOSPACE ||
dataList->at(cardType.blks[i] + j).contains('?'))
continue; continue;
result = util->execCMDWithOutput("hf mf csetblk " result = util->execCMDWithOutput(
+ QString::number(cardType.blks[i] + j) "hf mf csetblk " + QString::number(cardType.blks[i] + j) + " " +
+ " " dataList->at(cardType.blks[i] + j),
+ dataList->at(cardType.blks[i] + j), waitTime); waitTime);
} }
} }
} }
void Mifare::wipeC() void Mifare::wipeC()
{ {
util->execCMD("hf mf cwipe " util->execCMD("hf mf cwipe " + QString::number(cardType.type) + " f");
+ QString::number(cardType.type)
+ " f");
ui->funcTab->setCurrentIndex(1); ui->funcTab->setCurrentIndex(1);
} }
void Mifare::setParameterC() void Mifare::setParameterC()
{ {
QString result = info(true); QString result = info(true);
if(result == "") if (result == "")
QMessageBox::information(parent, tr("Info"), tr("Failed to read card.")); QMessageBox::information(parent, tr("Info"), tr("Failed to read card."));
else else
{ {
@ -429,9 +436,10 @@ void Mifare::setParameterC()
lis[0].replace(" ", ""); lis[0].replace(" ", "");
lis[1].replace(" ", ""); lis[1].replace(" ", "");
lis[2].replace(" ", ""); lis[2].replace(" ", "");
MF_UID_parameterDialog dialog(lis[0].toUpper(), lis[1].toUpper(), lis[2].mid(0, 2).toUpper()); MF_UID_parameterDialog dialog(lis[0].toUpper(), lis[1].toUpper(),
lis[2].mid(0, 2).toUpper());
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)
ui->funcTab->setCurrentIndex(1); ui->funcTab->setCurrentIndex(1);
} }
} }
@ -442,10 +450,75 @@ void Mifare::lockC()
util->execCMD("hf 14a raw -pa 43"); util->execCMD("hf 14a raw -pa 43");
util->execCMD("hf 14a raw -pa E0 00 39 F7"); 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 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 -pa 85 00 00 00 00 00 00 00 00 00 00 00 "
" 00 00 00 08 18 47");
util->execCMD("hf 14a raw 52"); util->execCMD("hf 14a raw 52");
} }
void Mifare::writeAllE()
{
const int waitTime = 200;
QString result;
for (int i = 0; i < cardType.sectors; i++)
{
for (int j = 0; j < cardType.blk[i]; j++)
{
result = "";
if (data_isDataValid(dataList->at(cardType.blks[i] + j)) != DATA_NOSPACE || dataList->at(cardType.blks[i] + j).contains('?'))
continue;
result = util->execCMDWithOutput(
"hf mf eset " + QString::number(cardType.blks[i] + j)
+ " "
+ dataList->at(cardType.blks[i] + j),
waitTime);
}
}
util->execCMDWithOutput("hf mf eget", waitTime); // to refresh output buffer;
}
void Mifare::readAllE()
{
QString result;
const int waitTime = 200;
QString tmp;
int offset = 0;
for (int i = 0; i < cardType.sectors; i++)
{
offset = 0;
for (int j = 0; j < cardType.blk[i]; j++)
{
qDebug() << "**********" ;
result = util->execCMDWithOutput("hf mf eget " + QString::number(cardType.blks[i] + j), waitTime);
qDebug() << result ;
offset = dataPattern->indexIn(result);
// offset = result.indexOf(*dataPattern, offset); // When I find the data position in this way, the Regex might fail to match.
tmp = result.mid(offset, 47).toUpper();
qDebug() << tmp << offset;
qDebug() << "**********" ;
if(offset == -1)
continue;
tmp.replace(" ", "");
dataList->replace(cardType.blks[i] + j, tmp);
data_syncWithDataWidget(false, cardType.blks[i] + j);
}
keyAList->replace(i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).left(12));
keyBList->replace(i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12));
data_syncWithKeyWidget(false, i, true);
data_syncWithKeyWidget(false, i, false);
}
}
void Mifare::wipeE()
{
util->execCMD("hf mf eclr");
}
void Mifare::dump() void Mifare::dump()
{ {
util->execCMD("hf mf dump"); util->execCMD("hf mf dump");
@ -461,15 +534,15 @@ void Mifare::restore()
void Mifare::data_syncWithDataWidget(bool syncAll, int block) void Mifare::data_syncWithDataWidget(bool syncAll, int block)
{ {
QString tmp; QString tmp;
if(syncAll) if (syncAll)
{ {
for(int i = 0; i < cardType.blocks; i++) for (int i = 0; i < cardType.blocks; i++)
{ {
tmp = ""; tmp = "";
if(dataList->at(i) != "") if (dataList->at(i) != "")
{ {
tmp += dataList->at(i).mid(0, 2); tmp += dataList->at(i).mid(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).mid(j * 2, 2);
@ -481,10 +554,10 @@ void Mifare::data_syncWithDataWidget(bool syncAll, int block)
else else
{ {
tmp = ""; tmp = "";
if(dataList->at(block) != "") if (dataList->at(block) != "")
{ {
tmp += dataList->at(block).mid(0, 2); tmp += dataList->at(block).mid(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).mid(j * 2, 2);
@ -496,9 +569,9 @@ void Mifare::data_syncWithDataWidget(bool syncAll, int block)
void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, bool isKeyA) void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, bool isKeyA)
{ {
if(syncAll) if (syncAll)
{ {
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
ui->MF_keyWidget->item(i, 1)->setText(keyAList->at(i)); ui->MF_keyWidget->item(i, 1)->setText(keyAList->at(i));
ui->MF_keyWidget->item(i, 2)->setText(keyBList->at(i)); ui->MF_keyWidget->item(i, 2)->setText(keyBList->at(i));
@ -506,7 +579,7 @@ void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, bool isKeyA)
} }
else else
{ {
if(isKeyA) if (isKeyA)
ui->MF_keyWidget->item(sector, 1)->setText(keyAList->at(sector)); ui->MF_keyWidget->item(sector, 1)->setText(keyAList->at(sector));
else else
ui->MF_keyWidget->item(sector, 2)->setText(keyBList->at(sector)); ui->MF_keyWidget->item(sector, 2)->setText(keyBList->at(sector));
@ -516,7 +589,7 @@ void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, bool isKeyA)
void Mifare::data_clearData() void Mifare::data_clearData()
{ {
dataList->clear(); dataList->clear();
for(int i = 0; i < cardType.blocks; i++) for (int i = 0; i < cardType.blocks; i++)
dataList->append(""); dataList->append("");
} }
@ -524,49 +597,50 @@ void Mifare::data_clearKey()
{ {
keyAList->clear(); keyAList->clear();
keyBList->clear(); keyBList->clear();
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
keyAList->append(""); keyAList->append("");
keyBList->append(""); keyBList->append("");
} }
} }
bool Mifare::data_isKeyValid(const QString& key) bool Mifare::data_isKeyValid(const QString &key)
{ {
if(key.length() != 12) if (key.length() != 12)
return false; return false;
for(int i = 0; i < 12; i++) for (int i = 0; i < 12; i++)
{ {
if(!((key[i] >= '0' && key[i] <= '9') || (key[i] >= 'A' && key[i] <= 'F'))) if (!((key[i] >= '0' && key[i] <= '9') || (key[i] >= 'A' && key[i] <= 'F')))
return false; return false;
} }
return true; return true;
} }
Mifare::DataType Mifare::data_isDataValid(QString data) // "?" will not been processd there Mifare::DataType
Mifare::data_isDataValid(QString data) // "?" will not been processd there
{ {
if(data.length() == 47) if (data.length() == 47)
{ {
for(int i = 0; i < 47; i++) for (int i = 0; i < 47; i++)
{ {
if(i % 3 != 0) if (i % 3 != 0)
{ {
if(!((data[i] >= '0' && data[i] <= '9') || (data[i] >= 'A' && data[i] <= 'F') || data[i] == '?')) if (!((data[i] >= '0' && data[i] <= '9') || (data[i] >= 'A' && data[i] <= 'F') || data[i] == '?'))
return DATA_INVALID; return DATA_INVALID;
} }
else else
{ {
if(data[i] != ' ') if (data[i] != ' ')
return DATA_INVALID; return DATA_INVALID;
} }
} }
return DATA_WITHSPACE; return DATA_WITHSPACE;
} }
else if(data.length() == 32) else if (data.length() == 32)
{ {
for(int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
{ {
if(!((data[i] >= '0' && data[i] <= '9') || (data[i] >= 'A' && data[i] <= 'F') || data[i] == '?')) if (!((data[i] >= '0' && data[i] <= '9') || (data[i] >= 'A' && data[i] <= 'F') || data[i] == '?'))
return DATA_INVALID; return DATA_INVALID;
} }
return DATA_NOSPACE; return DATA_NOSPACE;
@ -582,47 +656,43 @@ Mifare::CardType Mifare::getCardType()
void Mifare::setCardType(int type) void Mifare::setCardType(int type)
{ {
if(type == 0 || type == 1 || type == 2 || type == 4) if (type == 0 || type == 1 || type == 2 || type == 4)
{ {
if(type == 0) if (type == 0)
cardType = card_mini; cardType = card_mini;
else if(type == 1) else if (type == 1)
cardType = card_1k; cardType = card_1k;
else if(type == 2) else if (type == 2)
cardType = card_2k; cardType = card_2k;
else if(type == 4) else if (type == 4)
cardType = card_4k; cardType = card_4k;
data_clearKey(); data_clearKey();
data_clearData(); data_clearData();
} }
} }
bool Mifare::data_loadDataFile(const QString& filename) bool Mifare::data_loadDataFile(const QString &filename)
{ {
QFile file(filename, this); QFile file(filename, this);
if(file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly))
{ {
QByteArray buff; QByteArray buff;
buff = file.read(10000); buff = file.read(10000);
bool isBin = false; bool isBin = false;
for(int i = 0; i < cardType.blocks * 16; i++) // Detect the file type for (int i = 0; i < cardType.blocks * 16; i++) // Detect the file type
{ {
// qDebug() << (unsigned char)buff[i]; // qDebug() << (unsigned char)buff[i];
if(!((buff[i] >= 'A' && buff[i] <= 'F') || if (!((buff[i] >= 'A' && buff[i] <= 'F') || (buff[i] >= 'a' && buff[i] <= 'f') || (buff[i] >= '0' && buff[i] <= '9') || buff[i] == '\n' || buff[i] == '\r'))
(buff[i] >= 'a' && buff[i] <= 'f') ||
(buff[i] >= '0' && buff[i] <= '9') ||
buff[i] == '\n' ||
buff[i] == '\r'))
{ {
isBin = true; isBin = true;
break; break;
} }
} }
if(isBin) if (isBin)
{ {
if(file.size() < cardType.blocks * 16) if (file.size() < cardType.blocks * 16)
return false; return false;
for(int i = 0; i < cardType.blocks; i++) for (int i = 0; i < cardType.blocks; i++)
{ {
QString tmp = bin2text(buff, i, 16); QString tmp = bin2text(buff, i, 16);
dataList->replace(i, tmp.toUpper()); dataList->replace(i, tmp.toUpper());
@ -632,7 +702,7 @@ bool Mifare::data_loadDataFile(const QString& filename)
{ {
QString tmp = buff.left(cardType.blocks * 34); QString tmp = buff.left(cardType.blocks * 34);
QStringList tmpList = tmp.split("\r\n"); QStringList tmpList = tmp.split("\r\n");
for(int i = 0; i < cardType.blocks; i++) for (int i = 0; i < cardType.blocks; i++)
{ {
dataList->replace(i, tmpList[i].toUpper()); dataList->replace(i, tmpList[i].toUpper());
qDebug() << tmpList[i]; qDebug() << tmpList[i];
@ -648,17 +718,17 @@ bool Mifare::data_loadDataFile(const QString& filename)
} }
} }
bool Mifare::data_loadKeyFile(const QString& filename) bool Mifare::data_loadKeyFile(const QString &filename)
{ {
QFile file(filename, this); QFile file(filename, this);
if(file.open(QIODevice::ReadOnly)) if (file.open(QIODevice::ReadOnly))
{ {
QByteArray buff; QByteArray buff;
buff = file.read(10000); buff = file.read(10000);
bool isKey = file.size() <= cardType.sectors * 14; bool isKey = file.size() <= cardType.sectors * 14;
if(isKey) if (isKey)
{ {
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
QString tmp = bin2text(buff, i, 12); QString tmp = bin2text(buff, i, 12);
keyAList->replace(i, tmp.left(12).toUpper()); keyAList->replace(i, tmp.left(12).toUpper());
@ -667,7 +737,7 @@ bool Mifare::data_loadKeyFile(const QString& filename)
} }
else else
{ {
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
int blk = cardType.blks[i] + cardType.blk[i] - 1; int blk = cardType.blks[i] + cardType.blk[i] - 1;
QString tmp = bin2text(buff, blk, 16); QString tmp = bin2text(buff, blk, 16);
@ -685,12 +755,14 @@ bool Mifare::data_loadKeyFile(const QString& filename)
} }
} }
QString Mifare::bin2text(const QByteArray& buff, int i, int length) QString Mifare::bin2text(const QByteArray &buff, int i, int length)
{ {
QString ret = ""; QString ret = "";
char LByte, RByte; char LByte, RByte;
char map[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; char map[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
for(int j = 0; j < length; j++) '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
for (int j = 0; j < length; j++)
{ {
LByte = map[(unsigned char)buff[i * length + j] >> 4]; LByte = map[(unsigned char)buff[i * length + j] >> 4];
RByte = map[(unsigned char)buff[i * length + j] & 0xF]; RByte = map[(unsigned char)buff[i * length + j] & 0xF];
@ -701,26 +773,26 @@ QString Mifare::bin2text(const QByteArray& buff, int i, int length)
return ret; return ret;
} }
bool Mifare::data_saveDataFile(const QString& filename, bool isBin) bool Mifare::data_saveDataFile(const QString &filename, bool isBin)
{ {
QFile file(filename, this); QFile file(filename, this);
if(file.open(QIODevice::WriteOnly)) if (file.open(QIODevice::WriteOnly))
{ {
QByteArray buff; QByteArray buff;
QChar tmp; QChar tmp;
if(isBin) if (isBin)
{ {
for(int i = 0; i < cardType.blocks; i++) for (int i = 0; i < cardType.blocks; i++)
{ {
for(int j = 0; j < 16; j++) for (int j = 0; j < 16; j++)
{ {
unsigned char Byt[2]; unsigned char Byt[2];
for(int k = 0; k < 2; k++) for (int k = 0; k < 2; k++)
{ {
tmp = dataList->at(i).at(j * 2 + k).toUpper(); tmp = dataList->at(i).at(j * 2 + k).toUpper();
if(tmp >= '0' && tmp <= '9') if (tmp >= '0' && tmp <= '9')
Byt[k] = tmp.toLatin1() - '0'; Byt[k] = tmp.toLatin1() - '0';
else if(tmp >= 'A' && tmp <= 'F') else if (tmp >= 'A' && tmp <= 'F')
Byt[k] = tmp.toLatin1() - 'A' + 10; Byt[k] = tmp.toLatin1() - 'A' + 10;
} }
buff += (Byt[0] << 4) | Byt[1]; buff += (Byt[0] << 4) | Byt[1];
@ -729,7 +801,7 @@ bool Mifare::data_saveDataFile(const QString& filename, bool isBin)
} }
else else
{ {
for(int i = 0; i < cardType.blocks; i++) for (int i = 0; i < cardType.blocks; i++)
{ {
buff += dataList->at(i); buff += dataList->at(i);
buff += "\r\n"; buff += "\r\n";
@ -745,39 +817,39 @@ bool Mifare::data_saveDataFile(const QString& filename, bool isBin)
} }
} }
bool Mifare::data_saveKeyFile(const QString& filename, bool isBin) bool Mifare::data_saveKeyFile(const QString &filename, bool isBin)
{ {
QFile file(filename, this); QFile file(filename, this);
if(file.open(QIODevice::WriteOnly)) if (file.open(QIODevice::WriteOnly))
{ {
QByteArray buff; QByteArray buff;
QChar tmp; QChar tmp;
if(isBin) if (isBin)
{ {
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
for(int j = 0; j < 6; j++) for (int j = 0; j < 6; j++)
{ {
unsigned char Byt[2]; unsigned char Byt[2];
for(int k = 0; k < 2; k++) for (int k = 0; k < 2; k++)
{ {
tmp = keyAList->at(i).at(j * 2 + k).toUpper(); tmp = keyAList->at(i).at(j * 2 + k).toUpper();
if(tmp >= '0' && tmp <= '9') if (tmp >= '0' && tmp <= '9')
Byt[k] = tmp.toLatin1() - '0'; Byt[k] = tmp.toLatin1() - '0';
else if(tmp >= 'A' && tmp <= 'F') else if (tmp >= 'A' && tmp <= 'F')
Byt[k] = tmp.toLatin1() - 'A' + 10; Byt[k] = tmp.toLatin1() - 'A' + 10;
} }
buff += (Byt[0] << 4) | Byt[1]; buff += (Byt[0] << 4) | Byt[1];
} }
for(int j = 0; j < 6; j++) for (int j = 0; j < 6; j++)
{ {
unsigned char Byt[2]; unsigned char Byt[2];
for(int k = 0; k < 2; k++) for (int k = 0; k < 2; k++)
{ {
tmp = keyBList->at(i).at(j * 2 + k).toUpper(); tmp = keyBList->at(i).at(j * 2 + k).toUpper();
if(tmp >= '0' && tmp <= '9') if (tmp >= '0' && tmp <= '9')
Byt[k] = tmp.toLatin1() - '0'; Byt[k] = tmp.toLatin1() - '0';
else if(tmp >= 'A' && tmp <= 'F') else if (tmp >= 'A' && tmp <= 'F')
Byt[k] = tmp.toLatin1() - 'A' + 10; Byt[k] = tmp.toLatin1() - 'A' + 10;
} }
buff += (Byt[0] << 4) | Byt[1]; buff += (Byt[0] << 4) | Byt[1];
@ -786,7 +858,6 @@ bool Mifare::data_saveKeyFile(const QString& filename, bool isBin)
} }
else else
{ {
} }
bool ret = file.write(buff) != -1; bool ret = file.write(buff) != -1;
file.close(); file.close();
@ -800,20 +871,20 @@ bool Mifare::data_saveKeyFile(const QString& filename, bool isBin)
void Mifare::data_key2Data() void Mifare::data_key2Data()
{ {
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
QString tmp = ""; QString tmp = "";
if(data_isKeyValid(keyAList->at(i))) if (data_isKeyValid(keyAList->at(i)))
tmp += keyAList->at(i); tmp += keyAList->at(i);
else else
tmp += "????????????"; tmp += "????????????";
if(dataList->at(cardType.blks[i] + cardType.blk[i] - 1) == "") if (dataList->at(cardType.blks[i] + cardType.blk[i] - 1) == "")
tmp += "FF078069"; // default control bytes tmp += "FF078069"; // default control bytes
else else
tmp += dataList->at(cardType.blks[i] + cardType.blk[i] - 1).mid(12, 8); tmp += dataList->at(cardType.blks[i] + cardType.blk[i] - 1).mid(12, 8);
if(data_isKeyValid(keyBList->at(i))) if (data_isKeyValid(keyBList->at(i)))
tmp += keyBList->at(i); tmp += keyBList->at(i);
else else
tmp += "????????????"; tmp += "????????????";
@ -825,30 +896,32 @@ void Mifare::data_key2Data()
void Mifare::data_data2Key() void Mifare::data_data2Key()
{ {
for(int i = 0; i < cardType.sectors; i++) for (int i = 0; i < cardType.sectors; i++)
{ {
if(dataList->at(cardType.blks[i] + cardType.blk[i] - 1) == "") if (dataList->at(cardType.blks[i] + cardType.blk[i] - 1) == "")
{ {
keyAList->replace(i, "????????????"); keyAList->replace(i, "????????????");
keyBList->replace(i, "????????????"); keyBList->replace(i, "????????????");
} }
else else
{ {
keyAList->replace(i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).left(12)); keyAList->replace(
keyBList->replace(i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12)); i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).left(12));
keyBList->replace(
i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12));
} }
data_syncWithKeyWidget(); data_syncWithKeyWidget();
} }
} }
void Mifare::data_setData(int block, const QString& data) void Mifare::data_setData(int block, const QString &data)
{ {
dataList->replace(block, data); dataList->replace(block, data);
} }
void Mifare::data_setKey(int sector, bool isKeyA, const QString& key) void Mifare::data_setKey(int sector, bool isKeyA, const QString &key)
{ {
if(isKeyA) if (isKeyA)
keyAList->replace(sector, key); keyAList->replace(sector, key);
else else
keyBList->replace(sector, key); keyBList->replace(sector, key);

@ -105,6 +105,9 @@ public:
void data_setData(int block, const QString &data); void data_setData(int block, const QString &data);
void data_setKey(int sector, bool isKeyA, const QString &key); void data_setKey(int sector, bool isKeyA, const QString &key);
void lockC(); void lockC();
void writeAllE();
void readAllE();
void wipeE();
public slots: public slots:
signals: signals:

@ -6,10 +6,11 @@ MainWindow::MainWindow(QWidget *parent)
, ui(new Ui::MainWindow) , ui(new Ui::MainWindow)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->MF_simGroupBox->setVisible(false); // developing... // ui->MF_simGroupBox->setVisible(false); // developing...
ui->MF_sniffGroupBox->setVisible(false); // developing... ui->MF_sniffGroupBox->setVisible(false); // developing...
myInfo = new QAction("wh201906", this); myInfo = new QAction("wh201906", this);
connect(myInfo, &QAction::triggered, [ = ]() { connect(myInfo, &QAction::triggered, [ = ]()
{
QDesktopServices::openUrl(QUrl("https://github.com/wh201906")); QDesktopServices::openUrl(QUrl("https://github.com/wh201906"));
}); });
this->addAction(myInfo); this->addAction(myInfo);
@ -473,6 +474,25 @@ void MainWindow::on_MF_UID_lockButton_clicked()
mifare->lockC(); mifare->lockC();
} }
void MainWindow::on_MF_Sim_loadDataButton_clicked()
{
setState(false);
mifare->writeAllE();
setState(true);
}
void MainWindow::on_MF_Sim_writeAllButton_clicked()
{
setState(false);
mifare->readAllE();
setState(true);
}
void MainWindow::on_MF_Sim_clearButton_clicked()
{
mifare->wipeE();
}
void MainWindow::on_MF_Sniff_sniffButton_clicked() void MainWindow::on_MF_Sniff_sniffButton_clicked()
{ {
setState(false); setState(false);
@ -651,3 +671,5 @@ void MainWindow::setState(bool st)
} }
// *********************************************** // ***********************************************

@ -22,7 +22,8 @@
#include "common/util.h" #include "common/util.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { namespace Ui
{
class MainWindow; class MainWindow;
} }
QT_END_NAMESPACE QT_END_NAMESPACE
@ -119,6 +120,12 @@ private slots:
void on_MF_UID_lockButton_clicked(); void on_MF_UID_lockButton_clicked();
void on_MF_Sim_loadDataButton_clicked();
void on_MF_Sim_writeAllButton_clicked();
void on_MF_Sim_clearButton_clicked();
private: private:
Ui::MainWindow* ui; Ui::MainWindow* ui;
QButtonGroup* typeBtnGroup; QButtonGroup* typeBtnGroup;

@ -105,9 +105,6 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="mifareTab"> <widget class="QWidget" name="mifareTab">
<attribute name="title"> <attribute name="title">
<string>Mifare</string> <string>Mifare</string>

Loading…
Cancel
Save