Support read selected blocks

pull/4/head
wh201906 4 years ago
parent 25d7886f2a
commit 4dba7882e5

@ -7,10 +7,16 @@ A GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) client
## Features ## 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 + Have a friendly UI to test Mifare cards
+ Easy to edit Mifare data files + Support different card size(MINI, 1K, 2K, 4K)
+ Support binary(.bin .dump) files and text(.eml) files + 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
+ ... + ...
*** ***

@ -412,13 +412,27 @@ void Mifare::read()
} }
} }
void Mifare::readAll() void Mifare::readSelected(const QList<int>& selectedBlocks)
{ {
QStringList data, dataA, dataB; QStringList data, dataA, dataB;
QString trailerA, trailerB; QString trailerA, trailerB;
QList<bool> selectedSectors;
for(int i = 0; i < cardType.sector_size; i++) 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++) for(int j = 0; j < cardType.blk[i]; j++)
{ {
// dataA is always filled with "" because of the _readsec() // dataA is always filled with "" because of the _readsec()
@ -450,35 +464,62 @@ void Mifare::readAll()
} }
for(int j = 0; j < cardType.blk[i]; j++) for(int j = 0; j < cardType.blk[i]; j++)
{
if(selectedBlocks.contains(cardType.blks[i] + j))
{ {
dataList->replace(cardType.blks[i] + j, data[j]); dataList->replace(cardType.blks[i] + j, data[j]);
data_syncWithDataWidget(false, cardType.blks[i] + j); data_syncWithDataWidget(false, cardType.blks[i] + j);
} }
}
if(selectedBlocks.contains(cardType.blks[i] + cardType.blk[i] - 1))
{
// data widget has been updated, so this is just a temporary varient. // data widget has been updated, so this is just a temporary varient.
if(data[cardType.blk[i] - 1] == "") if(data[cardType.blk[i] - 1] == "")
data[cardType.blk[i] - 1] = "????????????????????????????????"; data[cardType.blk[i] - 1] = "????????????????????????????????";
// doesn't replace the existing key. // doesn't replace the existing key.
if(keyAList->at(i) == "" || keyAList->at(i) == "????????????") if(!data_isKeyValid(keyAList->at(i)))
keyAList->replace(i, data[cardType.blk[i] - 1].left(12)); keyAList->replace(i, data[cardType.blk[i] - 1].left(12));
if(keyBList->at(i) == "" || keyBList->at(i) == "????????????") if(!data_isKeyValid(keyBList->at(i)))
keyBList->replace(i, data[cardType.blk[i] - 1].right(12)); keyBList->replace(i, data[cardType.blk[i] - 1].right(12));
data_syncWithKeyWidget(false, i, KEY_A); data_syncWithKeyWidget(false, i, KEY_A);
data_syncWithKeyWidget(false, i, KEY_B); data_syncWithKeyWidget(false, i, KEY_B);
} }
}
} }
void Mifare::write() bool Mifare::_writeblk(int blockId, KeyType keyType, const QString& key, const QString& data, int waitTime)
{ {
int waitTime = 300; 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( QString result = util->execCMDWithOutput(
"hf mf wrbl " + ui->MF_RW_blockBox->currentText() + " " + "hf mf wrbl "
ui->MF_RW_keyTypeBox->currentText() + " " + + QString::number(blockId)
ui->MF_RW_keyEdit->text() + " " + + " "
ui->MF_RW_dataEdit->text().replace(" ", ""), + (char)keyType
+ " "
+ key
+ " "
+ input,
waitTime); waitTime);
if(result.indexOf("isOk:01") != -1) return (result.indexOf("isOk:01") != -1);
}
}
void Mifare::write()
{
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!")); QMessageBox::information(parent, tr("Info"), tr("Success!"));
} }
@ -490,46 +531,19 @@ void Mifare::write()
void Mifare::writeAll() void Mifare::writeAll()
{ {
const int waitTime = 300;
QString result;
for(int i = 0; i < cardType.sector_size; i++) for(int i = 0; i < cardType.sector_size; i++)
{ {
for(int j = 0; j < cardType.blk[i]; j++) 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. bool result = false;
if(data_isDataValid(dataList->at(cardType.blks[i] + j)) != DATA_NOSPACE || dataList->at(cardType.blks[i] + j).contains('?')) result = _writeblk(cardType.blks[i] + j, KEY_A, keyAList->at(i), dataList->at(cardType.blks[i] + j));
continue; if(!result)
if(data_isKeyValid(keyAList->at(i)))
{ {
result = util->execCMDWithOutput( result = _writeblk(cardType.blks[i] + j, KEY_B, keyBList->at(i), dataList->at(cardType.blks[i] + j));
"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)))
{
result = util->execCMDWithOutput(
"hf mf wrbl "
+ QString::number(cardType.blks[i] + j)
+ " B "
+ keyBList->at(i)
+ " "
+ dataList->at(cardType.blks[i] + j),
waitTime);
} }
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( result = _writeblk(cardType.blks[i] + j, KEY_A, "FFFFFFFFFFFF", dataList->at(cardType.blks[i] + j));
"hf mf wrbl "
+ QString::number(cardType.blks[i] + j)
+ " A FFFFFFFFFFFF "
+ dataList->at(cardType.blks[i] + j),
waitTime);
} }
} }
} }
@ -765,6 +779,7 @@ void Mifare::saveSniff(const QString& file)
void Mifare::data_syncWithDataWidget(bool syncAll, int block) void Mifare::data_syncWithDataWidget(bool syncAll, int block)
{ {
ui->MF_dataWidget->blockSignals(true);
QString tmp; QString tmp;
if(syncAll) 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->item(block, 2)->setText(tmp);
} }
ui->MF_dataWidget->blockSignals(false);
} }
void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, KeyType keyType) void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, KeyType keyType)
{ {
ui->MF_keyWidget->blockSignals(true);
if(syncAll) if(syncAll)
{ {
for(int i = 0; i < cardType.sector_size; i++) for(int i = 0; i < cardType.sector_size; i++)
@ -816,6 +833,7 @@ void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, KeyType keyType)
else else
ui->MF_keyWidget->item(sector, 2)->setText(keyBList->at(sector)); ui->MF_keyWidget->item(sector, 2)->setText(keyBList->at(sector));
} }
ui->MF_keyWidget->blockSignals(false);
} }
void Mifare::data_clearData() void Mifare::data_clearData()

@ -25,7 +25,7 @@ public:
void snoop(); void snoop();
void list(); void list();
void read(); void read();
void readAll(); void readSelected(const QList<int>& selectedBlocks);
void write(); void write();
void writeAll(); void writeAll();
void dump(); void dump();
@ -105,8 +105,6 @@ public:
void saveSniff(const QString& file); void saveSniff(const QString& file);
void data_fillKeys(); 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<quint8> data_getACBits(const QString &text); static QList<quint8> data_getACBits(const QString &text);
public slots: public slots:
signals: signals:
@ -124,8 +122,9 @@ private:
QRegularExpression* keyPattern; QRegularExpression* keyPattern;
QString bin2text(const QByteArray& buff, int start, int length); QString bin2text(const QByteArray& buff, int start, int length);
//QString _readblk(int blockId, 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); 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 #endif // MIFARE_H

@ -486,10 +486,16 @@ void MainWindow::on_MF_Attack_hardnestedButton_clicked()
mifare->hardnested(); mifare->hardnested();
} }
void MainWindow::on_MF_RW_readAllButton_clicked() void MainWindow::on_MF_RW_readSelectedButton_clicked()
{ {
setState(false); setState(false);
mifare->readAll(); QList<int> 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); setState(true);
} }
@ -919,5 +925,5 @@ void MainWindow::saveClientPath(const QString& path)
void MainWindow::on_testButton_clicked() void MainWindow::on_testButton_clicked()
{ {
mifare->_readsec(0, Mifare::KEY_A, "FFFFFFFFFFFF"); // mifare->_readsec(0, Mifare::KEY_A, "FFFFFFFFFFFF");
} }

@ -77,7 +77,7 @@ private slots:
void on_MF_Sniff_listButton_clicked(); void on_MF_Sniff_listButton_clicked();
void on_MF_RW_readAllButton_clicked(); void on_MF_RW_readSelectedButton_clicked();
void on_MF_RW_readBlockButton_clicked(); void on_MF_RW_readBlockButton_clicked();

@ -6,13 +6,13 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>870</width> <width>970</width>
<height>770</height> <height>770</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>870</width> <width>970</width>
<height>770</height> <height>770</height>
</size> </size>
</property> </property>
@ -631,7 +631,7 @@
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QPushButton" name="MF_RW_readAllButton"> <widget class="QPushButton" name="MF_RW_readSelectedButton">
<property name="text"> <property name="text">
<string>Read Selected</string> <string>Read Selected</string>
</property> </property>

Loading…
Cancel
Save