30 Commits

Author SHA1 Message Date
wh201906 f285f76a20 V0.2.2 2021-09-20 19:07:36 +08:00
wh201906 24adc08d84 LF config file 2021-09-20 15:32:00 +08:00
wh201906 d56c5f8dc7 Merge branch 'master' into dev 2021-09-20 00:01:57 +08:00
wh201906 222f271a31 Choose config file path 2021-09-19 23:59:55 +08:00
wh201906 0c339e91af Revert part of the commit 12a0837
I forgot I have designed "Keep the client active" for issue #22
isBusy() is deprecated for blocking the port, but it doesn't matter.
2021-09-19 21:33:53 +08:00
wh201906 85ea3fd744 Config file
_readsec(), hardnested(), _writeblk(), lockC(), setParameterC()
2021-09-19 21:00:23 +08:00
wh201906 d0bc6808d0 Config file for official client
Unfinished
Refactor darkside() _readblk(), loadSniff(), saveSniff()
Add extra waiting time when handling temp file of load/saveSniff()
2021-09-19 01:10:12 +08:00
wh201906 03d9c601fc Config fiie for official client
Unfinished
Refactor nested(), info(), chk()
2021-09-18 02:03:05 +08:00
wh201906 5a8ab42281 External command config file 2021-09-17 15:25:03 +08:00
wh201906 12a0837c50 Fix a bug
Trying to fix #22
Open client with QProcess::Text for proper newline character(s)
On Raspbian, the isBusy() function will always return false, even the serial port is actually connected.
2021-09-05 21:35:03 +08:00
wh201906 d6f02e7a69 Update building instructions 2021-08-14 17:05:13 +08:00
wh201906 02a8fe03e3 Fix a bug
#21
2021-08-07 11:21:19 +08:00
wh201906 3523c1eace Fix a bug
#20
I got a wrong tutorial saying that I should use xxx.ts on Linux
2021-08-05 11:57:35 +08:00
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
30 changed files with 3984 additions and 1266 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.2
QMAKE_TARGET_PRODUCT = "Proxmark3GUI"
QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI"
QMAKE_TARGET_COMPANY = "wh201906"
+24 -5
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
+ ...
@@ -33,14 +34,14 @@ A cross-platform GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) clie
## 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 is compatible with Iceman/RRG repo(tested on v4.9237)
The [Iceman fork/repo](https://github.com/RfidResearchGroup/proxmark3) has more powerful functions. 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 is compatible with Iceman/RRG repo(tested on v4.13441)
***
## 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.
@@ -50,7 +51,9 @@ Great thanks to him.
## Build on Linux
cd ~
git clone https://github.com/wh201906/Proxmark3GUI.git
sudo apt-get update
sudo apt-get install qt5-default libqt5serialport5 libqt5serialport5-dev
git clone https://github.com/wh201906/Proxmark3GUI.git --depth=1
cd Proxmark3GUI
mkdir build
cd build
@@ -58,12 +61,28 @@ Great thanks to him.
make
make clean
cp -r ../lang ./
cp -r ../config ./
./Proxmark3GUI
***
## Update Log:
### V0.2.2
+ Load command format from external json file
+ Fix bug [#20](https://github.com/wh201906/Proxmark3GUI/issues/20), [#21](https://github.com/wh201906/Proxmark3GUI/issues/21), [#22](https://github.com/wh201906/Proxmark3GUI/issues/22)
+ Support Iceman/RRG repo v4.13441
### V0.2.1
+ Optimize MIFARE Classic reading logic
+ Fix bug [#16](https://github.com/wh201906/Proxmark3GUI/issues/16)
+ Fix bug [#15](https://github.com/wh201906/Proxmark3GUI/issues/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
+22 -3
View File
@@ -19,7 +19,8 @@
+ 可以打开二进制/文本格式的扇区数据文件
+ 分析访问控制位(Access Bits
+ 支持UID卡操作(UID快速读写,UFUID锁卡)
+ 自定义UI界面
+ 支持部分低频命令
+ 自定义UI界面,各选项卡可拆分组合
+ ...
***
@@ -33,7 +34,7 @@
## 关于冰人版
[冰人版](https://github.com/RfidResearchGroup/proxmark3)(Iceman/RRG)的客户端和固件更新更为激进,相比官方版具有更多的功能
此GUI所有功能均兼容冰人版(在v4.9237上测试通过)
此GUI所有功能均兼容冰人版(在v4.13441上测试通过)
***
@@ -49,7 +50,9 @@ release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客
## 在Linux系统下编译
cd ~
git clone https://github.com/wh201906/Proxmark3GUI.git
sudo apt-get update
sudo apt-get install qt5-default libqt5serialport5 libqt5serialport5-dev
git clone https://github.com/wh201906/Proxmark3GUI.git --depth=1
cd Proxmark3GUI
mkdir build
cd build
@@ -57,12 +60,28 @@ release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客
make
make clean
cp -r ../lang ./
cp -r ../config ./
./Proxmark3GUI
***
## 更新日志:
### V0.2.2
+ 从外部文件加载客户端命令格式
+ 修复 [#20](https://github.com/wh201906/Proxmark3GUI/issues/20), [#21](https://github.com/wh201906/Proxmark3GUI/issues/21), [#22](https://github.com/wh201906/Proxmark3GUI/issues/22)
+ 兼容冰人版客户端 v4.13441
### V0.2.1
+ 优化MIFARE Classic读卡逻辑
+ 修复 [#16](https://github.com/wh201906/Proxmark3GUI/issues/16) (配合新版RRG固件时无法读取扇区数据)
+ 修复 [#15](https://github.com/wh201906/Proxmark3GUI/issues/15) (路径中支持空格)
### V0.2
+ 使用浮动窗口,界面配置更加灵活
+ 支持部分低频命令
+ 修复原始命令选项卡中的一个Bug
### V0.1.4
+ 优化性能
+ 优化用户界面
+5 -1
View File
@@ -13,4 +13,8 @@ Mifare Edit File:
![mf_editfile](../img/mf_editfile.gif)
Mifare Trailer Decoder:
![mf_trailer](../img/mf_trailer.gif)
![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

+33 -17
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,11 +23,10 @@ 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.
start(path, args, QProcess::Unbuffered | QProcess::ReadWrite);
start(path, args, QProcess::Unbuffered | QProcess::ReadWrite | QProcess::Text);
if(waitForStarted(10000))
{
waitForReadyRead(10000);
@@ -36,11 +36,13 @@ void PM3Process::connectPM3(const QString& path, const QString& port, const QStr
{
clientType = Util::CLIENTTYPE_ICEMAN;
setRequiringOutput(true);
write("hw version\r\n");
for(int i = 0; i < 10; i++)
write("hw version\n");
for(int i = 0; i < 50; i++)
{
waitForReadyRead(200);
result += *requiredOutput;
if(result.indexOf("os: ") != -1)
break;
}
setRequiringOutput(false);
}
@@ -52,14 +54,9 @@ void PM3Process::connectPM3(const QString& path, const QString& port, const QStr
{
emit changeClientType(clientType);
result = result.mid(result.indexOf("os: "));
result = result.left(result.indexOf("\r\n"));
result = result.mid(3, result.lastIndexOf(" ") - 3);
result = result.left(result.indexOf("\n"));
result = result.mid(4, result.indexOf(" ", 4) - 4);
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 +65,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 +84,7 @@ void PM3Process::setSerialListener(const QString& name, bool state)
{
if(state)
{
currPort = name;
portInfo = new QSerialPortInfo(name);
serialListener->start();
qDebug() << serialListener->thread();
@@ -94,18 +92,29 @@ void PM3Process::setSerialListener(const QString& name, bool state)
else
{
serialListener->stop();
delete portInfo;
if(portInfo != nullptr)
{
delete portInfo;
portInfo = nullptr;
}
}
}
void PM3Process::setSerialListener(bool state)
{
setSerialListener(currPort, state);
}
void PM3Process::onTimeout() //when the proxmark3 client is unexpectedly terminated or the PM3 hardware is removed, the isBusy() will return false(only tested on Windows);
{
// isBusy() is a deprecated function because it will block the serial port when the port is not in use.
// However, the PM3 client is supposed to use the target serial port exclusively, so it should be fine
// isBusy() will always return false on Raspbian, in this case, check "Keep the client active" in the Settings panel.
//
// qDebug()<<portInfo->isBusy();
if(!portInfo->isBusy())
{
kill();
emit PM3StatedChanged(false);
setSerialListener("", false);
killPM3();
}
}
@@ -144,3 +153,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:
+28 -3
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;
@@ -25,10 +31,10 @@ void Util::execCMD(const QString& cmd)
{
qDebug() << "executing: " << cmd;
if(isRunning)
emit write(cmd + "\r\n");
emit write(cmd + "\n");
}
QString Util::execCMDWithOutput(const QString& cmd, ReturnTrigger trigger)
QString Util::execCMDWithOutput(const QString& cmd, ReturnTrigger trigger, bool rawOutput)
{
// 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.
@@ -72,7 +78,7 @@ QString Util::execCMDWithOutput(const QString& cmd, ReturnTrigger trigger)
}
}
isRequiringOutput = false;
return (isResultFound || trigger.expectedOutputs.isEmpty() ? *requiredOutput : "");
return (isResultFound || trigger.expectedOutputs.isEmpty() || rawOutput ? *requiredOutput : "");
}
void Util::delay(unsigned int msec)
@@ -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;
}
+10 -3
View File
@@ -13,6 +13,9 @@
#include <QSettings>
#include <QMainWindow>
#include <QInputDialog>
#include <QDockWidget>
#include "ui_mainwindow.h"
class Util : public QObject
{
@@ -50,22 +53,26 @@ public:
explicit Util(QObject *parent = nullptr);
void execCMD(const QString& cmd);
QString execCMDWithOutput(const QString& cmd, ReturnTrigger trigger = 10000);
QString execCMDWithOutput(const QString& cmd, ReturnTrigger trigger = 10000, bool rawOutput = false);
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);
+195
View File
@@ -0,0 +1,195 @@
{
"//": "Based on Proxmark3 official repo v3.1.0, commit 6116334",
"//": "You can change this file if the command format of client changes",
"mifare classic": {
"nested": {
"cmd": "hf mf nested <card type> *",
"card type": {
"mini": "0",
"1k": "1",
"2k": "2",
"4k": "4"
},
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2,
"key B index": 4
},
"check": {
"cmd": "hf mf chk *<card type> ?",
"card type": {
"mini": "0",
"1k": "1",
"2k": "2",
"4k": "4"
},
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2,
"key B index": 3
},
"info": {
"cmd": "hf 14a info"
},
"sniff": {
"cmd": "hf mf sniff"
},
"sniff 14a": {
"cmd": "hf 14a snoop"
},
"list": {
"cmd": "hf list mf"
},
"dump": {
"cmd": "hf mf dump"
},
"restore": {
"cmd": "hf mf restore"
},
"emulator wipe": {
"cmd": "hf mf eclr"
},
"Magic Card wipe": {
"cmd": "hf mf cwipe <card type> f",
"card type": {
"mini": "0",
"1k": "1",
"2k": "2",
"4k": "4"
}
},
"emulator read block": {
"cmd": "hf mf eget <block>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read block": {
"cmd": "hf mf cgetblk <block>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"normal read block": {
"cmd": "hf mf rdbl <block> <key type> <key>",
"key type": {
"A": "A",
"B": "B"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"darkside": {
"cmd": "hf mf mifare"
},
"save sniff": {
"cmd": "hf list mf -s <filename>"
},
"load sniff": {
"cmd": "hf list mf -l <filename>"
},
"hardnested": {
"cmd": "hf mf hardnested <known key block> <known key type> <known key> <target key block> <target key type>",
"known key type": {
"A": "A",
"B": "B"
},
"target key type": {
"A": "A",
"B": "B"
}
},
"normal read sector": {
"cmd": "hf mf rdsc <sector> <key type> <key>",
"key type": {
"A": "A",
"B": "B"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read sector": {
"cmd": "hf mf cgetsc <sector>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"//": "When writing a block, if the result is not empty and doesn't contain the failed flag, the function will return true",
"normal write block": {
"cmd": "hf mf wrbl <block> <key type> <key> <data>",
"key type": {
"A": "A",
"B": "B"
},
"failed flag": [
"isOk:00"
]
},
"Magic Card write block": {
"cmd": "hf mf csetblk <block> <data>",
"failed flag": [
"No chinese magic"
]
},
"emulator write block": {
"cmd": "hf mf eset <block> <data>"
},
"Magic Card lock": {
"cmd": "hf 14a raw ",
"sequence": [
"-pa -b7 40",
"-pa 43",
"-pa E0 00 39 F7",
"-pa E1 00 E1 EE",
"-pa 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47",
"-a 52"
]
},
"Magic Card set parameter": {
"cmd": "hf mf csetuid <uid> <atqa> <sak>"
}
},
"lf": {
"read": {
"cmd": "lf read",
"show cmd": "data plot"
},
"sniff": {
"cmd": "lf snoop",
"show cmd": "data plot"
},
"search": {
"cmd": "lf search u"
},
"tune": {
"cmd": "hw tune l"
},
"get config": {
"cmd": "hw status",
"field start": "LF Sampling config:",
"field end": "USB Speed:",
"divisor": {
"flag": "divisor:",
"pattern": "\\d+"
},
"bits per sample": {
"flag": "bps:",
"pattern": "\\d+"
},
"decimation": {
"flag": "decimation:",
"pattern": "\\d+"
},
"averaging": {
"flag": "averaging:",
"pattern": "\\d+"
},
"trigger threshold": {
"flag": "trigger threshold:",
"pattern": "\\d+"
},
"samples to skip": {
"flag": "samples to skip:",
"pattern": "\\d+"
},
"//": "execute 'cmd' then find parameters between 'field stard' and 'field end'",
"//": "for each line, if the line doesn't have any flag, skip",
"//": "otherwise, delete characters before 'flag' and 'flag' itself, then use 'pattern' to get the parameter",
"//": "If 'replace' dict exists, replace all keys with respective values before getting parameters"
},
"set config": {
"cmd": "lf config q <divisor> b <bits per sample> d <decimation> a <averaging> t <trigger threshold> s <samples to skip>",
"divisor cmd": "hw setlfdivisor <divisor>"
}
}
}
+203
View File
@@ -0,0 +1,203 @@
{
"//": "Based on Proxmark3 rrg repo v4.13441, commit 35ddebc",
"//": "You can change this file if the command format of client changes",
"mifare classic": {
"nested": {
"cmd": "hf mf nested --<card type> --blk <block> -<key type> -k <key>",
"static cmd": "hf mf staticnested --<card type> --blk <block> -<key type> -k <key>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
},
"key type": {
"A": "a",
"B": "b"
},
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2,
"key B index": 4
},
"check": {
"cmd": "hf mf chk --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
},
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2,
"key B index": 4
},
"info": {
"cmd": "hf 14a info"
},
"sniff": {
"cmd": "hf sniff"
},
"sniff 14a": {
"cmd": "hf 14a sniff"
},
"list": {
"cmd": "trace list -t mf"
},
"dump": {
"cmd": "hf mf dump"
},
"restore": {
"cmd": "hf mf restore"
},
"emulator wipe": {
"cmd": "hf mf eclr"
},
"Magic Card wipe": {
"cmd": "hf mf cwipe"
},
"emulator read block": {
"cmd": "hf mf egetblk --blk <block>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read block": {
"cmd": "hf mf cgetblk --blk <block>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"normal read block": {
"cmd": "hf mf rdbl --blk <block> -<key type> -k <key>",
"key type": {
"A": "a",
"B": "b"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"darkside": {
"cmd": "hf mf darkside"
},
"save sniff": {
"cmd": "trace save -f <filename>"
},
"load sniff": {
"cmd": "trace load -f <filename>",
"show cmd": "trace list --buffer -t mf"
},
"hardnested": {
"cmd": "hf mf hardnested --blk <known key block> -<known key type> -k <known key> --tblk <target key block> --t<target key type>",
"known key type": {
"A": "a",
"B": "b"
},
"target key type": {
"A": "a",
"B": "b"
}
},
"normal read sector": {
"cmd": "hf mf rdsc --sec <sector> -<key type> -k <key>",
"key type": {
"A": "a",
"B": "b"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read sector": {
"cmd": "hf mf cgetsc --sec <sector>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"//": "When writing a block, if the result is not empty and doesn't contain the failed flag, the function will return true",
"normal write block": {
"cmd": "hf mf wrbl --blk <block> -<key type> -k <key> -d <data>",
"key type": {
"A": "a",
"B": "b"
},
"failed flag": [
"fail",
"error"
]
},
"Magic Card write block": {
"cmd": "hf mf csetblk --blk <block> -d <data>",
"failed flag": [
"fail",
"error"
]
},
"emulator write block": {
"cmd": "hf mf esetblk --blk <block> -d <data>"
},
"Magic Card lock": {
"cmd": "hf 14a raw ",
"sequence": [
"-ak -b 7 40",
"-ak 43",
"-ak E0 00 39 F7",
"-ak E1 00 E1 EE",
"-ak 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47",
"-a 52"
]
},
"Magic Card set parameter": {
"cmd": "hf mf csetuid --uid <uid> --atqa <atqa> --sak <sak>"
}
},
"lf": {
"read": {
"cmd": "lf read -v",
"show cmd": "data plot"
},
"sniff": {
"cmd": "lf sniff -v",
"show cmd": "data plot"
},
"search": {
"cmd": "lf search -u"
},
"tune": {
"cmd": "lf tune --divisor <divisor>"
},
"get config": {
"cmd": "hw status",
"field start": "LF Sampling config",
"field end": "LF Sampling Stack",
"divisor": {
"flag": "divisor",
"pattern": "\\d+"
},
"bits per sample": {
"flag": "bits per sample",
"pattern": "\\d+"
},
"decimation": {
"flag": "decimation",
"pattern": "\\d+"
},
"averaging": {
"flag": "averaging",
"pattern": "\\d+",
"replace": {
"yes": "1",
"no": "0",
"Yes": "1",
"No": "0"
}
},
"trigger threshold": {
"flag": "trigger threshold",
"pattern": "\\d+"
},
"samples to skip": {
"flag": "samples to skip",
"pattern": "\\d+"
},
"//": "execute 'cmd' then find parameters between 'field stard' and 'field end'",
"//": "for each line, if the line doesn't have any flag, skip",
"//": "otherwise, delete characters before 'flag' and 'flag' itself, then use 'pattern' to get the parameter",
"//": "If 'replace' dict exists, replace all keys with respective values before getting parameters"
},
"set config": {
"cmd": "lf config --divisor <divisor> --bps <bits per sample> --dec <decimation> --avg <averaging> --trig <trigger threshold> --skip <samples to skip>",
"divisor cmd": "hw setlfdivisor -d <divisor>"
}
}
}
+511 -213
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+539 -240
View File
File diff suppressed because it is too large Load Diff
+5 -6
View File
@@ -5,11 +5,13 @@
#include <QTranslator>
#include <QMessageBox>
#include <QTextCodec>
#include <QDir>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QDir *langPath = new QDir();
QApplication a(argc, argv);
MainWindow w;
@@ -29,14 +31,10 @@ int main(int argc, char *argv[])
else
currLang = "en_US";
}
currLang = "lang/" + currLang;
#ifdef Q_OS_WIN
currLang += ".qm";
#else
currLang += ".ts";;
#endif
langPath->cd("lang");
QTranslator* translator = new QTranslator(&w);
if(translator->load(currLang))
if(translator->load(currLang, langPath->absolutePath()))
{
a.installTranslator(translator);
}
@@ -45,6 +43,7 @@ int main(int argc, char *argv[])
QMessageBox::information(&w, "Error", "Can't load " + currLang + " as translation file.");
}
delete settings;
delete langPath;
w.initUI();
w.show();
return a.exec();
+154
View File
@@ -0,0 +1,154 @@
#include "lf.h"
#include <QJsonArray>
const LF::LFConfig LF::defaultLFConfig;
LF::LF(Ui::MainWindow *ui, Util *addr, QWidget *parent): QObject(parent)
{
this->parent = parent;
util = addr;
this->ui = ui;
LFconfigPattern = new QRegularExpression("(\\d+)|Yes|No");
currLFConfig = defaultLFConfig;
}
void LF::read()
{
QVariantMap config = configMap["read"].toMap();
util->execCMD(config["cmd"].toString());
Util::gotoRawTab();
util->execCMD(config["show cmd"].toString());
}
void LF::sniff()
{
QVariantMap config = configMap["sniff"].toMap();
util->execCMD(config["cmd"].toString());
Util::gotoRawTab();
util->execCMD(config["show cmd"].toString());
}
void LF::search()
{
QVariantMap config = configMap["search"].toMap();
util->execCMD(config["cmd"].toString());
Util::gotoRawTab();
}
void LF::tune()
{
QVariantMap config = configMap["tune"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<divisor>", QString::number(currLFConfig.divisor));
util->execCMD(cmd);
Util::gotoRawTab();
}
bool LF::getLFConfig_helper(const QVariantMap& map, QString& str, int* result)
{
int len;
QString flag = map["flag"].toString();
QRegularExpressionMatch reMatch;
if(!str.contains(flag))
return false;
len = str.length() - (str.indexOf(flag) + flag.length());
str = str.right(len);
if(map.contains("replace"))
{
QVariantMap table = map["replace"].toMap();
for(auto it = table.begin(); it != table.end(); it++)
{
str.replace(it.key(), it.value().toString());
}
}
reMatch = QRegularExpression(map["pattern"].toString()).match(str);
if(!reMatch.hasMatch())
return false;
*result = reMatch.captured().toInt();
qDebug() << *result;
return true;
}
void LF::getLFConfig()
{
QRegularExpressionMatch reMatch;
QString result;
QStringList resultList;
int start, end, temp;
QVariantMap config = configMap["get config"].toMap();
QString cmd = config["cmd"].toString();
result = util->execCMDWithOutput(cmd, 400);
start = result.indexOf(config["field start"].toString());
end = result.indexOf(config["field end"].toString());
result = result.mid(start, end - start);
resultList = result.split("\n", Qt::SkipEmptyParts);
qDebug() << "LF CONFIG GET\n" << resultList;
for(auto it = resultList.begin(); it != resultList.end(); it++)
{
if(getLFConfig_helper(config["divisor"].toMap(), *it, &temp))
currLFConfig.divisor = temp;
else if(getLFConfig_helper(config["bits per sample"].toMap(), *it, &temp))
currLFConfig.bitsPerSample = temp;
else if(getLFConfig_helper(config["decimation"].toMap(), *it, &temp))
currLFConfig.decimation = temp;
else if(getLFConfig_helper(config["averaging"].toMap(), *it, &temp))
currLFConfig.averaging = (bool)temp;
else if(getLFConfig_helper(config["trigger threshold"].toMap(), *it, &temp))
currLFConfig.triggerThreshold = temp;
else if(getLFConfig_helper(config["samples to skip"].toMap(), *it, &temp))
currLFConfig.samplesToSkip = temp;
}
syncWithUI();
}
void LF::setLFConfig(LF::LFConfig lfconfig)
{
currLFConfig = lfconfig;
QVariantMap config = configMap["set config"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<divisor>", QString::number(currLFConfig.divisor));
cmd.replace("<bits per sample>", QString::number(currLFConfig.bitsPerSample));
cmd.replace("<decimation>", QString::number(currLFConfig.decimation));
cmd.replace("<averaging>", currLFConfig.averaging ? "1" : "0");
cmd.replace("<trigger threshold>", QString::number(currLFConfig.triggerThreshold));
cmd.replace("<samples to skip>", QString::number(currLFConfig.samplesToSkip));
util->execCMDWithOutput(cmd, 500);
cmd = config["divisor cmd"].toString();
cmd.replace("<divisor>", QString::number(currLFConfig.divisor));
util->execCMDWithOutput(cmd, 500);
}
void LF::resetLFConfig()
{
setLFConfig(defaultLFConfig);
getLFConfig();
}
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_LFConf_freqDivisorBox->setValue(currLFConfig.divisor); // will trigger valueChanged()
ui->LF_LFConf_bitsPerSampleBox->setValue(currLFConfig.bitsPerSample);
ui->LF_LFConf_decimationBox->setValue(currLFConfig.decimation);
ui->LF_LFConf_averagingBox->setChecked(currLFConfig.averaging);
ui->LF_LFConf_thresholdBox->setValue(currLFConfig.triggerThreshold);
ui->LF_LFConf_skipsBox->setValue(currLFConfig.samplesToSkip);
}
void LF::setConfigMap(const QVariantMap& configMap)
{
this->configMap = configMap;
qDebug() << configMap;
}
+59
View File
@@ -0,0 +1,59 @@
#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 LFConfig
{
uint8_t divisor;
uint8_t bitsPerSample;
uint8_t decimation;
bool averaging;
uint8_t triggerThreshold;
uint16_t samplesToSkip;
};
static constexpr LFConfig defaultLFConfig =
{
95,
8,
1,
true,
0,
0
};
void read();
void sniff();
void search();
void tune();
void getLFConfig();
void setLFConfig(LF::LFConfig lfconfig);
void resetLFConfig();
static float divisor2Freq(uint8_t divisor);
static uint8_t freq2Divisor(float freq);
void setConfigMap(const QVariantMap &configMap);
private:
QWidget* parent;
Ui::MainWindow *ui;
Util* util;
LFConfig currLFConfig;
QRegularExpression* LFconfigPattern;
QVariantMap configMap;
void syncWithUI();
bool getLFConfig_helper(const QVariantMap& map, QString& str, int* result);
signals:
};
#endif // LF_H
+452 -442
View File
File diff suppressed because it is too large Load Diff
+8 -2
View File
@@ -11,6 +11,7 @@
#include <QStringList>
#include <QRegularExpression>
#include <QMessageBox>
#include <QJsonObject>
class Mifare : public QObject
{
Q_OBJECT
@@ -64,9 +65,9 @@ public:
static const AccessType trailerReadCondition[8][3];
static const AccessType trailerWriteCondition[8][3];
QString info(bool isRequiringOutput = false);
QMap<QString, QString> info(bool isRequiringOutput = false);
void chk();
void nested();
void nested(bool isStaticNested = false);
void darkside();
void hardnested();
void sniff();
@@ -111,6 +112,9 @@ 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
void setConfigMap(const QVariantMap& configMap);
public slots:
signals:
@@ -119,6 +123,8 @@ private:
Ui::MainWindow *ui;
Util* util;
QVariantMap configMap;
QStringList* keyAList;
QStringList* keyBList;
QStringList* dataList;
+310 -85
View File
@@ -1,14 +1,22 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QJsonDocument>
MainWindow::MainWindow(QWidget *parent):
QMainWindow(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 +25,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 +36,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()
@@ -57,12 +72,29 @@ MainWindow::~MainWindow()
delete pm3Thread;
}
void MainWindow::loadConfig()
{
QFile configList(ui->Set_Client_configPathEdit->text());
if(!configList.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::information(this, tr("Info"), tr("Failed to load config file"));
return;
}
QByteArray configData = configList.readAll();
QJsonDocument configJson(QJsonDocument::fromJson(configData));
mifare->setConfigMap(configJson.object()["mifare classic"].toObject().toVariantMap());
lf->setConfigMap(configJson.object()["lf"].toObject().toVariantMap());
}
void MainWindow::initUI() // will be called by main.app
{
ui->retranslateUi(this);
uiInit();
signalInit();
setState(false);
dockInit();
}
// ******************** basic functions ********************
@@ -89,43 +121,69 @@ 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(' ');
saveClientPath(ui->PM3_pathEdit->text());
QProcess envSetProcess;
QFileInfo envScriptPath(ui->Set_Client_envScriptEdit->text());
if(envScriptPath.exists())
{
qDebug() << envScriptPath.absoluteFilePath();
#ifdef Q_OS_WIN
// cmd /c "<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);
clientWorkingDir->setPath(QApplication::applicationDirPath());
qDebug() << clientWorkingDir->absolutePath();
clientWorkingDir->mkpath(ui->Set_Client_workingDirEdit->text());
qDebug() << clientWorkingDir->absolutePath();
clientWorkingDir->cd(ui->Set_Client_workingDirEdit->text());
qDebug() << clientWorkingDir->absolutePath();
emit setWorkingDir(clientWorkingDir->absolutePath());
emit connectPM3(ui->PM3_pathEdit->text(), port, args);
QMessageBox::information(this, 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;
QFileInfo envScriptPath(ui->Set_Client_envScriptEdit->text());
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", {}, QProcess::Unbuffered | QProcess::ReadWrite | QProcess::Text);
envSetProcess.write(QString("\"" + envScriptPath.absoluteFilePath() + "\">>nul\n").toLatin1());
envSetProcess.waitForReadyRead(10000);
envSetProcess.readAll();
envSetProcess.write("set\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);
QString envSetResult = QString(envSetProcess.readAll());
clientEnv = envSetResult.split("\n", 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();
clientWorkingDir->setPath(QApplication::applicationDirPath());
qDebug() << clientWorkingDir->absolutePath();
clientWorkingDir->mkpath(ui->Set_Client_workingDirEdit->text());
qDebug() << clientWorkingDir->absolutePath();
clientWorkingDir->cd(ui->Set_Client_workingDirEdit->text());
qDebug() << clientWorkingDir->absolutePath();
emit setWorkingDir(clientWorkingDir->absolutePath());
loadConfig();
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 +207,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 +231,7 @@ void MainWindow::on_stopButton_clicked()
break;
}
emit reconnectPM3();
emit setSerialListener(!keepClientActive);
}
}
// *********************************************************
@@ -240,33 +299,41 @@ 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(keyEvent.key() == Qt::Key_Up)
if(obj_addr == ui->Raw_CMDEdit)
{
if(stashedIndex > 0)
stashedIndex--;
else if(stashedIndex == -1)
stashedIndex = ui->Raw_CMDHistoryWidget->count() - 1;
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);
}
}
else if(keyEvent.key() == Qt::Key_Down)
else if(obj_addr == ui->Raw_outputEdit)
{
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);
if(keyEvent.key() == Qt::Key_Up || keyEvent.key() == Qt::Key_Down)
ui->Raw_CMDEdit->setFocus();
}
}
}
@@ -600,11 +667,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 +688,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 != "")
{
@@ -802,15 +873,16 @@ void MainWindow::on_MF_Sniff_loadButton_clicked() // use a tmp file to support c
QString filename = "";
title = tr("Plz select the trace file:");
filename = QFileDialog::getOpenFileName(this, title, "./", tr("Trace Files(*.trc);;All Files(*.*)"));
filename = QFileDialog::getOpenFileName(this, title, clientWorkingDir->absolutePath(), tr("Trace Files(*.trc);;All Files(*.*)"));
qDebug() << filename;
if(filename != "")
{
QString tmpFile = "tmp" + QString::number(QDateTime::currentDateTime().toTime_t()) + ".trc";
if(QFile::copy(filename, "./" + tmpFile))
if(QFile::copy(filename, clientWorkingDir->absolutePath() + "/" + tmpFile))
{
mifare->loadSniff(tmpFile);
QFile::remove("./" + tmpFile);
util->delay(3000);
QFile::remove(clientWorkingDir->absolutePath() + "/" + tmpFile);
}
else
{
@@ -825,17 +897,23 @@ void MainWindow::on_MF_Sniff_saveButton_clicked()
QString filename = "";
title = tr("Plz select the location to save trace file:");
filename = QFileDialog::getSaveFileName(this, title, "./", tr("Trace Files(*.trc)"));
filename = QFileDialog::getSaveFileName(this, title, clientWorkingDir->absolutePath(), tr("Trace Files(*.trc)"));
qDebug() << filename;
if(filename != "")
{
QString tmpFile = "tmp" + QString::number(QDateTime::currentDateTime().toTime_t()) + ".trc";
mifare->saveSniff(tmpFile);
if(!QFile::copy("./" + tmpFile, filename))
for(int i = 0; i < 100; i++)
{
util->delay(100);
if(QFile::exists(clientWorkingDir->absolutePath() + "/" + tmpFile))
break;
}
if(!QFile::copy(clientWorkingDir->absolutePath() + "/" + tmpFile, filename))
{
QMessageBox::information(this, tr("Info"), tr("Failed to save to") + "\n" + filename);
}
QFile::remove("./" + tmpFile);
QFile::remove(clientWorkingDir->absolutePath() + "/" + tmpFile);
}
}
@@ -907,11 +985,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 +1005,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,15 +1056,22 @@ 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());
ui->Set_Client_configPathEdit->setText(settings->value("configPath", "config.json").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);
}
void MainWindow::signalInit()
@@ -1006,9 +1084,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 +1183,8 @@ void MainWindow::setButtonsEnabled(bool st)
ui->MF_sniffGroupBox->setEnabled(st);
ui->Raw_CMDEdit->setEnabled(st);
ui->Raw_sendCMDButton->setEnabled(st);
ui->LF_LFconfigGroupBox->setEnabled(st);
ui->LF_operationGroupBox->setEnabled(st);
}
void MainWindow::on_GroupBox_clicked(bool checked)
@@ -1174,9 +1256,152 @@ void MainWindow::on_Set_Client_envScriptEdit_editingFinished()
settings->endGroup();
}
void MainWindow::on_Set_Client_saveWorkingDirButton_clicked()
void MainWindow::on_Set_Client_workingDirEdit_editingFinished()
{
settings->beginGroup("Client_Env");
settings->setValue("workingDir", ui->Set_Client_workingDirEdit->text());
settings->endGroup();
}
void MainWindow::on_Set_Client_configPathEdit_editingFinished()
{
settings->beginGroup("Client_Env");
settings->setValue("configPath", ui->Set_Client_configPathEdit->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_LFConf_freqSlider_valueChanged(int value)
{
onLFfreqConfChanged(value, true);
}
void MainWindow::onLFfreqConfChanged(int value, bool isCustomized)
{
ui->LF_LFConf_freqDivisorBox->blockSignals(true);
ui->LF_LFConf_freqSlider->blockSignals(true);
if(isCustomized)
ui->LF_LFConf_freqOtherButton->setChecked(true);
ui->LF_LFConf_freqLabel->setText(tr("Actural Freq: ") + QString("%1kHz").arg(LF::divisor2Freq(value), 0, 'f', 3));
ui->LF_LFConf_freqDivisorBox->setValue(value);
ui->LF_LFConf_freqSlider->setValue(value);
ui->LF_LFConf_freqDivisorBox->blockSignals(false);
ui->LF_LFConf_freqSlider->blockSignals(false);
}
void MainWindow::on_LF_LFConf_freqDivisorBox_valueChanged(int arg1)
{
onLFfreqConfChanged(arg1, true);
}
void MainWindow::on_LF_LFConf_freq125kButton_clicked()
{
onLFfreqConfChanged(95, false);
}
void MainWindow::on_LF_LFConf_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_LFConf_getButton_clicked()
{
setState(false);
lf->getLFConfig();
setState(true);
}
void MainWindow::on_LF_LFConf_setButton_clicked()
{
LF::LFConfig config;
setState(false);
config.divisor = ui->LF_LFConf_freqDivisorBox->value();
config.bitsPerSample = ui->LF_LFConf_bitsPerSampleBox->value();
config.decimation = ui->LF_LFConf_decimationBox->value();
config.averaging = ui->LF_LFConf_averagingBox->isChecked();
config.triggerThreshold = ui->LF_LFConf_thresholdBox->value();
config.samplesToSkip = ui->LF_LFConf_skipsBox->value();
lf->setLFConfig(config);
Util::gotoRawTab();
setState(true);
}
void MainWindow::on_LF_LFConf_resetButton_clicked()
{
setState(false);
lf->resetLFConfig();
setState(true);
}
+45 -4
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:
@@ -173,7 +177,33 @@ private slots:
void on_Set_Client_envScriptEdit_editingFinished();
void on_Set_Client_saveWorkingDirButton_clicked();
void on_Set_Client_keepClientActiveBox_stateChanged(int arg1);
void on_LF_LFConf_freqSlider_valueChanged(int value);
void on_LF_LFConf_freqDivisorBox_valueChanged(int arg1);
void on_LF_LFConf_freq125kButton_clicked();
void on_LF_LFConf_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_LFConf_getButton_clicked();
void on_LF_LFConf_setButton_clicked();
void on_LF_LFConf_resetButton_clicked();
void on_Set_Client_workingDirEdit_editingFinished();
void on_Set_Client_configPathEdit_editingFinished();
private:
Ui::MainWindow* ui;
@@ -182,6 +212,7 @@ private:
QLabel* programStatusBar;
QLabel* PM3VersionBar;
QPushButton* stopButton;
QAction* dockAllWindows;
QAction* myInfo;
QAction* currVersion;
QAction* checkUpdate;
@@ -197,6 +228,7 @@ private:
PM3Process* pm3;
bool pm3state;
bool keepButtonsEnabled;
bool keepClientActive;
QThread* pm3Thread;
QTimer* portSearchTimer;
QStringList portList;
@@ -204,20 +236,29 @@ 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();
void loadConfig();
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);
+1350 -195
View File
File diff suppressed because it is too large Load Diff
+11 -25
View File
@@ -1,16 +1,17 @@
#include "mf_attack_hardnesteddialog.h"
#include "ui_mf_attack_hardnesteddialog.h"
MF_Attack_hardnestedDialog::MF_Attack_hardnestedDialog(int blocks, QWidget *parent) :
MF_Attack_hardnestedDialog::MF_Attack_hardnestedDialog(int blocks, const QVariantMap& config, QWidget *parent) :
QDialog(parent),
ui(new Ui::MF_Attack_hardnestedDialog)
{
ui->setupUi(this);
for(int i = 0; i < blocks; i++)
{
ui->knownKeySectorBox->addItem(QString::number(i));
ui->targetKeySectorBox->addItem(QString::number(i));
ui->knownKeyBlockBox->addItem(QString::number(i));
ui->targetKeyBlockBox->addItem(QString::number(i));
}
this->config = config;
}
@@ -21,26 +22,11 @@ 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()
+ " "
+ ui->knownKeyTypeBox->currentText()
+ " "
+ ui->knownKeyBox->text()
+ " "
+ ui->targetKeySectorBox->currentText()
+ " "
+ ui->targetKeyTypeBox->currentText());
QString cmd = config["cmd"].toString();
cmd.replace("<known key block>", ui->knownKeyBlockBox->currentText());
cmd.replace("<known key type>", config["known key type"].toMap()[ui->knownKeyTypeBox->currentText()].toString());
cmd.replace("<known key>", ui->knownKeyBox->text());
cmd.replace("<target key block>", ui->targetKeyBlockBox->currentText());
cmd.replace("<target key type>", config["target key type"].toMap()[ui->targetKeyTypeBox->currentText()].toString());
emit sendCMD(cmd);
}
+2 -1
View File
@@ -14,12 +14,13 @@ class MF_Attack_hardnestedDialog : public QDialog
Q_OBJECT
public:
explicit MF_Attack_hardnestedDialog(int blocks, QWidget *parent = nullptr);
explicit MF_Attack_hardnestedDialog(int blocks, const QVariantMap& config, QWidget *parent = nullptr);
~MF_Attack_hardnestedDialog();
private:
Ui::MF_Attack_hardnestedDialog *ui;
QVariantMap config;
signals:
void sendCMD(const QString& cmd);
private slots:
+2 -2
View File
@@ -31,7 +31,7 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="knownKeySectorBox">
<widget class="QComboBox" name="knownKeyBlockBox">
<property name="minimumSize">
<size>
<width>60</width>
@@ -106,7 +106,7 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="targetKeySectorBox">
<widget class="QComboBox" name="targetKeyBlockBox">
<property name="minimumSize">
<size>
<width>60</width>
+7 -15
View File
@@ -1,7 +1,7 @@
#include "mf_uid_parameterdialog.h"
#include "ui_mf_uid_parameterdialog.h"
MF_UID_parameterDialog::MF_UID_parameterDialog(const QString& uid, const QString& atqa, const QString& sak, QWidget *parent) :
MF_UID_parameterDialog::MF_UID_parameterDialog(const QString& uid, const QString& atqa, const QString& sak, const QVariantMap& config, QWidget *parent) :
QDialog(parent),
ui(new Ui::MF_UID_parameterDialog)
{
@@ -9,6 +9,7 @@ MF_UID_parameterDialog::MF_UID_parameterDialog(const QString& uid, const QString
ui->UIDLineEdit->setText(uid);
ui->ATQALineEdit->setText(atqa);
ui->SAKLineEdit->setText(sak);
this->config = config;
}
MF_UID_parameterDialog::~MF_UID_parameterDialog()
@@ -18,18 +19,9 @@ 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()
+ " "
+ ui->ATQALineEdit->text()
+ " "
+ ui->SAKLineEdit->text());
QString cmd = config["cmd"].toString();
cmd.replace("<uid>", ui->UIDLineEdit->text());
cmd.replace("<atqa>", ui->ATQALineEdit->text());
cmd.replace("<sak>", ui->SAKLineEdit->text());
emit sendCMD(cmd);
}
+2 -1
View File
@@ -14,11 +14,12 @@ class MF_UID_parameterDialog : public QDialog
Q_OBJECT
public:
explicit MF_UID_parameterDialog(const QString& uid, const QString& atqa, const QString& sak, QWidget *parent = nullptr);
explicit MF_UID_parameterDialog(const QString& uid, const QString& atqa, const QString& sak, const QVariantMap& config, QWidget *parent = nullptr);
~MF_UID_parameterDialog();
private:
Ui::MF_UID_parameterDialog *ui;
QVariantMap config;
signals:
void sendCMD(const QString& cmd);
private slots: