Merge pull request #14 from wh201906/dev

V0.1.4
pull/33/head
wh201906 4 years ago committed by GitHub
commit 7f96c061dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

1
.gitignore vendored

@ -14,7 +14,6 @@
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core

@ -16,6 +16,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
common/myeventfilter.cpp \
main.cpp \
common/pm3process.cpp \
common/util.cpp \
@ -27,6 +28,7 @@ SOURCES += \
ui/mf_attack_hardnesteddialog.cpp \
HEADERS += \
common/myeventfilter.h \
common/pm3process.h \
common/util.h \
module/mifare.h \
@ -52,7 +54,7 @@ qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
VERSION = 0.1.3
VERSION = 0.1.4
QMAKE_TARGET_PRODUCT = "Proxmark3GUI"
QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI"
QMAKE_TARGET_COMPANY = "wh201906"

@ -1,5 +1,7 @@
# Proxmark3GUI
A GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) client
![downloads](https://img.shields.io/github/downloads/wh201906/Proxmark3GUI/total)
A cross-platform GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) client
[中文](README/doc/README_zh_CN.md)
@ -25,32 +27,53 @@ A GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) client
## Preview
![preview](README/img/preview.png)
more previews [here](README/doc/previews.md)
[more previews](README/doc/previews.md)
***
## About Iceman fork/repo
The [Iceman fork/repo](https://github.com/RfidResearchGroup/proxmark3) has more powerful functions like offline sniff. These guys even developed a new hardware called Proxmark3 RDV4 with smart card support. But the official repo and the Iceman repo is not fully compatible.
This GUI was designed for only official repo at first, but I'm trying to make it compatible with Iceman repo.
Supported functions when using Iceman client:
[supported functions](README/doc/supported_Iceman.md)
This GUI is compatible with Iceman/RRG repo(tested on v4.9237)
***
## About Compiled Windows clients
A cool guy [Gator96100](https://github.com/Gator96100) creates [ProxSpace](https://github.com/Gator96100/ProxSpace) and makes it possible to compile both the firmware and client on Windows.
Also, he makes the [pre-compiled Windows client](http://www.proxmark.org/forum/viewtopic.php?id=3975) so you can download it and run your PM3 client on Windows instantly.
Also, he makes the [pre-compiled Windows client](https://www.proxmarkbuilds.org/) so you can download it and run your PM3 client on Windows instantly.
I included his compiled client in my releases so you can use the GUI on the fly, and you can also use the GUI with your prefered client.
Great thanks to him.
***
## Build on Linux
cd ~
git clone https://github.com/wh201906/Proxmark3GUI.git
cd Proxmark3GUI
mkdir build
cd build
qmake ../
make
make clean
cp -r ../lang ./
./Proxmark3GUI
***
## Update Log:
### V0.1.4
+ Optimize performance
+ Optimize UI
+ Search available ports automatically
+ Add High-DPI support
+ Support configuring environment variables by script
(Useful when the client requires specific environment variables)
+ All functions are compatible with Iceman/RRG repo(tested on v4.9237)
+ Fix some bugs
### V0.1.3
+ Fix Trailer Decoder
+ Add feedback when writing selected blocks

@ -1,5 +1,7 @@
# Proxmark3GUI
一个自制的[Proxmark3](https://github.com/Proxmark/proxmark3) GUI
![downloads](https://img.shields.io/github/downloads/wh201906/Proxmark3GUI/total)
一个自制的[Proxmark3](https://github.com/Proxmark/proxmark3) GUI可在Windows/Linux系统下运行
[English](../../README.md)
@ -30,23 +32,47 @@
***
## 关于冰人版
这个GUI一开始是针对官方版本做的现在正在尽力让它兼容冰人版的功能
没钱买RDV4也没钱买两台PM3测一次冰人就要烧一次固件 qwq
[冰人版](https://github.com/RfidResearchGroup/proxmark3)(Iceman/RRG)的客户端和固件更新更为激进,相比官方版具有更多的功能
此GUI所有功能均兼容冰人版在v4.9237上测试通过)
[已支持功能](../doc/supported_Iceman.md)
***
## 关于预编译Windows客户端
国外大佬 [Gator96100](https://github.com/Gator96100) 做了个 [ProxSpace](https://github.com/Gator96100/ProxSpace) 以便在Windows平台上编译PM3固件和客户端他还把自己编译好的客户端放到了[论坛](http://www.proxmark.org/forum/viewtopic.php?id=3975)里面
文件都是放到Google Drive上面的国内网络无法访问所以我在release版本里面放了个带预编译客户端版本的GUI。这个GUI也可以搭配你自己的客户端使用
国外大佬 [Gator96100](https://github.com/Gator96100) 做了个 [ProxSpace](https://github.com/Gator96100/ProxSpace) 以便在Windows平台上编译PM3固件和客户端他还把自己编译好的客户端放到了[网站](https://www.proxmarkbuilds.org/)上
release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客户端使用
(本来打算在CSDN下载里面放几个最新版客户端的结果不能把下载币改为0)
感谢大佬
***
## 在Linux系统下编译
cd ~
git clone https://github.com/wh201906/Proxmark3GUI.git
cd Proxmark3GUI
mkdir build
cd build
qmake ../
make
make clean
cp -r ../lang ./
./Proxmark3GUI
***
## 更新日志:
### V0.1.4
+ 优化性能
+ 优化用户界面
+ 自动搜索可用端口
+ 支持高分屏
+ 可通过外部脚本配置环境变量
(在客户端需要配置环境变量时很有用)
+ 全功能兼容冰人版在v4.9237上测试通过)
+ 修复部分bug
### V0.1.3
+ 修复访问控制位解码器
+ 写多个块时显示写入结果

@ -1,9 +0,0 @@
## About Iceman fork/repo
The [Iceman fork/repo](https://github.com/RfidResearchGroup/proxmark3) has more powerful functions like offline sniff. These guys even developed a new hardware called Proxmark3 RDV4 with smart card support. But the official repo and the Iceman repo is not fully compatible. This GUI was designed for only official repo at first, but I'm trying to make it compatible with Iceman repo.
Supported functions when using Iceman client:
+ Command Line
+ Mifare Card info
+ Mifare Check default keys
+ Mifare Nested Attack
+ Mifare Read/Write

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 49 KiB

@ -0,0 +1,13 @@
#include "myeventfilter.h"
MyEventFilter::MyEventFilter(QEvent::Type filter)
{
targetEventType = filter;
}
bool MyEventFilter::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == targetEventType)
emit eventHappened(obj, *event);
return QObject::eventFilter(obj, event);
}

@ -0,0 +1,22 @@
#ifndef MYEVENTFILTER_H
#define MYEVENTFILTER_H
#include <QObject>
#include <QKeyEvent>
class MyEventFilter : public QObject
{
Q_OBJECT
public:
explicit MyEventFilter(QEvent::Type filter);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
signals:
void eventHappened(QObject* obj_addr, QEvent& event);
private:
QEvent::Type targetEventType;
};
#endif // MYEVENTFILTER_H

@ -14,17 +14,22 @@ 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;
Util::ClientType clientType;
setRequiringOutput(true);
// stash for reconnect
currPath = path;
currPort = port;
currArgs = args;
// 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);
waitForReadyRead(10000);
setRequiringOutput(false);
result = *requiredOutput;
if(result.indexOf("[=]") != -1)
@ -32,10 +37,17 @@ void PM3Process::connectPM3(const QString path, const QString port)
clientType = Util::CLIENTTYPE_ICEMAN;
setRequiringOutput(true);
write("hw version\r\n");
waitForReadyRead(1000);
result = *requiredOutput;
for(int i = 0; i < 10; i++)
{
waitForReadyRead(200);
result += *requiredOutput;
}
setRequiringOutput(false);
}
else
{
clientType = Util::CLIENTTYPE_OFFICIAL;
}
if(result.indexOf("os: ") != -1) // make sure the PM3 is connected
{
emit changeClientType(clientType);
@ -50,6 +62,11 @@ void PM3Process::connectPM3(const QString path, const QString port)
}
}
void PM3Process::reconnectPM3()
{
connectPM3(currPath, currPort, currArgs);
}
void PM3Process::setRequiringOutput(bool st)
{
isRequiringOutput = st;
@ -93,7 +110,6 @@ void PM3Process::testThread()
qDebug() << "PM3:" << QThread::currentThread();
}
qint64 PM3Process::write(QString data)
{
return QProcess::write(data.toLatin1());
@ -111,3 +127,10 @@ void PM3Process::onReadyRead()
}
}
void PM3Process::setProcEnv(const QStringList* env)
{
// qDebug() << "passed Env List" << *env;
this->setEnvironment(*env);
// qDebug() << "final Env List" << processEnvironment().toStringList();
}

@ -8,6 +8,7 @@
#include <QTimer>
#include <QtSerialPort/QSerialPortInfo>
#include <QtSerialPort/QSerialPort>
#include <QProcessEnvironment>
#include "util.h"
@ -21,9 +22,11 @@ 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);
void reconnectPM3();
void setProcEnv(const QStringList* env);
private slots:
void onTimeout();
void onReadyRead();
@ -33,9 +36,13 @@ private:
void setRequiringOutput(bool st);// It only works in this class now
QTimer* serialListener;
QSerialPortInfo* portInfo;
QString currPath;
QString currPort;
QStringList currArgs;
signals:
void PM3StatedChanged(bool st, QString info = "");
void newOutput(QString output);
void PM3StatedChanged(bool st, const QString& info = "");
void newOutput(const QString& output);
void changeClientType(Util::ClientType);
};

@ -1,15 +1,16 @@
#include "util.h"
Util::ClientType Util::clientType = CLIENTTYPE_OFFICIAL;
Util::Util(QObject *parent) : QObject(parent)
{
isRequiringOutput = false;
requiredOutput = new QString();
timeStamp = QTime::currentTime();
this->clientType = CLIENTTYPE_OFFICIAL;
qRegisterMetaType<Util::ClientType>("Util::ClientType");
}
void Util::processOutput(QString output)
void Util::processOutput(const QString& output)
{
// qDebug() << "Util::processOutput:" << output;
if(isRequiringOutput)
@ -20,30 +21,58 @@ void Util::processOutput(QString output)
emit refreshOutput(output);
}
void Util::execCMD(QString cmd)
void Util::execCMD(const QString& cmd)
{
qDebug() << cmd;
qDebug() << "executing: " << cmd;
if(isRunning)
emit write(cmd + "\r\n");
}
QString Util::execCMDWithOutput(QString cmd, unsigned long waitTime)
QString Util::execCMDWithOutput(const QString& cmd, ReturnTrigger trigger)
{
// if the trigger is empty, this function will wait trigger.waitTime then return all outputs during the wait time.
// otherwise, this function will return empty string if no trigger is detected, or return outputs if any trigger is detected.
// the waitTime will be refreshed if the client have new outputs
bool isResultFound = false;
QRegularExpression re;
re.setPatternOptions(QRegularExpression::DotMatchesEverythingOption);
if(!isRunning)
return "";
QTime currTime = QTime::currentTime();
QTime targetTime = QTime::currentTime().addMSecs(waitTime);
QTime targetTime = QTime::currentTime().addMSecs(trigger.waitTime);
isRequiringOutput = true;
requiredOutput->clear();
execCMD(cmd);
while(QTime::currentTime() < targetTime)
{
if(!isRunning)
break;
QApplication::processEvents();
if(timeStamp > currTime)
// qDebug() << "currOutput:" << *requiredOutput;
for(QString otpt : trigger.expectedOutputs)
{
re.setPattern(otpt);
isResultFound = re.match(*requiredOutput).hasMatch();
if(isResultFound)
{
qDebug() << "output Matched: " << *requiredOutput;
break;
}
}
if(isResultFound)
{
delay(200);
break;
}
if(timeStamp > currTime) //has new output
{
currTime = timeStamp;
targetTime = timeStamp.addMSecs(waitTime);
targetTime = timeStamp.addMSecs(trigger.waitTime);
}
}
isRequiringOutput = false;
return *requiredOutput;
return (isResultFound || trigger.expectedOutputs.isEmpty() ? *requiredOutput : "");
}
void Util::delay(unsigned int msec)
@ -52,12 +81,42 @@ void Util::delay(unsigned int msec)
while(QTime::currentTime() < timer)
QApplication::processEvents(QEventLoop::AllEvents, 100);
}
Util::ClientType Util::getClientType()
{
return this->clientType;
return Util::clientType;
}
void Util::setClientType(Util::ClientType clientType)
{
this->clientType = clientType;
Util::clientType = clientType;
}
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<QString, QString> 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;
}

@ -9,6 +9,10 @@
#include <QTime>
#include <QTimer>
#include <QMetaType>
#include <QRegularExpression>
#include <QSettings>
#include <QMainWindow>
#include <QInputDialog>
class Util : public QObject
{
@ -20,26 +24,51 @@ public:
CLIENTTYPE_ICEMAN,
};
struct ReturnTrigger
{
unsigned long waitTime;
QStringList expectedOutputs;
ReturnTrigger(unsigned long time)
{
waitTime = time;
expectedOutputs = QStringList();
}
ReturnTrigger(const QStringList& outputs)
{
waitTime = 10000;
expectedOutputs = outputs;
}
ReturnTrigger(unsigned long time, const QStringList& outputs)
{
waitTime = time;
expectedOutputs = outputs;
}
};
Q_ENUM(Util::ClientType)
explicit Util(QObject *parent = nullptr);
void execCMD(QString cmd);
QString execCMDWithOutput(QString cmd, unsigned long waitTime = 2000);
void execCMD(const QString& cmd);
QString execCMDWithOutput(const QString& cmd, ReturnTrigger trigger = 10000);
void delay(unsigned int msec);
ClientType getClientType();
static ClientType getClientType();
static const int rawTabIndex = 1;
static bool chooseLanguage(QSettings *guiSettings, QMainWindow *window);
public slots:
void processOutput(QString output);
void setClientType(Util::ClientType clientType);
void processOutput(const QString& output);
static void setClientType(Util::ClientType clientType);
void setRunningState(bool st);
private:
bool isRequiringOutput;
bool isRunning;
QString* requiredOutput;
QTime timeStamp;
ClientType clientType;
static ClientType clientType;
signals:
void refreshOutput(const QString& output);
void write(QString data);
void write(QString data); // connected to PM3Process::write(QString data);
};
#endif // UTIL_H

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,3 @@
[Languages]
en_US=English
zh_CN=简体中文

Binary file not shown.

File diff suppressed because it is too large Load Diff

@ -4,56 +4,50 @@
#include <QSettings>
#include <QTranslator>
#include <QMessageBox>
#include <QInputDialog>
#include <QTextCodec>
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();
}

@ -6,7 +6,8 @@ const Mifare::CardType Mifare::card_mini =
5,
20,
{4, 4, 4, 4, 4},
{0, 4, 8, 12, 16}
{0, 4, 8, 12, 16},
"mini"
};
const Mifare::CardType Mifare::card_1k =
{
@ -14,7 +15,8 @@ const Mifare::CardType Mifare::card_1k =
16,
64,
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60}
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60},
"1k"
};
const Mifare::CardType Mifare::card_2k =
{
@ -22,7 +24,8 @@ const Mifare::CardType Mifare::card_2k =
32,
128,
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124}
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124},
"2k"
};
const Mifare::CardType Mifare::card_4k =
{
@ -30,7 +33,8 @@ const Mifare::CardType Mifare::card_4k =
40,
256,
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, 16, 16, 16, 16},
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 144, 160, 176, 192, 208, 224, 240}
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 144, 160, 176, 192, 208, 224, 240},
"4k"
};
const Mifare::AccessType Mifare::dataCondition[8][4] =
@ -79,26 +83,24 @@ Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent): QObject(parent)
data_clearKey(); // fill with blank QString
data_clearData(); // fill with blank QString
dataPattern = new QRegularExpression("([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}");
keyPattern_res = new QRegularExpression("\\|\\d{3}\\|.+?\\|.+?\\|.+?\\|.+?\\|");
keyPattern = new QRegularExpression("\\|\\d{3}\\|.+?\\|.+?\\|");
keyPattern_res = new QRegularExpression("\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|");
keyPattern = new QRegularExpression("\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|");
}
QString Mifare::info(bool isRequiringOutput)
{
if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL || util->getClientType() == Util::CLIENTTYPE_ICEMAN)
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
if(isRequiringOutput)
{
QString result = util->execCMDWithOutput("hf 14a info", 500);
result.replace("UID :", "|||");
result.replace("ATQA :", "|||");
result.replace("SAK :", "|||");
result.replace("TYPE :", "|||");
QStringList lis = result.split("|||");
if(lis.length() > 4)
int begin, end;
begin = result.indexOf("UID");
if(begin != -1)
{
qDebug() << lis[1] + lis[2] + lis[3];
return lis[1] + lis[2] + lis[3];
end = result.indexOf("SAK", begin);
end = result.indexOf("\n", end);
return result.mid(begin, end - begin + 1);
}
else
return "";
@ -106,7 +108,7 @@ QString Mifare::info(bool isRequiringOutput)
else
{
util->execCMD("hf 14a info");
ui->funcTab->setCurrentIndex(1);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
return "";
}
}
@ -115,17 +117,17 @@ QString Mifare::info(bool isRequiringOutput)
void Mifare::chk()
{
QRegularExpressionMatch reMatch;
QString result = util->execCMDWithOutput(
QString result;
int offset = 0;
QString data;
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
result = util->execCMDWithOutput(
"hf mf chk *"
+ QString::number(cardType.type)
+ " ?",
1000 + cardType.type * 1000);
Util::ReturnTrigger(1000 + cardType.sector_size * 200, {"No valid", keyPattern->pattern()}));
qDebug() << result;
int offset = 0;
QString data;
if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
for(int i = 0; i < cardType.sector_size; i++)
{
reMatch = keyPattern->match(result, offset);
@ -146,8 +148,13 @@ void Mifare::chk()
}
}
}
else if(util->getClientType() == Util::CLIENTTYPE_ICEMAN)
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
result = util->execCMDWithOutput(
"hf mf chk --"
+ cardType.typeText,
Util::ReturnTrigger(1000 + cardType.sector_size * 200, {"No valid", keyPattern_res->pattern()}));
qDebug() << "mf_chk_iceman_result" << result;
for(int i = 0; i < cardType.sector_size; i++)
{
reMatch = keyPattern_res->match(result, offset);
@ -178,21 +185,22 @@ void Mifare::nested()
QString result;
int offset = 0;
QString data;
if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL)
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
result = util->execCMDWithOutput(
"hf mf nested "
+ QString::number(cardType.type)
+ " *", 10000);
+ " *",
Util::ReturnTrigger(15000, {"Can't found", "\\|000\\|"}));
}
else if(util->getClientType() == Util::CLIENTTYPE_ICEMAN)
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
QString knownKeyInfo = "";
for(int i = 0; i < cardType.sector_size; i++)
{
if(data_isKeyValid(keyAList->at(i)))
{
knownKeyInfo = " " + QString::number(i * 4) + " A " + keyAList->at(i);
knownKeyInfo = " --blk " + QString::number(i * 4) + " -a -k " + keyAList->at(i);
break;
}
}
@ -202,7 +210,7 @@ void Mifare::nested()
{
if(data_isKeyValid(keyBList->at(i)))
{
knownKeyInfo = " " + QString::number(i * 4) + " B " + keyBList->at(i);
knownKeyInfo = " --blk " + QString::number(i * 4) + " -b -k " + keyBList->at(i);
break;
}
}
@ -210,9 +218,10 @@ void Mifare::nested()
if(knownKeyInfo != "")
{
result = util->execCMDWithOutput(
"hf mf nested "
+ QString::number(cardType.type)
+ knownKeyInfo, 10000);
"hf mf nested --"
+ cardType.typeText
+ knownKeyInfo,
Util::ReturnTrigger(15000, {"Can't authenticate", keyPattern_res->pattern()}));
}
else
{
@ -248,34 +257,57 @@ void Mifare::hardnested()
MF_Attack_hardnestedDialog dialog(cardType.block_size);
connect(&dialog, &MF_Attack_hardnestedDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted)
ui->funcTab->setCurrentIndex(1);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::darkside()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf mf mifare");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf darkside");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::sniff()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf mf sniff");
ui->funcTab->setCurrentIndex(1);
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf sniff");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::snoop()
void Mifare::sniff14a()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf 14a snoop");
ui->funcTab->setCurrentIndex(1);
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf 14a sniff");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::list()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf list mf");
ui->funcTab->setCurrentIndex(1);
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("trace list -t mf");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, TargetType targetType, int waitTime)
{
QString data;
QString result;
bool isKeyBlock = (blockId < 128 && ((blockId + 1) % 4 == 0)) || ((blockId + 1) % 16 == 0);
QRegularExpressionMatch currMatch;
bool isTrailerBlock = (blockId < 128 && ((blockId + 1) % 4 == 0)) || ((blockId + 1) % 16 == 0);
if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL || util->getClientType() == Util::CLIENTTYPE_ICEMAN)
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
if(targetType == TARGET_MIFARE)
{
@ -292,13 +324,14 @@ QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, Targe
+ " "
+ key,
waitTime);
if(result.indexOf("isOk:01") != -1)
currMatch = dataPattern->match(result);
if(currMatch.hasMatch())
{
data = dataPattern->match(result).captured().toUpper();
data = currMatch.captured().toUpper();
data.remove(" ");
// when the target block is a key block and the given key type is KeyA, try to check whether the KeyB is valid(by Access Bits)
// if the given key type is KeyB, it will never get the KeyA from the key block
if(isKeyBlock && keyType == KEY_A) // in this case, the Access Bits is always accessible
if(isTrailerBlock && keyType == KEY_A) // in this case, the Access Bits is always accessible
{
data.replace(0, 12, key);
QList<quint8> ACBits = data_getACBits(data.mid(12, 8));
@ -307,7 +340,7 @@ QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, Targe
data.replace(20, 12, "????????????");
}
}
else if(isKeyBlock && keyType == KEY_B)
else if(isTrailerBlock && keyType == KEY_B)
{
data.replace(20, 12, key);;
data.replace(0, 12, "????????????"); // fill the keyA part with ?
@ -322,15 +355,19 @@ QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, Targe
"hf mf cgetblk "
+ QString::number(blockId),
waitTime);
if(result.indexOf("Chinese magic") != -1)
currMatch = dataPattern->match(result);
if(currMatch.hasMatch())
{
data = dataPattern->match(result).captured().toUpper();
data = currMatch.captured().toUpper();
data.remove(" ");
}
else
data = "";
}
else if(targetType == TARGET_EMULATOR)
}
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
if(targetType == TARGET_EMULATOR)
{
result = util->execCMDWithOutput(
"hf mf eget "
@ -340,6 +377,18 @@ QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, Targe
data.remove(" ");
}
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
if(targetType == TARGET_EMULATOR)
{
result = util->execCMDWithOutput(
"hf mf egetblk "
+ QString::number(blockId),
150);
data = dataPattern->match(result).captured().toUpper();
data.remove(" ");
}
}
return data;
}
@ -348,14 +397,14 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
QStringList data;
QString result, tmp;
QRegularExpressionMatch reMatch;
int offset = -1;
int offset = -1; // for targetType == TARGET_EMULATOR
for(int i = 0; i < cardType.blk[sectorId]; i++)
{
data.append("");
}
if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL || util->getClientType() == Util::CLIENTTYPE_ICEMAN)
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
// try to read all blocks together
if(targetType == TARGET_MIFARE)
@ -372,7 +421,7 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
+ " "
+ key,
waitTime);
offset = result.indexOf("isOk:01");
offset = result.indexOf("isOk:01"); // find successful flag
}
else if(targetType == TARGET_UID)
{
@ -380,7 +429,7 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
"hf mf cgetsc "
+ QString::number(sectorId),
waitTime);
offset = result.indexOf("Chinese magic");
offset = result.indexOf("error") == -1 ? 0 : -1; // find failed flag
}
if(offset != -1)
{
@ -399,7 +448,7 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
}
// if failed, try to read them seperately.
// (when one of the block cannot be read, the rdsc will return nothing, so you need to read the rest of blocks manually)
else if(targetType != TARGET_UID) // if the targetType is Chinese Magic Card, then the result implies the backdoor command is invalid.
else if(targetType == TARGET_UID || targetType == TARGET_EMULATOR) // if the targetType is Chinese Magic Card, then the result implies the backdoor command is invalid.
{
for(int i = 0; i < cardType.blk[sectorId]; i++)
data[i] = _readblk(cardType.blks[sectorId] + i, keyType, key, targetType, waitTime);
@ -536,12 +585,12 @@ bool Mifare::_writeblk(int blockId, KeyType keyType, const QString& key, const Q
{
QString result;
QString input = data.toUpper();
input.remove(" ");
input.remove(" ");
if(data_isDataValid(input) != DATA_NOSPACE)
return false;
if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL || util->getClientType() == Util::CLIENTTYPE_ICEMAN)
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
if(targetType == TARGET_MIFARE)
{
@ -567,7 +616,7 @@ bool Mifare::_writeblk(int blockId, KeyType keyType, const QString& key, const Q
+ " "
+ input,
waitTime);
return (result.indexOf("Chinese magic") != -1);
return (result.indexOf("error") == -1); // failed flag
}
else if(targetType == TARGET_EMULATOR)
{
@ -601,6 +650,8 @@ void Mifare::writeSelected(TargetType targetType)
{
QList<int> failedBlocks;
QList<int> selectedBlocks;
bool yes2All = false, no2All = false;
for(int i = 0; i < cardType.block_size; i++)
{
if(ui->MF_dataWidget->item(i, 1)->checkState() == Qt::Checked)
@ -609,6 +660,29 @@ void Mifare::writeSelected(TargetType targetType)
for(int item : selectedBlocks)
{
bool result = false;
bool isTrailerBlock = (item < 128 && ((item + 1) % 4 == 0)) || ((item + 1) % 16 == 0);
if(isTrailerBlock && !data_isACBitsValid(dataList->at(item).mid(12, 8))) // trailer block is invalid
{
if(!yes2All && !no2All)
{
QMessageBox::StandardButton choice = QMessageBox::information(parent, tr("Info"),
tr("The Access Bits is invalid!\nIt could make the whole sector blocked irreversibly!\nContinue to write?"),
QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll);
if(choice == QMessageBox::No)
continue;
else if(choice == QMessageBox::YesToAll)
yes2All = true;
else if(choice == QMessageBox::NoToAll)
{
no2All = true;
continue;
}
}
else if(no2All)
continue;
}
if(targetType == TARGET_MIFARE)
{
result = _writeblk(item, KEY_A, keyAList->at(data_b2s(item)), dataList->at(item), TARGET_MIFARE);
@ -667,23 +741,32 @@ void Mifare::writeSelected(TargetType targetType)
void Mifare::dump()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf dump");
ui->funcTab->setCurrentIndex(1);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::restore()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf restore");
ui->funcTab->setCurrentIndex(1);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::wipeC()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
util->execCMD(
"hf mf cwipe "
+ QString::number(cardType.type)
+ " f");
ui->funcTab->setCurrentIndex(1);
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
util->execCMD("hf mf cwipe");
}
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::setParameterC()
@ -693,50 +776,78 @@ void Mifare::setParameterC()
QMessageBox::information(parent, tr("Info"), tr("Failed to read card."));
else
{
QStringList lis = result.split("\r\n");
lis[0].replace(" ", "");
lis[1].replace(" ", "");
lis[2].replace(" ", "");
MF_UID_parameterDialog dialog(lis[0].toUpper(), lis[1].toUpper(), lis[2].mid(0, 2).toUpper());
result.replace("\r\n", "");
result.replace(QRegularExpression("\\[.\\]"), "");
result.replace("UID", "");
result.replace("ATQA", "");
result.replace("SAK", "");
result.replace(" ", "");
QStringList lis = result.split(':');
qDebug() << lis;
MF_UID_parameterDialog dialog(lis[1].toUpper(), lis[2].toUpper(), lis[3].toUpper());
connect(&dialog, &MF_UID_parameterDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted)
ui->funcTab->setCurrentIndex(1);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
}
void Mifare::lockC()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
util->execCMD("hf 14a raw -pa -b7 40");
util->execCMD("hf 14a raw -pa 43");
util->execCMD("hf 14a raw -pa E0 00 39 F7");
util->execCMD("hf 14a raw -pa E1 00 E1 EE");
util->execCMD("hf 14a raw -pa 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47");
util->execCMD("hf 14a raw 52");
util->execCMD("hf 14a raw -a 52");
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
util->execCMD("hf 14a raw -ak -b 7 40");
util->execCMD("hf 14a raw -ak 43");
util->execCMD("hf 14a raw -ak E0 00 39 F7");
util->execCMD("hf 14a raw -ak E1 00 E1 EE");
util->execCMD("hf 14a raw -ak 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47");
util->execCMD("hf 14a raw -a 52");
}
}
void Mifare::wipeE()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf eclr");
}
void Mifare::simulate()
{
MF_Sim_simDialog dialog(cardType.type);
MF_Sim_simDialog dialog(cardType.type, cardType.typeText);
connect(&dialog, &MF_Sim_simDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted)
ui->funcTab->setCurrentIndex(1);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::loadSniff(const QString& file)
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf list mf -l " + file);
ui->funcTab->setCurrentIndex(1);
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
if(util->execCMDWithOutput("trace load -f " + file, Util::ReturnTrigger({"loaded"})) != "")
util->execCMD("trace list -t mf");
}
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::saveSniff(const QString& file)
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf list mf -s " + file);
ui->funcTab->setCurrentIndex(1);
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("trace save -f " + file);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
}
void Mifare::data_syncWithDataWidget(bool syncAll, int block)
@ -1192,24 +1303,36 @@ int Mifare::data_b2s(int block)
return -1;
}
QList<quint8> Mifare::data_getACBits(const QString& text) //return empty QList if the text is invalid
bool Mifare::data_isACBitsValid(const QString& text, QList<quint8>* returnHalfBytes)
{
QString input = text;
QList<quint8> result;
input.remove(" ");
if(input.length() < 6)
{
return result;
return false;
}
input = input.left(6);
quint32 val = input.toUInt(nullptr, 16);
quint8 halfBytes[6];
QList<quint8> halfBytes;
for(int i = 0; i < 6; i++)
{
halfBytes[i] = (val >> ((5 - i) * 4)) & 0xf;
halfBytes.append((val >> ((5 - i) * 4)) & 0xf);
}
qDebug() << val;
if((~halfBytes[0] & 0xf) == halfBytes[5] && (~halfBytes[1] & 0xf) == halfBytes[2] && (~halfBytes[3] & 0xf) == halfBytes[4])
{
if(returnHalfBytes != nullptr)
*returnHalfBytes = halfBytes;
return true;
}
else
return false;
}
QList<quint8> Mifare::data_getACBits(const QString& text) //return empty QList if the text is invalid
{
QList<quint8> halfBytes, result;
if(data_isACBitsValid(text, &halfBytes))
{
for(int i = 0; i < 4; i++)
{

@ -37,6 +37,7 @@ public:
quint16 block_size;
quint8 blk[40];
quint8 blks[40];
QString typeText;
};
enum AccessType
@ -66,9 +67,10 @@ public:
QString info(bool isRequiringOutput = false);
void chk();
void nested();
void darkside();
void hardnested();
void sniff();
void snoop();
void sniff14a();
void list();
void readOne(TargetType targetType = TARGET_MIFARE);
void readSelected(TargetType targetType = TARGET_MIFARE);
@ -108,6 +110,7 @@ public:
static QList<quint8> data_getACBits(const QString& text);
static int data_b2s(int block);
static bool data_isACBitsValid(const QString& text, QList<quint8> *returnHalfBytes = nullptr);
public slots:
signals:

@ -7,6 +7,7 @@ MainWindow::MainWindow(QWidget *parent):
{
ui->setupUi(this);
myInfo = new QAction("wh201906", this);
currVersion = new QAction("Ver: " + QApplication::applicationVersion().section('.', 0, -2), this); // ignore the 4th version number
checkUpdate = new QAction(tr("Check Update"), this);
connect(myInfo, &QAction::triggered, [ = ]()
{
@ -17,9 +18,11 @@ MainWindow::MainWindow(QWidget *parent):
QDesktopServices::openUrl(QUrl("https://github.com/wh201906/Proxmark3GUI/releases"));
});
this->addAction(myInfo);
this->addAction(currVersion);
this->addAction(checkUpdate);
settings = new QSettings("GUIsettings.ini", QSettings::IniFormat);
settings->setIniCodec("UTF-8");
pm3Thread = new QThread(this);
pm3 = new PM3Process(pm3Thread);
@ -29,6 +32,18 @@ MainWindow::MainWindow(QWidget *parent):
util = new Util(this);
mifare = new Mifare(ui, util, this);
keyEventFilter = new MyEventFilter(QEvent::KeyRelease);
resizeEventFilter = new MyEventFilter(QEvent::Resize);
// hide unused tabs
ui->funcTab->removeTab(1);
ui->funcTab->removeTab(1);
portSearchTimer = new QTimer(this);
portSearchTimer->setInterval(2000);
connect(portSearchTimer, &QTimer::timeout, this, &MainWindow::on_portSearchTimer_timeout);
portSearchTimer->start();
}
MainWindow::~MainWindow()
@ -51,52 +66,70 @@ void MainWindow::initUI() // will be called by main.app
// ******************** basic functions ********************
void MainWindow::on_PM3_refreshPortButton_clicked()
void MainWindow::on_portSearchTimer_timeout()
{
ui->PM3_portBox->clear();
QSerialPort serial;
QStringList serialList;
QStringList newPortList;
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
qDebug() << info.isBusy() << info.isNull() << info.portName();
serial.setPort(info);
if(serial.open(QIODevice::ReadWrite))
{
serialList << info.portName();
serial.close();
}
// qDebug() << info.isBusy() << info.isNull() << info.portName() << info.description();
if(!info.isNull())
newPortList << info.portName();
}
foreach(QString port, serialList)
if(newPortList != portList) // update PM3_portBox when available ports changed
{
ui->PM3_portBox->addItem(port);
portList = newPortList;
ui->PM3_portBox->clear();
ui->PM3_portBox->addItems(portList);
}
}
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
{
QStringList args = ui->Set_Client_startArgsEdit->text().replace("<port>", port).split(' ');
saveClientPath(ui->PM3_pathEdit->text());
emit connectPM3(ui->PM3_pathEdit->text(), port);
QProcess envSetProcess;
QFileInfo envScriptPath(ui->Set_Client_envScriptEdit->text());
if(envScriptPath.exists())
{
qDebug() << envScriptPath.absoluteFilePath();
#ifdef Q_OS_WIN
// cmd /c "<path>">>nul && set
envSetProcess.start("cmd /c \"" + envScriptPath.absoluteFilePath() + "\">>nul && set");
#else
// sh -c '. "<path>">>/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);
emit connectPM3(ui->PM3_pathEdit->text(), port, args);
}
}
void MainWindow::onPM3StateChanged(bool st, QString info)
void MainWindow::onPM3StateChanged(bool st, const QString& info)
{
pm3state = st;
setState(st);
if(st == true)
{
portSearchTimer->stop();
setStatusBar(PM3VersionBar, info);
setStatusBar(connectStatusBar, tr("Connected"));
}
else
{
portSearchTimer->start();
setStatusBar(PM3VersionBar, "");
setStatusBar(connectStatusBar, tr("Not Connected"));
}
@ -104,11 +137,8 @@ void MainWindow::onPM3StateChanged(bool st, QString info)
void MainWindow::on_PM3_disconnectButton_clicked()
{
pm3state = false;
setState(false);
emit killPM3();
emit setSerialListener("", false);
setStatusBar(connectStatusBar, tr("Not Connected"));
}
void MainWindow::refreshOutput(const QString& output)
@ -118,17 +148,31 @@ void MainWindow::refreshOutput(const QString& output)
ui->Raw_outputEdit->moveCursor(QTextCursor::End);
}
void MainWindow::refreshCMD(const QString& cmd)
void MainWindow::on_stopButton_clicked()
{
ui->Raw_CMDEdit->setText(cmd);
if(cmd != "" && (ui->Raw_CMDHistoryWidget->count() == 0 || ui->Raw_CMDHistoryWidget->item(ui->Raw_CMDHistoryWidget->count() - 1)->text() != cmd))
ui->Raw_CMDHistoryWidget->addItem(cmd);
if(!pm3state)
on_PM3_disconnectButton_clicked();
else
{
on_PM3_disconnectButton_clicked();
for(int i = 0; i < 10; i++)
{
util->delay(200);
if(!pm3state)
break;
}
emit reconnectPM3();
}
}
// *********************************************************
// ******************** raw command ********************
void MainWindow::on_Raw_CMDEdit_textChanged(const QString &arg1)
{
stashedCMDEditText = arg1;
}
void MainWindow::on_Raw_sendCMDButton_clicked()
{
util->execCMD(ui->Raw_CMDEdit->text());
@ -173,17 +217,73 @@ void MainWindow::sendMSG() // send command when pressing Enter
on_Raw_sendCMDButton_clicked();
}
void MainWindow::refreshCMD(const QString& cmd)
{
ui->Raw_CMDEdit->blockSignals(true);
ui->Raw_CMDEdit->setText(cmd);
if(cmd != "" && (ui->Raw_CMDHistoryWidget->count() == 0 || ui->Raw_CMDHistoryWidget->item(ui->Raw_CMDHistoryWidget->count() - 1)->text() != cmd))
ui->Raw_CMDHistoryWidget->addItem(cmd);
stashedCMDEditText = cmd;
stashedIndex = -1;
ui->Raw_CMDEdit->blockSignals(false);
}
void MainWindow::on_Raw_CMDEdit_keyPressed(QObject* obj_addr, QEvent& event)
{
if(obj_addr == ui->Raw_CMDEdit && event.type() == QEvent::KeyRelease)
{
QKeyEvent& keyEvent = static_cast<QKeyEvent&>(event);
if(keyEvent.key() == Qt::Key_Up)
{
if(stashedIndex > 0)
stashedIndex--;
else if(stashedIndex == -1)
stashedIndex = ui->Raw_CMDHistoryWidget->count() - 1;
}
else if(keyEvent.key() == Qt::Key_Down)
{
if(stashedIndex < ui->Raw_CMDHistoryWidget->count() - 1 && stashedIndex != -1)
stashedIndex++;
else if(stashedIndex == ui->Raw_CMDHistoryWidget->count() - 1)
stashedIndex = -1;
}
if(keyEvent.key() == Qt::Key_Up || keyEvent.key() == Qt::Key_Down)
{
ui->Raw_CMDEdit->blockSignals(true);
if(stashedIndex == -1)
ui->Raw_CMDEdit->setText(stashedCMDEditText);
else
ui->Raw_CMDEdit->setText(ui->Raw_CMDHistoryWidget->item(stashedIndex)->text());
ui->Raw_CMDEdit->blockSignals(false);
}
}
}
// *****************************************************
// ******************** mifare ********************
void MainWindow::MF_onTypeChanged(int id, bool st)
void MainWindow::on_MF_keyWidget_resized(QObject* obj_addr, QEvent& event)
{
typeBtnGroup->blockSignals(true);
qDebug() << id << typeBtnGroup->checkedId();
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_onMFCardTypeChanged(int id, bool st)
{
MFCardTypeBtnGroup->blockSignals(true);
qDebug() << id << MFCardTypeBtnGroup->checkedId();
if(!st)
{
int result;
if(id > typeBtnGroup->checkedId()) // id is specified in uiInit() with a proper order, so I can compare the size by id.
if(id > MFCardTypeBtnGroup->checkedId()) // id is specified in uiInit() with a proper order, so I can compare the size by id.
{
result = QMessageBox::question(this, tr("Info"), tr("Some of the data and key will be cleared.") + "\n" + tr("Continue?"), QMessageBox::Yes | QMessageBox::No);
}
@ -194,7 +294,7 @@ void MainWindow::MF_onTypeChanged(int id, bool st)
if(result == QMessageBox::Yes)
{
qDebug() << "Yes";
mifare->setCardType(typeBtnGroup->checkedId());
mifare->setCardType(MFCardTypeBtnGroup->checkedId());
MF_widgetReset();
mifare->data_syncWithDataWidget();
mifare->data_syncWithKeyWidget();
@ -202,10 +302,10 @@ void MainWindow::MF_onTypeChanged(int id, bool st)
else
{
qDebug() << "No";
typeBtnGroup->button(id)->setChecked(true);
MFCardTypeBtnGroup->button(id)->setChecked(true);
}
}
typeBtnGroup->blockSignals(false);
MFCardTypeBtnGroup->blockSignals(false);
}
void MainWindow::on_MF_selectAllBox_stateChanged(int arg1)
@ -736,10 +836,10 @@ void MainWindow::on_MF_Sniff_sniffButton_clicked()
setState(true);
}
void MainWindow::on_MF_Sniff_snoopButton_clicked()
void MainWindow::on_MF_14aSniff_snoopButton_clicked()
{
setState(false);
mifare->snoop();
mifare->sniff14a();
setState(true);
}
@ -752,6 +852,7 @@ void MainWindow::MF_widgetReset()
{
int secs = mifare->cardType.sector_size;
int blks = mifare->cardType.block_size;
QBrush trailerItemForeColor = QBrush(QColor(0, 160, 255));
ui->MF_RW_blockBox->clear();
ui->MF_keyWidget->setRowCount(secs);
ui->MF_dataWidget->setRowCount(blks);
@ -776,8 +877,10 @@ void MainWindow::MF_widgetReset()
setTableItem(ui->MF_keyWidget, i, 1, "");
setTableItem(ui->MF_keyWidget, i, 2, "");
setTableItem(ui->MF_dataWidget, mifare->cardType.blks[i], 0, QString::number(i));
ui->MF_dataWidget->item(mifare->cardType.blks[i] + mifare->cardType.blk[i] - 1, 2)->setForeground(trailerItemForeColor);
ui->MF_dataWidget->item(mifare->cardType.blks[i], 0)->setCheckState(Qt::Checked);
}
ui->MF_dataWidget->item(0, 2)->setForeground(QBrush(QColor(255, 160, 0)));
ui->MF_selectAllBox->setCheckState(Qt::Checked);
ui->MF_selectTrailerBox->setCheckState(Qt::Checked);
@ -794,42 +897,44 @@ void MainWindow::MF_widgetReset()
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);
PM3VersionBar = new QLabel(this);
stopButton = new QPushButton(this);
setStatusBar(connectStatusBar, tr("Not Connected"));
setStatusBar(programStatusBar, tr("Idle"));
setStatusBar(PM3VersionBar, "");
stopButton->setText(tr("Stop"));
ui->statusbar->addPermanentWidget(PM3VersionBar, 1);
ui->statusbar->addPermanentWidget(connectStatusBar, 1);
ui->statusbar->addPermanentWidget(programStatusBar, 1);
ui->statusbar->addPermanentWidget(stopButton);
ui->MF_dataWidget->setColumnCount(3);
ui->MF_dataWidget->setHorizontalHeaderItem(0, new QTableWidgetItem(tr("Sec")));
ui->MF_dataWidget->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Blk")));
ui->MF_dataWidget->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Data")));
ui->MF_dataWidget->verticalHeader()->setVisible(false);
ui->MF_dataWidget->setColumnWidth(0, 55);
ui->MF_dataWidget->setColumnWidth(1, 55);
ui->MF_dataWidget->setColumnWidth(2, 430);
ui->MF_keyWidget->setColumnCount(3);
ui->MF_keyWidget->setHorizontalHeaderItem(0, new QTableWidgetItem(tr("Sec")));
ui->MF_keyWidget->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("KeyA")));
ui->MF_keyWidget->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("KeyB")));
ui->MF_keyWidget->verticalHeader()->setVisible(false);
ui->MF_keyWidget->setColumnWidth(0, 35);
ui->MF_keyWidget->setColumnWidth(1, 115);
ui->MF_keyWidget->setColumnWidth(2, 115);
ui->MF_keyWidget->setColumnWidth(0, 45);
MF_widgetReset();
typeBtnGroup = new QButtonGroup(this);
typeBtnGroup->addButton(ui->MF_Type_miniButton, 0);
typeBtnGroup->addButton(ui->MF_Type_1kButton, 1);
typeBtnGroup->addButton(ui->MF_Type_2kButton, 2);
typeBtnGroup->addButton(ui->MF_Type_4kButton, 4);
connect(typeBtnGroup, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), this, &MainWindow::MF_onTypeChanged);
MFCardTypeBtnGroup = new QButtonGroup(this);
MFCardTypeBtnGroup->addButton(ui->MF_Type_miniButton, 0);
MFCardTypeBtnGroup->addButton(ui->MF_Type_1kButton, 1);
MFCardTypeBtnGroup->addButton(ui->MF_Type_2kButton, 2);
MFCardTypeBtnGroup->addButton(ui->MF_Type_4kButton, 4);
connect(MFCardTypeBtnGroup, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), this, &MainWindow::MF_onMFCardTypeChanged);
ui->MF_keyWidget->installEventFilter(this);
ui->MF_dataWidget->installEventFilter(this);
@ -860,11 +965,23 @@ void MainWindow::uiInit()
ui->PM3_pathEdit->setText(settings->value("path", "proxmark3").toString());
settings->endGroup();
settings->beginGroup("Client_Args");
ui->Set_Client_startArgsEdit->setText(settings->value("args", "<port> -f").toString());
settings->endGroup();
settings->beginGroup("Client_forceButtonsEnabled");
keepButtonsEnabled = settings->value("state", false).toBool();
ui->Set_Client_forceEnabledBox->setChecked(keepButtonsEnabled);
settings->endGroup();
settings->beginGroup("Client_Env");
ui->Set_Client_envScriptEdit->setText(settings->value("scriptPath").toString());
settings->endGroup();
ui->MF_RW_keyTypeBox->addItem("A", Mifare::KEY_A);
ui->MF_RW_keyTypeBox->addItem("B", Mifare::KEY_B);
on_Raw_CMDHistoryBox_stateChanged(Qt::Unchecked);
on_PM3_refreshPortButton_clicked();
}
void MainWindow::signalInit()
@ -874,8 +991,11 @@ void MainWindow::signalInit()
connect(util, &Util::refreshOutput, this, &MainWindow::refreshOutput);
connect(this, &MainWindow::connectPM3, pm3, &PM3Process::connectPM3);
connect(this, &MainWindow::reconnectPM3, pm3, &PM3Process::reconnectPM3);
connect(pm3, &PM3Process::PM3StatedChanged, this, &MainWindow::onPM3StateChanged);
connect(pm3, &PM3Process::PM3StatedChanged, util, &Util::setRunningState);
connect(this, &MainWindow::killPM3, pm3, &PM3Process::kill);
connect(this, &MainWindow::setProcEnv, pm3, &PM3Process::setProcEnv);
connect(util, &Util::write, pm3, &PM3Process::write);
@ -886,6 +1006,8 @@ void MainWindow::signalInit()
connect(ui->MF_UIDGroupBox, &QGroupBox::clicked, this, &MainWindow::on_GroupBox_clicked);
connect(ui->MF_simGroupBox, &QGroupBox::clicked, this, &MainWindow::on_GroupBox_clicked);
connect(ui->MF_sniffGroupBox, &QGroupBox::clicked, this, &MainWindow::on_GroupBox_clicked);
connect(stopButton, &QPushButton::clicked, this, &MainWindow::on_stopButton_clicked);
}
void MainWindow::setStatusBar(QLabel * target, const QString& text)
@ -956,6 +1078,11 @@ void MainWindow::setState(bool st)
{
setStatusBar(programStatusBar, tr("Idle"));
}
setButtonsEnabled(st || keepButtonsEnabled);
}
void MainWindow::setButtonsEnabled(bool st)
{
ui->MF_attackGroupBox->setEnabled(st);
ui->MF_normalGroupBox->setEnabled(st);
ui->MF_UIDGroupBox->setEnabled(st);
@ -990,3 +1117,46 @@ void MainWindow::saveClientPath(const QString & path)
settings->endGroup();
}
// ***********************************************
void MainWindow::on_MF_Attack_darksideButton_clicked()
{
setState(false);
mifare->darkside();
setState(true);
}
void MainWindow::on_Set_Client_startArgsEdit_editingFinished()
{
settings->beginGroup("Client_Args");
settings->setValue("args", ui->Set_Client_startArgsEdit->text());
settings->endGroup();
}
void MainWindow::on_Set_Client_forceEnabledBox_stateChanged(int arg1)
{
settings->beginGroup("Client_forceButtonsEnabled");
keepButtonsEnabled = (arg1 == Qt::Checked);
settings->setValue("state", keepButtonsEnabled);
settings->endGroup();
if(keepButtonsEnabled)
setButtonsEnabled(true);
}
void MainWindow::on_Set_GUI_setLanguageButton_clicked()
{
Util::chooseLanguage(settings, this);
}
void MainWindow::on_PM3_refreshPortButton_clicked()
{
on_portSearchTimer_timeout();
}
void MainWindow::on_Set_Client_envScriptEdit_editingFinished()
{
settings->beginGroup("Client_Env");
settings->setValue("scriptPath", ui->Set_Client_envScriptEdit->text());
settings->endGroup();
}

@ -19,7 +19,12 @@
#include <QGroupBox>
#include <QSizePolicy>
#include <QSettings>
#include <QPushButton>
#include <QProcessEnvironment>
#include <QScrollBar>
#include <QTimer>
#include "common/myeventfilter.h"
#include "common/pm3process.h"
#include "module/mifare.h"
#include "common/util.h"
@ -46,8 +51,10 @@ public slots:
void refreshOutput(const QString& output);
void refreshCMD(const QString& cmd);
void setStatusBar(QLabel* target, const QString& text);
void onPM3StateChanged(bool st, QString info);
void MF_onTypeChanged(int id, bool st);
void onPM3StateChanged(bool st, const QString& info);
void MF_onMFCardTypeChanged(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();
@ -59,7 +66,8 @@ private slots:
void on_Raw_clearOutputButton_clicked();
void sendMSG();
void on_PM3_refreshPortButton_clicked();
void on_portSearchTimer_timeout();
void on_Raw_CMDHistoryBox_stateChanged(int arg1);
@ -87,7 +95,6 @@ private slots:
void on_MF_RW_writeSelectedButton_clicked();
void on_MF_RW_dumpButton_clicked();
void on_MF_RW_restoreButton_clicked();
@ -142,27 +149,56 @@ private slots:
void on_MF_fillKeysButton_clicked();
void on_MF_Sniff_snoopButton_clicked();
void on_MF_14aSniff_snoopButton_clicked();
void on_MF_trailerDecoderButton_clicked();
void on_MF_selectTrailerBox_stateChanged(int arg1);
void on_stopButton_clicked();
void on_Raw_CMDEdit_textChanged(const QString &arg1);
void on_MF_Attack_darksideButton_clicked();
void on_Set_Client_startArgsEdit_editingFinished();
void on_Set_Client_forceEnabledBox_stateChanged(int arg1);
void on_Set_GUI_setLanguageButton_clicked();
void setButtonsEnabled(bool st);
void on_PM3_refreshPortButton_clicked();
void on_Set_Client_envScriptEdit_editingFinished();
private:
Ui::MainWindow* ui;
QButtonGroup* typeBtnGroup;
QButtonGroup* MFCardTypeBtnGroup;
QLabel* connectStatusBar;
QLabel* programStatusBar;
QLabel* PM3VersionBar;
QPushButton* stopButton;
QAction* myInfo;
QAction* currVersion;
QAction* checkUpdate;
QSettings* settings;
MyEventFilter* keyEventFilter;
MyEventFilter* resizeEventFilter;
QString stashedCMDEditText;
int stashedIndex = -1;
void uiInit();
PM3Process* pm3;
bool pm3state;
bool keepButtonsEnabled;
QThread* pm3Thread;
QTimer* portSearchTimer;
QStringList portList;
QStringList clientEnv;
Mifare* mifare;
Util* util;
@ -176,8 +212,10 @@ 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 reconnectPM3();
void killPM3();
void setSerialListener(const QString& name, bool state);
void setProcEnv(const QStringList *env);
};
#endif // MAINWINDOW_H

@ -6,14 +6,14 @@
<rect>
<x>0</x>
<y>0</y>
<width>970</width>
<height>770</height>
<width>1050</width>
<height>700</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>970</width>
<height>770</height>
<width>800</width>
<height>600</height>
</size>
</property>
<property name="contextMenuPolicy">
@ -53,13 +53,20 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Path:</string>
<string>Client Path:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="PM3_pathEdit"/>
</item>
<item>
<widget class="QLabel" name="label_18">
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="PM3_portBox">
<property name="minimumSize">
@ -68,6 +75,9 @@
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
@ -79,7 +89,7 @@
</size>
</property>
<property name="text">
<string>Refresh</string>
<string>Refresh Ports</string>
</property>
</widget>
</item>
@ -170,6 +180,12 @@
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>20</number>
</attribute>
@ -329,6 +345,9 @@
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>20</number>
</attribute>
@ -568,6 +587,19 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="MF_Attack_darksideButton">
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Darkside</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
@ -1097,7 +1129,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="MF_Sniff_snoopButton">
<widget class="QPushButton" name="MF_14aSniff_snoopButton">
<property name="minimumSize">
<size>
<width>40</width>
@ -1105,7 +1137,7 @@
</size>
</property>
<property name="text">
<string>Snoop</string>
<string>Sniff(14a)</string>
</property>
</widget>
</item>
@ -1168,6 +1200,222 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="lfTab">
<property name="enabled">
<bool>true</bool>
</property>
<attribute name="title">
<string>LF/Data</string>
</attribute>
<widget class="QGroupBox" name="LF_configGroupBox">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>121</width>
<height>211</height>
</rect>
</property>
<property name="title">
<string>LF Config</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QGroupBox" name="LF_Conf_freqGroupBox">
<property name="title">
<string>Frequency</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QRadioButton" name="LF_Conf_freq125kButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>125k</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="LF_Conf_freq134kButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>134k</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>BitRate:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Decimation:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="LF_Conf_decimationBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Averaging:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="LF_Conf_averagingBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Threshold:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="LF_Conf_thresholdBox"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Skips:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QSpinBox" name="LF_Conf_skipsBox"/>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="LF_Conf_bitRateBox"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_14">
<item>
<widget class="QPushButton" name="LF_Conf_getButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Get</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="LF_Conf_setButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Set</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="t55xxTab">
<attribute name="title">
<string>T55xx</string>
</attribute>
<widget class="QTableWidget" name="T55_dataWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>256</width>
<height>192</height>
</rect>
</property>
</widget>
</widget>
<widget class="QWidget" name="rawTab">
<attribute name="title">
<string>RawCommand</string>
@ -1198,6 +1446,9 @@
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
@ -1283,6 +1534,212 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="settingsTab">
<attribute name="title">
<string>Settings</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
<widget class="QGroupBox" name="Set_clientGroupBox">
<property name="title">
<string>Client</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Preload script path:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="Set_Client_envScriptEdit">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>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</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>Start arguments</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="Set_Client_startArgsEdit">
<property name="text">
<string>&lt;port&gt; -f</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_14">
<property name="text">
<string>Note:
-f is necessary because the GUI need to handle the output in time
In some cases the arguments should be set to &quot;-p /dev/&lt;port&gt; -f&quot;
or &quot;-p &lt;port&gt; -f&quot;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QCheckBox" name="Set_Client_forceEnabledBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_15">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Keep buttons enabled even the client is running or disconnected</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>GUI</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_17">
<item>
<widget class="QLabel" name="label_16">
<property name="text">
<string>Language: </string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="Set_GUI_setLanguageButton">
<property name="text">
<string>Choose Language</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_17">
<property name="text">
<string>(Restart this app to use new language)</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_10">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>

@ -21,6 +21,18 @@ MF_Attack_hardnestedDialog::~MF_Attack_hardnestedDialog()
void MF_Attack_hardnestedDialog::on_buttonBox_accepted()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
emit sendCMD("hf mf hardnested "
+ ui->knownKeySectorBox->currentText()
+ " "
+ ui->knownKeyTypeBox->currentText()
+ " "
+ ui->knownKeyBox->text()
+ " "
+ ui->targetKeySectorBox->currentText()
+ " "
+ ui->targetKeyTypeBox->currentText());
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN) // same format in v4.9237
emit sendCMD("hf mf hardnested "
+ ui->knownKeySectorBox->currentText()
+ " "

@ -2,8 +2,10 @@
#define MF_ATTACK_HARDNESTEDDIALOG_H
#include <QDialog>
#include "common/util.h"
namespace Ui {
namespace Ui
{
class MF_Attack_hardnestedDialog;
}
@ -19,7 +21,7 @@ public:
private:
Ui::MF_Attack_hardnestedDialog *ui;
signals:
void sendCMD(QString cmd);
void sendCMD(const QString& cmd);
private slots:
void on_buttonBox_accepted();
};

@ -1,12 +1,34 @@
#include "mf_sim_simdialog.h"
#include "ui_mf_sim_simdialog.h"
MF_Sim_simDialog::MF_Sim_simDialog(int cardType, QWidget *parent) :
MF_Sim_simDialog::MF_Sim_simDialog(int cardType, QString cardTypeText, QWidget *parent) :
QDialog(parent),
ui(new Ui::MF_Sim_simDialog)
{
ui->setupUi(this);
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
ui->atqaGroupBox->setVisible(false);
ui->atqaLine->setVisible(false);
ui->sakGroupBox->setVisible(false);
ui->sakLine->setVisible(false);
ui->vGroupBox->setVisible(false);
ui->vLine->setVisible(false);
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
ui->fGroupBox->setVisible(false);
ui->fLine->setVisible(false);
ui->rGroupBox->setVisible(false);
ui->rLine->setVisible(false);
ui->uBox->setText("-u");
ui->nBox->setText("-n");
ui->iBox->setText("-i");
ui->xBox->setText("--crack");
ui->eBox->setText("-e");
}
this->cardType = cardType;
this->cardTypeText = cardTypeText;
}
MF_Sim_simDialog::~MF_Sim_simDialog()
@ -55,6 +77,8 @@ void MF_Sim_simDialog::on_fBox_clicked(bool checked)
void MF_Sim_simDialog::on_buttonBox_accepted()
{
QString paras;
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
paras += (ui->uBox->isChecked() ? "u " + ui->uEdit->text() + " " : "");
paras += (ui->nBox->isChecked() ? "n " + ui->nEdit->text() + " " : "");
paras += (ui->iBox->isChecked() ? "i " : "");
@ -64,3 +88,16 @@ void MF_Sim_simDialog::on_buttonBox_accepted()
paras += (ui->rBox->isChecked() ? "r " : "");
emit sendCMD(QString("hf mf sim ") + "*" + QString::number(cardType) + " " + paras.trimmed());
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
paras += (ui->uBox->isChecked() ? "-u " + ui->uEdit->text() + " " : "");
paras += (ui->atqaBox->isChecked() ? "--atqa " + ui->atqaEdit->text() + " " : "");
paras += (ui->sakBox->isChecked() ? "--sak " + ui->sakEdit->text() + " " : "");
paras += (ui->nBox->isChecked() ? "-n " + ui->nEdit->text() + " " : "");
paras += (ui->iBox->isChecked() ? "-i " : "");
paras += (ui->xBox->isChecked() ? "--crack " : "");
paras += (ui->eBox->isChecked() ? "-e " : "");
paras += (ui->vBox->isChecked() ? "-v " : "");
emit sendCMD(QString("hf mf sim --") + cardTypeText + " " + paras.trimmed());
}
}

@ -3,6 +3,7 @@
#include <QDialog>
#include <QDebug>
#include "common/util.h"
namespace Ui
{
@ -14,7 +15,7 @@ class MF_Sim_simDialog : public QDialog
Q_OBJECT
public:
explicit MF_Sim_simDialog(int cardType, QWidget *parent = nullptr);
explicit MF_Sim_simDialog(int cardType, QString cardTypeText, QWidget *parent = nullptr);
~MF_Sim_simDialog();
private slots:
@ -25,8 +26,9 @@ private slots:
private:
Ui::MF_Sim_simDialog *ui;
int cardType;
QString cardTypeText;
signals:
void sendCMD(QString cmd);
void sendCMD(const QString& cmd);
private slots:
void on_buttonBox_accepted();
};

@ -7,30 +7,31 @@
<x>0</x>
<y>0</y>
<width>461</width>
<height>456</height>
<height>524</height>
</rect>
</property>
<property name="windowTitle">
<string>Simulate</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="uGroupBox">
<layout class="QHBoxLayout" name="uLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>5</number>
<number>0</number>
</property>
<property name="topMargin">
<number>5</number>
<number>0</number>
</property>
<property name="rightMargin">
<number>5</number>
<number>0</number>
</property>
<property name="bottomMargin">
<number>5</number>
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="uBox">
<property name="text">
@ -71,16 +72,167 @@
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_6">
<widget class="Line" name="uLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<widget class="QGroupBox" name="atqaGroupBox">
<layout class="QHBoxLayout" name="atqaLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="atqaBox">
<property name="text">
<string>--atqa</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="atqaEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Provide explicit ATQA (2 bytes)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="atqaLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="sakGroupBox">
<layout class="QHBoxLayout" name="sakLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="sakBox">
<property name="text">
<string>--sak</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="sakEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_9">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Provide explicit SAK (1 byte)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="sakLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="nGroupBox">
<layout class="QHBoxLayout" name="nLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="nBox">
<property name="text">
@ -121,16 +273,33 @@
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_5">
<widget class="Line" name="nLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<widget class="QGroupBox" name="iGroupBox">
<layout class="QHBoxLayout" name="iLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="iBox">
<property name="text">
@ -155,16 +324,33 @@
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_4">
<widget class="Line" name="iLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<widget class="QGroupBox" name="xGroupBox">
<layout class="QHBoxLayout" name="xLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="xBox">
<property name="text">
@ -189,16 +375,33 @@
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<widget class="Line" name="xLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<widget class="QGroupBox" name="eGroupBox">
<layout class="QHBoxLayout" name="eLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="eBox">
<property name="text">
@ -215,7 +418,7 @@
</sizepolicy>
</property>
<property name="text">
<string>set keys found from 'reader attack' to emulator memory (implies x and i)</string>
<string>set keys found from 'reader attack' to emulator memory (implies x(--crack) and i)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -223,16 +426,33 @@
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<widget class="Line" name="eLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<widget class="QGroupBox" name="fGroupBox">
<layout class="QHBoxLayout" name="fLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="fBox">
<property name="text">
@ -273,16 +493,33 @@
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line">
<widget class="Line" name="fLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<widget class="QGroupBox" name="rGroupBox">
<layout class="QHBoxLayout" name="rLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="rBox">
<property name="text">
@ -307,9 +544,61 @@
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="rLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="vGroupBox">
<layout class="QHBoxLayout" name="vLayout">
<property name="spacing">
<number>5</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="vBox">
<property name="text">
<string>-v</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>verbose output</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="Line" name="line_7">
<widget class="Line" name="vLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>

@ -15,10 +15,10 @@ MF_trailerDecoderDialog::MF_trailerDecoderDialog(QWidget *parent) :
sizeGroup->addButton(ui->size4Button, 4);
sizeGroup->addButton(ui->size16Button, 16);
connect(sizeGroup, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), this, &MF_trailerDecoderDialog::on_blockSizeChanged);
connect(ui->C0Box, &QSpinBox::textChanged, this, &MF_trailerDecoderDialog::on_boxChanged);
connect(ui->C1Box, &QSpinBox::textChanged, this, &MF_trailerDecoderDialog::on_boxChanged);
connect(ui->C2Box, &QSpinBox::textChanged, this, &MF_trailerDecoderDialog::on_boxChanged);
connect(ui->C3Box, &QSpinBox::textChanged, this, &MF_trailerDecoderDialog::on_boxChanged);
connect(ui->C0Box, QOverload<int>::of(&QSpinBox::valueChanged), this, &MF_trailerDecoderDialog::on_boxChanged);
connect(ui->C1Box, QOverload<int>::of(&QSpinBox::valueChanged), this, &MF_trailerDecoderDialog::on_boxChanged);
connect(ui->C2Box, QOverload<int>::of(&QSpinBox::valueChanged), this, &MF_trailerDecoderDialog::on_boxChanged);
connect(ui->C3Box, QOverload<int>::of(&QSpinBox::valueChanged), this, &MF_trailerDecoderDialog::on_boxChanged);
ui->dataBlockWidget->setRowCount(3);
ui->dataBlockWidget->setColumnCount(4);
@ -123,7 +123,7 @@ void MF_trailerDecoderDialog::setTableItem(QTableWidget* widget, int row, int co
widget->item(row, column)->setText(text);
}
void MF_trailerDecoderDialog::on_boxChanged(const QString &arg1)
void MF_trailerDecoderDialog::on_boxChanged(int arg1)
{
quint8 ACBits[4];
ACBits[0] = ui->C0Box->value();

@ -27,7 +27,7 @@ private slots:
void on_blockSizeChanged(int id, bool st);
void on_boxChanged(const QString &arg1);
void on_boxChanged(int arg1);
private:
Ui::MF_trailerDecoderDialog *ui;
QRegularExpressionValidator* validator;

@ -18,6 +18,14 @@ MF_UID_parameterDialog::~MF_UID_parameterDialog()
void MF_UID_parameterDialog::on_buttonBox_accepted()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
emit sendCMD("hf mf csetuid "
+ ui->UIDLineEdit->text()
+ " "
+ ui->ATQALineEdit->text()
+ " "
+ ui->SAKLineEdit->text());
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN) // same format in v4.9237
emit sendCMD("hf mf csetuid "
+ ui->UIDLineEdit->text()
+ " "

@ -2,8 +2,10 @@
#define MF_UID_PARAMETERDIALOG_H
#include <QDialog>
#include "common/util.h"
namespace Ui {
namespace Ui
{
class MF_UID_parameterDialog;
}
@ -18,7 +20,7 @@ public:
private:
Ui::MF_UID_parameterDialog *ui;
signals:
void sendCMD(QString cmd);
void sendCMD(const QString& cmd);
private slots:
void on_buttonBox_accepted();
};

Loading…
Cancel
Save