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
+ 优化性能
+ 优化用户界面
+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

+32 -16
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();
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
+292 -282
View File
@@ -1,4 +1,5 @@
#include "mifare.h"
#include <QJsonArray>
const Mifare::CardType Mifare::card_mini =
{
@@ -87,29 +88,37 @@ Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent): QObject(parent)
keyPattern = new QRegularExpression("\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|");
}
QString Mifare::info(bool isRequiringOutput)
void Mifare::setConfigMap(const QVariantMap& configMap)
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
this->configMap = configMap;
qDebug() << configMap;
}
QMap<QString, QString> Mifare::info(bool isRequiringOutput)
{
QMap<QString, QString> map;
QVariantMap config = configMap["info"].toMap();
if(isRequiringOutput)
{
QString result = util->execCMDWithOutput("hf 14a info", 500);
int begin, end;
begin = result.indexOf("UID");
if(begin != -1)
QString result = util->execCMDWithOutput(config["cmd"].toString(), 500);
QStringList lineList = result.split("\n");
for(auto line = lineList.begin(); line != lineList.end(); line++)
{
end = result.indexOf("SAK", begin);
end = result.indexOf("\n", end);
return result.mid(begin, end - begin + 1);
if(line->contains("UID"))
map["UID"] = line->replace("UID", "").replace(QRegularExpression("[^0-9a-fA-F]"), "").trimmed();
else if(line->contains("ATQA"))
map["ATQA"] = line->replace("ATQA", "").replace(QRegularExpression("[^0-9a-fA-F]"), "").trimmed();
else if(line->contains("SAK"))
map["SAK"] = line->replace("SAK", "").replace(QRegularExpression("\\[.+?\\]"), "").replace(QRegularExpression("[^0-9a-fA-F]"), "").trimmed();
}
}
else
{
util->execCMD("hf 14a info");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
util->execCMD(config["cmd"].toString());
Util::gotoRawTab();
}
}
return "";
return map;
}
void Mifare::chk()
@@ -118,131 +127,117 @@ void Mifare::chk()
QString result;
int offset = 0;
QString data;
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
QVariantMap config = configMap["check"].toMap();
QString cmd = config["cmd"].toString();
int keyAindex = config["key A index"].toInt();
int keyBindex = config["key B index"].toInt();
QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString());
cmd.replace("<card type>", config["card type"].toMap()[cardType.typeText].toString());
result = util->execCMDWithOutput(
"hf mf chk *"
+ QString::number(cardType.type)
+ " ?",
Util::ReturnTrigger(1000 + cardType.sector_size * 200, {"No valid", keyPattern->pattern()}));
qDebug() << result;
cmd,
Util::ReturnTrigger(1000 + cardType.sector_size * 200, {"No valid", keyPattern.pattern()}));
for(int i = 0; i < cardType.sector_size; i++)
{
reMatch = keyPattern->match(result, offset);
reMatch = keyPattern.match(result, offset);
offset = reMatch.capturedStart();
if(reMatch.hasMatch())
{
data = reMatch.captured().toUpper();
offset += data.length();
QStringList cells = data.remove(" ").split("|");
if(!cells[2].contains("?"))
if(!cells[keyAindex].contains(QRegularExpression("[^0-9a-fA-F]")))
{
keyAList->replace(i, cells[2]);
keyAList->replace(i, cells[keyAindex]);
}
if(!cells[3].contains("?"))
if(!cells[keyBindex].contains(QRegularExpression("[^0-9a-fA-F]")))
{
keyBList->replace(i, cells[3]);
}
}
}
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
result = util->execCMDWithOutput(
"hf mf chk --"
+ cardType.typeText,
Util::ReturnTrigger(1000 + cardType.sector_size * 200, {"No valid", keyPattern_res->pattern()}));
qDebug() << "mf_chk_iceman_result" << result;
for(int i = 0; i < cardType.sector_size; i++)
{
reMatch = keyPattern_res->match(result, offset);
offset = reMatch.capturedStart();
if(reMatch.hasMatch())
{
data = reMatch.captured().toUpper();
offset += data.length();
QStringList cells = data.remove(" ").split("|");
if(cells[3] == "1")
{
keyAList->replace(i, cells[2]);
}
if(cells[5] == "1")
{
keyBList->replace(i, cells[4]);
keyBList->replace(i, cells[keyBindex]);
}
}
}
}
data_syncWithKeyWidget();
}
void Mifare::nested()
void Mifare::nested(bool isStaticNested)
{
QVariantMap config = configMap["nested"].toMap();
QString cmd;
if(isStaticNested)
cmd = config["static cmd"].toString();
else
cmd = config["cmd"].toString();
int keyAindex = config["key A index"].toInt();
int keyBindex = config["key B index"].toInt();
QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString());
QRegularExpressionMatch reMatch;
QString result;
int offset = 0;
QString data;
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
cmd.replace("<card type>", config["card type"].toMap()[cardType.typeText].toString());
if(cmd.contains(QRegularExpression("<.+>"))) // need at least one section key
{
result = util->execCMDWithOutput(
"hf mf nested "
+ QString::number(cardType.type)
+ " *",
Util::ReturnTrigger(15000, {"Can't found", "\\|000\\|"}));
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
QString knownKeyInfo = "";
QString knownKey, knownKeyType;
int knownKeySector = -1;
for(int i = 0; i < cardType.sector_size; i++)
{
if(data_isKeyValid(keyAList->at(i)))
{
knownKeyInfo = " --blk " + QString::number(i * 4) + " -a -k " + keyAList->at(i);
knownKeyType = "A";
knownKey = keyAList->at(i);
knownKeySector = i;
break;
}
else if(data_isKeyValid(keyBList->at(i)))
{
knownKeyType = "B";
knownKey = keyBList->at(i);
knownKeySector = i;
break;
}
}
if(knownKeyInfo == "")
if(knownKeySector != -1)
{
for(int i = 0; i < cardType.sector_size; i++)
{
if(data_isKeyValid(keyBList->at(i)))
{
knownKeyInfo = " --blk " + QString::number(i * 4) + " -b -k " + keyBList->at(i);
break;
}
}
}
if(knownKeyInfo != "")
{
result = util->execCMDWithOutput(
"hf mf nested --"
+ cardType.typeText
+ knownKeyInfo,
Util::ReturnTrigger(15000, {"Can't authenticate", keyPattern_res->pattern()}));
cmd.replace("<block>", QString::number(cardType.blks[knownKeySector]));
cmd.replace("<key type>", config["key type"].toMap()[knownKeyType].toString());
cmd.replace("<key>", knownKey);
}
else
{
QMessageBox::information(parent, tr("Info"), tr("Plz provide at least one known key"));
return;
}
}
result = util->execCMDWithOutput(
cmd,
Util::ReturnTrigger(15000, {"Can't found", "Can't authenticate", keyPattern_res->pattern()}),
true);
if(result.contains("static") && !isStaticNested)
{
nested(true);
return;
}
for(int i = 0; i < cardType.sector_size; i++)
{
reMatch = keyPattern_res->match(result, offset);
reMatch = keyPattern.match(result, offset);
offset = reMatch.capturedStart();
if(reMatch.hasMatch())
{
data = reMatch.captured().toUpper();
offset += data.length();
QStringList cells = data.remove(" ").split("|");
if(cells[3] == "1")
if(!cells[keyAindex].contains(QRegularExpression("[^0-9a-fA-F]")))
{
keyAList->replace(i, cells[2]);
keyAList->replace(i, cells[keyAindex]);
}
if(cells[5] == "1")
if(!cells[keyBindex].contains(QRegularExpression("[^0-9a-fA-F]")))
{
keyBList->replace(i, cells[4]);
keyBList->replace(i, cells[keyBindex]);
}
}
}
@@ -252,50 +247,43 @@ void Mifare::nested()
void Mifare::hardnested()
{
MF_Attack_hardnestedDialog dialog(cardType.block_size);
QVariantMap config = configMap["hardnested"].toMap();
MF_Attack_hardnestedDialog dialog(cardType.block_size, config);
connect(&dialog, &MF_Attack_hardnestedDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted)
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::darkside()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf mf mifare");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf darkside");
QVariantMap config = configMap["darkside"].toMap();
util->execCMD(config["cmd"].toString());
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::sniff()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf mf sniff");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf sniff");
QVariantMap config = configMap["sniff"].toMap();
util->execCMD(config["cmd"].toString());
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::sniff14a()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf 14a snoop");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf 14a sniff");
QVariantMap config = configMap["sniff 14a"].toMap();
util->execCMD(config["cmd"].toString());
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::list()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf list mf");
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("trace list -t mf");
QVariantMap config = configMap["list"].toMap();
util->execCMD(config["cmd"].toString());
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, TargetType targetType, int waitTime)
@@ -305,24 +293,22 @@ QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, Targe
QRegularExpressionMatch currMatch;
bool isTrailerBlock = (blockId < 128 && ((blockId + 1) % 4 == 0)) || ((blockId + 1) % 16 == 0);
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
if(targetType == TARGET_MIFARE)
{
if(!data_isKeyValid(key))
{
return "";
}
QVariantMap config = configMap["normal read block"].toMap();
QString cmd = config["cmd"].toString();
QRegularExpression dataPattern = QRegularExpression(config["data pattern"].toString());
cmd.replace("<block>", QString::number(blockId));
cmd.replace("<key type>", config["key type"].toMap()[QString((char)keyType)].toString());
cmd.replace("<key>", key);
// use the given key type to read the target block
result = util->execCMDWithOutput(
"hf mf rdbl "
+ QString::number(blockId)
+ " "
+ (char)keyType
+ " "
+ key,
waitTime);
currMatch = dataPattern->match(result);
result = util->execCMDWithOutput(cmd, waitTime);
currMatch = dataPattern.match(result);
if(currMatch.hasMatch())
{
data = currMatch.captured().toUpper();
@@ -349,11 +335,12 @@ QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, Targe
}
else if(targetType == TARGET_UID)
{
result = util->execCMDWithOutput(
"hf mf cgetblk "
+ QString::number(blockId),
waitTime);
currMatch = dataPattern->match(result);
QVariantMap config = configMap["Magic Card read block"].toMap();
QString cmd = config["cmd"].toString();
QRegularExpression dataPattern = QRegularExpression(config["data pattern"].toString());
cmd.replace("<block>", QString::number(blockId));
result = util->execCMDWithOutput(cmd, waitTime);
currMatch = dataPattern.match(result);
if(currMatch.hasMatch())
{
data = currMatch.captured().toUpper();
@@ -362,36 +349,23 @@ QString Mifare::_readblk(int blockId, KeyType keyType, const QString& key, Targe
else
data = "";
}
}
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
else if(targetType == TARGET_EMULATOR)
{
if(targetType == TARGET_EMULATOR)
{
result = util->execCMDWithOutput(
"hf mf eget "
+ QString::number(blockId),
150);
data = dataPattern->match(result).captured().toUpper();
QVariantMap config = configMap["emulator read block"].toMap();
QString cmd = config["cmd"].toString();
QRegularExpression dataPattern = QRegularExpression(config["data pattern"].toString());
cmd.replace("<block>", QString::number(blockId));
result = util->execCMDWithOutput(cmd, 150);
data = dataPattern.match(result).captured().toUpper();
data.remove(" ");
}
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
if(targetType == TARGET_EMULATOR)
{
result = util->execCMDWithOutput(
"hf mf egetblk "
+ QString::number(blockId),
150);
data = dataPattern->match(result).captured().toUpper();
data.remove(" ");
}
}
return data;
}
QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key, TargetType targetType, int waitTime)
{
QVariantMap config;
QStringList data;
QString result, tmp;
QRegularExpressionMatch reMatch;
@@ -402,8 +376,6 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
data.append("");
}
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
// try to read all blocks together
if(targetType == TARGET_MIFARE)
{
@@ -411,29 +383,37 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
{
return data;
}
result = util->execCMDWithOutput(
"hf mf rdsc "
+ QString::number(sectorId)
+ " "
+ (char)keyType
+ " "
+ key,
waitTime);
offset = result.indexOf("isOk:01"); // find successful flag
config = configMap["normal read sector"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<sector>", QString::number(sectorId));
cmd.replace("<key type>", config["key type"].toMap()[QString((char)keyType)].toString());
cmd.replace("<key>", key);
result = util->execCMDWithOutput(cmd, waitTime);
}
else if(targetType == TARGET_UID)
{
result = util->execCMDWithOutput(
"hf mf cgetsc "
+ QString::number(sectorId),
waitTime);
offset = result.indexOf("error") == -1 ? 0 : -1; // find failed flag
config = configMap["Magic Card read sector"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<sector>", QString::number(sectorId));
result = util->execCMDWithOutput(cmd, waitTime);
}
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
// if targetType == TARGET_EMULATOR, this function has returned
QRegularExpression dataPattern = QRegularExpression(config["data pattern"].toString());
reMatch = dataPattern.match(result);
offset = reMatch.capturedStart();
if(reMatch.hasMatch()) // read successful
{
for(int i = 0; i < cardType.blk[sectorId]; i++)
{
reMatch = dataPattern->match(result, offset);
reMatch = dataPattern.match(result, offset);
offset = reMatch.capturedStart();
if(reMatch.hasMatch())
{
@@ -444,13 +424,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];
@@ -472,7 +450,7 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
}
data[cardType.blk[sectorId] - 1] = trailer;
}
}
return data;
}
@@ -493,7 +471,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 +490,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 +505,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 +553,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 +567,6 @@ void Mifare::readSelected(TargetType targetType)
data_syncWithKeyWidget(false, i, KEY_A);
data_syncWithKeyWidget(false, i, KEY_B);
}
}
}
}
@@ -588,45 +579,57 @@ bool Mifare::_writeblk(int blockId, KeyType keyType, const QString& key, const Q
if(data_isDataValid(input) != DATA_NOSPACE)
return false;
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
if(targetType == TARGET_MIFARE)
{
if(!data_isKeyValid(key))
return false;
result = util->execCMDWithOutput(
"hf mf wrbl "
+ QString::number(blockId)
+ " "
+ (char)keyType
+ " "
+ key
+ " "
+ input,
waitTime);
return (result.indexOf("isOk:01") != -1);
QVariantMap config = configMap["normal write block"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<block>", QString::number(blockId));
cmd.replace("<key type>", config["key type"].toMap()[QString((char)keyType)].toString());
cmd.replace("<key>", key);
cmd.replace("<data>", input);
result = util->execCMDWithOutput(cmd, waitTime);
if(result.isEmpty())
return false;
QVariantList failedFlag = config["failed flag"].toJsonArray().toVariantList();
for(auto flag = failedFlag.begin(); flag != failedFlag.end(); flag++)
{
if(result.contains(flag->toString()))
return false;
}
return true;
}
else if(targetType == TARGET_UID)
{
result = util->execCMDWithOutput(
"hf mf csetblk "
+ QString::number(blockId)
+ " "
+ input,
waitTime);
return (result.indexOf("error") == -1); // failed flag
QVariantMap config = configMap["Magic Card write block"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<block>", QString::number(blockId));
cmd.replace("<data>", input);
result = util->execCMDWithOutput(cmd, waitTime);
if(result.isEmpty())
return false;
QVariantList failedFlag = config["failed flag"].toJsonArray().toVariantList();
for(auto flag = failedFlag.begin(); flag != failedFlag.end(); flag++)
{
if(result.contains(flag->toString()))
return false;
}
return true;
}
else if(targetType == TARGET_EMULATOR)
{
util->execCMD(
"hf mf eset "
+ QString::number(blockId)
+ " "
+ input);
QVariantMap config = configMap["emulator write block"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<block>", QString::number(blockId));
cmd.replace("<data>", input);
util->execCMD(cmd);
util->delay(5);
return true;
}
}
return false;
}
@@ -740,82 +743,62 @@ void Mifare::writeSelected(TargetType targetType)
void Mifare::dump()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf dump");
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
QVariantMap config = configMap["dump"].toMap();
util->execCMD(config["cmd"].toString());
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);
QVariantMap config = configMap["restore"].toMap();
util->execCMD(config["cmd"].toString());
Util::gotoRawTab();
}
void Mifare::wipeC()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
{
util->execCMD(
"hf mf cwipe "
+ QString::number(cardType.type)
+ " f");
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
util->execCMD("hf mf cwipe");
}
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
QVariantMap config = configMap["Magic Card wipe"].toMap();
QString cmd = config["cmd"].toString();
if(cmd.contains("<card type>"))
cmd.replace("<card type>", config["card type"].toMap()[cardType.typeText].toString());
util->execCMD(cmd);
Util::gotoRawTab();
}
void Mifare::setParameterC()
{
QString result = info(true);
if(result == "")
QVariantMap config = configMap["Magic Card set parameter"].toMap();
QMap<QString, QString> result = info(true);
if(result.isEmpty())
{
QMessageBox::information(parent, tr("Info"), tr("Failed to read card."));
return;
}
else
{
result.replace("\r\n", "");
result.replace(QRegularExpression("\\[.\\]"), "");
result.replace("UID", "");
result.replace("ATQA", "");
result.replace("SAK", "");
result.replace(" ", "");
QStringList lis = result.split(':');
qDebug() << lis;
MF_UID_parameterDialog dialog(lis[1].toUpper(), lis[2].toUpper(), lis[3].toUpper());
MF_UID_parameterDialog dialog(result["UID"].toUpper(), result["ATQA"].toUpper(), result["SAK"].toUpper(), config);
connect(&dialog, &MF_UID_parameterDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted)
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
}
void Mifare::lockC()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
QVariantMap config = configMap["Magic Card lock"].toMap();
QString cmd = config["cmd"].toString();
QVariantList list = config["sequence"].toJsonArray().toVariantList();
for(auto item = list.begin(); item != list.end(); item++)
{
util->execCMD("hf 14a raw -pa -b7 40");
util->execCMD("hf 14a raw -pa 43");
util->execCMD("hf 14a raw -pa E0 00 39 F7");
util->execCMD("hf 14a raw -pa E1 00 E1 EE");
util->execCMD("hf 14a raw -pa 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47");
util->execCMD("hf 14a raw -a 52");
}
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
{
util->execCMD("hf 14a raw -ak -b 7 40");
util->execCMD("hf 14a raw -ak 43");
util->execCMD("hf 14a raw -ak E0 00 39 F7");
util->execCMD("hf 14a raw -ak E1 00 E1 EE");
util->execCMD("hf 14a raw -ak 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47");
util->execCMD("hf 14a raw -a 52");
qDebug() << cmd + item->toString();
util->execCMD(cmd + item->toString());
}
}
void Mifare::wipeE()
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL || Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("hf mf eclr");
QVariantMap config = configMap["emulator wipe"].toMap();
util->execCMD(config["cmd"].toString());
}
void Mifare::simulate()
@@ -823,30 +806,35 @@ 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)
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf list mf -l " + file);
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
QVariantMap config = configMap["load sniff"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<filename>", file);
if(config.contains("show cmd"))
{
if(util->execCMDWithOutput("trace load -f " + file, Util::ReturnTrigger({"loaded"})) != "")
util->execCMD("trace list -t mf");
if(util->execCMDWithOutput(cmd, Util::ReturnTrigger({"loaded"})) != "")
util->execCMD(config["show cmd"].toString());
}
else
{
util->execCMD(cmd);
}
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::saveSniff(const QString& file)
{
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
util->execCMD("hf list mf -s " + file);
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
util->execCMD("trace save -f " + file);
QVariantMap config = configMap["save sniff"].toMap();
QString cmd = config["cmd"].toString();
cmd.replace("<filename>", file);
util->execCMD(cmd);
ui->funcTab->setCurrentIndex(Util::rawTabIndex);
Util::gotoRawTab();
}
void Mifare::data_syncWithDataWidget(bool syncAll, int block)
@@ -860,11 +848,11 @@ void Mifare::data_syncWithDataWidget(bool syncAll, int block)
tmp = "";
if(dataList->at(i) != "")
{
tmp += dataList->at(i).mid(0, 2);
tmp += dataList->at(i).midRef(0, 2);
for(int j = 1; j < 16; j++)
{
tmp += " ";
tmp += dataList->at(i).mid(j * 2, 2);
tmp += dataList->at(i).midRef(j * 2, 2);
}
}
ui->MF_dataWidget->item(i, 2)->setText(tmp);
@@ -875,11 +863,11 @@ void Mifare::data_syncWithDataWidget(bool syncAll, int block)
tmp = "";
if(dataList->at(block) != "")
{
tmp += dataList->at(block).mid(0, 2);
tmp += dataList->at(block).midRef(0, 2);
for(int j = 1; j < 16; j++)
{
tmp += " ";
tmp += dataList->at(block).mid(j * 2, 2);
tmp += dataList->at(block).midRef(j * 2, 2);
}
}
ui->MF_dataWidget->item(block, 2)->setText(tmp);
@@ -1052,7 +1040,7 @@ bool Mifare::data_loadDataFile(const QString& filename)
else
{
QString tmp = buff.left(cardType.block_size * 34);
QStringList tmpList = tmp.split("\r\n");
QStringList tmpList = tmp.split("\n");
for(int i = 0; i < cardType.block_size; i++)
{
dataList->replace(i, tmpList[i].toUpper());
@@ -1090,7 +1078,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());
@@ -1155,7 +1143,7 @@ bool Mifare::data_saveDataFile(const QString& filename, bool isBin)
for(int i = 0; i < cardType.block_size; i++)
{
buff += dataList->at(i);
buff += "\r\n";
buff += "\n";
}
}
bool ret = file.write(buff) != -1;
@@ -1230,17 +1218,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)).midRef(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 +1237,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 +1329,25 @@ 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);
}
+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;
+265 -40
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,11 +121,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(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;
@@ -101,20 +141,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", {}, 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);
clientEnv = QString(envSetProcess.readAll()).split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
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();
emit setProcEnv(&clientEnv);
clientWorkingDir->setPath(QApplication::applicationDirPath());
qDebug() << clientWorkingDir->absolutePath();
@@ -124,8 +176,14 @@ void MainWindow::on_PM3_connectButton_clicked()
qDebug() << clientWorkingDir->absolutePath();
emit setWorkingDir(clientWorkingDir->absolutePath());
emit connectPM3(ui->PM3_pathEdit->text(), port, args);
}
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,11 +299,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 +330,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 +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);
+1231 -76
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: