mirror of
				https://github.com/wh201906/Proxmark3GUI.git
				synced 2025-11-04 16:23:23 +08:00 
			
		
		
		
	Support read selected blocks
This commit is contained in:
		
							parent
							
								
									25d7886f2a
								
							
						
					
					
						commit
						4dba7882e5
					
				
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							@ -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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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()
 | 
					void Mifare::write()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int waitTime = 300;
 | 
					    int blockId = ui->MF_RW_blockBox->currentText().toInt();
 | 
				
			||||||
    QString result = util->execCMDWithOutput(
 | 
					    Mifare::KeyType keyType = (Mifare::KeyType)(ui->MF_RW_keyTypeBox->currentData().toInt());
 | 
				
			||||||
                         "hf mf wrbl " + ui->MF_RW_blockBox->currentText() + " " +
 | 
					    bool isSuccessful = _writeblk(blockId, keyType, ui->MF_RW_keyEdit->text().toUpper(), ui->MF_RW_dataEdit->text());
 | 
				
			||||||
                         ui->MF_RW_keyTypeBox->currentText() + " " +
 | 
					    if(isSuccessful)
 | 
				
			||||||
                         ui->MF_RW_keyEdit->text() + " " +
 | 
					 | 
				
			||||||
                         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!"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -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)
 | 
				
			||||||
            if(result.indexOf("isOk:01") == -1 && data_isKeyValid(keyBList->at(i)))
 | 
					 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                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)
 | 
					 | 
				
			||||||
                             + " 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
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                result = util->execCMDWithOutput(
 | 
					 | 
				
			||||||
                             "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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user