From 4dba7882e50192f9c2fe1042baa875d14ea1bedd Mon Sep 17 00:00:00 2001 From: wh201906 Date: Fri, 7 Aug 2020 23:51:24 +0800 Subject: [PATCH] Support read selected blocks --- README.md | 12 +++-- module/mifare.cpp | 126 ++++++++++++++++++++++++++-------------------- module/mifare.h | 9 ++-- ui/mainwindow.cpp | 12 +++-- ui/mainwindow.h | 2 +- ui/mainwindow.ui | 6 +-- 6 files changed, 98 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 809caac..1d1dd84 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,16 @@ A GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) client ## Features -+ Support raw commands of Proxmark3 client ++ Easy to find available Serial Port ++ Support raw commands of Proxmark3 client(Official/Iceman) + Have a friendly UI to test Mifare cards -+ Easy to edit Mifare data files -+ Support binary(.bin .dump) files and text(.eml) files + + Support different card size(MINI, 1K, 2K, 4K) + + Easy to edit Mifare data files + + Easy to read all blocks with well-designed read logic + + Support binary(.bin .dump) files and text(.eml) files + + Analyze Access Bits + + Support Chinese Magic Card ++ Customize UI + ... *** diff --git a/module/mifare.cpp b/module/mifare.cpp index dc7d98a..8eeb023 100644 --- a/module/mifare.cpp +++ b/module/mifare.cpp @@ -412,13 +412,27 @@ void Mifare::read() } } -void Mifare::readAll() +void Mifare::readSelected(const QList& selectedBlocks) { QStringList data, dataA, dataB; QString trailerA, trailerB; + QList selectedSectors; for(int i = 0; i < cardType.sector_size; i++) { + selectedSectors.append(false); + } + for(int item : selectedBlocks) + { + selectedSectors[item / 4] = true; + } + + for(int i = 0; i < cardType.sector_size; i++) + { + if(!selectedSectors[i]) + { + continue; + } for(int j = 0; j < cardType.blk[i]; j++) { // dataA is always filled with "" because of the _readsec() @@ -451,34 +465,61 @@ void Mifare::readAll() for(int j = 0; j < cardType.blk[i]; j++) { - dataList->replace(cardType.blks[i] + j, data[j]); - data_syncWithDataWidget(false, cardType.blks[i] + j); + if(selectedBlocks.contains(cardType.blks[i] + j)) + { + dataList->replace(cardType.blks[i] + j, data[j]); + data_syncWithDataWidget(false, cardType.blks[i] + j); + } } - // data widget has been updated, so this is just a temporary varient. - if(data[cardType.blk[i] - 1] == "") - data[cardType.blk[i] - 1] = "????????????????????????????????"; + if(selectedBlocks.contains(cardType.blks[i] + cardType.blk[i] - 1)) + { + // data widget has been updated, so this is just a temporary varient. + if(data[cardType.blk[i] - 1] == "") + data[cardType.blk[i] - 1] = "????????????????????????????????"; + + // doesn't replace the existing key. + if(!data_isKeyValid(keyAList->at(i))) + keyAList->replace(i, data[cardType.blk[i] - 1].left(12)); + if(!data_isKeyValid(keyBList->at(i))) + keyBList->replace(i, data[cardType.blk[i] - 1].right(12)); + data_syncWithKeyWidget(false, i, KEY_A); + data_syncWithKeyWidget(false, i, KEY_B); + } - // doesn't replace the existing key. - if(keyAList->at(i) == "" || keyAList->at(i) == "????????????") - keyAList->replace(i, data[cardType.blk[i] - 1].left(12)); - if(keyBList->at(i) == "" || keyBList->at(i) == "????????????") - keyBList->replace(i, data[cardType.blk[i] - 1].right(12)); - data_syncWithKeyWidget(false, i, KEY_A); - data_syncWithKeyWidget(false, i, KEY_B); + } +} + +bool Mifare::_writeblk(int blockId, KeyType keyType, const QString& key, const QString& data, int waitTime) +{ + QString input = data.toUpper(); + input.remove(" "); + + if(!data_isKeyValid(key) || data_isDataValid(input) != DATA_NOSPACE) + return false; + + if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL || util->getClientType() == Util::CLIENTTYPE_ICEMAN) + { + QString result = util->execCMDWithOutput( + "hf mf wrbl " + + QString::number(blockId) + + " " + + (char)keyType + + " " + + key + + " " + + input, + waitTime); + return (result.indexOf("isOk:01") != -1); } } void Mifare::write() { - int waitTime = 300; - QString result = util->execCMDWithOutput( - "hf mf wrbl " + ui->MF_RW_blockBox->currentText() + " " + - ui->MF_RW_keyTypeBox->currentText() + " " + - ui->MF_RW_keyEdit->text() + " " + - ui->MF_RW_dataEdit->text().replace(" ", ""), - waitTime); - if(result.indexOf("isOk:01") != -1) + int blockId = ui->MF_RW_blockBox->currentText().toInt(); + Mifare::KeyType keyType = (Mifare::KeyType)(ui->MF_RW_keyTypeBox->currentData().toInt()); + bool isSuccessful = _writeblk(blockId, keyType, ui->MF_RW_keyEdit->text().toUpper(), ui->MF_RW_dataEdit->text()); + if(isSuccessful) { QMessageBox::information(parent, tr("Info"), tr("Success!")); } @@ -490,46 +531,19 @@ void Mifare::write() void Mifare::writeAll() { - const int waitTime = 300; - QString result; for(int i = 0; i < cardType.sector_size; i++) { for(int j = 0; j < cardType.blk[i]; j++) { - result = ""; // if the KeyA is valid and the result is not empty, the KeyB will not be tested. - if(data_isDataValid(dataList->at(cardType.blks[i] + j)) != DATA_NOSPACE || dataList->at(cardType.blks[i] + j).contains('?')) - continue; - if(data_isKeyValid(keyAList->at(i))) - { - result = util->execCMDWithOutput( - "hf mf wrbl " + - QString::number(cardType.blks[i] + j) - + " A " - + keyAList->at(i) - + " " - + dataList->at(cardType.blks[i] + j), - waitTime); - } - qDebug() << i << j << result.indexOf("isOk:01") << data_isKeyValid(keyBList->at(i)); - if(result.indexOf("isOk:01") == -1 && data_isKeyValid(keyBList->at(i))) + bool result = false; + result = _writeblk(cardType.blks[i] + j, KEY_A, keyAList->at(i), dataList->at(cardType.blks[i] + j)); + if(!result) { - result = util->execCMDWithOutput( - "hf mf wrbl " - + QString::number(cardType.blks[i] + j) - + " B " - + keyBList->at(i) - + " " - + dataList->at(cardType.blks[i] + j), - waitTime); + result = _writeblk(cardType.blks[i] + j, KEY_B, keyBList->at(i), dataList->at(cardType.blks[i] + j)); } - if(result.indexOf("isOk:01") == -1 && keyAList->at(i) != "FFFFFFFFFFFF") // Try default key. It's useful when writing to a blank card + if(!result) { - result = util->execCMDWithOutput( - "hf mf wrbl " - + QString::number(cardType.blks[i] + j) - + " A FFFFFFFFFFFF " - + dataList->at(cardType.blks[i] + j), - waitTime); + result = _writeblk(cardType.blks[i] + j, KEY_A, "FFFFFFFFFFFF", dataList->at(cardType.blks[i] + j)); } } } @@ -765,6 +779,7 @@ void Mifare::saveSniff(const QString& file) void Mifare::data_syncWithDataWidget(bool syncAll, int block) { + ui->MF_dataWidget->blockSignals(true); QString tmp; if(syncAll) { @@ -797,10 +812,12 @@ void Mifare::data_syncWithDataWidget(bool syncAll, int block) } ui->MF_dataWidget->item(block, 2)->setText(tmp); } + ui->MF_dataWidget->blockSignals(false); } void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, KeyType keyType) { + ui->MF_keyWidget->blockSignals(true); if(syncAll) { for(int i = 0; i < cardType.sector_size; i++) @@ -816,6 +833,7 @@ void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, KeyType keyType) else ui->MF_keyWidget->item(sector, 2)->setText(keyBList->at(sector)); } + ui->MF_keyWidget->blockSignals(false); } void Mifare::data_clearData() diff --git a/module/mifare.h b/module/mifare.h index ac0be02..dfa1db5 100644 --- a/module/mifare.h +++ b/module/mifare.h @@ -25,7 +25,7 @@ public: void snoop(); void list(); void read(); - void readAll(); + void readSelected(const QList& selectedBlocks); void write(); void writeAll(); void dump(); @@ -105,8 +105,6 @@ public: void saveSniff(const QString& file); void data_fillKeys(); - QString _readblk(int blockId, KeyType keyType, const QString &key, int waitTime = 300); - QStringList _readsec(int sectorId, KeyType keyType, const QString &key, int waitTime = 300); static QList data_getACBits(const QString &text); public slots: signals: @@ -124,8 +122,9 @@ private: QRegularExpression* keyPattern; QString bin2text(const QByteArray& buff, int start, int length); - //QString _readblk(int blockId, KeyType keyType, const QString &key, int waitTime = 300); - //QStringList _readsec(int sectorId, KeyType keyType, const QString &key, int waitTime = 300); + QString _readblk(int blockId, KeyType keyType, const QString &key, int waitTime = 300); + QStringList _readsec(int sectorId, KeyType keyType, const QString &key, int waitTime = 300); + bool _writeblk(int blockId, KeyType keyType, const QString &key, const QString &data, int waitTime = 300); }; #endif // MIFARE_H diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 0777242..b87a5ae 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -486,10 +486,16 @@ void MainWindow::on_MF_Attack_hardnestedButton_clicked() mifare->hardnested(); } -void MainWindow::on_MF_RW_readAllButton_clicked() +void MainWindow::on_MF_RW_readSelectedButton_clicked() { setState(false); - mifare->readAll(); + QList selectedBlocks; + for(int i = 0; i < mifare->cardType.block_size; i++) + { + if(ui->MF_dataWidget->item(i, 1)->checkState() == Qt::Checked) + selectedBlocks.append(i); + } + mifare->readSelected(selectedBlocks); setState(true); } @@ -919,5 +925,5 @@ void MainWindow::saveClientPath(const QString& path) void MainWindow::on_testButton_clicked() { - mifare->_readsec(0, Mifare::KEY_A, "FFFFFFFFFFFF"); +// mifare->_readsec(0, Mifare::KEY_A, "FFFFFFFFFFFF"); } diff --git a/ui/mainwindow.h b/ui/mainwindow.h index 3a02dd5..9427cf2 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -77,7 +77,7 @@ private slots: void on_MF_Sniff_listButton_clicked(); - void on_MF_RW_readAllButton_clicked(); + void on_MF_RW_readSelectedButton_clicked(); void on_MF_RW_readBlockButton_clicked(); diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 454dd5a..762b548 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -6,13 +6,13 @@ 0 0 - 870 + 970 770 - 870 + 970 770 @@ -631,7 +631,7 @@ - + Read Selected