diff --git a/common/pm3process.cpp b/common/pm3process.cpp index 35d59e1..f107060 100644 --- a/common/pm3process.cpp +++ b/common/pm3process.cpp @@ -12,9 +12,10 @@ PM3Process::PM3Process(QThread* thread, QObject* parent): QProcess(parent) serialListener->setTimerType(Qt::VeryCoarseTimer); connect(serialListener, &QTimer::timeout, this, &PM3Process::onTimeout); connect(this, &PM3Process::readyRead, this, &PM3Process::onReadyRead); + portInfo = nullptr; } -void PM3Process::connectPM3(const QString& path, const QString& port, const QStringList args) +void PM3Process::connectPM3(const QString& path, const QStringList args) { QString result; Util::ClientType clientType; @@ -22,7 +23,6 @@ void PM3Process::connectPM3(const QString& path, const QString& port, const QStr // stash for reconnect currPath = path; - currPort = port; currArgs = args; // using "-f" option to make the client output flushed after every print. @@ -55,11 +55,6 @@ void PM3Process::connectPM3(const QString& path, const QString& port, const QStr result = result.left(result.indexOf("\r\n")); result = result.mid(3, result.lastIndexOf(" ") - 3); emit PM3StatedChanged(true, result); - - // if the arguments don't contain , then disable the port listener - // useful when using offline sniff - if(args.indexOf(port) != -1) - setSerialListener(port, true); } else kill(); @@ -68,7 +63,7 @@ void PM3Process::connectPM3(const QString& path, const QString& port, const QStr void PM3Process::reconnectPM3() { - connectPM3(currPath, currPort, currArgs); + connectPM3(currPath, currArgs); } void PM3Process::setRequiringOutput(bool st) @@ -87,6 +82,7 @@ void PM3Process::setSerialListener(const QString& name, bool state) { if(state) { + currPort = name; portInfo = new QSerialPortInfo(name); serialListener->start(); qDebug() << serialListener->thread(); @@ -94,10 +90,19 @@ void PM3Process::setSerialListener(const QString& name, bool state) else { serialListener->stop(); - delete portInfo; + if(portInfo != nullptr) + { + delete portInfo; + portInfo = nullptr; + } } } +void PM3Process::setSerialListener(bool state) +{ + setSerialListener(currPort, state); +} + void PM3Process::onTimeout() //when the proxmark3 client is unexpectedly terminated or the PM3 hardware is removed, the isBusy() will return false(only tested on Windows); { // qDebug()<isBusy(); @@ -105,7 +110,7 @@ void PM3Process::onTimeout() //when the proxmark3 client is unexpectedly termina { kill(); emit PM3StatedChanged(false); - setSerialListener("", false); + setSerialListener(false); } } diff --git a/common/pm3process.h b/common/pm3process.h index 7b0e253..3749422 100644 --- a/common/pm3process.h +++ b/common/pm3process.h @@ -23,8 +23,9 @@ public: void testThread(); public slots: - void connectPM3(const QString& path, const QString& port, const QStringList args); + void connectPM3(const QString& path, const QStringList args); void setSerialListener(const QString& name, bool state); + void setSerialListener(bool state); qint64 write(QString data); void reconnectPM3(); void setProcEnv(const QStringList* env); @@ -39,7 +40,7 @@ private: QTimer* serialListener; QSerialPortInfo* portInfo; QString currPath; - QString currPort; + QString currPort = ""; QStringList currArgs; signals: diff --git a/lang/en_US.ts b/lang/en_US.ts index 60f26b2..444fe83 100644 --- a/lang/en_US.ts +++ b/lang/en_US.ts @@ -377,13 +377,13 @@ It could make the whole sector blocked irreversibly! - + Save - + Data @@ -479,7 +479,7 @@ It could make the whole sector blocked irreversibly! - + About UID Card @@ -658,76 +658,76 @@ It could make the whole sector blocked irreversibly! - - + + History: - + ClearHistory - + Send - + ClearOutput - + Settings - + Client - + Preload script path: - + Note: 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: - + ../data - + Note: 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 - + <port> -f - + Note: -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" @@ -735,75 +735,80 @@ or "-p <port> -f" - + Keep buttons enabled even the client is running or disconnected - + + Keep te client active even the PM3 hardware is disconnected.(Experimental) + + + + GUI - + Language: - + Choose Language - + (Restart this app to use new language) - - - - - - - - - - - + + + + + + + + + + + Info - + Plz choose a port first - + Connected - - + + Not Connected - + Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml);;All Files(*.*) - - - + + + Failed to open - + Continue? @@ -813,222 +818,222 @@ or "-p <port> -f" - + 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: - + Plz select the key file: - + Binary Key Files(*.bin *.dump);;Binary Data Files(*.bin *.dump);;All Files(*.*) - + Plz select the location to save data file: - + Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml) - - - + + + Failed to save to - + Plz select the location to save key file: - + Binary Key Files(*.bin *.dump) - + 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: - + Trace Files(*.trc);;All Files(*.*) - + Plz select the location to save trace file: - + Trace Files(*.trc) - - + + Idle - + Stop - - + + Sec - + Blk - + KeyA - + KeyB - + HW Version: - + PM3: - + State: - + Running diff --git a/lang/zh_CN.qm b/lang/zh_CN.qm index 3ab4033..99a5e6b 100644 Binary files a/lang/zh_CN.qm and b/lang/zh_CN.qm differ diff --git a/lang/zh_CN.ts b/lang/zh_CN.ts index 415074d..8dda48b 100644 --- a/lang/zh_CN.ts +++ b/lang/zh_CN.ts @@ -381,13 +381,13 @@ It could make the whole sector blocked irreversibly! - + Save 保存 - + Data 数据 @@ -483,7 +483,7 @@ It could make the whole sector blocked irreversibly! - + About UID Card 关于UID卡 @@ -662,43 +662,43 @@ It could make the whole sector blocked irreversibly! 原始命令 - - + + History: 命令历史: - + ClearHistory 清空历史 - + Send 发送 - + ClearOutput 清空输出 - + Settings 设置 - + Client 客户端 - + Preload script path: 预加载脚本路径: - + Note: 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 @@ -706,34 +706,34 @@ then put the path of the script there 如果客户端需要配置环境变量才能正常运行,可以将配置环境变量所需的脚本文件(Windows系统内为*.bat,linux系统内为*.sh)路径填入此处 - + Client working directory: 客户端工作路径: - + ../data - + Note: 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 启动参数 - + <port> -f - + Note: -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" @@ -744,75 +744,80 @@ or "-p <port> -f" 或"-p <port> -f" - + + Keep te client active even the PM3 hardware is disconnected.(Experimental) + 在PM3断开后保持客户端运行(实验性功能) + + + Language: 语言: - + Choose Language 选择语言 - + (Restart this app to use new language) (重启此程序以使用新语言) - + Keep buttons enabled even the client is running or disconnected 保持所有按钮可点击,即使未连接客户端或有任务正在运行 - + GUI 图形化界面 - - - - - - - - - - - + + + + + + + + + + + Info 信息 - + Plz choose a port first 请先选择端口 - + Connected 已连接 - - + + Not Connected 未连接 - + Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml);;All Files(*.*) 二进制数据文件(*.bin *.dump);;文本数据文件(*.txt *.eml);;所有文件(*.*) - - - + + + Failed to open 无法打开 - + Continue? 确定? @@ -822,222 +827,222 @@ or "-p <port> -f" 检查更新 - + 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: 请选择数据文件: - + Plz select the key file: 请选择密钥文件: - + Binary Key Files(*.bin *.dump);;Binary Data Files(*.bin *.dump);;All Files(*.*) 二进制密钥文件(*.bin *.dump)二进制密钥文件(*.bin *.dump);所有文件(*.*) - + Plz select the location to save data file: 请选择数据文件保存的位置: - + Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml) 二进制数据文件(*.bin *.dump);文本数据文件(*.txt *.eml) - - - + + + Failed to save to 无法保存至 - + Plz select the location to save key file: 请选择密钥文件保存的位置: - + Binary Key Files(*.bin *.dump) 二进制密码文件(*.bin *.dump) - + 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文件: - + Trace Files(*.trc);;All Files(*.*) Trace文件(*.trc);;所有文件(*.*) - + Plz select the location to save trace file: 请选择trace文件保存的位置: - + Trace Files(*.trc) Trace文件(*.trc) - - + + Idle 空闲 - + Stop 停止 - - + + Sec 扇区 - + Blk - + KeyA 密钥A - + KeyB 密钥B - + HW Version: 固件版本: - + PM3: 连接状态: - + State: 运行状态: - + Running 正在运行 diff --git a/module/mifare.cpp b/module/mifare.cpp index 204d03a..2ca057e 100644 --- a/module/mifare.cpp +++ b/module/mifare.cpp @@ -1341,3 +1341,10 @@ QList Mifare::data_getACBits(const QString& text) //return empty QList i return result; } +QString Mifare::data_getUID() +{ + if(data_isDataValid(dataList->at(0))) + return dataList->at(0).left(8); + else + return ""; +} diff --git a/module/mifare.h b/module/mifare.h index b50ff33..6c60ab7 100644 --- a/module/mifare.h +++ b/module/mifare.h @@ -111,6 +111,7 @@ public: static QList data_getACBits(const QString& text); static int data_b2s(int block); static bool data_isACBitsValid(const QString& text, QList *returnHalfBytes = nullptr); + QString data_getUID(); public slots: signals: diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 773d42e..bab1524 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -89,43 +89,56 @@ void MainWindow::on_PM3_connectButton_clicked() qDebug() << "Main:" << QThread::currentThread(); QString port = ui->PM3_portBox->currentText(); - if(port == "") - QMessageBox::information(NULL, tr("Info"), tr("Plz choose a port first"), QMessageBox::Ok); - else + QString startArgs = ui->Set_Client_startArgsEdit->text(); + + // on RRG repo, if no port is specified, the client will search the available port + if(port == "" && startArgs.contains("")) // has , no port { - QStringList args = ui->Set_Client_startArgsEdit->text().replace("", port).split(' '); - saveClientPath(ui->PM3_pathEdit->text()); + QMessageBox::information(NULL, tr("Info"), tr("Plz choose a port first"), QMessageBox::Ok); + return; + } - QProcess envSetProcess; - QFileInfo envScriptPath(ui->Set_Client_envScriptEdit->text()); - if(envScriptPath.exists()) - { - qDebug() << envScriptPath.absoluteFilePath(); + if(!startArgs.contains("")) // no + port = ""; // a symbol + + QStringList args = startArgs.replace("", port).split(' '); + saveClientPath(ui->PM3_pathEdit->text()); + + QProcess envSetProcess; + QFileInfo envScriptPath(ui->Set_Client_envScriptEdit->text()); + if(envScriptPath.exists()) + { + qDebug() << envScriptPath.absoluteFilePath(); #ifdef Q_OS_WIN - // cmd /c "">>nul && set - envSetProcess.start("cmd /c \"" + envScriptPath.absoluteFilePath() + "\">>nul && set"); + // cmd /c "">>nul && set + envSetProcess.start("cmd /c \"" + envScriptPath.absoluteFilePath() + "\">>nul && set"); #else - // sh -c '. "">>/dev/null && env' - envSetProcess.start("sh -c \' . \"" + envScriptPath.absoluteFilePath() + "\">>/dev/null && env"); + // sh -c '. "">>/dev/null && env' + envSetProcess.start("sh -c \' . \"" + envScriptPath.absoluteFilePath() + "\">>/dev/null && env"); #endif - envSetProcess.waitForReadyRead(10000); - clientEnv = QString(envSetProcess.readAll()).split(QRegExp("[\r\n]"), QString::SkipEmptyParts); -// qDebug() << "Get Env List" << clientEnv; - } - else - clientEnv.clear(); - emit setProcEnv(&clientEnv); - - clientWorkingDir->setPath(QApplication::applicationDirPath()); - qDebug() << clientWorkingDir->absolutePath(); - clientWorkingDir->mkpath(ui->Set_Client_workingDirEdit->text()); - qDebug() << clientWorkingDir->absolutePath(); - clientWorkingDir->cd(ui->Set_Client_workingDirEdit->text()); - qDebug() << clientWorkingDir->absolutePath(); - emit setWorkingDir(clientWorkingDir->absolutePath()); - - emit connectPM3(ui->PM3_pathEdit->text(), port, args); + envSetProcess.waitForReadyRead(10000); + clientEnv = QString(envSetProcess.readAll()).split(QRegExp("[\r\n]"), QString::SkipEmptyParts); +// qDebug() << "Get Env List" << clientEnv; } + else + clientEnv.clear(); + emit setProcEnv(&clientEnv); + + clientWorkingDir->setPath(QApplication::applicationDirPath()); + qDebug() << clientWorkingDir->absolutePath(); + clientWorkingDir->mkpath(ui->Set_Client_workingDirEdit->text()); + qDebug() << clientWorkingDir->absolutePath(); + clientWorkingDir->cd(ui->Set_Client_workingDirEdit->text()); + qDebug() << clientWorkingDir->absolutePath(); + emit setWorkingDir(clientWorkingDir->absolutePath()); + + emit connectPM3(ui->PM3_pathEdit->text(), args); + if(port != "" && !keepClientActive) + emit setSerialListener(port, true); + else if(!keepClientActive) + emit setSerialListener(false); + + } void MainWindow::onPM3StateChanged(bool st, const QString& info) @@ -149,7 +162,7 @@ void MainWindow::onPM3StateChanged(bool st, const QString& info) void MainWindow::on_PM3_disconnectButton_clicked() { emit killPM3(); - emit setSerialListener("", false); + emit setSerialListener(false); } void MainWindow::refreshOutput(const QString& output) @@ -173,6 +186,7 @@ void MainWindow::on_stopButton_clicked() break; } emit reconnectPM3(); + emit setSerialListener(!keepClientActive); } } // ********************************************************* @@ -608,11 +622,15 @@ void MainWindow::on_MF_File_saveButton_clicked() QString title = ""; QString filename = ""; QString selectedType = ""; + QString defaultName = mifare->data_getUID(); + if(defaultName != "") + defaultName += "_"; + defaultName += QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss"); if(ui->MF_File_dataBox->isChecked()) { title = tr("Plz select the location to save data file:"); - filename = QFileDialog::getSaveFileName(this, title, "./", tr("Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml)"), &selectedType); + filename = QFileDialog::getSaveFileName(this, title, "./data_" + defaultName, tr("Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml)"), &selectedType); qDebug() << filename; if(filename != "") { @@ -625,7 +643,7 @@ void MainWindow::on_MF_File_saveButton_clicked() else if(ui->MF_File_keyBox->isChecked()) { title = tr("Plz select the location to save key file:"); - filename = QFileDialog::getSaveFileName(this, title, "./", tr("Binary Key Files(*.bin *.dump)"), &selectedType); + filename = QFileDialog::getSaveFileName(this, title, "./key_" + defaultName, tr("Binary Key Files(*.bin *.dump)"), &selectedType); qDebug() << filename; if(filename != "") { @@ -994,6 +1012,11 @@ void MainWindow::uiInit() ui->Set_Client_forceEnabledBox->setChecked(keepButtonsEnabled); settings->endGroup(); + settings->beginGroup("Client_keepClientActive"); + keepClientActive = settings->value("state", false).toBool(); + ui->Set_Client_keepClientActiveBox->setChecked(keepClientActive); + settings->endGroup(); + settings->beginGroup("Client_Env"); ui->Set_Client_envScriptEdit->setText(settings->value("scriptPath").toString()); ui->Set_Client_workingDirEdit->setText(settings->value("workingDir", "../data").toString()); @@ -1019,6 +1042,8 @@ void MainWindow::signalInit() connect(this, &MainWindow::killPM3, pm3, &PM3Process::kill); connect(this, &MainWindow::setProcEnv, pm3, &PM3Process::setProcEnv); connect(this, &MainWindow::setWorkingDir, pm3, &PM3Process::setWorkingDir); + connect(this, QOverload::of(&MainWindow::setSerialListener), pm3, QOverload::of(&PM3Process::setSerialListener)); + connect(this, QOverload::of(&MainWindow::setSerialListener), pm3, QOverload::of(&PM3Process::setSerialListener)); connect(util, &Util::write, pm3, &PM3Process::write); @@ -1190,3 +1215,12 @@ void MainWindow::on_Set_Client_saveWorkingDirButton_clicked() settings->setValue("workingDir", ui->Set_Client_workingDirEdit->text()); settings->endGroup(); } + +void MainWindow::on_Set_Client_keepClientActiveBox_stateChanged(int arg1) +{ + settings->beginGroup("Client_keepClientActive"); + keepClientActive = (arg1 == Qt::Checked); + settings->setValue("state", keepClientActive); + settings->endGroup(); + emit setSerialListener(!keepClientActive); +} diff --git a/ui/mainwindow.h b/ui/mainwindow.h index 36a0785..d179581 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "common/myeventfilter.h" #include "common/pm3process.h" @@ -175,6 +176,8 @@ private slots: void on_Set_Client_saveWorkingDirButton_clicked(); + void on_Set_Client_keepClientActiveBox_stateChanged(int arg1); + private: Ui::MainWindow* ui; QButtonGroup* MFCardTypeBtnGroup; @@ -197,6 +200,7 @@ private: PM3Process* pm3; bool pm3state; bool keepButtonsEnabled; + bool keepClientActive; QThread* pm3Thread; QTimer* portSearchTimer; QStringList portList; @@ -214,9 +218,10 @@ private: void setState(bool st); void saveClientPath(const QString& path); signals: - void connectPM3(const QString& path, const QString& port, const QStringList args); + void connectPM3(const QString& path, const QStringList args); void reconnectPM3(); void killPM3(); + void setSerialListener(bool state); void setSerialListener(const QString& name, bool state); void setProcEnv(const QStringList *env); void setWorkingDir(const QString& dir); diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 2135250..3724b36 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -1535,7 +1535,7 @@ Settings - + @@ -1700,6 +1700,45 @@ or "-p <port> -f" + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + Keep te client active even the PM3 hardware is disconnected.(Experimental) + + + true + + + + +