17 Commits

Author SHA1 Message Date
wh201906 bac6207634 V0.2.1 2021-03-16 11:23:01 +08:00
wh201906 ccb07651cc Mifare: Optimize read logic
Fix bug #16 mentioned in http://www.proxmark.org/forum/viewtopic.php?pid=42123 (see the 17th post)
This is caused by the output change in RRG repo
Optimize _readsec() logic
Implement getTrailerBlockId()
2021-03-16 11:06:26 +08:00
wh201906 f706d59c48 Update UI 2021-03-15 11:29:17 +08:00
wh201906 9e31496131 Fail to support non-ASCII chars in path
Using "chcp" seems to have no effect there
I fix a small bug then
2021-03-12 11:59:51 +08:00
wh201906 a232e4ec83 Fix #15 partially
The path of the start script or the client can contain spaces now(on Windows)
TODO:
Test the issue on Linux and implement the fix if it's needed
Support non-ASCII chars in the path
2021-03-11 00:46:56 +08:00
wh201906 1bec73d1ad T55xx: Add some useless UI 2021-03-08 23:02:16 +08:00
wh201906 a8b1a4a82e V0.2 2021-02-23 20:40:55 +08:00
wh201906 03bb57ee58 Update translations 2021-02-23 19:47:36 +08:00
wh201906 15538a9892 LF: Support write LF config
When setting LF freq, the "lf config" and "hw setlfdivisor" will both be called.
Change some UI
2021-02-23 18:14:59 +08:00
wh201906 466cd0ecc1 LF: support read LF config 2021-02-23 16:35:58 +08:00
wh201906 019afed198 Add QAction: Dock all windows 2021-02-22 22:20:49 +08:00
wh201906 799e00d66e Replace QTabWidget with QDockWidget
dock it(√)
doki(?)
2021-02-22 15:57:32 +08:00
wh201906 ae9e4d1a4f LF: support read(), sniff(), search() and tune() 2021-02-22 13:55:45 +08:00
wh201906 c3aafc3d31 Fix a bug in disconnect() 2021-02-22 12:47:55 +08:00
wh201906 fb8e1a6e1b New experimental feature
Keep client active even the PM3 hardware is disconnected
2021-02-21 23:00:07 +08:00
wh201906 90e4fde882 Fix a bug in RawCommand Tab
Not all of the keys should be redirected.
2021-02-21 21:30:22 +08:00
wh201906 705c8de54c Fix a bug in RawCommand Tab
If a widget is set to NoFocus, then it will not respond to the key Event
2021-02-20 20:51:26 +08:00
22 changed files with 3029 additions and 749 deletions
+3 -1
View File
@@ -20,6 +20,7 @@ SOURCES += \
main.cpp \
common/pm3process.cpp \
common/util.cpp \
module/lf.cpp \
module/mifare.cpp \
ui/mf_trailerdecoderdialog.cpp \
ui/mf_sim_simdialog.cpp \
@@ -31,6 +32,7 @@ HEADERS += \
common/myeventfilter.h \
common/pm3process.h \
common/util.h \
module/lf.h \
module/mifare.h \
ui/mf_trailerdecoderdialog.h \
ui/mf_sim_simdialog.h \
@@ -54,7 +56,7 @@ qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
VERSION = 0.1.4
VERSION = 0.2.1
QMAKE_TARGET_PRODUCT = "Proxmark3GUI"
QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI"
QMAKE_TARGET_COMPANY = "wh201906"
+13 -2
View File
@@ -3,7 +3,7 @@
A cross-platform GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) client
[中文](README/doc/README_zh_CN.md)
[中文介绍](README/doc/README_zh_CN.md)
***
@@ -19,6 +19,7 @@ A cross-platform GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) clie
+ Support binary(.bin .dump) files and text(.eml) files
+ Analyze Access Bits
+ Support Chinese Magic Card
+ Have basic support for LF commands
+ Customize UI
+ ...
@@ -40,7 +41,7 @@ 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.
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 the client on Windows.
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.
@@ -64,6 +65,16 @@ Great thanks to him.
## Update Log:
### V0.2.1
+ Optimize MIFARE Classic reading logic
+ Fix bug #16
+ Fix bug #15 partially (the path can contain spaces now)
### V0.2
+ Use Dock widget for more flexible layout
+ Support basic LF commands
+ Fix a bug in RawCommand tab
### V0.1.4
+ Optimize performance
+ Optimize UI
+12 -1
View File
@@ -19,7 +19,8 @@
+ 可以打开二进制/文本格式的扇区数据文件
+ 分析访问控制位(Access Bits
+ 支持UID卡操作(UID快速读写,UFUID锁卡)
+ 自定义UI界面
+ 支持部分低频命令
+ 自定义UI界面,各选项卡可拆分组合
+ ...
***
@@ -63,6 +64,16 @@ release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客
## 更新日志:
### V0.2.1
+ 优化MIFARE Classic读卡逻辑
+ 修复 #16 (配合新版RRG固件时无法读取扇区数据)
+ 修复 #15 (路径中支持空格)
### V0.2
+ 使用浮动窗口,界面配置更加灵活
+ 支持部分低频命令
+ 修复原始命令选项卡中的一个Bug
### V0.1.4
+ 优化性能
+ 优化用户界面
+4
View File
@@ -14,3 +14,7 @@ Mifare Edit File:
Mifare Trailer Decoder:
![mf_trailer](../img/mf_trailer.gif)
Dock Widget:
![dock1](../img/dock1.png)
![dock2](../img/dock2.png)
Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 50 KiB

+21 -11
View File
@@ -12,9 +12,10 @@ PM3Process::PM3Process(QThread* thread, QObject* parent): QProcess(parent)
serialListener->setTimerType(Qt::VeryCoarseTimer);
connect(serialListener, &QTimer::timeout, this, &PM3Process::onTimeout);
connect(this, &PM3Process::readyRead, this, &PM3Process::onReadyRead);
portInfo = nullptr;
}
void PM3Process::connectPM3(const QString& path, const QString& port, const QStringList args)
void PM3Process::connectPM3(const QString& path, const QStringList args)
{
QString result;
Util::ClientType clientType;
@@ -22,7 +23,6 @@ void PM3Process::connectPM3(const QString& path, const QString& port, const QStr
// stash for reconnect
currPath = path;
currPort = port;
currArgs = args;
// using "-f" option to make the client output flushed after every print.
@@ -55,11 +55,6 @@ void PM3Process::connectPM3(const QString& path, const QString& port, const QStr
result = result.left(result.indexOf("\r\n"));
result = result.mid(3, result.lastIndexOf(" ") - 3);
emit PM3StatedChanged(true, result);
// if the arguments don't contain <port>, then disable the port listener
// useful when using offline sniff
if(args.indexOf(port) != -1)
setSerialListener(port, true);
}
else
kill();
@@ -68,7 +63,7 @@ void PM3Process::connectPM3(const QString& path, const QString& port, const QStr
void PM3Process::reconnectPM3()
{
connectPM3(currPath, currPort, currArgs);
connectPM3(currPath, currArgs);
}
void PM3Process::setRequiringOutput(bool st)
@@ -87,6 +82,7 @@ void PM3Process::setSerialListener(const QString& name, bool state)
{
if(state)
{
currPort = name;
portInfo = new QSerialPortInfo(name);
serialListener->start();
qDebug() << serialListener->thread();
@@ -94,8 +90,17 @@ void PM3Process::setSerialListener(const QString& name, bool state)
else
{
serialListener->stop();
if(portInfo != nullptr)
{
delete portInfo;
portInfo = nullptr;
}
}
}
void PM3Process::setSerialListener(bool state)
{
setSerialListener(currPort, state);
}
void PM3Process::onTimeout() //when the proxmark3 client is unexpectedly terminated or the PM3 hardware is removed, the isBusy() will return false(only tested on Windows);
@@ -103,9 +108,7 @@ void PM3Process::onTimeout() //when the proxmark3 client is unexpectedly termina
// qDebug()<<portInfo->isBusy();
if(!portInfo->isBusy())
{
kill();
emit PM3StatedChanged(false);
setSerialListener("", false);
killPM3();
}
}
@@ -144,3 +147,10 @@ void PM3Process::setWorkingDir(const QString& dir)
// the working directory cannot be the default, or the client will failed to load the dll
this->setWorkingDirectory(dir);
}
void PM3Process::killPM3()
{
kill();
emit PM3StatedChanged(false);
setSerialListener(false);
}
+4 -2
View File
@@ -23,12 +23,14 @@ public:
void testThread();
public slots:
void connectPM3(const QString& path, const QString& port, const QStringList args);
void connectPM3(const QString& path, const QStringList args);
void setSerialListener(const QString& name, bool state);
void setSerialListener(bool state);
qint64 write(QString data);
void reconnectPM3();
void setProcEnv(const QStringList* env);
void setWorkingDir(const QString& dir);
void killPM3();
private slots:
void onTimeout();
void onReadyRead();
@@ -39,7 +41,7 @@ private:
QTimer* serialListener;
QSerialPortInfo* portInfo;
QString currPath;
QString currPort;
QString currPort = "";
QStringList currArgs;
signals:
+25
View File
@@ -2,6 +2,11 @@
Util::ClientType Util::clientType = CLIENTTYPE_OFFICIAL;
int Util::rawTabIndex = 0;
QDockWidget* Util::rawDockPtr = nullptr;
Ui::MainWindow* Util::ui = nullptr;
Util::Util(QObject *parent) : QObject(parent)
{
isRequiringOutput = false;
@@ -10,6 +15,7 @@ Util::Util(QObject *parent) : QObject(parent)
qRegisterMetaType<Util::ClientType>("Util::ClientType");
}
void Util::processOutput(const QString& output)
{
// qDebug() << "Util::processOutput:" << output;
@@ -120,3 +126,22 @@ bool Util::chooseLanguage(QSettings* guiSettings, QMainWindow* window)
}
return isOk;
}
void Util::gotoRawTab()
{
Util::ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::rawDockPtr->setVisible(true);
Util::rawDockPtr->raise();
}
void Util::setUI(Ui::MainWindow *ui)
{
Util::ui = ui;
}
void Util::setRawTab(QDockWidget *dockPtr, int tabIndex)
{
Util::rawDockPtr = dockPtr;
Util::rawTabIndex = tabIndex;
}
+9 -2
View File
@@ -13,6 +13,9 @@
#include <QSettings>
#include <QMainWindow>
#include <QInputDialog>
#include <QDockWidget>
#include "ui_mainwindow.h"
class Util : public QObject
{
@@ -53,19 +56,23 @@ public:
QString execCMDWithOutput(const QString& cmd, ReturnTrigger trigger = 10000);
void delay(unsigned int msec);
static ClientType getClientType();
static const int rawTabIndex = 1;
static int rawTabIndex;
static QDockWidget* rawDockPtr;
static bool chooseLanguage(QSettings *guiSettings, QMainWindow *window);
public slots:
void processOutput(const QString& output);
static void setClientType(Util::ClientType clientType);
void setRunningState(bool st);
static void gotoRawTab();
static void setUI(Ui::MainWindow *ui);
static void setRawTab(QDockWidget* dockPtr, int tabIndex);
private:
bool isRequiringOutput;
bool isRunning;
QString* requiredOutput;
QTime timeStamp;
static ClientType clientType;
static Ui::MainWindow *ui;
signals:
void refreshOutput(const QString& output);
void write(QString data); // connected to PM3Process::write(QString data);
+478 -193
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+495 -203
View File
File diff suppressed because it is too large Load Diff
+167
View File
@@ -0,0 +1,167 @@
#include "lf.h"
const LF::Config LF::defaultConfig;
LF::LF(Ui::MainWindow *ui, Util *addr, QWidget *parent): QObject(parent)
{
this->parent = parent;
util = addr;
this->ui = ui;
configPattern = new QRegularExpression("(\\d+)|Yes|No");
currConfig = defaultConfig;
}
void LF::read()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("lf read");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("lf read -v");
Util::gotoRawTab();
util->execCMD("data plot");
}
void LF::sniff()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("lf snoop");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("lf sniff -v");
Util::gotoRawTab();
util->execCMD("data plot");
}
void LF::search()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("lf search u");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("lf search -u");
Util::gotoRawTab();
}
void LF::tune()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hw tune l");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("lf tune --divisor " + QString::number(currConfig.divisor));
Util::gotoRawTab();
}
void LF::getConfig()
{
QRegularExpressionMatch reMatch;
QString result;
QStringList resultList;
QStringList symbolList =
{
"divisor",
"bps",
"bits per sample",
"decimation",
"averaging",
"trigger threshold",
"samples to skip"
};
int offset;
QStringList configList = {"", "", "", "", "", "", ""};
result = util->execCMDWithOutput("hw status", 400); // not all output from "hw status will be processed".
result = result.right(result.length() - result.indexOf("LF Sampling config"));
offset = result.indexOf("samples to skip");
offset = result.indexOf("\r\n", offset);
result = result.mid(0, offset + 2);
qDebug() << "LF CONFIG GET\n" << result;
resultList = result.split("\r\n");
for(int i = 0; i < resultList.length(); i++)
{
for(int j = 0; j < symbolList.length(); j++)
{
if(!configList[j].isEmpty())
continue;
offset = resultList[i].indexOf(symbolList[j]);
if(offset != -1)
{
reMatch = configPattern->match(resultList[i]);
qDebug() << "finded: " << resultList[i];
if(!reMatch.hasMatch())
continue;
qDebug() << "captured: " << reMatch.captured();
configList[j] = reMatch.captured();
break;
}
}
}
qDebug() << "configList: " << configList;
currConfig.divisor = configList[0].toUInt();
currConfig.decimation = configList[3].toUInt();
currConfig.triggerThreshold = configList[5].toUInt();
currConfig.samplesToSkip = configList[6].toUInt();
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
currConfig.bitPerSample = configList[1].toUInt();
currConfig.averaging = (configList[4] == "1");
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
currConfig.bitPerSample = configList[2].toUInt();
currConfig.averaging = (configList[4] == "Yes");
}
syncWithUI();
}
void LF::setConfig(LF::Config config)
{
currConfig = config;
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
util->execCMDWithOutput(QString("lf config")
+ " q " + QString::number(currConfig.divisor)
+ " b " + QString::number(currConfig.bitPerSample)
+ " d " + QString::number(currConfig.decimation)
+ " a " + QString(currConfig.averaging ? "1" : "0")
+ " t " + QString::number(currConfig.triggerThreshold)
+ " s " + QString::number(currConfig.samplesToSkip),
500);
util->execCMDWithOutput("hw setlfdivisor " + QString::number(currConfig.divisor), 500);
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
util->execCMDWithOutput(QString("lf config")
+ " -a " + QString(currConfig.averaging ? "1" : "0")
+ " -b " + QString::number(currConfig.bitPerSample)
+ " --dec " + QString::number(currConfig.decimation)
+ " --divisor " + QString::number(currConfig.divisor)
+ " -s " + QString::number(currConfig.samplesToSkip)
+ " -t " + QString::number(currConfig.triggerThreshold),
500);
util->execCMDWithOutput("hw setlfdivisor -d " + QString::number(currConfig.divisor), 500);
}
}
void LF::resetConfig()
{
setConfig(defaultConfig);
getConfig();
}
float LF::divisor2Freq(uint8_t divisor)
{
return (12000.0 / (divisor + 1.0));
}
uint8_t LF::freq2Divisor(float freq)
{
return ((uint16_t)(12000.0 / freq + 0.5) - 1); // uint16_t for (divisor + 1) = 256
}
void LF::syncWithUI()
{
ui->LF_Conf_freqDivisorBox->setValue(currConfig.divisor); // will trigger valueChanged()
ui->LF_Conf_bitPerSampleBox->setValue(currConfig.bitPerSample);
ui->LF_Conf_decimationBox->setValue(currConfig.decimation);
ui->LF_Conf_averagingBox->setChecked(currConfig.averaging);
ui->LF_Conf_thresholdBox->setValue(currConfig.triggerThreshold);
ui->LF_Conf_skipsBox->setValue(currConfig.samplesToSkip);
}
+56
View File
@@ -0,0 +1,56 @@
#ifndef LF_H
#define LF_H
#include <QObject>
#include "common/util.h"
#include "ui_mainwindow.h"
class LF : public QObject
{
Q_OBJECT
public:
explicit LF(Ui::MainWindow *ui, Util *addr, QWidget *parent = nullptr);
struct Config
{
uint8_t divisor;
uint8_t bitPerSample;
uint8_t decimation;
bool averaging;
uint8_t triggerThreshold;
uint16_t samplesToSkip;
};
static constexpr Config defaultConfig =
{
95,
8,
1,
true,
0,
0
};
void read();
void sniff();
void search();
void tune();
void getConfig();
void setConfig(LF::Config config);
void resetConfig();
static float divisor2Freq(uint8_t divisor);
static uint8_t freq2Divisor(float freq);
private:
QWidget* parent;
Ui::MainWindow *ui;
Util* util;
Config currConfig;
QRegularExpression* configPattern;
void syncWithUI();
signals:
};
#endif // LF_H
+79 -39
View File
@@ -106,7 +106,7 @@ QString Mifare::info(bool isRequiringOutput)
else
{
util->execCMD("hf 14a info");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
}
return "";
@@ -255,7 +255,7 @@ 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(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::darkside()
@@ -265,7 +265,7 @@ void Mifare::darkside()
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf darkside");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::sniff()
@@ -275,7 +275,7 @@ void Mifare::sniff()
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf sniff");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::sniff14a()
@@ -285,7 +285,7 @@ void Mifare::sniff14a()
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf 14a sniff");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::list()
@@ -295,7 +295,7 @@ void Mifare::list()
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("trace list -t mf");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, TargetType targetType, int waitTime)
@@ -419,7 +419,6 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
+ " "
+ key,
waitTime);
offset = result.indexOf("isOk:01"); // find successful flag
}
else if(targetType == TARGET_UID)
{
@@ -427,9 +426,18 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
"hf mf cgetsc "
+ QString::number(sectorId),
waitTime);
offset = result.indexOf("error") == -1 ? 0 : -1; // find failed flag
}
if(offset != -1)
else if(targetType == TARGET_EMULATOR)
{
for(int i = 0; i < cardType.blk[sectorId]; i++)
data[i] = _readblk(cardType.blks[sectorId] + i, keyType, key, targetType, waitTime);
return data;
}
// for TARGET_MIFARE and TARGET_UID
reMatch = dataPattern->match(result);
offset = reMatch.capturedStart();
if(reMatch.hasMatch()) // read successful
{
for(int i = 0; i < cardType.blk[sectorId]; i++)
{
@@ -444,13 +452,11 @@ 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 || 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);
}
// when one of the block cannot be read, the rdsc will return nothing, so you need to read the rest of blocks manually
// the following rdbl operation is not handled there, for better speed(rdsc_A->rdsc_B->rdbl0~3)
else if(targetType == TARGET_UID) // treat as MIFARE
data = _readsec(sectorId, keyType, key, TARGET_MIFARE, waitTime);
//process trailer(like _readblk())
QString trailer = data[cardType.blk[sectorId] - 1];
@@ -493,7 +499,6 @@ void Mifare::readOne(TargetType targetType)
void Mifare::readSelected(TargetType targetType)
{
QStringList data, dataA, dataB;
QString trailerA, trailerB;
QList<bool> selectedSectors;
QList<int> selectedBlocks;
@@ -513,12 +518,11 @@ void Mifare::readSelected(TargetType targetType)
}
for(int i = 0; i < cardType.sector_size; i++)
{
{
if(!selectedSectors[i])
{
continue;
}
QStringList data, dataA, dataB;
for(int j = 0; j < cardType.blk[i]; j++)
{
// dataA is always filled with "" because of the _readsec()
@@ -529,24 +533,41 @@ void Mifare::readSelected(TargetType targetType)
dataA = _readsec(i, Mifare::KEY_A, keyAList->at(i), targetType);
// in other situations, the key doesn't matters
// so the dataA is the final result
//
// if the targetType is TARGET_MIFARE and the dataA has unknown part, try to read by keyB
if(targetType == TARGET_MIFARE && (dataA.contains("") || dataA[cardType.blk[i] - 1].right(12) == "????????????"))
dataB = _readsec(i, Mifare::KEY_B, keyBList->at(i), targetType);
// process trailer block seperately
if(dataA[cardType.blk[i] - 1] == "" && selectedBlocks.contains(getTrailerBlockId(i)))
dataA[cardType.blk[i] - 1] = _readblk(getTrailerBlockId(i), Mifare::KEY_A, keyAList->at(i), targetType);
if(dataB[cardType.blk[i] - 1] == "" && dataA[cardType.blk[i] - 1].right(12) == "????????????" && selectedBlocks.contains(getTrailerBlockId(i)))
dataB[cardType.blk[i] - 1] = _readblk(getTrailerBlockId(i), Mifare::KEY_B, keyBList->at(i), targetType);
for(int j = 0; j < cardType.blk[i]; j++)
{
if(dataA[j] != "")
data[j] = dataA[j];
else
data[j] = dataB[j];
if(data[j] == "" && selectedBlocks.contains(cardType.blks[i] + j)) // try rdbl seperately
{
data[j] = _readblk(cardType.blks[i] + j, Mifare::KEY_A, keyAList->at(i), targetType);
if(data[j] == "")
data[j] = _readblk(cardType.blks[i] + j, Mifare::KEY_B, keyBList->at(i), targetType);
}
}
// process trailer block seperately
trailerA = dataA[cardType.blk[i] - 1];
trailerB = dataB[cardType.blk[i] - 1];
if(trailerA != "" && trailerB != "")
if(trailerA != "" && trailerB != "") // if KeyA and KeyB can both read the trailer, then concat them
{
QString ACbits = trailerA.mid(12, 8);
QString key_A = trailerA.left(12);
QString key_A = trailerA.left(12); // KeyA cannot be read by KeyB
QString key_B = trailerA.at(31) != '?' ? trailerA.right(12) : trailerB.right(12);
data[cardType.blk[i] - 1] = key_A + ACbits + key_B;
}
@@ -560,7 +581,7 @@ void Mifare::readSelected(TargetType targetType)
}
}
if(selectedBlocks.contains(cardType.blks[i] + cardType.blk[i] - 1))
if(selectedBlocks.contains(getTrailerBlockId(i)))
{
// data widget has been updated, so this is just a temporary varient.
if(data[cardType.blk[i] - 1] == "")
@@ -574,8 +595,6 @@ void Mifare::readSelected(TargetType targetType)
data_syncWithKeyWidget(false, i, KEY_A);
data_syncWithKeyWidget(false, i, KEY_B);
}
}
}
}
@@ -742,14 +761,14 @@ void Mifare::dump()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf dump");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::restore()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf restore");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::wipeC()
@@ -765,7 +784,7 @@ void Mifare::wipeC()
{
util->execCMD("hf mf cwipe");
}
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::setParameterC()
@@ -786,7 +805,7 @@ void Mifare::setParameterC()
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(Util::rawTabIndex);
Util::gotoRawTab();
}
}
@@ -823,7 +842,7 @@ void Mifare::simulate()
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(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::loadSniff(const QString& file)
@@ -836,7 +855,7 @@ void Mifare::loadSniff(const QString& file)
util->execCMD("trace list -t mf");
}
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::saveSniff(const QString& file)
@@ -846,7 +865,7 @@ void Mifare::saveSniff(const QString& file)
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("trace save -f " + file);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::data_syncWithDataWidget(bool syncAll, int block)
@@ -1090,7 +1109,7 @@ bool Mifare::data_loadKeyFile(const QString& filename)
{
for(int i = 0; i < cardType.sector_size; i++)
{
int blk = cardType.blks[i] + cardType.blk[i] - 1;
int blk = getTrailerBlockId(i);
QString tmp = bin2text(buff, blk, 16);
keyAList->replace(i, tmp.left(12).toUpper());
keyBList->replace(i, tmp.right(12).toUpper());
@@ -1230,17 +1249,17 @@ void Mifare::data_key2Data()
else
tmp += "????????????";
if(dataList->at(cardType.blks[i] + cardType.blk[i] - 1) == "")
if(dataList->at(getTrailerBlockId(i)) == "")
tmp += "FF078069"; // default control bytes
else
tmp += dataList->at(cardType.blks[i] + cardType.blk[i] - 1).mid(12, 8);
tmp += dataList->at(getTrailerBlockId(i)).mid(12, 8);
if(data_isKeyValid(keyBList->at(i)))
tmp += keyBList->at(i);
else
tmp += "????????????";
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, tmp);
dataList->replace(getTrailerBlockId(i), tmp);
data_syncWithDataWidget();
}
}
@@ -1249,15 +1268,15 @@ void Mifare::data_data2Key()
{
for(int i = 0; i < cardType.sector_size; i++)
{
if(dataList->at(cardType.blks[i] + cardType.blk[i] - 1) == "")
if(dataList->at(getTrailerBlockId(i)) == "")
{
keyAList->replace(i, "????????????");
keyBList->replace(i, "????????????");
}
else
{
keyAList->replace(i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).left(12));
keyBList->replace(i, dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12));
keyAList->replace(i, dataList->at(getTrailerBlockId(i)).left(12));
keyBList->replace(i, dataList->at(getTrailerBlockId(i)).right(12));
}
data_syncWithKeyWidget();
}
@@ -1341,3 +1360,24 @@ QList<quint8> Mifare::data_getACBits(const QString& text) //return empty QList i
return result;
}
QString Mifare::data_getUID()
{
if(data_isDataValid(dataList->at(0)))
return dataList->at(0).left(8);
else
return "";
}
quint16 Mifare::getTrailerBlockId(quint8 sectorId, qint8 cardTypeId)
{
if(cardTypeId == 0)
return (card_mini.blks[sectorId] + card_mini.blk[sectorId] - 1);
else if(cardTypeId == 1)
return (card_1k.blks[sectorId] + card_1k.blk[sectorId] - 1);
else if(cardTypeId == 2)
return (card_2k.blks[sectorId] + card_2k.blk[sectorId] - 1);
else if(cardTypeId == 4)
return (card_4k.blks[sectorId] + card_4k.blk[sectorId] - 1);
else
// other cardTypeId: use current cardtype(include default -1)
return (cardType.blks[sectorId] + cardType.blk[sectorId] - 1);
}
+2
View File
@@ -111,6 +111,8 @@ 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);
QString data_getUID();
quint16 getTrailerBlockId(quint8 sectorId, qint8 cardTypeId = -1); // -1: use current cardtype
public slots:
signals:
+222 -33
View File
@@ -6,9 +6,15 @@ MainWindow::MainWindow(QWidget *parent):
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
dockAllWindows = new QAction(tr("Dock all windows"), this);
myInfo = new QAction("wh201906", this);
currVersion = new QAction("Ver: " + QApplication::applicationVersion().section('.', 0, -2), this); // ignore the 4th version number
currVersion = new QAction(tr("Ver: ") + QApplication::applicationVersion().section('.', 0, -2), this); // ignore the 4th version number
checkUpdate = new QAction(tr("Check Update"), this);
connect(dockAllWindows, &QAction::triggered, [ = ]()
{
for(int i = 0; i < dockList.size(); i++)
dockList[i]->setFloating(false);
});
connect(myInfo, &QAction::triggered, [ = ]()
{
QDesktopServices::openUrl(QUrl("https://github.com/wh201906"));
@@ -17,9 +23,6 @@ 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");
@@ -31,20 +34,30 @@ MainWindow::MainWindow(QWidget *parent):
clientWorkingDir = new QDir;
util = new Util(this);
Util::setUI(ui);
mifare = new Mifare(ui, util, this);
lf = new LF(ui, util, this);
keyEventFilter = new MyEventFilter(QEvent::KeyRelease);
keyEventFilter = new MyEventFilter(QEvent::KeyPress);
resizeEventFilter = new MyEventFilter(QEvent::Resize);
// hide unused tabs
ui->funcTab->removeTab(1);
ui->funcTab->removeTab(1);
// ui->funcTab->removeTab(1);
ui->funcTab->removeTab(2);
portSearchTimer = new QTimer(this);
portSearchTimer->setInterval(2000);
connect(portSearchTimer, &QTimer::timeout, this, &MainWindow::on_portSearchTimer_timeout);
portSearchTimer->start();
contextMenu = new QMenu();
contextMenu->addAction(dockAllWindows);
contextMenu->addSeparator();
contextMenu->addAction(myInfo);
currVersion->setEnabled(false);
contextMenu->addAction(currVersion);
contextMenu->addAction(checkUpdate);
}
MainWindow::~MainWindow()
@@ -63,6 +76,7 @@ void MainWindow::initUI() // will be called by main.app
uiInit();
signalInit();
setState(false);
dockInit();
}
// ******************** basic functions ********************
@@ -89,11 +103,19 @@ void MainWindow::on_PM3_connectButton_clicked()
qDebug() << "Main:" << QThread::currentThread();
QString port = ui->PM3_portBox->currentText();
if(port == "")
QMessageBox::information(NULL, tr("Info"), tr("Plz choose a port first"), QMessageBox::Ok);
else
QString startArgs = ui->Set_Client_startArgsEdit->text();
// on RRG repo, if no port is specified, the client will search the available port
if(port == "" && startArgs.contains("<port>")) // has <port>, no port
{
QStringList args = ui->Set_Client_startArgsEdit->text().replace("<port>", port).split(' ');
QMessageBox::information(NULL, tr("Info"), tr("Plz choose a port first"), QMessageBox::Ok);
return;
}
if(!startArgs.contains("<port>")) // no <port>
port = ""; // a symbol
QStringList args = startArgs.replace("<port>", port).split(' ');
saveClientPath(ui->PM3_pathEdit->text());
QProcess envSetProcess;
@@ -101,20 +123,32 @@ void MainWindow::on_PM3_connectButton_clicked()
if(envScriptPath.exists())
{
qDebug() << envScriptPath.absoluteFilePath();
// use the shell session to keep the environment then read it
#ifdef Q_OS_WIN
// cmd /c "<path>">>nul && set
envSetProcess.start("cmd /c \"" + envScriptPath.absoluteFilePath() + "\">>nul && set");
envSetProcess.start("cmd");
envSetProcess.write(QString("\"" + envScriptPath.absoluteFilePath() + "\">>nul\r\n").toLatin1());
envSetProcess.waitForReadyRead(10000);
envSetProcess.readAll();
envSetProcess.write("set\r\n");
#else
// need implementation(or test if space works)
// 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);
QString envSetResult = QString(envSetProcess.readAll());
clientEnv = envSetResult.split(QRegExp("[\r\n]{1,2}"), QString::SkipEmptyParts);
if(clientEnv.size() > 2) // the first element is "set" and the last element is the current path
{
clientEnv.removeFirst();
clientEnv.removeLast();
emit setProcEnv(&clientEnv);
}
// qDebug() << "Get Env List" << clientEnv;
}
else
clientEnv.clear();
emit setProcEnv(&clientEnv);
clientWorkingDir->setPath(QApplication::applicationDirPath());
qDebug() << clientWorkingDir->absolutePath();
@@ -124,8 +158,13 @@ void MainWindow::on_PM3_connectButton_clicked()
qDebug() << clientWorkingDir->absolutePath();
emit setWorkingDir(clientWorkingDir->absolutePath());
emit connectPM3(ui->PM3_pathEdit->text(), port, args);
}
emit connectPM3(ui->PM3_pathEdit->text(), args);
if(port != "" && !keepClientActive)
emit setSerialListener(port, true);
else if(!keepClientActive)
emit setSerialListener(false);
envSetProcess.kill();
}
void MainWindow::onPM3StateChanged(bool st, const QString& info)
@@ -149,13 +188,13 @@ void MainWindow::onPM3StateChanged(bool st, const QString& info)
void MainWindow::on_PM3_disconnectButton_clicked()
{
emit killPM3();
emit setSerialListener("", false);
emit setSerialListener(false);
}
void MainWindow::refreshOutput(const QString& output)
{
// qDebug() << "MainWindow::refresh:" << output;
ui->Raw_outputEdit->insertPlainText(output);
ui->Raw_outputEdit->appendPlainText(output);
ui->Raw_outputEdit->moveCursor(QTextCursor::End);
}
@@ -173,6 +212,7 @@ void MainWindow::on_stopButton_clicked()
break;
}
emit reconnectPM3();
emit setSerialListener(!keepClientActive);
}
}
// *********************************************************
@@ -240,11 +280,13 @@ void MainWindow::refreshCMD(const QString& cmd)
ui->Raw_CMDEdit->blockSignals(false);
}
void MainWindow::on_Raw_CMDEdit_keyPressed(QObject* obj_addr, QEvent& event)
void MainWindow::on_Raw_keyPressed(QObject* obj_addr, QEvent& event)
{
if(obj_addr == ui->Raw_CMDEdit && event.type() == QEvent::KeyRelease)
if(event.type() == QEvent::KeyPress)
{
QKeyEvent& keyEvent = static_cast<QKeyEvent&>(event);
if(obj_addr == ui->Raw_CMDEdit)
{
if(keyEvent.key() == Qt::Key_Up)
{
if(stashedIndex > 0)
@@ -269,6 +311,12 @@ void MainWindow::on_Raw_CMDEdit_keyPressed(QObject* obj_addr, QEvent& event)
ui->Raw_CMDEdit->blockSignals(false);
}
}
else if(obj_addr == ui->Raw_outputEdit)
{
if(keyEvent.key() == Qt::Key_Up || keyEvent.key() == Qt::Key_Down)
ui->Raw_CMDEdit->setFocus();
}
}
}
// *****************************************************
@@ -600,11 +648,15 @@ void MainWindow::on_MF_File_saveButton_clicked()
QString title = "";
QString filename = "";
QString selectedType = "";
QString defaultName = mifare->data_getUID();
if(defaultName != "")
defaultName += "_";
defaultName += QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss");
if(ui->MF_File_dataBox->isChecked())
{
title = tr("Plz select the location to save data file:");
filename = QFileDialog::getSaveFileName(this, title, "./", tr("Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml)"), &selectedType);
filename = QFileDialog::getSaveFileName(this, title, "./data_" + defaultName, tr("Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml)"), &selectedType);
qDebug() << filename;
if(filename != "")
{
@@ -617,7 +669,7 @@ void MainWindow::on_MF_File_saveButton_clicked()
else if(ui->MF_File_keyBox->isChecked())
{
title = tr("Plz select the location to save key file:");
filename = QFileDialog::getSaveFileName(this, title, "./", tr("Binary Key Files(*.bin *.dump)"), &selectedType);
filename = QFileDialog::getSaveFileName(this, title, "./key_" + defaultName, tr("Binary Key Files(*.bin *.dump)"), &selectedType);
qDebug() << filename;
if(filename != "")
{
@@ -907,11 +959,12 @@ void MainWindow::MF_widgetReset()
void MainWindow::uiInit()
{
connect(ui->Raw_CMDEdit, &QLineEdit::editingFinished, this, &MainWindow::sendMSG);
connect(ui->Raw_CMDEdit, &QLineEdit::returnPressed, this, &MainWindow::sendMSG);
ui->Raw_CMDEdit->installEventFilter(keyEventFilter);
connect(keyEventFilter, &MyEventFilter::eventHappened, this, &MainWindow::on_Raw_CMDEdit_keyPressed);
connect(keyEventFilter, &MyEventFilter::eventHappened, this, &MainWindow::on_Raw_keyPressed);
ui->MF_keyWidget->installEventFilter(resizeEventFilter);
connect(resizeEventFilter, &MyEventFilter::eventHappened, this, &MainWindow::on_MF_keyWidget_resized);
ui->Raw_outputEdit->installEventFilter(keyEventFilter);
connectStatusBar = new QLabel(this);
programStatusBar = new QLabel(this);
@@ -926,17 +979,9 @@ void MainWindow::uiInit()
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->setColumnWidth(0, 55);
ui->MF_dataWidget->setColumnWidth(1, 55);
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->setColumnWidth(0, 45);
MF_widgetReset();
@@ -985,6 +1030,11 @@ void MainWindow::uiInit()
ui->Set_Client_forceEnabledBox->setChecked(keepButtonsEnabled);
settings->endGroup();
settings->beginGroup("Client_keepClientActive");
keepClientActive = settings->value("state", false).toBool();
ui->Set_Client_keepClientActiveBox->setChecked(keepClientActive);
settings->endGroup();
settings->beginGroup("Client_Env");
ui->Set_Client_envScriptEdit->setText(settings->value("scriptPath").toString());
ui->Set_Client_workingDirEdit->setText(settings->value("workingDir", "../data").toString());
@@ -994,6 +1044,7 @@ void MainWindow::uiInit()
ui->MF_RW_keyTypeBox->addItem("B", Mifare::KEY_B);
on_Raw_CMDHistoryBox_stateChanged(Qt::Unchecked);
}
void MainWindow::signalInit()
@@ -1006,9 +1057,11 @@ void MainWindow::signalInit()
connect(this, &MainWindow::reconnectPM3, pm3, &PM3Process::reconnectPM3);
connect(pm3, &PM3Process::PM3StatedChanged, this, &MainWindow::onPM3StateChanged);
connect(pm3, &PM3Process::PM3StatedChanged, util, &Util::setRunningState);
connect(this, &MainWindow::killPM3, pm3, &PM3Process::kill);
connect(this, &MainWindow::killPM3, pm3, &PM3Process::killPM3);
connect(this, &MainWindow::setProcEnv, pm3, &PM3Process::setProcEnv);
connect(this, &MainWindow::setWorkingDir, pm3, &PM3Process::setWorkingDir);
connect(this, QOverload<bool>::of(&MainWindow::setSerialListener), pm3, QOverload<bool>::of(&PM3Process::setSerialListener));
connect(this, QOverload<const QString&, bool>::of(&MainWindow::setSerialListener), pm3, QOverload<const QString&, bool>::of(&PM3Process::setSerialListener));
connect(util, &Util::write, pm3, &PM3Process::write);
@@ -1103,6 +1156,8 @@ void MainWindow::setButtonsEnabled(bool st)
ui->MF_sniffGroupBox->setEnabled(st);
ui->Raw_CMDEdit->setEnabled(st);
ui->Raw_sendCMDButton->setEnabled(st);
ui->LF_configGroupBox->setEnabled(st);
ui->LF_operationGroupBox->setEnabled(st);
}
void MainWindow::on_GroupBox_clicked(bool checked)
@@ -1180,3 +1235,137 @@ void MainWindow::on_Set_Client_saveWorkingDirButton_clicked()
settings->setValue("workingDir", ui->Set_Client_workingDirEdit->text());
settings->endGroup();
}
void MainWindow::on_Set_Client_keepClientActiveBox_stateChanged(int arg1)
{
settings->beginGroup("Client_keepClientActive");
keepClientActive = (arg1 == Qt::Checked);
settings->setValue("state", keepClientActive);
settings->endGroup();
emit setSerialListener(!keepClientActive);
}
void MainWindow::on_LF_Conf_freqSlider_valueChanged(int value)
{
onLFfreqConfChanged(value, true);
}
void MainWindow::onLFfreqConfChanged(int value, bool isCustomized)
{
ui->LF_Conf_freqDivisorBox->blockSignals(true);
ui->LF_Conf_freqSlider->blockSignals(true);
if(isCustomized)
ui->LF_Conf_freqOtherButton->setChecked(true);
ui->LF_Conf_freqLabel->setText(tr("Actural Freq: ") + QString("%1kHz").arg(LF::divisor2Freq(value), 0, 'f', 3));
ui->LF_Conf_freqDivisorBox->setValue(value);
ui->LF_Conf_freqSlider->setValue(value);
ui->LF_Conf_freqDivisorBox->blockSignals(false);
ui->LF_Conf_freqSlider->blockSignals(false);
}
void MainWindow::on_LF_Conf_freqDivisorBox_valueChanged(int arg1)
{
onLFfreqConfChanged(arg1, true);
}
void MainWindow::on_LF_Conf_freq125kButton_clicked()
{
onLFfreqConfChanged(95, false);
}
void MainWindow::on_LF_Conf_freq134kButton_clicked()
{
onLFfreqConfChanged(88, false);
}
void MainWindow::on_LF_Op_searchButton_clicked()
{
setState(false);
lf->search();
setState(true);
}
void MainWindow::on_LF_Op_readButton_clicked()
{
setState(false);
lf->read();
setState(true);
}
void MainWindow::on_LF_Op_tuneButton_clicked()
{
setState(false);
lf->tune();
setState(true);
}
void MainWindow::on_LF_Op_sniffButton_clicked()
{
setState(false);
lf->sniff();
setState(true);
}
void MainWindow::dockInit()
{
setDockNestingEnabled(true);
QDockWidget* dock;
QWidget* widget;
int count = ui->funcTab->count();
qDebug() << "dock count" << count;
for(int i = 0; i < count; i++)
{
dock = new QDockWidget(ui->funcTab->tabText(0), this);
qDebug() << "dock name" << ui->funcTab->tabText(0);
dock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);// movable is necessary, otherwise the dock cannot be dragged
dock->setAllowedAreas(Qt::BottomDockWidgetArea);
dock->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
widget = ui->funcTab->widget(0);
dock->setWidget(widget);
if(widget->objectName() == "rawTab")
Util::setRawTab(dock, i);
addDockWidget(Qt::BottomDockWidgetArea, dock);
if(!dockList.isEmpty())
tabifyDockWidget(dockList[0], dock);
dockList.append(dock);
}
ui->funcTab->setVisible(false);
dockList[0]->setVisible(true);
dockList[0]->raise();
}
void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
contextMenu->exec(event->globalPos());
}
void MainWindow::on_LF_Conf_getButton_clicked()
{
setState(false);
lf->getConfig();
setState(true);
}
void MainWindow::on_LF_Conf_setButton_clicked()
{
LF::Config config;
setState(false);
config.divisor = ui->LF_Conf_freqDivisorBox->value();
config.bitPerSample = ui->LF_Conf_bitPerSampleBox->value();
config.decimation = ui->LF_Conf_decimationBox->value();
config.averaging = ui->LF_Conf_averagingBox->isChecked();
config.triggerThreshold = ui->LF_Conf_thresholdBox->value();
config.samplesToSkip = ui->LF_Conf_skipsBox->value();
lf->setConfig(config);
Util::gotoRawTab();
setState(true);
}
void MainWindow::on_LF_Conf_resetButton_clicked()
{
setState(false);
lf->resetConfig();
setState(true);
}
+41 -3
View File
@@ -23,10 +23,14 @@
#include <QProcessEnvironment>
#include <QScrollBar>
#include <QTimer>
#include <QDateTime>
#include <QDockWidget>
#include <QMenu>
#include "common/myeventfilter.h"
#include "common/pm3process.h"
#include "module/mifare.h"
#include "module/lf.h"
#include "common/util.h"
#include "ui/mf_trailerdecoderdialog.h"
@@ -53,7 +57,7 @@ public slots:
void setStatusBar(QLabel* target, const QString& text);
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_Raw_keyPressed(QObject *obj_addr, QEvent &event);
void on_MF_keyWidget_resized(QObject *obj_addr, QEvent &event);
private slots:
@@ -175,6 +179,30 @@ private slots:
void on_Set_Client_saveWorkingDirButton_clicked();
void on_Set_Client_keepClientActiveBox_stateChanged(int arg1);
void on_LF_Conf_freqSlider_valueChanged(int value);
void on_LF_Conf_freqDivisorBox_valueChanged(int arg1);
void on_LF_Conf_freq125kButton_clicked();
void on_LF_Conf_freq134kButton_clicked();
void on_LF_Op_searchButton_clicked();
void on_LF_Op_readButton_clicked();
void on_LF_Op_tuneButton_clicked();
void on_LF_Op_sniffButton_clicked();
void on_LF_Conf_getButton_clicked();
void on_LF_Conf_setButton_clicked();
void on_LF_Conf_resetButton_clicked();
private:
Ui::MainWindow* ui;
QButtonGroup* MFCardTypeBtnGroup;
@@ -182,6 +210,7 @@ private:
QLabel* programStatusBar;
QLabel* PM3VersionBar;
QPushButton* stopButton;
QAction* dockAllWindows;
QAction* myInfo;
QAction* currVersion;
QAction* checkUpdate;
@@ -197,6 +226,7 @@ private:
PM3Process* pm3;
bool pm3state;
bool keepButtonsEnabled;
bool keepClientActive;
QThread* pm3Thread;
QTimer* portSearchTimer;
QStringList portList;
@@ -204,20 +234,28 @@ private:
QDir* clientWorkingDir;
Mifare* mifare;
LF* lf;
Util* util;
MF_trailerDecoderDialog* decDialog;
QList<QDockWidget*> dockList;
QMenu* contextMenu;
MF_trailerDecoderDialog* decDialog;
void signalInit();
void MF_widgetReset();
void setTableItem(QTableWidget *widget, int row, int column, const QString& text);
void setState(bool st);
void saveClientPath(const QString& path);
void onLFfreqConfChanged(int value, bool isCustomized);
void dockInit();
protected:
void contextMenuEvent(QContextMenuEvent *event) override;
signals:
void connectPM3(const QString& path, const QString& port, const QStringList args);
void connectPM3(const QString& path, const QStringList args);
void reconnectPM3();
void killPM3();
void setSerialListener(bool state);
void setSerialListener(const QString& name, bool state);
void setProcEnv(const QStringList *env);
void setWorkingDir(const QString& dir);
+1194 -55
View File
File diff suppressed because it is too large Load Diff