From 83445c7eef017d6b12a808f81dbbecbf116834c7 Mon Sep 17 00:00:00 2001 From: wh201906 Date: Sun, 14 Feb 2021 22:47:56 +0800 Subject: [PATCH] Add new features Support change language in Settings Support customized start arguments Strech data section in MF_dataWidget and key section in MF_keyWidget --- common/pm3process.cpp | 4 +- common/pm3process.h | 2 +- common/util.cpp | 24 ++++++ common/util.h | 4 + lang/en_US.ts | 162 ++++++++++++++++++++++------------------ lang/languages.ini | 3 + lang/zh_CN.ts | 170 +++++++++++++++++++++++------------------- main.cpp | 49 ++++++------ ui/mainwindow.cpp | 51 +++++++++---- ui/mainwindow.h | 8 +- ui/mainwindow.ui | 31 +++++--- 11 files changed, 303 insertions(+), 205 deletions(-) diff --git a/common/pm3process.cpp b/common/pm3process.cpp index 8181353..2313ddf 100644 --- a/common/pm3process.cpp +++ b/common/pm3process.cpp @@ -14,14 +14,14 @@ PM3Process::PM3Process(QThread* thread, QObject* parent): QProcess(parent) connect(this, &PM3Process::readyRead, this, &PM3Process::onReadyRead); } -void PM3Process::connectPM3(const QString& path, const QString& port) +void PM3Process::connectPM3(const QString& path, const QString& port, const QStringList args) { QString result; Util::ClientType clientType = Util::CLIENTTYPE_OFFICIAL; setRequiringOutput(true); // using "-f" option to make the client output flushed after every print. - start(path, QStringList() << port << "-f", QProcess::Unbuffered | QProcess::ReadWrite); + start(path, args, QProcess::Unbuffered | QProcess::ReadWrite); if(waitForStarted(10000)) { waitForReadyRead(1000); diff --git a/common/pm3process.h b/common/pm3process.h index 749c501..d6c55a0 100644 --- a/common/pm3process.h +++ b/common/pm3process.h @@ -21,7 +21,7 @@ public: void testThread(); public slots: - void connectPM3(const QString& path, const QString& port); + void connectPM3(const QString& path, const QString& port, const QStringList args); void setSerialListener(const QString& name, bool state); qint64 write(QString data); private slots: diff --git a/common/util.cpp b/common/util.cpp index e9bf045..3443441 100644 --- a/common/util.cpp +++ b/common/util.cpp @@ -93,3 +93,27 @@ void Util::setRunningState(bool st) { this->isRunning = st; } + +bool Util::chooseLanguage(QSettings* guiSettings, QMainWindow* window) +{ + // make sure the GUISettings is not in any group + QSettings* langSettings = new QSettings("lang/languages.ini", QSettings::IniFormat); + QMap langMap; + langSettings->setIniCodec("UTF-8"); + langSettings->beginGroup("Languages"); + QStringList langList = langSettings->allKeys(); + for(int i = 0; i < langList.size(); i++) + langMap.insert(langSettings->value(langList[i]).toString(), langList[i]); + langSettings->endGroup(); + delete langSettings; + bool isOk = false; + QString selectedText = QInputDialog::getItem(window, "", "Choose a language:", langMap.keys(), 0, false, &isOk); + if(isOk) + { + guiSettings->beginGroup("lang"); + guiSettings->setValue("language", langMap[selectedText]); + guiSettings->endGroup(); + guiSettings->sync(); + } + return isOk; +} diff --git a/common/util.h b/common/util.h index 05d0467..3327330 100644 --- a/common/util.h +++ b/common/util.h @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include class Util : public QObject { @@ -51,6 +54,7 @@ public: void delay(unsigned int msec); ClientType getClientType(); static const int rawTabIndex = 1; + static bool chooseLanguage(QSettings *guiSettings, QMainWindow *window); public slots: void processOutput(const QString& output); void setClientType(Util::ClientType clientType); diff --git a/lang/en_US.ts b/lang/en_US.ts index 5a58b0b..2d3f93a 100644 --- a/lang/en_US.ts +++ b/lang/en_US.ts @@ -363,13 +363,12 @@ It could make the whole sector blocked irreversibly! - + Data - Key @@ -465,7 +464,7 @@ It could make the whole sector blocked irreversibly! - + About UID Card @@ -626,7 +625,7 @@ It could make the whole sector blocked irreversibly! - + History: @@ -660,6 +659,11 @@ It could make the whole sector blocked irreversibly! Preload environment variables + + + Variable + + Value @@ -711,55 +715,65 @@ or "-p <port> -f" - - Language + + 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? @@ -769,222 +783,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/languages.ini b/lang/languages.ini index e69de29..439ccd6 100644 --- a/lang/languages.ini +++ b/lang/languages.ini @@ -0,0 +1,3 @@ +[Language] +English=en_US +简体中文=zh_CN \ No newline at end of file diff --git a/lang/zh_CN.ts b/lang/zh_CN.ts index ac86f92..a2abf8a 100644 --- a/lang/zh_CN.ts +++ b/lang/zh_CN.ts @@ -367,13 +367,12 @@ It could make the whole sector blocked irreversibly! - + Data 数据 - Key 密钥 @@ -469,7 +468,7 @@ It could make the whole sector blocked irreversibly! - + About UID Card 关于UID卡 @@ -630,7 +629,7 @@ It could make the whole sector blocked irreversibly! - + History: 命令历史: @@ -664,6 +663,11 @@ It could make the whole sector blocked irreversibly! Preload environment variables 预加载环境变量 + + + Variable + 变量 + Value @@ -709,6 +713,21 @@ or "-p <port> -f" 部分情况下启动参数需设置为"-p /dev/<port> -f" 或"-p <port> -f" + + + Language: + 语言: + + + + Choose Language + 选择语言 + + + + (Restart this app to use new language) + (重启以使用新语言) + Note: -f is necessary because the GUI need to handle the output in time 注意:-f选项用于使客户端实时返回命令回显,必须添加 @@ -724,55 +743,54 @@ or "-p <port> -f" 图形化界面 - Language - 语言 - - - - - - - - - - - - - + 语言 + + + + + + + + + + + + + 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? 确定? @@ -782,222 +800,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/main.cpp b/main.cpp index 94d2ec7..4f87d81 100644 --- a/main.cpp +++ b/main.cpp @@ -4,57 +4,50 @@ #include #include #include -#include +#include int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); QApplication a(argc, argv); MainWindow w; + QSettings* settings = new QSettings("GUIsettings.ini", QSettings::IniFormat); + settings->setIniCodec("UTF-8"); settings->beginGroup("lang"); - QVariant lang = settings->value("language", "null"); - if(lang == "null") + QString currLang = settings->value("language", "").toString(); + settings->endGroup(); + if(currLang == "") { -#ifdef Q_OS_WIN - lang = "lang/en_US.qm"; -#else - lang = "lang/en_US.ts"; -#endif - QStringList langList; - langList.append("English"); - langList.append("简体中文"); - QString seletedText = QInputDialog::getItem(&w, "", "Choose a language:", langList, 0, false); - if(seletedText == "English") + if(Util::chooseLanguage(settings, &w)) { -#ifdef Q_OS_WIN - lang = "lang/en_US.qm"; -#else - lang = "lang/en_US.ts"; -#endif + settings->beginGroup("lang"); + currLang = settings->value("language", "").toString(); + settings->endGroup(); } - else if(seletedText == "简体中文") - { + else + currLang = "en_US"; + } + currLang = "lang/" + currLang; #ifdef Q_OS_WIN - lang = "lang/zh_CN.qm"; + currLang += ".qm"; #else - lang = "lang/zh_CN.ts"; + currLang += ".ts";; #endif - } - } QTranslator* translator = new QTranslator(&w); - if(translator->load(lang.toString())) + if(translator->load(currLang)) { a.installTranslator(translator); - settings->setValue("language", lang); } else { - QMessageBox::information(&w, "Error", "Can't load " + lang.toString() + " as translation file."); + QMessageBox::information(&w, "Error", "Can't load " + currLang + " as translation file."); } - settings->endGroup(); delete settings; w.initUI(); w.show(); return a.exec(); } + + diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index c4d0f7e..8b50189 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -22,6 +22,7 @@ MainWindow::MainWindow(QWidget *parent): this->addAction(checkUpdate); settings = new QSettings("GUIsettings.ini", QSettings::IniFormat); + settings->setIniCodec("UTF-8"); pm3Thread = new QThread(this); pm3 = new PM3Process(pm3Thread); @@ -32,7 +33,7 @@ MainWindow::MainWindow(QWidget *parent): mifare = new Mifare(ui, util, this); keyEventFilter = new MyEventFilter(QEvent::KeyRelease); - + resizeEventFilter = new MyEventFilter(QEvent::Resize); // hide unused tabs ui->funcTab->removeTab(1); @@ -66,7 +67,7 @@ void MainWindow::on_PM3_refreshPortButton_clicked() QStringList serialList; foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { - qDebug() << info.isBusy() << info.isNull() << info.portName(); + qDebug() << info.isBusy() << info.isNull() << info.portName() << info.description(); serial.setPort(info); if(serial.open(QIODevice::ReadWrite)) @@ -89,8 +90,9 @@ void MainWindow::on_PM3_connectButton_clicked() QMessageBox::information(NULL, tr("Info"), tr("Plz choose a port first"), QMessageBox::Ok); else { + QStringList args = ui->Set_Client_startArgsEdit->text().replace("", port).split(' '); saveClientPath(ui->PM3_pathEdit->text()); - emit connectPM3(ui->PM3_pathEdit->text(), port); + emit connectPM3(ui->PM3_pathEdit->text(), port, args); } QProcess proc; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); @@ -240,6 +242,20 @@ void MainWindow::on_Raw_CMDEdit_keyPressed(QObject* obj_addr, QEvent& event) // ***************************************************** // ******************** mifare ******************** +void MainWindow::on_MF_keyWidget_resized(QObject* obj_addr, QEvent& event) +{ + if(obj_addr == ui->MF_keyWidget && event.type() == QEvent::Resize) + { + QTableWidget* widget = (QTableWidget*)obj_addr; + int keyItemWidth = widget->width(); + keyItemWidth -= widget->verticalScrollBar()->width(); + keyItemWidth -= 2 * widget->frameWidth(); + keyItemWidth -= widget->horizontalHeader()->sectionSize(0); + widget->horizontalHeader()->resizeSection(1, keyItemWidth / 2); + widget->horizontalHeader()->resizeSection(2, keyItemWidth / 2); + } +} + void MainWindow::MF_onTypeChanged(int id, bool st) { typeBtnGroup->blockSignals(true); @@ -860,6 +876,8 @@ void MainWindow::uiInit() connect(ui->Raw_CMDEdit, &QLineEdit::editingFinished, this, &MainWindow::sendMSG); ui->Raw_CMDEdit->installEventFilter(keyEventFilter); connect(keyEventFilter, &MyEventFilter::eventHappened, this, &MainWindow::on_Raw_CMDEdit_keyPressed); + ui->MF_keyWidget->installEventFilter(resizeEventFilter); + connect(resizeEventFilter, &MyEventFilter::eventHappened, this, &MainWindow::on_MF_keyWidget_resized); connectStatusBar = new QLabel(this); programStatusBar = new QLabel(this); @@ -904,7 +922,7 @@ void MainWindow::uiInit() settings->beginGroup("UI_grpbox_preference"); QStringList boxNames = settings->allKeys(); - QGroupBox* boxptr; + QGroupBox * boxptr; foreach(QString name, boxNames) { boxptr = this->findChild(name); @@ -932,7 +950,8 @@ void MainWindow::uiInit() settings->endGroup(); settings->beginGroup("Client_forceButtonsEnabled"); - ui->Set_Client_forceEnabledBox->setChecked(settings->value("state", false).toBool()); + keepButtonsEnabled = settings->value("state", false).toBool(); + ui->Set_Client_forceEnabledBox->setChecked(keepButtonsEnabled); settings->endGroup(); ui->MF_RW_keyTypeBox->addItem("A", Mifare::KEY_A); @@ -1036,13 +1055,13 @@ void MainWindow::setState(bool st) { setStatusBar(programStatusBar, tr("Idle")); } - ui->MF_attackGroupBox->setEnabled(st); - ui->MF_normalGroupBox->setEnabled(st); - ui->MF_UIDGroupBox->setEnabled(st); - ui->MF_simGroupBox->setEnabled(st); - ui->MF_sniffGroupBox->setEnabled(st); - ui->Raw_CMDEdit->setEnabled(st); - ui->Raw_sendCMDButton->setEnabled(st); + ui->MF_attackGroupBox->setEnabled(st || keepButtonsEnabled); + ui->MF_normalGroupBox->setEnabled(st || keepButtonsEnabled); + ui->MF_UIDGroupBox->setEnabled(st || keepButtonsEnabled); + ui->MF_simGroupBox->setEnabled(st || keepButtonsEnabled); + ui->MF_sniffGroupBox->setEnabled(st || keepButtonsEnabled); + ui->Raw_CMDEdit->setEnabled(st || keepButtonsEnabled); + ui->Raw_sendCMDButton->setEnabled(st || keepButtonsEnabled); } void MainWindow::on_GroupBox_clicked(bool checked) @@ -1136,8 +1155,14 @@ void MainWindow::on_Set_Client_startArgsEdit_editingFinished() void MainWindow::on_Set_Client_forceEnabledBox_stateChanged(int arg1) { settings->beginGroup("Client_forceButtonsEnabled"); - settings->setValue("state", arg1 == Qt::Checked); + keepButtonsEnabled = (arg1 == Qt::Checked); + settings->setValue("state", keepButtonsEnabled); settings->endGroup(); } + +void MainWindow::on_Set_GUI_setLanguageButton_clicked() +{ + Util::chooseLanguage(settings, this); +} diff --git a/ui/mainwindow.h b/ui/mainwindow.h index e0f9e9d..ebd4791 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "common/myeventfilter.h" #include "common/pm3process.h" @@ -52,6 +53,7 @@ public slots: void onPM3StateChanged(bool st, const QString& info); void MF_onTypeChanged(int id, bool st); void on_Raw_CMDEdit_keyPressed(QObject *obj_addr, QEvent &event); + void on_MF_keyWidget_resized(QObject *obj_addr, QEvent &event); private slots: void on_PM3_connectButton_clicked(); @@ -170,6 +172,8 @@ private slots: void on_Set_Client_envClearButton_clicked(); + void on_Set_GUI_setLanguageButton_clicked(); + private: Ui::MainWindow* ui; QButtonGroup* typeBtnGroup; @@ -182,6 +186,7 @@ private: QAction* checkUpdate; QSettings* settings; MyEventFilter* keyEventFilter; + MyEventFilter* resizeEventFilter; QString stashedCMDEditText; int stashedIndex = -1; @@ -190,6 +195,7 @@ private: PM3Process* pm3; bool pm3state; + bool keepButtonsEnabled; QThread* pm3Thread; Mifare* mifare; @@ -204,7 +210,7 @@ private: void setState(bool st); void saveClientPath(const QString& path); signals: - void connectPM3(const QString& path, const QString& port); + void connectPM3(const QString& path, const QString& port, const QStringList args); void killPM3(); void setSerialListener(const QString& name, bool state); }; diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 813c8c3..642ae2d 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -120,7 +120,7 @@ - 4 + 0 @@ -1559,7 +1559,7 @@ - Key + Variable @@ -1714,17 +1714,28 @@ or "-p <port> -f" GUI - - - - Language - - - - + + + Language: + + + + + + + Choose Language + + + + + + + (Restart this app to use new language) + +