From 9dcd291894b5555a2cf1cddfe0dd094081a2b9d3 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Mon, 21 Mar 2022 15:45:31 +0800 Subject: [PATCH 01/11] Misc Terminate the child thread properly Optimize write logic --- src/module/mifare.cpp | 6 +++++- src/ui/mainwindow.cpp | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/module/mifare.cpp b/src/module/mifare.cpp index 7f7398e..0531a0c 100644 --- a/src/module/mifare.cpp +++ b/src/module/mifare.cpp @@ -691,10 +691,14 @@ void Mifare::writeSelected(TargetType targetType) { result = _writeblk(item, KEY_B, keyBList->at(data_b2s(item)), dataList->at(item), TARGET_MIFARE); } - if(!result) + if(!result && keyAList->at(data_b2s(item)) != "FFFFFFFFFFFF") { result = _writeblk(item, KEY_A, "FFFFFFFFFFFF", dataList->at(item), TARGET_MIFARE); } + if(!result && keyBList->at(data_b2s(item)) != "FFFFFFFFFFFF") // for access bits like "80 f7 87", the block can only be written with keyB + { + result = _writeblk(item, KEY_B, "FFFFFFFFFFFF", dataList->at(item), TARGET_MIFARE); + } } else // key doesn't matter when writing to Chinese Magic Card and Emulator Memory { diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index d2e338b..59efc1d 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -30,7 +30,9 @@ MainWindow::MainWindow(QWidget *parent): settings->setIniCodec("UTF-8"); pm3Thread = new QThread(this); + connect(QApplication::instance(), &QApplication::aboutToQuit, pm3Thread, &QThread::quit); pm3 = new PM3Process(pm3Thread); + connect(pm3Thread, &QThread::finished, pm3, &PM3Process::deleteLater); pm3Thread->start(); pm3state = false; clientWorkingDir = new QDir; From ef9972d24ad8c2da015710dd1743efd5e553b466 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Tue, 28 Jun 2022 00:27:32 +0800 Subject: [PATCH 02/11] Fix default lf config --- src/ui/mainwindow.ui | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/mainwindow.ui b/src/ui/mainwindow.ui index df5e334..f055503 100644 --- a/src/ui/mainwindow.ui +++ b/src/ui/mainwindow.ui @@ -1454,8 +1454,8 @@ When setting the freq, the "hw setlfdivisor" will also be called. - - + + true From da2f6ead6e5094070ac7cceaf28ddf54a0caa571 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Wed, 23 Nov 2022 14:01:19 +0800 Subject: [PATCH 03/11] Add feedback of failing to start the client plus, make setRequiringOutput() matched in PM3Process::connectPM3() --- src/common/pm3process.cpp | 4 ++++ src/ui/mainwindow.cpp | 9 +++++++++ src/ui/mainwindow.h | 1 + 3 files changed, 14 insertions(+) diff --git a/src/common/pm3process.cpp b/src/common/pm3process.cpp index 0546e2c..9af256b 100644 --- a/src/common/pm3process.cpp +++ b/src/common/pm3process.cpp @@ -13,6 +13,8 @@ PM3Process::PM3Process(QThread* thread, QObject* parent): QProcess(parent) connect(serialListener, &QTimer::timeout, this, &PM3Process::onTimeout); connect(this, &PM3Process::readyRead, this, &PM3Process::onReadyRead); portInfo = nullptr; + + qRegisterMetaType("QProcess::ProcessError"); } void PM3Process::connectPM3(const QString& path, const QStringList args) @@ -61,6 +63,8 @@ void PM3Process::connectPM3(const QString& path, const QStringList args) else kill(); } + + setRequiringOutput(false); } void PM3Process::reconnectPM3() diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 59efc1d..db13580 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -195,6 +195,14 @@ void MainWindow::on_PM3_connectButton_clicked() envSetProcess.kill(); } +void MainWindow::onPM3ErrorOccurred(QProcess::ProcessError error) +{ + qDebug() << "PM3 Error:" << error << pm3->errorString(); + if(error == QProcess::FailedToStart) + QMessageBox::information(this, tr("Info"), tr("Failed to start the client")); + +} + void MainWindow::onPM3StateChanged(bool st, const QString& info) { pm3state = st; @@ -1093,6 +1101,7 @@ void MainWindow::signalInit() connect(this, &MainWindow::reconnectPM3, pm3, &PM3Process::reconnectPM3); connect(pm3, &PM3Process::PM3StatedChanged, this, &MainWindow::onPM3StateChanged); connect(pm3, &PM3Process::PM3StatedChanged, util, &Util::setRunningState); + connect(pm3, &PM3Process::errorOccurred, this, &MainWindow::onPM3ErrorOccurred); connect(this, &MainWindow::killPM3, pm3, &PM3Process::killPM3); connect(this, &MainWindow::setProcEnv, pm3, &PM3Process::setProcEnv); connect(this, &MainWindow::setWorkingDir, pm3, &PM3Process::setWorkingDir); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 5eaef2f..135be32 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -60,6 +60,7 @@ public slots: void MF_onMFCardTypeChanged(int id, bool st); void on_Raw_keyPressed(QObject *obj_addr, QEvent &event); void on_MF_keyWidget_resized(QObject *obj_addr, QEvent &event); + void onPM3ErrorOccurred(QProcess::ProcessError error); private slots: void on_PM3_connectButton_clicked(); From b2cb1ea8e7b404badeff16e1bb1f8de267dc0dbe Mon Sep 17 00:00:00 2001 From: wh201906 Date: Wed, 23 Nov 2022 14:16:51 +0800 Subject: [PATCH 04/11] Show current working directory of GUI in Settings --- src/ui/mainwindow.cpp | 2 ++ src/ui/mainwindow.ui | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index db13580..c74e0f4 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -1064,6 +1064,8 @@ void MainWindow::uiInit() ui->PM3_pathEdit->setText(settings->value("path", "proxmark3").toString()); settings->endGroup(); + ui->Set_Client_GUIWorkingDirLabel->setText(QDir::currentPath()); + settings->beginGroup("Client_Args"); ui->Set_Client_startArgsEdit->setText(settings->value("args", " -f").toString()); settings->endGroup(); diff --git a/src/ui/mainwindow.ui b/src/ui/mainwindow.ui index f055503..9381e7e 100644 --- a/src/ui/mainwindow.ui +++ b/src/ui/mainwindow.ui @@ -2650,6 +2650,23 @@ or the communication between a tag and a reader. Client + + + + GUI working directory: + + + + + + + + + + Qt::Horizontal + + + From a9b19f92d684e1199825c4d0fa06ccd6155bf67f Mon Sep 17 00:00:00 2001 From: wh201906 Date: Wed, 23 Nov 2022 15:26:15 +0800 Subject: [PATCH 05/11] More hints For serial ports which look like PM3 hardware, show a '*' behind them. Show message box if the GUI fails to connect to the hardware --- src/common/pm3process.cpp | 3 +++ src/common/pm3process.h | 1 + src/ui/mainwindow.cpp | 28 +++++++++++++++++++++++----- src/ui/mainwindow.h | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/common/pm3process.cpp b/src/common/pm3process.cpp index 9af256b..73ed3fb 100644 --- a/src/common/pm3process.cpp +++ b/src/common/pm3process.cpp @@ -61,7 +61,10 @@ void PM3Process::connectPM3(const QString& path, const QStringList args) emit PM3StatedChanged(true, result); } else + { + emit HWConnectFailed(); kill(); + } } setRequiringOutput(false); diff --git a/src/common/pm3process.h b/src/common/pm3process.h index 44c7b3e..5ae747b 100644 --- a/src/common/pm3process.h +++ b/src/common/pm3process.h @@ -48,6 +48,7 @@ signals: void PM3StatedChanged(bool st, const QString& info = ""); void newOutput(const QString& output); void changeClientType(Util::ClientType); + void HWConnectFailed(); }; #endif // PM3PROCESS_H diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index c74e0f4..a79bf8c 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -106,18 +106,31 @@ void MainWindow::initUI() // will be called by main.app void MainWindow::on_portSearchTimer_timeout() { - QStringList newPortList; + QStringList newPortList; // for actural port name + QStringList newPortNameList; // for display name +// QStringList portList; foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { -// qDebug() << info.isBusy() << info.isNull() << info.portName() << info.description(); +// qDebug() << info.isNull() << info.portName() << info.description() << info.serialNumber() << info.manufacturer(); if(!info.isNull()) - newPortList << info.portName(); + { + QString idString = (info.description() + info.serialNumber() + info.manufacturer()).toUpper(); + QString portName = info.portName(); + const QString hint = " *"; + newPortList << portName; + if(info.hasProductIdentifier() && info.hasVendorIdentifier() && info.vendorIdentifier() == 0x9AC4 && info.productIdentifier() == 0x4B8F) + portName += hint; + else if(idString.contains("proxmark") || idString.contains("iceman")) + portName += hint; + newPortNameList << portName; + } } if(newPortList != portList) // update PM3_portBox when available ports changed { portList = newPortList; ui->PM3_portBox->clear(); - ui->PM3_portBox->addItems(portList); + for(int i = 0; i < portList.size(); i++) + ui->PM3_portBox->addItem(newPortNameList[i], newPortList[i]); } } @@ -125,7 +138,7 @@ void MainWindow::on_PM3_connectButton_clicked() { qDebug() << "Main:" << QThread::currentThread(); - QString port = ui->PM3_portBox->currentText(); + QString port = ui->PM3_portBox->currentData().toString(); QString startArgs = ui->Set_Client_startArgsEdit->text(); // on RRG repo, if no port is specified, the client will search the available port @@ -200,7 +213,11 @@ void MainWindow::onPM3ErrorOccurred(QProcess::ProcessError error) qDebug() << "PM3 Error:" << error << pm3->errorString(); if(error == QProcess::FailedToStart) QMessageBox::information(this, tr("Info"), tr("Failed to start the client")); +} +void MainWindow::onPM3HWConnectFailed() +{ + QMessageBox::information(this, tr("Info"), tr("Failed to connect to the hardware")); } void MainWindow::onPM3StateChanged(bool st, const QString& info) @@ -1104,6 +1121,7 @@ void MainWindow::signalInit() connect(pm3, &PM3Process::PM3StatedChanged, this, &MainWindow::onPM3StateChanged); connect(pm3, &PM3Process::PM3StatedChanged, util, &Util::setRunningState); connect(pm3, &PM3Process::errorOccurred, this, &MainWindow::onPM3ErrorOccurred); + connect(pm3, &PM3Process::HWConnectFailed, this, &MainWindow::onPM3HWConnectFailed); connect(this, &MainWindow::killPM3, pm3, &PM3Process::killPM3); connect(this, &MainWindow::setProcEnv, pm3, &PM3Process::setProcEnv); connect(this, &MainWindow::setWorkingDir, pm3, &PM3Process::setWorkingDir); diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 135be32..37fccaa 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -61,6 +61,7 @@ public slots: void on_Raw_keyPressed(QObject *obj_addr, QEvent &event); void on_MF_keyWidget_resized(QObject *obj_addr, QEvent &event); void onPM3ErrorOccurred(QProcess::ProcessError error); + void onPM3HWConnectFailed(); private slots: void on_PM3_connectButton_clicked(); From 757fdcfc21e5f80c63b7b765fe1840c07d440998 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Wed, 23 Nov 2022 16:13:15 +0800 Subject: [PATCH 06/11] Misc select available PM3 hardware port when updating the serial port list remove extra empty lines in raw command output by replacing appendPlainText() with insertPlainText() rather than starting the client with QProcess::Text --- src/common/pm3process.cpp | 3 ++- src/ui/mainwindow.cpp | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/common/pm3process.cpp b/src/common/pm3process.cpp index 73ed3fb..19e9012 100644 --- a/src/common/pm3process.cpp +++ b/src/common/pm3process.cpp @@ -28,7 +28,8 @@ void PM3Process::connectPM3(const QString& path, const QStringList args) currArgs = args; // using "-f" option to make the client output flushed after every print. - start(path, args, QProcess::Unbuffered | QProcess::ReadWrite | QProcess::Text); + // single '\r' might appears. Don't use QProcess::Text there or '\r' is ignored. + start(path, args, QProcess::Unbuffered | QProcess::ReadWrite); if(waitForStarted(10000)) { waitForReadyRead(10000); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index a79bf8c..5ff50e0 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -108,7 +108,8 @@ void MainWindow::on_portSearchTimer_timeout() { QStringList newPortList; // for actural port name QStringList newPortNameList; // for display name -// QStringList portList; + const QString hint = " *"; + foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { // qDebug() << info.isNull() << info.portName() << info.description() << info.serialNumber() << info.manufacturer(); @@ -116,7 +117,7 @@ void MainWindow::on_portSearchTimer_timeout() { QString idString = (info.description() + info.serialNumber() + info.manufacturer()).toUpper(); QString portName = info.portName(); - const QString hint = " *"; + newPortList << portName; if(info.hasProductIdentifier() && info.hasVendorIdentifier() && info.vendorIdentifier() == 0x9AC4 && info.productIdentifier() == 0x4B8F) portName += hint; @@ -129,8 +130,15 @@ void MainWindow::on_portSearchTimer_timeout() { portList = newPortList; ui->PM3_portBox->clear(); + int selectId = -1; for(int i = 0; i < portList.size(); i++) + { ui->PM3_portBox->addItem(newPortNameList[i], newPortList[i]); + if(selectId == -1 && newPortNameList[i].endsWith(hint)) + selectId = i; + } + if(selectId != -1) + ui->PM3_portBox->setCurrentIndex(selectId); } } @@ -247,7 +255,8 @@ void MainWindow::on_PM3_disconnectButton_clicked() void MainWindow::refreshOutput(const QString& output) { // qDebug() << "MainWindow::refresh:" << output; - ui->Raw_outputEdit->appendPlainText(output); + ui->Raw_outputEdit->moveCursor(QTextCursor::End); + ui->Raw_outputEdit->insertPlainText(output); ui->Raw_outputEdit->moveCursor(QTextCursor::End); } From 9c89df45198ea4edb2c5b1be680b4e2434500a86 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Thu, 24 Nov 2022 01:24:13 +0800 Subject: [PATCH 07/11] Misc add config file to resource system move language folder --- README.md | 1 - config/config.qrc | 6 ++++++ doc/README/README_zh_CN.md | 1 - {src/i18n => i18n}/en_US.qm | Bin {src/i18n => i18n}/en_US.ts | 0 {src/i18n => i18n}/language.qrc | 0 {src/i18n => i18n}/languages.ini | 2 +- {src/i18n => i18n}/zh_CN.qm | Bin {src/i18n => i18n}/zh_CN.ts | 0 src/Proxmark3GUI.pro | 3 ++- src/common/pm3process.cpp | 2 +- src/common/util.cpp | 19 +++++++++++++---- src/common/util.h | 1 + src/main.cpp | 31 ++++++++++++++------------- src/ui/mainwindow.cpp | 35 ++++++++++++++++++++++++++++--- src/ui/mainwindow.h | 5 ++++- src/ui/mainwindow.ui | 26 ++++++++++++++++++++++- 17 files changed, 103 insertions(+), 29 deletions(-) create mode 100644 config/config.qrc rename {src/i18n => i18n}/en_US.qm (100%) rename {src/i18n => i18n}/en_US.ts (100%) rename {src/i18n => i18n}/language.qrc (100%) rename {src/i18n => i18n}/languages.ini (61%) rename {src/i18n => i18n}/zh_CN.qm (100%) rename {src/i18n => i18n}/zh_CN.ts (100%) diff --git a/README.md b/README.md index a3aa31e..ce9e834 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,6 @@ Great thanks to him. mkdir build && cd build qmake ../src make -j4 && make clean - cp -r ../config ./ ./Proxmark3GUI *** diff --git a/config/config.qrc b/config/config.qrc new file mode 100644 index 0000000..36db67f --- /dev/null +++ b/config/config.qrc @@ -0,0 +1,6 @@ + + + config_official.json + config_rrgv4.13.json + + diff --git a/doc/README/README_zh_CN.md b/doc/README/README_zh_CN.md index 9e050d5..1a6d8eb 100644 --- a/doc/README/README_zh_CN.md +++ b/doc/README/README_zh_CN.md @@ -57,7 +57,6 @@ release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客 mkdir build && cd build qmake ../src make -j4 && make clean - cp -r ../config ./ ./Proxmark3GUI *** diff --git a/src/i18n/en_US.qm b/i18n/en_US.qm similarity index 100% rename from src/i18n/en_US.qm rename to i18n/en_US.qm diff --git a/src/i18n/en_US.ts b/i18n/en_US.ts similarity index 100% rename from src/i18n/en_US.ts rename to i18n/en_US.ts diff --git a/src/i18n/language.qrc b/i18n/language.qrc similarity index 100% rename from src/i18n/language.qrc rename to i18n/language.qrc diff --git a/src/i18n/languages.ini b/i18n/languages.ini similarity index 61% rename from src/i18n/languages.ini rename to i18n/languages.ini index 10c2e3f..d0914d1 100644 --- a/src/i18n/languages.ini +++ b/i18n/languages.ini @@ -1,4 +1,4 @@ [Languages] en_US=English zh_CN=简体中文 -ext=Load from external file +(ext)=Load from external file diff --git a/src/i18n/zh_CN.qm b/i18n/zh_CN.qm similarity index 100% rename from src/i18n/zh_CN.qm rename to i18n/zh_CN.qm diff --git a/src/i18n/zh_CN.ts b/i18n/zh_CN.ts similarity index 100% rename from src/i18n/zh_CN.ts rename to i18n/zh_CN.ts diff --git a/src/Proxmark3GUI.pro b/src/Proxmark3GUI.pro index e915502..d60391e 100644 --- a/src/Proxmark3GUI.pro +++ b/src/Proxmark3GUI.pro @@ -65,4 +65,5 @@ QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI" QMAKE_TARGET_COMPANY = "wh201906" RESOURCES += \ - i18n/language.qrc + ../i18n/language.qrc \ + ../config/config.qrc diff --git a/src/common/pm3process.cpp b/src/common/pm3process.cpp index 19e9012..2b46748 100644 --- a/src/common/pm3process.cpp +++ b/src/common/pm3process.cpp @@ -28,7 +28,7 @@ void PM3Process::connectPM3(const QString& path, const QStringList args) currArgs = args; // using "-f" option to make the client output flushed after every print. - // single '\r' might appears. Don't use QProcess::Text there or '\r' is ignored. + // single '\r' might appear. Don't use QProcess::Text there or '\r' is ignored. start(path, args, QProcess::Unbuffered | QProcess::ReadWrite); if(waitForStarted(10000)) { diff --git a/src/common/util.cpp b/src/common/util.cpp index 9f3199b..21e2aa2 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -123,13 +123,24 @@ bool Util::chooseLanguage(QSettings* guiSettings, QMainWindow* window) delete langSettings; bool isOk = false; QString selectedText = QInputDialog::getItem(window, "", "Choose a language:", langMap.keys(), 0, false, &isOk); - if(isOk) + if(!isOk) + return false; + if(langMap[selectedText] == "(ext)") { - guiSettings->beginGroup("lang"); - guiSettings->setValue("language", langMap[selectedText]); + QString extPath = QFileDialog::getOpenFileName(nullptr, "Select the translation file:"); + if(extPath.isEmpty()) + return false; + + guiSettings->beginGroup("language"); + guiSettings->setValue("extPath", extPath); guiSettings->endGroup(); - guiSettings->sync(); } + + guiSettings->beginGroup("language"); + guiSettings->setValue("name", langMap[selectedText]); + guiSettings->endGroup(); + guiSettings->sync(); + return isOk; } diff --git a/src/common/util.h b/src/common/util.h index 23705d4..bda759b 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "ui_mainwindow.h" diff --git a/src/main.cpp b/src/main.cpp index 40b577b..9b6054f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,33 +27,34 @@ int main(int argc, char *argv[]) QSettings* settings = new QSettings("GUIsettings.ini", QSettings::IniFormat); settings->setIniCodec("UTF-8"); - settings->beginGroup("lang"); - QString currLang = settings->value("language", "").toString(); + settings->beginGroup("language"); + QString languageFile = settings->value("extPath").toString(); + QString languageName = settings->value("name").toString(); settings->endGroup(); - if(currLang == "") + if(languageName == "") { if(Util::chooseLanguage(settings, &w)) { - settings->beginGroup("lang"); - currLang = settings->value("language", "").toString(); + settings->beginGroup("language"); + languageName = settings->value("name").toString(); settings->endGroup(); } else - currLang = "en_US"; + languageName = "en_US"; + } + if(languageName == "(ext)") + { + settings->beginGroup("language"); + languageFile = settings->value("extPath").toString(); + settings->endGroup(); } - if(currLang == "ext") - currLang = QFileDialog::getOpenFileName(nullptr, "Select the translation file:"); else - currLang = ":/i18n/" + currLang + ".qm"; + languageFile = ":/i18n/" + languageName + ".qm"; QTranslator* translator = new QTranslator(&w); - if(translator->load(currLang)) - { + if(translator->load(languageFile)) a.installTranslator(translator); - } else - { - QMessageBox::information(&w, "Error", "Can't load " + currLang + " as translation file."); - } + QMessageBox::information(&w, "Error", "Can't load " + languageFile + " as translation file."); delete settings; w.initUI(); w.show(); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 5ff50e0..0bd31e7 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -2,6 +2,7 @@ #include "ui_mainwindow.h" #include +#include MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) @@ -79,7 +80,11 @@ MainWindow::~MainWindow() void MainWindow::loadConfig() { - QFile configList(ui->Set_Client_configPathEdit->text()); + QString filename = ui->Set_Client_configFileBox->currentData().toString(); + if(filename == "(ext)") + filename = ui->Set_Client_configPathEdit->text(); + qDebug() << "config file:" << filename; + QFile configList(filename); if(!configList.open(QFile::ReadOnly | QFile::Text)) { QMessageBox::information(this, tr("Info"), tr("Failed to load config file")); @@ -1106,11 +1111,27 @@ void MainWindow::uiInit() ui->Set_Client_keepClientActiveBox->setChecked(keepClientActive); settings->endGroup(); + QDirIterator configFiles(":/config/"); + ui->Set_Client_configFileBox->blockSignals(true); + while(configFiles.hasNext()) + { + configFiles.next(); + ui->Set_Client_configFileBox->addItem(configFiles.fileName(), configFiles.filePath()); + } + ui->Set_Client_configFileBox->addItem(tr("External file"), "(ext)"); + + int configId = -1; settings->beginGroup("Client_Env"); ui->Set_Client_envScriptEdit->setText(settings->value("scriptPath").toString()); ui->Set_Client_workingDirEdit->setText(settings->value("workingDir", "../data").toString()); - ui->Set_Client_configPathEdit->setText(settings->value("configPath", "config.json").toString()); + configId = ui->Set_Client_configFileBox->findData(settings->value("configFile")); + ui->Set_Client_configPathEdit->setText(settings->value("extConfigFilePath", "config.json").toString()); settings->endGroup(); + if(configId != -1) + ui->Set_Client_configFileBox->setCurrentIndex(configId); + ui->Set_Client_configFileBox->blockSignals(false); + on_Set_Client_configFileBox_currentIndexChanged(ui->Set_Client_configFileBox->currentIndex()); + ui->MF_RW_keyTypeBox->addItem("A", Mifare::KEY_A); ui->MF_RW_keyTypeBox->addItem("B", Mifare::KEY_B); @@ -1314,7 +1335,7 @@ void MainWindow::on_Set_Client_workingDirEdit_editingFinished() void MainWindow::on_Set_Client_configPathEdit_editingFinished() { settings->beginGroup("Client_Env"); - settings->setValue("configPath", ui->Set_Client_configPathEdit->text()); + settings->setValue("extConfigFilePath", ui->Set_Client_configPathEdit->text()); settings->endGroup(); } @@ -1452,3 +1473,11 @@ void MainWindow::on_LF_LFConf_resetButton_clicked() setState(true); } +void MainWindow::on_Set_Client_configFileBox_currentIndexChanged(int index) +{ + ui->Set_Client_configPathEdit->setVisible(ui->Set_Client_configFileBox->itemData(index).toString() == "(ext)"); + settings->beginGroup("Client_Env"); + settings->setValue("configFile", ui->Set_Client_configFileBox->currentData()); + settings->endGroup(); +} + diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 37fccaa..1fcdb7f 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -51,7 +51,7 @@ public: ~MainWindow(); void initUI(); - bool eventFilter(QObject *watched, QEvent *event); + bool eventFilter(QObject *watched, QEvent *event) override; public slots: void refreshOutput(const QString& output); void refreshCMD(const QString& cmd); @@ -209,6 +209,9 @@ private slots: void on_Set_Client_configPathEdit_editingFinished(); void setState(bool st); + + void on_Set_Client_configFileBox_currentIndexChanged(int index); + private: Ui::MainWindow* ui; QButtonGroup* MFCardTypeBtnGroup; diff --git a/src/ui/mainwindow.ui b/src/ui/mainwindow.ui index 9381e7e..f734d6a 100644 --- a/src/ui/mainwindow.ui +++ b/src/ui/mainwindow.ui @@ -2763,10 +2763,34 @@ or the communication between a tag and a reader. - Config file path(Reconnect to apply): + Config file(Reconnect to apply): + + + + + + QComboBox::AdjustToContents + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + From d8d9178ce8a0ae257b5a83921f24d01c042f3aae Mon Sep 17 00:00:00 2001 From: wh201906 Date: Thu, 24 Nov 2022 01:34:25 +0800 Subject: [PATCH 08/11] Fix PM3 hardware detection --- src/ui/mainwindow.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 0bd31e7..6434627 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -120,12 +120,19 @@ void MainWindow::on_portSearchTimer_timeout() // qDebug() << info.isNull() << info.portName() << info.description() << info.serialNumber() << info.manufacturer(); if(!info.isNull()) { - QString idString = (info.description() + info.serialNumber() + info.manufacturer()).toUpper(); + QString idString = (info.description() + info.serialNumber() + info.manufacturer()).toLower(); QString portName = info.portName(); newPortList << portName; - if(info.hasProductIdentifier() && info.hasVendorIdentifier() && info.vendorIdentifier() == 0x9AC4 && info.productIdentifier() == 0x4B8F) - portName += hint; + if(info.hasVendorIdentifier() && info.hasProductIdentifier()) + { + quint16 vid = info.vendorIdentifier(); + quint16 pid = info.productIdentifier(); + if(vid == 0x9AC4 && pid == 0x4B8F) + portName += hint; + else if(vid == 0x2D2D && pid == 0x504D) + portName += hint; + } else if(idString.contains("proxmark") || idString.contains("iceman")) portName += hint; newPortNameList << portName; From 2b5c94974d2683443f045b5fe1838bfc7ae63938 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Thu, 24 Nov 2022 19:44:59 +0800 Subject: [PATCH 09/11] Add support for rrg v4.15864 Add key result as comment in config files Specify card size in hf mf dump/restore Use regular expression to detect lf config text Skip the useless waiting when hf mf nested detects the static nonce then perform staticnested attack --- config/config.qrc | 3 +- config/config_official.json | 48 +++- ..._rrgv4.13.json => config_rrgv4.13441.json} | 48 +++- config/config_rrgv4.15864.json | 241 ++++++++++++++++++ src/module/lf.cpp | 6 +- src/module/mifare.cpp | 16 +- 6 files changed, 334 insertions(+), 28 deletions(-) rename config/{config_rrgv4.13.json => config_rrgv4.13441.json} (79%) create mode 100644 config/config_rrgv4.15864.json diff --git a/config/config.qrc b/config/config.qrc index 36db67f..6d3107c 100644 --- a/config/config.qrc +++ b/config/config.qrc @@ -1,6 +1,7 @@ config_official.json - config_rrgv4.13.json + config_rrgv4.13441.json + config_rrgv4.15864.json diff --git a/config/config_official.json b/config/config_official.json index 0438ed8..b28c942 100644 --- a/config/config_official.json +++ b/config/config_official.json @@ -10,6 +10,13 @@ "2k": "2", "4k": "4" }, + "//": "|---|----------------|---|----------------|---| ", + "//": "|sec|key A |res|key B |res| ", + "//": "|---|----------------|---|----------------|---| ", + "//": "|000| ffffffffffff | 1 | ffffffffffff | 1 | ", + "//": "......", + "//": "|---|----------------|---|----------------|---| ", + "//": "", "key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|", "key A index": 2, "key B index": 4 @@ -22,6 +29,15 @@ "2k": "2", "4k": "4" }, + "//": "|---|----------------|----------------| ", + "//": "|sec|key A |key B | ", + "//": "|---|----------------|----------------| ", + "//": "|000| ffffffffffff | ffffffffffff | ", + "//": "......", + "//": "|004| ? | ? | ", + "//": "......", + "//": "|---|----------------|----------------| ", + "//": " ", "key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|", "key A index": 2, "key B index": 3 @@ -39,10 +55,22 @@ "cmd": "hf list mf" }, "dump": { - "cmd": "hf mf dump" + "cmd": "hf mf dump ", + "card type": { + "mini": "0", + "1k": "1", + "2k": "2", + "4k": "4" + } }, "restore": { - "cmd": "hf mf restore" + "cmd": "hf mf restore ", + "card type": { + "mini": "0", + "1k": "1", + "2k": "2", + "4k": "4" + } }, "emulator wipe": { "cmd": "hf mf eclr" @@ -192,14 +220,14 @@ "divisor cmd": "hw setlfdivisor " } }, - "t55xx":{ - "clone em410x":{ - "read":"lf search", - "successful read flag":"Valid EM410x ID", - "pattern":"EM TAG ID\\s*:\\s\\K[0-9a-fA-F]{10}", - "clone cmd":"lf em 410xwrite ", - "t5555 flag":"0", - "t55x7 flag":"1" + "t55xx": { + "clone em410x": { + "read": "lf search", + "successful read flag": "Valid EM410x ID", + "pattern": "EM TAG ID\\s*:\\s\\K[0-9a-fA-F]{10}", + "clone cmd": "lf em 410xwrite ", + "t5555 flag": "0", + "t55x7 flag": "1" } } } \ No newline at end of file diff --git a/config/config_rrgv4.13.json b/config/config_rrgv4.13441.json similarity index 79% rename from config/config_rrgv4.13.json rename to config/config_rrgv4.13441.json index 8d5680d..40784b4 100644 --- a/config/config_rrgv4.13.json +++ b/config/config_rrgv4.13441.json @@ -15,6 +15,13 @@ "A": "a", "B": "b" }, + "//": "[+] |-----|----------------|---|----------------|---|", + "//": "[+] | Sec | key A |res| key B |res|", + "//": "[+] |-----|----------------|---|----------------|---|", + "//": "[+] | 000 | ffffffffffff | 1 | ffffffffffff | 1 |", + "//": "......", + "//": "[+] |-----|----------------|---|----------------|---|", + "//": "[+] ( 0:Failed / 1:Success )", "key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|", "key A index": 2, "key B index": 4 @@ -27,6 +34,15 @@ "2k": "2k", "4k": "4k" }, + "//": "[+] |-----|----------------|---|----------------|---|", + "//": "[+] | Sec | key A |res| key B |res|", + "//": "[+] |-----|----------------|---|----------------|---|", + "//": "[+] | 000 | ffffffffffff | 1 | ffffffffffff | 1 |", + "//": "......", + "//": "[+] | 004 | ------------ | 0 | ------------ | 0 |", + "//": "......", + "//": "[+] |-----|----------------|---|----------------|---|", + "//": "[+] ( 0:Failed / 1:Success )", "key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|", "key A index": 2, "key B index": 4 @@ -44,10 +60,22 @@ "cmd": "trace list -t mf" }, "dump": { - "cmd": "hf mf dump" + "cmd": "hf mf dump --", + "card type": { + "mini": "mini", + "1k": "1k", + "2k": "2k", + "4k": "4k" + } }, "restore": { - "cmd": "hf mf restore" + "cmd": "hf mf restore --", + "card type": { + "mini": "mini", + "1k": "1k", + "2k": "2k", + "4k": "4k" + } }, "emulator wipe": { "cmd": "hf mf eclr" @@ -200,14 +228,14 @@ "divisor cmd": "hw setlfdivisor -d " } }, - "t55xx":{ - "clone em410x":{ - "read":"lf em 410x reader", - "successful read flag":"EM 410x ID", - "pattern":"EM 410x ID\\s*\\K[0-9a-fA-F]{10}", - "clone cmd":"lf em 410x clone --id ", - "t5555 flag":"--q5", - "t55x7 flag":"" + "t55xx": { + "clone em410x": { + "read": "lf em 410x reader", + "successful read flag": "EM 410x ID", + "pattern": "EM 410x ID\\s*\\K[0-9a-fA-F]{10}", + "clone cmd": "lf em 410x clone --id ", + "t5555 flag": "--q5", + "t55x7 flag": "" } } } \ No newline at end of file diff --git a/config/config_rrgv4.15864.json b/config/config_rrgv4.15864.json new file mode 100644 index 0000000..a9aad17 --- /dev/null +++ b/config/config_rrgv4.15864.json @@ -0,0 +1,241 @@ +{ + "//": "Based on Proxmark3 rrg repo v4.15864, commit 1f75adc", + "//": "You can change this file if the command format of client changes", + "mifare classic": { + "nested": { + "cmd": "hf mf nested -- --blk - -k ", + "static cmd": "hf mf staticnested -- --blk - -k ", + "card type": { + "mini": "mini", + "1k": "1k", + "2k": "2k", + "4k": "4k" + }, + "key type": { + "A": "a", + "B": "b" + }, + "//": "[+] -----+-----+--------------+---+--------------+----", + "//": "[+] Sec | Blk | key A |res| key B |res", + "//": "[+] -----+-----+--------------+---+--------------+----", + "//": "[+] 000 | 003 | FFFFFFFFFFFF | 1 | FFFFFFFFFFFF | 1", + "//": "......", + "//": "[+] -----+-----+--------------+---+--------------+----", + "//": "[+] ( 0:Failed / 1:Success )", + "key pattern": "\\s*\\d{3}\\s*\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*$", + "key A index": 2, + "key B index": 4 + }, + "check": { + "cmd": "hf mf chk --", + "card type": { + "mini": "mini", + "1k": "1k", + "2k": "2k", + "4k": "4k" + }, + "//": "[+] -----+-----+--------------+---+--------------+----", + "//": "[+] Sec | Blk | key A |res| key B |res", + "//": "[+] -----+-----+--------------+---+--------------+----", + "//": "[+] 000 | 003 | FFFFFFFFFFFF | 1 | FFFFFFFFFFFF | 1", + "//": "......", + "//": "[+] 004 | 019 | ------------ | 0 | ------------ | 0", + "//": "......", + "//": "[+] -----+-----+--------------+---+--------------+----", + "//": "[+] ( 0:Failed / 1:Success )", + "key pattern": "\\s*\\d{3}\\s*\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*$", + "key A index": 2, + "key B index": 4 + }, + "info": { + "cmd": "hf 14a info" + }, + "sniff": { + "cmd": "hf sniff" + }, + "sniff 14a": { + "cmd": "hf 14a sniff" + }, + "list": { + "cmd": "trace list -t mf" + }, + "dump": { + "cmd": "hf mf dump --", + "card type": { + "mini": "mini", + "1k": "1k", + "2k": "2k", + "4k": "4k" + } + }, + "restore": { + "cmd": "hf mf restore --", + "card type": { + "mini": "mini", + "1k": "1k", + "2k": "2k", + "4k": "4k" + } + }, + "emulator wipe": { + "cmd": "hf mf eclr" + }, + "Magic Card wipe": { + "cmd": "hf mf cwipe" + }, + "emulator read block": { + "cmd": "hf mf egetblk --blk ", + "data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}" + }, + "Magic Card read block": { + "cmd": "hf mf cgetblk --blk ", + "data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}" + }, + "normal read block": { + "cmd": "hf mf rdbl --blk - -k ", + "key type": { + "A": "a", + "B": "b" + }, + "data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}" + }, + "darkside": { + "cmd": "hf mf darkside" + }, + "save sniff": { + "cmd": "trace save -f " + }, + "load sniff": { + "cmd": "trace load -f ", + "show cmd": "trace list --buffer -t mf" + }, + "hardnested": { + "cmd": "hf mf hardnested --blk - -k --tblk --t", + "known key type": { + "A": "a", + "B": "b" + }, + "target key type": { + "A": "a", + "B": "b" + } + }, + "normal read sector": { + "cmd": "hf mf rdsc --sec - -k ", + "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 ", + "data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}" + }, + "//": "When writing a block, if the result is not empty and doesn't contain the failed flag, the function will return true", + "normal write block": { + "cmd": "hf mf wrbl --blk - -k -d ", + "key type": { + "A": "a", + "B": "b" + }, + "failed flag": [ + "fail", + "error" + ] + }, + "Magic Card write block": { + "cmd": "hf mf csetblk --blk -d ", + "failed flag": [ + "fail", + "error" + ] + }, + "emulator write block": { + "cmd": "hf mf esetblk --blk -d " + }, + "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 --atqa --sak " + } + }, + "lf": { + "read": { + "cmd": "lf read -v", + "show cmd": "data plot" + }, + "sniff": { + "cmd": "lf sniff -v", + "show cmd": "data plot" + }, + "search": { + "cmd": "lf search -u" + }, + "tune": { + "cmd": "lf tune --divisor " + }, + "get config": { + "cmd": "hw status", + "field start": "LF Sampling config", + "field end": "\\[#\\] \\S", + "divisor": { + "flag": "divisor", + "pattern": "\\d+" + }, + "bits per sample": { + "flag": "bits per sample", + "pattern": "\\d+" + }, + "decimation": { + "flag": "decimation", + "pattern": "\\d+" + }, + "averaging": { + "flag": "averaging", + "pattern": "\\d+", + "replace": { + "yes": "1", + "no": "0", + "Yes": "1", + "No": "0" + } + }, + "trigger threshold": { + "flag": "trigger threshold", + "pattern": "\\d+" + }, + "samples to skip": { + "flag": "samples to skip", + "pattern": "\\d+" + }, + "//": "execute 'cmd' then find parameters between 'field stard' and 'field end'", + "//": "for each line, if the line doesn't have any flag, skip", + "//": "otherwise, delete characters before 'flag' and 'flag' itself, then use 'pattern' to get the parameter", + "//": "If 'replace' dict exists, replace all keys with respective values before getting parameters" + }, + "set config": { + "cmd": "lf config --divisor --bps --dec --avg --trig --skip ", + "divisor cmd": "hw setlfdivisor -d " + } + }, + "t55xx": { + "clone em410x": { + "read": "lf em 410x reader", + "successful read flag": "EM 410x ID", + "pattern": "EM 410x ID\\s*\\K[0-9a-fA-F]{10}", + "clone cmd": "lf em 410x clone --id ", + "t5555 flag": "--q5", + "t55x7 flag": "" + } + } +} \ No newline at end of file diff --git a/src/module/lf.cpp b/src/module/lf.cpp index 758f0f8..98a2899 100644 --- a/src/module/lf.cpp +++ b/src/module/lf.cpp @@ -81,8 +81,10 @@ void LF::getLFConfig() QVariantMap config = configMap["get config"].toMap(); QString cmd = config["cmd"].toString(); result = util->execCMDWithOutput(cmd, 400); - start = result.indexOf(config["field start"].toString()); - end = result.indexOf(config["field end"].toString()); + reMatch = QRegularExpression(config["field start"].toString(), QRegularExpression::MultilineOption).match(result); + start = reMatch.hasMatch() ? reMatch.capturedEnd() : 0; + reMatch = QRegularExpression(config["field end"].toString(), QRegularExpression::MultilineOption).match(result, start); + end = reMatch.hasMatch() ? reMatch.capturedStart() : result.length(); result = result.mid(start, end - start); #if (QT_VERSION <= QT_VERSION_CHECK(5,14,0)) resultList = result.split("\n", QString::SkipEmptyParts); diff --git a/src/module/mifare.cpp b/src/module/mifare.cpp index 0531a0c..53ee243 100644 --- a/src/module/mifare.cpp +++ b/src/module/mifare.cpp @@ -130,7 +130,7 @@ void Mifare::chk() QString cmd = config["cmd"].toString(); int keyAindex = config["key A index"].toInt(); int keyBindex = config["key B index"].toInt(); - QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString()); + QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString(), QRegularExpression::MultilineOption); cmd.replace("", config["card type"].toMap()[cardType.typeText].toString()); result = util->execCMDWithOutput( @@ -169,7 +169,7 @@ void Mifare::nested(bool isStaticNested) cmd = config["cmd"].toString(); int keyAindex = config["key A index"].toInt(); int keyBindex = config["key B index"].toInt(); - QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString()); + QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString(), QRegularExpression::MultilineOption); QRegularExpressionMatch reMatch; QString result; int offset = 0; @@ -212,7 +212,7 @@ void Mifare::nested(bool isStaticNested) } result = util->execCMDWithOutput( cmd, - Util::ReturnTrigger(15000, {"Can't found", "Can't authenticate", keyPattern_res->pattern()}), + Util::ReturnTrigger(15000, {"Quit", "Can't found", "Can't authenticate", keyPattern_res->pattern()}), true); if(result.contains("static") && !isStaticNested) @@ -747,14 +747,20 @@ void Mifare::writeSelected(TargetType targetType) void Mifare::dump() { QVariantMap config = configMap["dump"].toMap(); - util->execCMD(config["cmd"].toString()); + QString cmd = config["cmd"].toString(); + if(cmd.contains("")) + cmd.replace("", config["card type"].toMap()[cardType.typeText].toString()); + util->execCMD(cmd); Util::gotoRawTab(); } void Mifare::restore() { QVariantMap config = configMap["restore"].toMap(); - util->execCMD(config["cmd"].toString()); + QString cmd = config["cmd"].toString(); + if(cmd.contains("")) + cmd.replace("", config["card type"].toMap()[cardType.typeText].toString()); + util->execCMD(cmd); Util::gotoRawTab(); } From 2704b7cfc2620008e82a859b603bf4719310b61f Mon Sep 17 00:00:00 2001 From: wh201906 Date: Thu, 24 Nov 2022 23:46:11 +0800 Subject: [PATCH 10/11] Update translations --- i18n/en_US.qm | Bin 23 -> 33 bytes i18n/en_US.ts | 722 +++++++++++++++++++++++-------------------- i18n/languages.ini | 1 - i18n/zh_CN.qm | Bin 21891 -> 22406 bytes i18n/zh_CN.ts | 720 ++++++++++++++++++++++-------------------- src/Proxmark3GUI.pro | 4 +- src/common/util.cpp | 5 +- 7 files changed, 768 insertions(+), 684 deletions(-) diff --git a/i18n/en_US.qm b/i18n/en_US.qm index 9dad8dffceb9623e88f8b96d9cd0caf25574c6fa..937ea3e78662d66ef3264d8fa715599d03e338ed 100644 GIT binary patch literal 33 ocmcE7ks@*G{hX<16=n7(EZlo{IRgU&YieG6XmAIR#l*-60Q^r2(EtDd literal 23 fcmcE7ks@*G{hX<16=n7(EZlpygMop8iIEWihQJ9+ diff --git a/i18n/en_US.ts b/i18n/en_US.ts index ab3a8ae..e7bdd94 100644 --- a/i18n/en_US.ts +++ b/i18n/en_US.ts @@ -4,35 +4,35 @@ MF_Attack_hardnestedDialog - + Hardnested Attack - + Known Block: - - + + Block: - - + + A - - + + B - + Target Block: @@ -40,107 +40,107 @@ MF_Sim_simDialog - + Simulate - + u - + UID 4 or 7 bytes. If not specified, the UID 4B from emulator memory will be used - + --atqa - + Provide explicit ATQA (2 bytes) - + --sak - + n - + Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite - + i - + Interactive, means that console will not be returned until simulation finishes or is aborted - + x - + Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s) - + e - + set keys found from 'reader attack' to emulator memory (implies x(--crack) and i) - + -v - + verbose output - + f - + Provide explicit SAK (1 byte) - + get UIDs to use for 'reader attack' from file 'f <filename.txt>' (implies x and i) - + r - + Generate random nonces instead of sequential nonces. Standard reader attack won't work with this option, only moebius attack works @@ -148,22 +148,22 @@ MF_UID_parameterDialog - + Set Parameter - + UID: - + ATQA: - + SAK: @@ -171,155 +171,155 @@ MF_trailerDecoderDialog - + Trailer Decoder - + Blocks - + 4 - + 16 - + Trailer Data: (like "FF0780" or "FF 07 80") - + Or set bits manually - + Cx0 - + Cx1 - + Cx2 - + Cx3 - + Data Block Permission: - + Block0 - + Block1 - + Block2 - - + + Read - - + + Write - + Increase - + Decrease/Transfer/Restore - + Trailer Block Permission: - - + + KeyA - + Access Bits - - + + KeyB - + Reference: MF1S70YYX_V1 Product data sheet Rev. 3.2 — 23 November 2017 - + Note:the Access Bits usually contains 4 bytes(8 hex symbols), but only the first 3 bytes matters. You can set the 4th byte randomly. - + Invalid! It could make the whole sector blocked irreversibly! - + Valid - - - - - - + + + + + + Block - + KeyA+B @@ -327,1027 +327,1049 @@ It could make the whole sector blocked irreversibly! MainWindow - + Proxmark3GUI - + Connect - + Disconnect - + Mifare - + Select Trailer - + Card Type - + MINI 320 - + 1K 1024 - + 2K 2048 - + 4K 4096 - + File - - + + Load - - + + Save - - + + Data - + Key - + Attack - + Card Info - + Check Default - + Nested - + Hardnested - + Darkside - + Read/Write - + Block: - + Key: - + Key Type: - + List Data - + LF - + other - + Divisor: - + Actural Freq: 125.000kHz - + Trigger threshold: - + Samples to skip: - + Get Config - + Set Config - - + + Data: - + Normal(Require Password) - + Dump - + Restore - + Chinese Magic Card(Without Password) - + Lock UFUID Card - - + + About UID Card - + Set Parameter - + Wipe - - + + Simulate - - + + Clear - + Client Path: - + Port: - + Refresh Ports - + Select All - + KeyBlocks->Key - + KeyBlocks<-Key - + Fill Keys - + Trailer Decoder - + Set Fonts - - + + Read One - - + + Write One - - - + + + Read Selected - - - + + + Write Selected - - - + + + Sniff - + Sniff(14a) - + LF Config - + Frequency - + 125k - + 134k - + You might need a modified LF antenna if the freq is not 125k/134k. When setting the freq, the "hw setlfdivisor" will also be called. - + Bits per sample: - + Decimation: - + Averaging: - + Reset - + LF Operation - + Search - + Read and search for valid known tag. - + Read - + Sniff low frequency signal with LF field ON. Use this to get raw data from a tag. - + Tune - + Measure LF antenna tuning. If the antenna voltage has a obvious drop after putting card on the antenna, it is likely that the tag is a LF tag. On Iceman/RRG repo, press the button on PM3 to stop measuring - + Sniff low frequency signal with LF field OFF. Use this to get raw data from a reader or the communication between a tag and a reader. - - + + T55xx - + Basic Configuration(Page 0 Block 0) - - + + Hex: - - + + Bin: - - + + Get from Data - - + + Set to Data - - + + Locked: - + Master Key: - + Data Bit Rate: - + eXtended Mode: - - + + Modulation: - + PSK Clock Freq: - + Answer on Request: - + One Time Pad: - + Max Block: - + Password: - + Seq. Terminator: - + Seq. Start Marker: - + Fast Downlink: - + Inverse Data: - + Init-Delay: - + Analog Front-End Option(Page 1 Block 3) - + Option Key: - + Soft Modulation: - + Clamp Voltage: - + Modulation Voltage: - + Clock Detection Threshold: - + Gap Detection Threshold: - + Write Dampling: - + Demod Delay: - + Downlink Protocol: - + T55xx Read Config - + Bit Rate: - + Seq. Term. - + Offset: - + Inverted: - + T5577 - + T5555 - + RawCommand - - + + History: - + ClearHistory - + Send - + ClearOutput - + Settings - + Client - + + GUI working directory: + + + + Preload script path(Reconnect to apply): - + If the client requires some enviroment variables, you can make a script file(*.bat on Windows or *.sh on Linux) to configure them, then put the path of the script there. - + Client working directory(Reconnect to apply): - + On Windows, the client working directory should not be identical to the path of GUI, otherwise the client will use the wrong .dll file. - + Start arguments(Reconnect to apply): - + -f is necessary because the GUI need to handle the output in time. In some cases, the arguments should be set to "-p /dev/<port> -f" or "-p <port> -f". - - Config file path(Reconnect to apply): - - - - + config.json - + Different clients require different config files. You can change the content of config file if the command format changes. - + Keep the client active even the PM3 hardware is disconnected.(Experimental) - + ../data - + <port> -f - + + Config file(Reconnect to apply): + + + + Keep buttons enabled even the client is running or disconnected - + GUI - + Language: - + Choose Language - + (Restart this app to use new language) - - - - - - - - - - - - + + + + + + + + + + + + + + Info - + Plz choose a port first - + Connected - - + + Not Connected - - - + + + Failed to open - + Continue? - + Dock all windows - + Ver: - + Check Update - + Failed to load config file - + Some of the data and key will be cleared. - + Plz select the font of data widget and key widget - + Data must consists of 32 Hex symbols(Whitespace is allowed) - - + + Key must consists of 12 Hex symbols(Whitespace is allowed) - + Plz select the data file: - - - + + + Binary Data Files(*.bin *.dump) - - - + + + All Files(*.*) - + Plz select the key file: - + Plz select the location to save data file: - - - + + + Failed to save to - + Plz select the location to save key file: - - - + + + Binary Key Files(*.bin *.dump) - - + + Failed to start the client + + + + + Failed to connect to the hardware + + + + + Text Data Files(*.txt *.eml) - + Normally, the Block 0 of a typical Mifare card, which contains the UID, is locked during the manufacture. Users cannot write anything to Block 0 or set a new UID to a normal Mifare card. - + Chinese Magic Cards(aka UID Cards) are some special cards whose Block 0 are writeable. And you can change UID by writing to it. - + There are two versions of Chinese Magic Cards, the Gen1 and the Gen2. - + Gen1: - + also called UID card in China. It responses to some backdoor commands so you can access any blocks without password. The Proxmark3 has a bunch of related commands(csetblk, cgetblk, ...) to deal with this type of card, and my GUI also support these commands. - + Gen2: - + doesn't response to the backdoor commands, which means that a reader cannot detect whether it is a Chinese Magic Card or not by sending backdoor commands. - + There are some types of Chinese Magic Card Gen2. - + CUID Card: - + the Block 0 is writeable, you can write to this block repeatedly by normal wrbl command. - + (hf mf wrbl 0 A FFFFFFFFFFFF <the data you want to write>) - + FUID Card: - + you can only write to Block 0 once. After that, it seems like a typical Mifare card(Block 0 cannot be written to). - + (some readers might try changing the Block 0, which could detect the CUID Card. In that case, you should use FUID card.) - + UFUID Card: - + It behaves like a CUID card(or UID card? I'm not sure) before you send some special command to lock it. Once it is locked, you cannot change its Block 0(just like a typical Mifare card). - + Seemingly, these Chinese Magic Cards are more easily to be compromised by Nested Attack(it takes little time to get an unknown key). - + Plz select the trace file: - + Plz select the location to save trace file: - - + + External file + + + + + Trace Files(*.trc) - - + + Idle - + Stop - - + + Sec - + Blk - + KeyA - + KeyB - + HW Version: - + PM3: - + State: - + Running - + Actural Freq: @@ -1355,56 +1377,56 @@ or the communication between a tag and a reader. Mifare - + Success! - - - - - - - + + + + + + + Info - + Plz provide at least one known key - - + + Failed! - + The Access Bits is invalid! It could make the whole sector blocked irreversibly! Continue to write? - + Successful! - + Failed to write to these blocks: - + Select them? - + Failed to read card. @@ -1412,39 +1434,57 @@ Continue to write? T55xxTab - + Clone to T55xx - + Target Type: - + T5555 - + T55x7 - + EM410x - + Read - + Clone + + Util + + + Load from external file + + + + + Choose a language: + + + + + Select the translation file: + + + diff --git a/i18n/languages.ini b/i18n/languages.ini index d0914d1..6d802f0 100644 --- a/i18n/languages.ini +++ b/i18n/languages.ini @@ -1,4 +1,3 @@ [Languages] en_US=English zh_CN=简体中文 -(ext)=Load from external file diff --git a/i18n/zh_CN.qm b/i18n/zh_CN.qm index f2a033678e184c8d6b6529e42bbf79963578aeff..451272513eb3761a82a4f41c9d8259ee0ab2f7da 100644 GIT binary patch delta 2131 zcmZ8h4OCO-8Gde(o7~)75f9ZEa4!`{g1@hs=$Jomfzec$hW zpXd3$w>p`3x)`73=L=`|jWsv)`)WSTZ@cu>Q2=bk)=de9ctCc)-m^-iE30n^aSxdf ztnLNE4gu>=11t8_-}JHfLvnEi5Ht$Ozye@#3nULN0HLLjOwl^@I#|h9m4B?(msRXU4(z4_4o{iQ{22jU>OTG!UjYXg3a6pymAlhj&A|^Q?NDkKGn5t z<{^4&1`U2-5A;xXIsT;Q&-s?^B_-9haD8 z_VnK%wK^3Dyp6QQEFk4(Fn%er%~U4Z71?{=rZPn{Xh$`Wgk{q8xy@H*l5wC+Mq z?-d|65xE&(0P%UqdvgMq#UZb!o3=fSjde$89Svj9BOqoUcAoegcIYLjEp@W2LTkF1 zi0#19;G2{%iO%g&L})8|?;IzI)?%QYhzKgeL-YYFKW03S)dN1`Ope2S=oRAn%w~CG?O_TETL>GHRfcqyin0#0C^`}EXjnHA{|NY5-i$NKR#vVIpcIm%pL1ukL3x zgWr)O&$9lxCxE1KHufqhAKAj{hi?E2m$7LbXNVtvw!oFzTcu%taf;&f!K}S0kd*X& z%r@;kKu+Aic2rlBCEVDPZex^K$aW_Z!NF-#{p~7JE=QWKA!6dTNmq~c5kZ5}oZnNt zpIT}$TmXD?r3d1Z0ByIlIgRGdh?Ke4UjsA~GB2kk4Oe8^3W|%4lKDFw?|)9FpL>&( zjQN`^E5SetU6r-*gh}7XJ~Wa-D{gbj7Bdms&$<2OUo`0xF06-?2)W7?_Gi$05w}G? zLKw#FZ0!J+f5z?FyA7ECbFNyX1ZK0`{w5k=;eM`pEj19;!1aAh7LDD`4IAfB9Rv5U z#_=;Y$gcaN{9vjdMXZtcWO`A=5qWR*0@8d!{@0{Oz?@fks2l097eE7ntHqvSdZ_?kRP6WQFdx9wF2MhwchQ zZHMAm$Pc8!9z}2EBx&F}sOU?fNfxCj`XBBBl4})1hc^PM0L9218{K0@L7hZ}{c?r; z-PBOnlu*!3B1U~B><;oJH=PvTl?T%4c`CgBsF%#*D>RHzy_atZ7kv8YyGi(jA?D(x z!j<-ebS<0|ZoDx>jX`*9i1whw9O0h@ByL)V@Fe3J@KTG5_RW2Cin?4P=N+d4Q!aHX z6S?RImk%asEsJuQoJAPj;)s^bv!~rsHu_RuI!4)9RzxNqRDN`Z2ZaA9KYF~I-cKvf zFLi!juDq-x1de1TDF*rv|G%@ zCP$|}@buq91<71)y}ItcGv;}=OJcdrRAMm}JA8EBu^y)3;+wT!Z$6T>1er)jczN*) zvA#)0s#d7AS+$$37K>@K&G~5CYSL~smK2s5OB_t1r(-Pqyh`b;vo3_65Bk=#Som<+cY9g;YnS5bi b%^FkjGg4?sTZz$9T5PnLt(IpcUg+Sz4~ACT delta 1560 zcmX9;X;4#V6g^4a%kmPUU=1P>h!r#}QG#GWHra%P$TDo42&jhka zF8-RHNwuOWnD7L}MM&P;3YgLf|Dm`JD|@a1!2w8#yACW%Ksj?$IT&)}vhH5L9@s;tf? z0sEx3zr7_!&!u|H22$WMAIGZPm!6mA7v}(Tw@XWeN?;Z%{l1b+T~H~lN-6;SOQgN$ z>HXjg{t&A(`&^Ng8|Kk*w9FE3PsbIqo)T9;FfMx(^%9u9l!K~*mZXlGp(R?}B)8Bo zNL!M`#aHS8huK`(0F_%B%dMFrTRpPAfO%(Jv&_B2P^=(AIRww>+NV*(Sxk4G$>)wc_s#vc*`<$4OLnhEba% zlf+vRU^6*`Fz_I6mN+FEZz?M^#8N+@tlySJ)6}gzbCv@X@04doi)f6;m2KX1@8hlP zP-oNhG%N4EIz^_3DyMF^ldSKic_u!iU38lku5Y02`j{V)s3c)Ilxu2lQApe8+o(%T z=Df_^D<-}hN!!Ku$2urn!#~Yim!0LZE_;0@|7D~H-xR>K%vmI7_@>2ee4}q;%P~JM Gm;V7{w6=o) diff --git a/i18n/zh_CN.ts b/i18n/zh_CN.ts index ba372a9..185d42b 100644 --- a/i18n/zh_CN.ts +++ b/i18n/zh_CN.ts @@ -4,35 +4,35 @@ MF_Attack_hardnestedDialog - + Hardnested Attack Hardnested攻击 - + Known Block: 已知块: - - + + Block: 块: - - + + A - - + + B - + Target Block: 目标块: @@ -40,107 +40,107 @@ MF_Sim_simDialog - + Simulate 模拟 - + u - + UID 4 or 7 bytes. If not specified, the UID 4B from emulator memory will be used 4或7字节的UID,如果不指定,则使用模拟器内存中的4字节UID - + --atqa - + Provide explicit ATQA (2 bytes) 指定ATQA(2个字节) - + --sak - + Provide explicit SAK (1 byte) 指定SAK(1个字节) - + n - + Automatically exit simulation after <numreads> blocks have been read by reader. 0 = infinite 在读卡器读取<n>个块后自动退出模拟,n为0或不指定时永远不退出 - + i - + Interactive, means that console will not be returned until simulation finishes or is aborted 交互模式,勾选后PM3客户端将在模拟完成或者模拟中断后才可继续使用 - + x - + Crack, performs the 'reader attack', nr/ar attack against a legitimate reader, fishes out the key(s) 破解,对读卡器进行攻击,通过nr/ar攻击来钓出密码(无卡嗅探) - + e - + set keys found from 'reader attack' to emulator memory (implies x(--crack) and i) 在获得密码后自动将密码写入模拟器内存(自动勾选x(--crack)和i) - + -v - + verbose output 更多输出内容 - + f - + get UIDs to use for 'reader attack' from file 'f <filename.txt>' (implies x and i) 从<filename.txt>当中获取用于破解读卡器的UID(批量模拟)(自动勾选x和i) - + r - + Generate random nonces instead of sequential nonces. Standard reader attack won't work with this option, only moebius attack works 生成随机nonce而不是顺序的nonce,这种情况下PM3将不对读卡器进行标准攻击,只进行moebius攻击 @@ -148,22 +148,22 @@ MF_UID_parameterDialog - + Set Parameter 设置卡参数 - + UID: 卡号: - + ATQA: - + SAK: @@ -171,123 +171,123 @@ MF_trailerDecoderDialog - + Trailer Decoder Trailer解码 - + Blocks 块大小 - + 4 - + 16 - + Trailer Data: (like "FF0780" or "FF 07 80") 输入控制位数据 (形如“FF0780”或“FF 07 80”) - + Or set bits manually 手动设置访问情况: - + Cx0 - + Cx1 - + Cx2 - + Cx3 - + Data Block Permission: 数据块访问权限: - + Block0 块0 - + Block1 块1 - + Block2 块2 - - + + Read - - + + Write - + Increase 增加 - + Decrease/Transfer/Restore 减少/从缓冲区写入/读入至缓冲区 - + Trailer Block Permission: Trailer访问权限: - - + + KeyA 密钥A - + Access Bits 控制位 - - + + KeyB 密钥B - + Reference: MF1S70YYX_V1 Product data sheet Rev. 3.2 — 23 November 2017 @@ -296,34 +296,34 @@ MF1S70YYX_V1 Product data sheet Rev. 3.2 — 23 November 2017 - + Note:the Access Bits usually contains 4 bytes(8 hex symbols), but only the first 3 bytes matters. You can set the 4th byte randomly. 注意:Access Bits一般包含4个字节(8个16进制字符),但只有前3个字节决定访问情况,最后一个字节可任意设置。 - + Invalid! It could make the whole sector blocked irreversibly! 无效! 可能导致整个扇区被不可逆转地锁定! - + Valid 有效 - - - - - - + + + + + + Block - + KeyA+B 密钥A+B @@ -331,365 +331,365 @@ It could make the whole sector blocked irreversibly! MainWindow - + Proxmark3GUI - + Connect 连接 - + Disconnect 断开 - + Mifare Mifare(IC)卡 - + Select Trailer 选中密码块 - + Card Type 卡片类型 - + MINI 320 - + 1K 1024 - + 2K 2048 - + 4K 4096 - + File 文件 - - + + Load 加载 - - + + Save 保存 - - + + Data 数据 - + Key 密钥 - + Attack 破解 - + Card Info 读卡信息 - + Check Default 验证默认密码 - + Nested Nested攻击 - + Hardnested Hardested攻击 - + Darkside Darkside攻击 - + Read/Write 读/写 - + Block: 块: - + Key: 密钥: - + Key Type: 密钥类型: - + List Data 列出嗅探数据 - - + + Data: 数据: - + Normal(Require Password) 普通卡(需要密码) - + Dump Dump命令 - + Restore Restore命令 - + Chinese Magic Card(Without Password) UID卡(不需要密码) - + Lock UFUID Card 锁定UFUID卡 - - + + About UID Card 关于UID卡 - + Set Parameter 设置卡参数 - + Wipe 擦除 - - + + Simulate 模拟 - - + + Clear 清空 - + Client Path: 客户端路径: - + Port: 端口: - + Refresh Ports 刷新端口 - + Select All 全选 - + KeyBlocks->Key 密码区->密码 - + KeyBlocks<-Key 密码区<-密码 - + Fill Keys 填充密码 - + Trailer Decoder Trailer解码 - + Set Fonts 设置字体 - - + + Read One 读取单个块 - - + + Write One 写入单个块 - - - + + + Read Selected 读取选中块 - - - + + + Write Selected 写入选中块 - - - + + + Sniff 嗅探 - + Sniff(14a) 嗅探(14a) - + LF Config 低频配置 - + Frequency 频率 - + 125k - + 134k - + You might need a modified LF antenna if the freq is not 125k/134k. When setting the freq, the "hw setlfdivisor" will also be called. 如果频率不为125k/134k,则原装天线可能不适用。 设置频率后GUI会使用"hw setlfdivisor"改变底层分频系数。 - + Bits per sample: 采样精度(Bits per sample): - + Decimation: 抽取(Decimation): - + Averaging: 平均化(Averaging): - + Reset 重置 - + LF Operation 低频操作 - + Search 搜索 - + Read and search for valid known tag. 读卡并寻找已知类型的卡 - + Read 读取 - + Sniff low frequency signal with LF field ON. Use this to get raw data from a tag. 激活低频电磁场并读取原始信号。 该功能用于获取卡片原始数据。 - + Tune 调谐 - + Measure LF antenna tuning. If the antenna voltage has a obvious drop after putting card on the antenna, it is likely that the tag is a LF tag. On Iceman/RRG repo, press the button on PM3 to stop measuring @@ -698,7 +698,7 @@ On Iceman/RRG repo, press the button on PM3 to stop measuring 在冰人版固件下,如果需要停止测量,请按下PM3侧面的按钮 - + Sniff low frequency signal with LF field OFF. Use this to get raw data from a reader or the communication between a tag and a reader. @@ -707,499 +707,520 @@ or the communication between a tag and a reader. 或者卡片与读卡器的交互过程。 - - + + T55xx - + Basic Configuration(Page 0 Block 0) 基本配置区(页0 块0) - - + + Hex: 16进制: - - + + Bin: 2进制: - - + + Get from Data 从数据区导入 - - + + Set to Data 导出到数据区 - - + + Locked: 锁定(Locked): - + Master Key: - + Data Bit Rate: 数据比特率(Data Bit Rate): - + eXtended Mode: 扩展模式(eXtended Mode): - - + + Modulation: 调制方式(Modulation): - + PSK Clock Freq: - + Answer on Request: - + One Time Pad: - + Max Block: - + Password: 密码(Password): - + Seq. Terminator: - + Seq. Start Marker: - + Fast Downlink: - + Inverse Data: - + Init-Delay: - + Analog Front-End Option(Page 1 Block 3) 模拟前端选项区(页1 块3) - + Option Key: - + Soft Modulation: - + Clamp Voltage: - + Modulation Voltage: - + Clock Detection Threshold: - + Gap Detection Threshold: - + Write Dampling: - + Demod Delay: - + Downlink Protocol: - + T55xx Read Config T55xx读卡配置区 - + Bit Rate: 比特率(Bit Rate): - + Seq. Term. - + Offset: - + Inverted: - + T5577 - + T5555 - + RawCommand 原始命令 - - + + History: 命令历史: - + ClearHistory 清空历史 - + Send 发送 - + ClearOutput 清空输出 - + Settings 设置 - + Client 客户端 - + + GUI working directory: + GUI工作路径: + + + ../data - + <port> -f - + + Config file(Reconnect to apply): + 配置文件(重连后生效): + + + Language: 语言: - + Choose Language 选择语言 - + (Restart this app to use new language) (重启此程序以使用新语言) - + Keep buttons enabled even the client is running or disconnected 保持所有按钮可点击,即使未连接客户端或有任务正在运行 - + LF 低频 - + other 其它 - + Divisor: 分频系数(Divisor): - + Actural Freq: 125.000kHz 实际频率: 125.000kHz - + Trigger threshold: 触发阈值(Trigger threshold): - + Samples to skip: 跳过前n个采样(Samples to skip): - + Get Config 获取当前配置 - + Set Config 改变当前配置 - + Preload script path(Reconnect to apply): 预加载脚本路径(重连后生效): - + If the client requires some enviroment variables, you can make a script file(*.bat on Windows or *.sh on Linux) to configure them, then put the path of the script there. 如果客户端需要配置环境变量才能正常运行,可以将配置环境变量所需的脚本文件(Windows系统内为*.bat,linux系统内为*.sh)路径填入此处。 - + Client working directory(Reconnect to apply): 客户端工作路径(重连后生效): - + On Windows, the client working directory should not be identical to the path of GUI, otherwise the client will use the wrong .dll file. 在Windows系统中,客户端工作路径与GUI程序所在路径不能相同,否则客户端会使用错误的.dll文件。 - + Start arguments(Reconnect to apply): 启动参数(重连后生效): - + -f is necessary because the GUI need to handle the output in time. In some cases, the arguments should be set to "-p /dev/<port> -f" or "-p <port> -f". -f选项用于使客户端实时返回命令回显,必须添加。部分情况下启动参数需设置为"-p /dev/<port> -f"或"-p <port> -f"。 - Config file path(Reconnect to apply): - 配置文件路径(重连后生效): + 配置文件路径(重连后生效): - + config.json - + Different clients require different config files. You can change the content of config file if the command format changes. 不同客户端需要使用不同的配置文件。若命令格式发生改变,你可以尝试手动修改配置文件以适配。 - + Keep the client active even the PM3 hardware is disconnected.(Experimental) 在PM3断开后保持客户端运行(实验性功能) - + GUI 图形化界面 - - - - - - - - - - - - + + + + + + + + + + + + + + Info 信息 - + Plz choose a port first 请先选择端口 - + Connected 已连接 - - + + Not Connected 未连接 - - - + + + Failed to open 无法打开 - + Continue? 确定? - + Dock all windows 吸附所有悬浮窗口 - + Ver: 版本: - + Check Update 检查更新 - + Failed to load config file 无法打开配置文件 - + + Failed to start the client + 无法启动客户端 + + + + Failed to connect to the hardware + 无法连接到PM3硬件 + + + Some of the data and key will be cleared. 部分数据和密码将被清除 - + Plz select the font of data widget and key widget 请选择数据窗口和密钥窗口的字体 - + Data must consists of 32 Hex symbols(Whitespace is allowed) 数据必须由32个十六进制字符组成(中间可含有空格) - - + + Key must consists of 12 Hex symbols(Whitespace is allowed) 密钥必须由12个十六进制字符组成(中间可含有空格) - + Plz select the data file: 请选择数据文件: - - - + + + Binary Data Files(*.bin *.dump) 二进制数据文件(*.bin *.dump) - - - + + + All Files(*.*) 所有文件(*.*) - + Plz select the key file: 请选择密钥文件: - + Plz select the location to save data file: 请选择数据文件保存的位置: - - - + + + Failed to save to 无法保存至 - + Plz select the location to save key file: 请选择密钥文件保存的位置: - - - + + + Binary Key Files(*.bin *.dump) 二进制密码文件(*.bin *.dump) - - + + Text Data Files(*.txt *.eml) 文本数据文件(*.txt *.eml) @@ -1208,160 +1229,165 @@ or the communication between a tag and a reader. 文本密码文件(*.txt *.eml) - + Normally, the Block 0 of a typical Mifare card, which contains the UID, is locked during the manufacture. Users cannot write anything to Block 0 or set a new UID to a normal Mifare card. 普通Mifare卡的块0无法写入,卡号也不能更改 - + Chinese Magic Cards(aka UID Cards) are some special cards whose Block 0 are writeable. And you can change UID by writing to it. UID卡(在国外叫Chinese Magic Card)的块0可写,卡号可变。 - + There are two versions of Chinese Magic Cards, the Gen1 and the Gen2. 国外把UID卡分为Chinese Magic Card Gen1和Gen2 - + Gen1: - + also called UID card in China. It responses to some backdoor commands so you can access any blocks without password. The Proxmark3 has a bunch of related commands(csetblk, cgetblk, ...) to deal with this type of card, and my GUI also support these commands. 指通常所说的UID卡,可以通过后门指令直接读写块而无需密码,在PM3和此GUI中有特殊命令处理这类卡片 - + Gen2: - + doesn't response to the backdoor commands, which means that a reader cannot detect whether it is a Chinese Magic Card or not by sending backdoor commands. 这个叫法在国内比较罕见,在国外指CUID/FUID/UFUID这类对后门指令不响应的卡(防火墙卡) - + There are some types of Chinese Magic Card Gen2. 以下是Gen2卡的详细介绍 - + CUID Card: CUID卡: - + the Block 0 is writeable, you can write to this block repeatedly by normal wrbl command. 可通过普通的写块命令来写块0,可重复擦写 - + (hf mf wrbl 0 A FFFFFFFFFFFF <the data you want to write>) (hf mf wrbl 0 A FFFFFFFFFFFF <待写入数据>) - + FUID Card: FUID卡: - + you can only write to Block 0 once. After that, it seems like a typical Mifare card(Block 0 cannot be written to). 块0只能写入一次 - + (some readers might try changing the Block 0, which could detect the CUID Card. In that case, you should use FUID card.) (更高级的穿防火墙卡,可以过一些能识别出CUID卡的读卡器) - + UFUID Card: UFUID卡: - + It behaves like a CUID card(or UID card? I'm not sure) before you send some special command to lock it. Once it is locked, you cannot change its Block 0(just like a typical Mifare card). 锁卡前和普通UID/CUID卡一样可以反复读写块0,用特殊命令锁卡后就和FUID卡一样了 - + Seemingly, these Chinese Magic Cards are more easily to be compromised by Nested Attack(it takes little time to get an unknown key). 所有UID卡都似乎更容易被Nested攻击破解 - + Plz select the trace file: 请选择trace文件: - + Plz select the location to save trace file: 请选择trace文件保存的位置: - - + + External file + 外部文件 + + + + Trace Files(*.trc) Trace文件(*.trc) - - + + Idle 空闲 - + Stop 停止 - - + + Sec 扇区 - + Blk - + KeyA 密钥A - + KeyB 密钥B - + HW Version: 固件版本: - + PM3: 连接状态: - + State: 运行状态: - + Running 正在运行 - + Actural Freq: 实际频率: @@ -1369,34 +1395,34 @@ or the communication between a tag and a reader. Mifare - + Success! 成功! - - - - - - - + + + + + + + Info 信息 - + Plz provide at least one known key 请至少提供一个已知密码 - - + + Failed! 失败! - + The Access Bits is invalid! It could make the whole sector blocked irreversibly! Continue to write? @@ -1405,22 +1431,22 @@ Continue to write? 确定要写入吗? - + Successful! 成功! - + Failed to write to these blocks: 写入以下块失败: - + Select them? 选中这些块? - + Failed to read card. 读卡失败。 @@ -1428,39 +1454,57 @@ Continue to write? T55xxTab - + Clone to T55xx 复制到T55xx卡 - + Target Type: 目标卡片类型: - + T5555 - + T55x7 - + EM410x - + Read 读卡 - + Clone 复制 + + Util + + + Load from external file + 从外部文件加载 + + + + Choose a language: + 选择语言: + + + + Select the translation file: + 选择翻译文件: + + diff --git a/src/Proxmark3GUI.pro b/src/Proxmark3GUI.pro index d60391e..92374cc 100644 --- a/src/Proxmark3GUI.pro +++ b/src/Proxmark3GUI.pro @@ -51,8 +51,8 @@ FORMS += \ ui/mf_attack_hardnesteddialog.ui TRANSLATIONS += \ - i18n/zh_CN.ts \ - i18n/en_US.ts + ../i18n/zh_CN.ts \ + ../i18n/en_US.ts # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin diff --git a/src/common/util.cpp b/src/common/util.cpp index 21e2aa2..0130a42 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -119,15 +119,16 @@ bool Util::chooseLanguage(QSettings* guiSettings, QMainWindow* window) QStringList langList = langSettings->allKeys(); for(int i = 0; i < langList.size(); i++) langMap.insert(langSettings->value(langList[i]).toString(), langList[i]); + langMap.insert(tr("Load from external file"), "(ext)"); langSettings->endGroup(); delete langSettings; bool isOk = false; - QString selectedText = QInputDialog::getItem(window, "", "Choose a language:", langMap.keys(), 0, false, &isOk); + QString selectedText = QInputDialog::getItem(window, "", tr("Choose a language:"), langMap.keys(), 0, false, &isOk); if(!isOk) return false; if(langMap[selectedText] == "(ext)") { - QString extPath = QFileDialog::getOpenFileName(nullptr, "Select the translation file:"); + QString extPath = QFileDialog::getOpenFileName(nullptr, tr("Select the translation file:")); if(extPath.isEmpty()) return false; From ce973fda9684ca50d782f301c8c97a69d5b72769 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Fri, 25 Nov 2022 01:10:37 +0800 Subject: [PATCH 11/11] V0.2.6 Update deploy/deploy.py --- CHANGELOG.md | 17 ++++++-- deploy/deploy.py | 67 +++++++++++++++++++++----------- doc/CHANGELOG/CHANGELOG_zh_CN.md | 11 ++++++ src/Proxmark3GUI.pro | 2 +- 4 files changed, 71 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 698e40f..9b55da5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,15 +2,26 @@ [中文](doc/CHANGELOG/CHANGELOG_zh_CN.md) +### V0.2.6 ++ Add support for Iceman/RRG repo v4.15864 [#37](https://github.com/wh201906/Proxmark3GUI/issues/37) ++ Optimize mifare classic block writing logic ++ Fix the default lf config ++ Add feedback for the GUI failing to start the client ++ Add feedback for the client failing to connect to PM3 hardware ++ Detect PM3 hardware when searching serial ports ++ Remove extra empty lines in raw command output ++ Use embedded config files ++ Remove the wait time between performing nested attack then switching to staticnested attack + ### V0.2.5 -+ Fix bug [#28](https://github.com/wh201906/Proxmark3GUI/issues/28) ++ Fix bug [#28](https://github.com/wh201906/Proxmark3GUI/issues/28) ### V0.2.4 + Clone EM410x card to T55xx card ### V0.2.3 -+ Fix bug [#27](https://github.com/wh201906/Proxmark3GUI/issues/27) -+ Try to support Non-ASCII path ++ Fix bug [#27](https://github.com/wh201906/Proxmark3GUI/issues/27) ++ Try to support Non-ASCII path ### V0.2.2 + Load command format from external json file diff --git a/deploy/deploy.py b/deploy/deploy.py index 44ced91..f11e277 100644 --- a/deploy/deploy.py +++ b/deploy/deploy.py @@ -1,17 +1,19 @@ import os, sys, shutil from win32api import GetFileVersionInfo from json import load -from re import fullmatch, IGNORECASE +from re import fullmatch, sub, IGNORECASE compressDirList = [] def getPEVersion(fname): try: - fileInfo = GetFileVersionInfo(fname, '\\') - version = "V%d.%d.%d" % (fileInfo['FileVersionMS'] / 65536, - fileInfo['FileVersionMS'] % 65536, - fileInfo['FileVersionLS'] / 65536) + fileInfo = GetFileVersionInfo(fname, "\\") + version = "V%d.%d.%d" % ( + fileInfo["FileVersionMS"] / 65536, + fileInfo["FileVersionMS"] % 65536, + fileInfo["FileVersionLS"] / 65536, + ) except Exception: print("Cannot get version number of", fname) return version @@ -19,7 +21,7 @@ def getPEVersion(fname): os.chdir(sys.path[0]) print("Current Directory:", os.getcwd()) -targetName = os.path.abspath(os.getcwd()).split('\\')[-2] +targetName = os.path.abspath(os.getcwd()).split("\\")[-2] print("Target Name", targetName) src32Dir = "" @@ -63,11 +65,6 @@ elif not os.path.exists(dst32Dir): print(dst32Dir, "doesn't exist, creating...") shutil.copytree("./32", dst32Dir) shutil.copyfile(src32Path, dst32Path) -configPath = dst32Dir + "/config" -if os.path.exists(configPath): - print(configPath, "exists, replacing...") - shutil.rmtree(configPath) -shutil.copytree("../config", configPath) compressDirList.append(dst32Dir) if os.path.exists(dst64Dir) and os.path.exists(dst64Path): @@ -77,19 +74,23 @@ elif not os.path.exists(dst64Dir): print(dst64Dir, "doesn't exist, creating...") shutil.copytree("./64", dst64Dir) shutil.copyfile(src64Path, dst64Path) -configPath = dst64Dir + "/config" -if os.path.exists(configPath): - print(configPath, "exists, replacing...") - shutil.rmtree(configPath) -shutil.copytree("../config", configPath) compressDirList.append(dst64Dir) # TODO: GUI+client clientList = [ - "official-v3.1.0", "rrg_other-v4.13441", "rrg_other-v4.14434", - "rrg_other-v4.14831" + "official-v3.1.0", + "rrg_other-v4.13441", + "rrg_other-v4.14434", + "rrg_other-v4.14831", + "rrg_other-v4.15864", ] +configList = [] +for config in os.listdir("../config"): + configPath = os.path.join("../config", config) + if os.path.isfile(configPath) and config.endswith(".json"): + configList.append(config) + def generateClient(clientName): global compressDirList @@ -105,12 +106,34 @@ def generateClient(clientName): shutil.copytree(clientSrcDir, clientDstDir) shutil.copytree(dst64Dir, clientDstGUIDir) if "official" in clientName: - shutil.copyfile("./client/GUIsettings_Official.ini", - clientDstGUIDir + "/GUIsettings.ini") + shutil.copyfile( + "./client/GUIsettings_Official.ini", clientDstGUIDir + "/GUIsettings.ini" + ) elif "rrg" in clientName: - shutil.copyfile("./client/GUIsettings_RRG.ini", - clientDstGUIDir + "/GUIsettings.ini") + shutil.copyfile( + "./client/GUIsettings_RRG.ini", clientDstGUIDir + "/GUIsettings.ini" + ) + # Use exactly matched configFile if possible + version = clientName[clientName.find("v") :] + for config in configList: + if version in config: + print("Find matched config file", config) + with open( + clientDstGUIDir + "/GUIsettings.ini", "r", encoding="utf-8" + ) as f: + data = f.read() + data = sub( + "configFile=:/config/.+\\.json", + "configFile=:/config/" + config, + data, + ) + with open( + clientDstGUIDir + "/GUIsettings.ini", "w", encoding="utf-8" + ) as f: + f.write(data) + compressDirList.append(clientDstDir) + return clientDstDir for cl in clientList: diff --git a/doc/CHANGELOG/CHANGELOG_zh_CN.md b/doc/CHANGELOG/CHANGELOG_zh_CN.md index f71b335..8e660a4 100644 --- a/doc/CHANGELOG/CHANGELOG_zh_CN.md +++ b/doc/CHANGELOG/CHANGELOG_zh_CN.md @@ -2,6 +2,17 @@ [English](../../CHANGELOG.md) +### V0.2.6 ++ 支持冰人版客户端 v4.15864 [#37](https://github.com/wh201906/Proxmark3GUI/issues/37) ++ 优化Mifare Classic卡写卡逻辑 ++ 修复lf config默认配置 ++ 添加客户端无法启动的提示 ++ 添加PM3硬件连接失败的提示 ++ 为PM3对应串口添加提示,并自动选中 ++ 修复原始指令框中有多余空行的问题 ++ 内嵌不同客户端的配置文件 ++ 去除从nested attack切换到staticnested attack的等待时间 + ### V0.2.5 + 修复 [#28](https://github.com/wh201906/Proxmark3GUI/issues/28) diff --git a/src/Proxmark3GUI.pro b/src/Proxmark3GUI.pro index 92374cc..761d1fa 100644 --- a/src/Proxmark3GUI.pro +++ b/src/Proxmark3GUI.pro @@ -59,7 +59,7 @@ qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target -VERSION = 0.2.5 +VERSION = 0.2.6 QMAKE_TARGET_PRODUCT = "Proxmark3GUI" QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI" QMAKE_TARGET_COMPANY = "wh201906"