Merge pull request #2 from wh201906/dev

V0.1
pull/5/head
wh201906 5 years ago committed by GitHub
commit 5f1df6782a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,22 +17,36 @@ DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
mainwindow.cpp \ common/pm3process.cpp \
pm3process.cpp common/util.cpp \
module/mifare.cpp \
ui/mf_uid_parameterdialog.cpp \
ui/mainwindow.cpp \
ui/mf_attack_hardnesteddialog.cpp \
HEADERS += \ HEADERS += \
mainwindow.h \ common/pm3process.h \
pm3process.h common/util.h \
module/mifare.h \
ui/mf_uid_parameterdialog.h \
ui/mainwindow.h \
ui/mf_attack_hardnesteddialog.h \
FORMS += \ FORMS += \
mainwindow.ui ui/mf_uid_parameterdialog.ui \
ui/mainwindow.ui \
ui/mf_attack_hardnesteddialog.ui
TRANSLATIONS += \
lang/zh_CN.ts \
lang/en_US.ts
# Default rules for deployment. # Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target !isEmpty(target.path): INSTALLS += target
VERSION = 0.0.1 VERSION = 0.1
QMAKE_TARGET_PRODUCT = "Proxmark3GUI" QMAKE_TARGET_PRODUCT = "Proxmark3GUI"
QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI" QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI"
QMAKE_TARGET_COMPANY = "wh201906" QMAKE_TARGET_COMPANY = "wh201906"

@ -1,9 +1,35 @@
# Proxmark3GUI # Proxmark3GUI
A GUI for Proxmark3 client A GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) client
[中文](README/README.zh_CN.md)
***
## Features
+ Support raw commands of Proxmark3 client
+ Have a friendly UI to test Mifare cards
+ Easy to edit Mifare data files
+ Support binary(.bin .dump) files and text(.eml) files
+ ...
***
## Previews
![nested_attack](README/mf_nested_attack.gif)
![mf_load_file](README/mf_load_file.gif)
![mf_edit_file](README/mf_edit_file.gif)
![raw_command](README/raw_command.gif)
*** ***
Update Log: ## Update Log:
### V0.1
+ Able to deal with Mifare card and related files
## V0.0.1 ### V0.0.1
+ a dumb version with a useless GUI and a serial choose box. + a dumb version with a useless GUI and a serial choose box.

@ -0,0 +1,35 @@
# Proxmark3GUI
一个自制的[Proxmark3](https://github.com/Proxmark/proxmark3) GUI
[English](../README.md)
***
## 特色功能
+ 支持直接输入PM3命令
+ 有针对于Mifare卡IC卡的图形界面
+ 支持编辑Mifare扇区数据文件
+ 可以打开二进制/文本格式的扇区数据文件
+ ...
***
## 预览图
![nested_attack](mf_nested_attack.gif)
![mf_load_file](mf_load_file.gif)
![mf_edit_file](mf_edit_file.gif)
![raw_command](raw_command.gif)
***
## 更新日志:
### V0.1
+ 支持处理Mifare卡片及相关数据文件
### V0.0.1
+ 一个带串口选择框的实验版本

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 857 KiB

@ -0,0 +1,102 @@
#include "pm3process.h"
PM3Process::PM3Process(QThread* thread, QObject* parent): QProcess(parent)
{
moveToThread(thread);
setProcessChannelMode(PM3Process::MergedChannels);
isRequiringOutput = false;
requiredOutput = new QString();
serialListener = new QTimer(); // if using new QTimer(this), the debug output will show "Cannot create children for a parent that is in a different thread."
serialListener->moveToThread(this->thread());// I've tried many ways to creat a QTimer instance, but all of the instances are in the main thread(UI thread), so I have to move it manually
serialListener->setInterval(1000);
serialListener->setTimerType(Qt::VeryCoarseTimer);
connect(serialListener, &QTimer::timeout, this, &PM3Process::onTimeout);
connect(this, &PM3Process::readyRead, this, &PM3Process::onReadyRead);
}
void PM3Process::connectPM3(const QString path, const QString port)
{
setRequiringOutput(true);
// using "-f" option to make the client output flushed after every print.
start(path, QStringList() << port << "-f", QProcess::Unbuffered | QProcess::ReadWrite);
if(waitForStarted(10000))
{
while(waitForReadyRead(1000))
;
setRequiringOutput(false);
QString result = *requiredOutput;
if(result.indexOf("os: ") != -1) // make sure the PM3 is connected
{
result = result.mid(result.indexOf("os: "));
result = result.left(result.indexOf("\r\n"));
result = result.mid(3, result.lastIndexOf(" ") - 3);
emit PM3StatedChanged(true, result);
setSerialListener(port, true);
}
else
kill();
}
}
void PM3Process::setRequiringOutput(bool st)
{
isRequiringOutput = st;
if(isRequiringOutput)
requiredOutput->clear();
}
bool PM3Process::waitForReadyRead(int msecs)
{
return QProcess::waitForReadyRead(msecs);
}
void PM3Process::setSerialListener(const QString& name, bool state)
{
if(state)
{
portInfo = new QSerialPortInfo(name);
serialListener->start();
qDebug() << serialListener->thread();
}
else
{
serialListener->stop();
delete portInfo;
}
}
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);
{
// qDebug()<<portInfo->isBusy();
if(!portInfo->isBusy())
{
kill();
emit PM3StatedChanged(false);
setSerialListener("", false);
}
}
void PM3Process::testThread()
{
qDebug() << "PM3:" << QThread::currentThread();
}
qint64 PM3Process::write(QString data)
{
return QProcess::write(data.toLatin1());
}
void PM3Process::onReadyRead()
{
QString out = readAll();
if(isRequiringOutput)
requiredOutput->append(out);
if(out != "")
{
// qDebug() << "PM3Process::onReadyRead:" << out;
emit newOutput(out);
}
}

@ -0,0 +1,39 @@
#ifndef PM3PROCESS_H
#define PM3PROCESS_H
#include <QProcess>
#include <QThread>
#include <QString>
#include <QDebug>
#include <QTimer>
#include <QtSerialPort/QSerialPortInfo>
#include <QtSerialPort/QSerialPort>
class PM3Process : public QProcess
{
Q_OBJECT
public:
explicit PM3Process(QThread* thread, QObject* parent = nullptr);
bool waitForReadyRead(int msecs = 2000);
void testThread();
public slots:
void connectPM3(const QString path, const QString port);
void setSerialListener(const QString &name, bool state);
qint64 write(QString data);
private slots:
void onTimeout();
void onReadyRead();
private:
bool isRequiringOutput;
QString* requiredOutput; // It only works in this class now
void setRequiringOutput(bool st);// It only works in this class now
QTimer* serialListener;
QSerialPortInfo* portInfo;
signals:
void PM3StatedChanged(bool st, QString info = "");
void newOutput(QString output);
};
#endif // PM3PROCESS_H

@ -0,0 +1,52 @@
#include "util.h"
Util::Util(QObject *parent) : QObject(parent)
{
isRequiringOutput = false;
requiredOutput = new QString();
timeStamp = QTime::currentTime();
}
void Util::processOutput(QString output)
{
// qDebug() << "Util::processOutput:" << output;
if(isRequiringOutput)
{
requiredOutput->append(output);
timeStamp = QTime::currentTime();
}
emit refreshOutput(output);
}
void Util::execCMD(QString cmd)
{
qDebug() << cmd;
emit write(cmd + "\r\n");
}
QString Util::execCMDWithOutput(QString cmd, unsigned long timeout)
{
QTime currTime = QTime::currentTime();
QTime targetTime = QTime::currentTime().addMSecs(timeout);
isRequiringOutput = true;
requiredOutput->clear();
execCMD(cmd);
while( QTime::currentTime() < targetTime)
{
QApplication::processEvents();
if(timeStamp > currTime)
{
currTime = timeStamp;
targetTime = timeStamp.addMSecs(timeout);
}
}
isRequiringOutput = false;
return *requiredOutput;
}
void Util::delay(unsigned int msec)
{
QTime timer = QTime::currentTime().addMSecs(msec);
while( QTime::currentTime() < timer )
QApplication::processEvents(QEventLoop::AllEvents, 100);
}

@ -0,0 +1,33 @@
#ifndef UTIL_H
#define UTIL_H
#include <QObject>
#include <QString>
#include <QDebug>
#include <QThread>
#include <QApplication>
#include <QTime>
#include <QTimer>
class Util : public QObject
{
Q_OBJECT
public:
explicit Util(QObject *parent = nullptr);
void execCMD(QString cmd);
QString execCMDWithOutput(QString cmd, unsigned long timeout = 2000);
void delay(unsigned int msec);
public slots:
void processOutput(QString output);
private:
bool isRequiringOutput;
QString* requiredOutput;
QTime timeStamp;
signals:
void refreshOutput(const QString& output);
void write(QString data);
};
#endif // UTIL_H

@ -0,0 +1,608 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
<context>
<name>MF_Attack_hardnestedDialog</name>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="14"/>
<source>Hardnested Attack</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="20"/>
<source>Known Block:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="29"/>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="104"/>
<source>Block:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="68"/>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="143"/>
<source>A</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="73"/>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="148"/>
<source>B</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="95"/>
<source>Target Block:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MF_UID_parameterDialog</name>
<message>
<location filename="../ui/mf_uid_parameterdialog.ui" line="14"/>
<source>Set Parameter</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mf_uid_parameterdialog.ui" line="22"/>
<source>UID:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mf_uid_parameterdialog.ui" line="32"/>
<source>ATQA:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mf_uid_parameterdialog.ui" line="42"/>
<source>SAK:</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../ui/mainwindow.ui" line="23"/>
<source>Proxmark3GUI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="56"/>
<source>Path:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="80"/>
<source>Refresh</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="87"/>
<source>Connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="94"/>
<source>Disconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="113"/>
<source>Mifare</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="206"/>
<source>&gt;&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="231"/>
<source>&lt;&lt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="263"/>
<source>F</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="320"/>
<source>Card Type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="335"/>
<source>MINI</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="342"/>
<source>1K</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="352"/>
<source>2K</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="359"/>
<source>4K</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="369"/>
<source>File</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="387"/>
<location filename="../ui/mainwindow.ui" line="944"/>
<source>Load</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="400"/>
<location filename="../ui/mainwindow.ui" line="957"/>
<source>Save</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="420"/>
<location filename="../ui/mainwindow.cpp" line="534"/>
<source>Data</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="430"/>
<source>Key</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="440"/>
<source>Attack</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="465"/>
<source>Card Info</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="478"/>
<source>Check Default</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="491"/>
<source>Nested</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="498"/>
<source>Hardnested</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="523"/>
<source>Read/Write</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="533"/>
<source>Block:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="565"/>
<source>Key:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="584"/>
<source>Key Type:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="604"/>
<source>A</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="609"/>
<source>B</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="632"/>
<source>Normal(Require Password)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="647"/>
<location filename="../ui/mainwindow.ui" line="736"/>
<source>Read Block</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="654"/>
<location filename="../ui/mainwindow.ui" line="743"/>
<source>Write Block</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="661"/>
<location filename="../ui/mainwindow.ui" line="750"/>
<location filename="../ui/mainwindow.ui" line="850"/>
<source>Read All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="668"/>
<location filename="../ui/mainwindow.ui" line="757"/>
<source>Write All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="687"/>
<source>Dump</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="700"/>
<source>Restore</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="710"/>
<source>Chinese Magic Card(Without Password)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="722"/>
<source>Lock UFUID Card</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="729"/>
<location filename="../ui/mainwindow.cpp" line="461"/>
<source>About UID Card</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="770"/>
<source>Set Parameter</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="789"/>
<source>Wipe</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="815"/>
<location filename="../ui/mainwindow.ui" line="870"/>
<source>Simulate</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="843"/>
<source>Load from data above</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="413"/>
<location filename="../ui/mainwindow.ui" line="863"/>
<source>Clear</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="893"/>
<location filename="../ui/mainwindow.ui" line="924"/>
<source>Sniff</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="931"/>
<source>List Sniff Data</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="983"/>
<source>RawCommand</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="1030"/>
<location filename="../ui/mainwindow.cpp" line="143"/>
<source>History:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="1062"/>
<source>ClearHistory</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="1081"/>
<source>Send</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="1088"/>
<source>ClearOutput</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="77"/>
<location filename="../ui/mainwindow.cpp" line="179"/>
<location filename="../ui/mainwindow.cpp" line="229"/>
<location filename="../ui/mainwindow.cpp" line="246"/>
<location filename="../ui/mainwindow.cpp" line="259"/>
<location filename="../ui/mainwindow.cpp" line="278"/>
<location filename="../ui/mainwindow.cpp" line="291"/>
<location filename="../ui/mainwindow.cpp" line="314"/>
<location filename="../ui/mainwindow.cpp" line="327"/>
<source>Info</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="77"/>
<source>Plz choose a port first</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="91"/>
<source>Connected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="95"/>
<location filename="../ui/mainwindow.cpp" line="105"/>
<location filename="../ui/mainwindow.cpp" line="524"/>
<source>Not Connected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="272"/>
<source>Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml);;All Files(*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="278"/>
<location filename="../ui/mainwindow.cpp" line="291"/>
<source>Failed to open</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="179"/>
<source>When Changeing card type, the data and keys in this app will be cleard.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="179"/>
<source>Continue?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="208"/>
<source>Plz select the font of data widget and key widget</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="229"/>
<source>Data must consists of 32 Hex symbols(Whitespace is allowed)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="246"/>
<location filename="../ui/mainwindow.cpp" line="259"/>
<source>Key must consists of 12 Hex symbols(Whitespace is allowed)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="271"/>
<source>Plz select the data file:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="284"/>
<source>Plz select the key file:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="285"/>
<source>Binary Key Files(*.bin *.dump);;Binary Data Files(*.bin *.dump);;All Files(*.*)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="307"/>
<source>Plz select the location to save data file:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="308"/>
<source>Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="314"/>
<location filename="../ui/mainwindow.cpp" line="327"/>
<source>Failed to save to</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="320"/>
<source>Plz select the location to save key file:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="321"/>
<source>Binary Key Files(*.bin *.dump)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="446"/>
<source> Normally, the Block 0 of a typical Mifare card, which contains the UID, is locked during the manufacture. Users cannot write anything to Block 0 or set a new UID to a normal Mifare card.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="447"/>
<source> Chinese Magic Cards(aka UID Cards) are some special cards whose Block 0 are writeable. And you can change UID by writing to it.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="449"/>
<source>There are two versions of Chinese Magic Cards, the Gen1 and the Gen2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="450"/>
<source> Gen1:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="450"/>
<source> also called UID card in China. It responses to some backdoor commands so you can access any blocks without password. The Proxmark3 has a bunch of related commands(csetblk, cgetblk, ...) to deal with this type of card, and my GUI also support these commands.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="451"/>
<source> Gen2:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="451"/>
<source> doesn&apos;t response to the backdoor commands, which means that a reader cannot detect whether it is a Chinese Magic Card or not by sending backdoor commands.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="453"/>
<source>There are some types of Chinese Magic Card Gen2.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="454"/>
<source> CUID Card:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="454"/>
<source> the Block 0 is writeable, you can write to this block repeatedly by normal wrbl command.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="455"/>
<source> (hf mf wrbl 0 A FFFFFFFFFFFF &lt;the data you want to write&gt;)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="456"/>
<source> FUID Card:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="456"/>
<source> you can only write to Block 0 once. After that, it seems like a typical Mifare card(Block 0 cannot be written to).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="457"/>
<source> (some readers might try changing the Block 0, which could detect the CUID Card. In that case, you should use FUID card.)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="458"/>
<source> UFUID Card:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="458"/>
<source> It behaves like a CUID card(or UID card? I&apos;m not sure) before you send some special command to lock it. Once it is locked, you cannot change its Block 0(just like a typical Mifare card).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="460"/>
<source> Seemingly, these Chinese Magic Cards are more easily to be compromised by Nested Attack(it takes little time to get an unknown key).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="525"/>
<location filename="../ui/mainwindow.cpp" line="642"/>
<source>Idle</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="532"/>
<location filename="../ui/mainwindow.cpp" line="541"/>
<source>Sec</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="533"/>
<source>Blk</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="542"/>
<source>KeyA</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="543"/>
<source>KeyB</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="579"/>
<source>HW Version:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="581"/>
<source>PM3:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="583"/>
<source>State:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="638"/>
<source>Running</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Mifare</name>
<message>
<location filename="../module/mifare.cpp" line="289"/>
<location filename="../module/mifare.cpp" line="386"/>
<source>Success!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../module/mifare.cpp" line="289"/>
<location filename="../module/mifare.cpp" line="293"/>
<location filename="../module/mifare.cpp" line="386"/>
<location filename="../module/mifare.cpp" line="390"/>
<location filename="../module/mifare.cpp" line="425"/>
<source>Info</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../module/mifare.cpp" line="293"/>
<location filename="../module/mifare.cpp" line="390"/>
<source>Failed!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../module/mifare.cpp" line="425"/>
<source>Failed to read card.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

@ -0,0 +1,649 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
<name>MF_Attack_hardnestedDialog</name>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="14"/>
<source>Hardnested Attack</source>
<translation>Hardnested</translation>
</message>
<message>
<source>Known Key:</source>
<translation type="obsolete">Key</translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="20"/>
<source>Known Block:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="29"/>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="104"/>
<source>Block:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="68"/>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="143"/>
<source>A</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="73"/>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="148"/>
<source>B</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mf_attack_hardnesteddialog.ui" line="95"/>
<source>Target Block:</source>
<translation></translation>
</message>
<message>
<source>Target Block: </source>
<translation type="vanished"></translation>
</message>
</context>
<context>
<name>MF_UID_parameterDialog</name>
<message>
<source>Dialog</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../ui/mf_uid_parameterdialog.ui" line="14"/>
<source>Set Parameter</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mf_uid_parameterdialog.ui" line="22"/>
<source>UID:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mf_uid_parameterdialog.ui" line="32"/>
<source>ATQA:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mf_uid_parameterdialog.ui" line="42"/>
<source>SAK:</source>
<translation></translation>
</message>
<message>
<source>The parameter will not change if you leave it empty.</source>
<translation type="vanished"></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../ui/mainwindow.ui" line="23"/>
<source>Proxmark3GUI</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="56"/>
<source>Path:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="80"/>
<source>Refresh</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="87"/>
<source>Connect</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="94"/>
<source>Disconnect</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="113"/>
<source>Mifare</source>
<translation>Mifare(IC)</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="206"/>
<source>&gt;&gt;</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="231"/>
<source>&lt;&lt;</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="263"/>
<source>F</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="320"/>
<source>Card Type</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="335"/>
<source>MINI</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="342"/>
<source>1K</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="352"/>
<source>2K</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="359"/>
<source>4K</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="369"/>
<source>File</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="387"/>
<location filename="../ui/mainwindow.ui" line="944"/>
<source>Load</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="400"/>
<location filename="../ui/mainwindow.ui" line="957"/>
<source>Save</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="420"/>
<location filename="../ui/mainwindow.cpp" line="534"/>
<source>Data</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="430"/>
<source>Key</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="440"/>
<source>Attack</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="465"/>
<source>Card Info</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="478"/>
<source>Check Default</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="491"/>
<source>Nested</source>
<translation>Nested</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="498"/>
<source>Hardnested</source>
<translation>Hardested</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="523"/>
<source>Read/Write</source>
<translation>/</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="533"/>
<source>Block:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="565"/>
<source>Key:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="584"/>
<source>Key Type:</source>
<translation>Key</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="604"/>
<source>A</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="609"/>
<source>B</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="632"/>
<source>Normal(Require Password)</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="647"/>
<location filename="../ui/mainwindow.ui" line="736"/>
<source>Read Block</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="654"/>
<location filename="../ui/mainwindow.ui" line="743"/>
<source>Write Block</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="661"/>
<location filename="../ui/mainwindow.ui" line="750"/>
<location filename="../ui/mainwindow.ui" line="850"/>
<source>Read All</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="668"/>
<location filename="../ui/mainwindow.ui" line="757"/>
<source>Write All</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="687"/>
<source>Dump</source>
<translation>Dump</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="700"/>
<source>Restore</source>
<translation>Restore</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="710"/>
<source>Chinese Magic Card(Without Password)</source>
<translation>UID</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="722"/>
<source>Lock UFUID Card</source>
<translation>UFUID</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="729"/>
<location filename="../ui/mainwindow.cpp" line="461"/>
<source>About UID Card</source>
<translation>UID</translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="770"/>
<source>Set Parameter</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="789"/>
<source>Wipe</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="815"/>
<location filename="../ui/mainwindow.ui" line="870"/>
<source>Simulate</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="843"/>
<source>Load from data above</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="413"/>
<location filename="../ui/mainwindow.ui" line="863"/>
<source>Clear</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="893"/>
<location filename="../ui/mainwindow.ui" line="924"/>
<source>Sniff</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="931"/>
<source>List Sniff Data</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="983"/>
<source>RawCommand</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="1030"/>
<location filename="../ui/mainwindow.cpp" line="143"/>
<source>History:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="1062"/>
<source>ClearHistory</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="1081"/>
<source>Send</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.ui" line="1088"/>
<source>ClearOutput</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="77"/>
<location filename="../ui/mainwindow.cpp" line="179"/>
<location filename="../ui/mainwindow.cpp" line="229"/>
<location filename="../ui/mainwindow.cpp" line="246"/>
<location filename="../ui/mainwindow.cpp" line="259"/>
<location filename="../ui/mainwindow.cpp" line="278"/>
<location filename="../ui/mainwindow.cpp" line="291"/>
<location filename="../ui/mainwindow.cpp" line="314"/>
<location filename="../ui/mainwindow.cpp" line="327"/>
<source>Info</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="77"/>
<source>Plz choose a port first</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="91"/>
<source>Connected</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="95"/>
<location filename="../ui/mainwindow.cpp" line="105"/>
<location filename="../ui/mainwindow.cpp" line="524"/>
<source>Not Connected</source>
<translation></translation>
</message>
<message>
<source>When Changeing card type, the data and keys in this app will be cleard.
Continue?</source>
<translation type="vanished">datakey\n</translation>
</message>
<message>
<source>Plz choose the data file:</source>
<translation type="vanished">data</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="272"/>
<source>Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml);;All Files(*.*)</source>
<translation>Data(*.bin *.dump);;Data(*.txt *.eml);;(*.*)</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="278"/>
<location filename="../ui/mainwindow.cpp" line="291"/>
<source>Failed to open</source>
<translation></translation>
</message>
<message>
<source>Plz choose the key file:</source>
<translation type="vanished">key</translation>
</message>
<message>
<source>Binary Key Files(*.bin *.dump);;All Files(*.*)</source>
<translation type="vanished">Key(*.bin *.dump);;(*.*)</translation>
</message>
<message>
<source>Save data to</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="179"/>
<source>When Changeing card type, the data and keys in this app will be cleard.</source>
<translation>DataKey</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="179"/>
<source>Continue?</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="208"/>
<source>Plz select the font of data widget and key widget</source>
<translation>DataKey</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="229"/>
<source>Data must consists of 32 Hex symbols(Whitespace is allowed)</source>
<translation>Data32</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="246"/>
<location filename="../ui/mainwindow.cpp" line="259"/>
<source>Key must consists of 12 Hex symbols(Whitespace is allowed)</source>
<translation>Key12</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="271"/>
<source>Plz select the data file:</source>
<translation>data</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="284"/>
<source>Plz select the key file:</source>
<translation>key</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="285"/>
<source>Binary Key Files(*.bin *.dump);;Binary Data Files(*.bin *.dump);;All Files(*.*)</source>
<translation>Key(*.bin *.dump)Data(*.bin *.dump);;(*.*)</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="307"/>
<source>Plz select the location to save data file:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="308"/>
<source>Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml)</source>
<translation>Data(*.bin *.dump);;Data(*.txt *.eml)</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="314"/>
<location filename="../ui/mainwindow.cpp" line="327"/>
<source>Failed to save to</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="320"/>
<source>Plz select the location to save key file:</source>
<translation>key</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="321"/>
<source>Binary Key Files(*.bin *.dump)</source>
<translation>Key(*.bin *.dump)</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="446"/>
<source> Normally, the Block 0 of a typical Mifare card, which contains the UID, is locked during the manufacture. Users cannot write anything to Block 0 or set a new UID to a normal Mifare card.</source>
<translation> MifareBlock0UID</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="447"/>
<source> Chinese Magic Cards(aka UID Cards) are some special cards whose Block 0 are writeable. And you can change UID by writing to it.</source>
<translation> UIDChinese Magic CardBlock0UID</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="449"/>
<source>There are two versions of Chinese Magic Cards, the Gen1 and the Gen2.</source>
<translation>UIDChinese Magic Card Gen1Gen2</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="450"/>
<source> Gen1:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="450"/>
<source> also called UID card in China. It responses to some backdoor commands so you can access any blocks without password. The Proxmark3 has a bunch of related commands(csetblk, cgetblk, ...) to deal with this type of card, and my GUI also support these commands.</source>
<translation> UIDPM3GUI</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="451"/>
<source> Gen2:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="451"/>
<source> doesn&apos;t response to the backdoor commands, which means that a reader cannot detect whether it is a Chinese Magic Card or not by sending backdoor commands.</source>
<translation> CUID/FUID/UFUID</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="453"/>
<source>There are some types of Chinese Magic Card Gen2.</source>
<translation>Gen2</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="454"/>
<source> CUID Card:</source>
<translation> CUID</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="454"/>
<source> the Block 0 is writeable, you can write to this block repeatedly by normal wrbl command.</source>
<translation> Block0</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="455"/>
<source> (hf mf wrbl 0 A FFFFFFFFFFFF &lt;the data you want to write&gt;)</source>
<translation> (hf mf wrbl 0 A FFFFFFFFFFFF &lt;&gt;)</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="456"/>
<source> FUID Card:</source>
<translation> FUID</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="456"/>
<source> you can only write to Block 0 once. After that, it seems like a typical Mifare card(Block 0 cannot be written to).</source>
<translation> Block0</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="457"/>
<source> (some readers might try changing the Block 0, which could detect the CUID Card. In that case, you should use FUID card.)</source>
<translation> (穿CUID)</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="458"/>
<source> UFUID Card:</source>
<translation> UFUID</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="458"/>
<source> It behaves like a CUID card(or UID card? I&apos;m not sure) before you send some special command to lock it. Once it is locked, you cannot change its Block 0(just like a typical Mifare card).</source>
<translation> UID/CUIDBlock0FUID</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="460"/>
<source> Seemingly, these Chinese Magic Cards are more easily to be compromised by Nested Attack(it takes little time to get an unknown key).</source>
<translation> UIDNested</translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="525"/>
<location filename="../ui/mainwindow.cpp" line="642"/>
<source>Idle</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="532"/>
<location filename="../ui/mainwindow.cpp" line="541"/>
<source>Sec</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="533"/>
<source>Blk</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="542"/>
<source>KeyA</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="543"/>
<source>KeyB</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="579"/>
<source>HW Version:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="581"/>
<source>PM3:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="583"/>
<source>State:</source>
<translation></translation>
</message>
<message>
<location filename="../ui/mainwindow.cpp" line="638"/>
<source>Running</source>
<translation></translation>
</message>
</context>
<context>
<name>Mifare</name>
<message>
<source>info</source>
<translation type="vanished"></translation>
</message>
<message>
<location filename="../module/mifare.cpp" line="289"/>
<location filename="../module/mifare.cpp" line="386"/>
<source>Success!</source>
<translation></translation>
</message>
<message>
<location filename="../module/mifare.cpp" line="289"/>
<location filename="../module/mifare.cpp" line="293"/>
<location filename="../module/mifare.cpp" line="386"/>
<location filename="../module/mifare.cpp" line="390"/>
<location filename="../module/mifare.cpp" line="425"/>
<source>Info</source>
<translation></translation>
</message>
<message>
<location filename="../module/mifare.cpp" line="293"/>
<location filename="../module/mifare.cpp" line="390"/>
<source>Failed!</source>
<translation></translation>
</message>
<message>
<location filename="../module/mifare.cpp" line="425"/>
<source>Failed to read card.</source>
<translation></translation>
</message>
</context>
</TS>

@ -1,11 +1,57 @@
#include "mainwindow.h" #include "ui/mainwindow.h"
#include <QApplication> #include <QApplication>
#include <QSettings>
#include <QTranslator>
#include <QMessageBox>
#include <QInputDialog>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QApplication a(argc, argv); QApplication a(argc, argv);
MainWindow w; MainWindow w;
QSettings* settings = new QSettings("GUIsettings.ini", QSettings::IniFormat);
QVariant lang = settings->value("lang", "null");
if(lang == "null")
{
#ifdef Q_OS_WIN
lang = "lang/en_US.qm";
#else
lang = "lang/en_US.ts";
#endif
QStringList langList;
langList.append("English");
langList.append("简体中文");
QString seletedText = QInputDialog::getItem(&w, "", "Choose a language:", langList, 0, false);
if(seletedText == "English")
{
#ifdef Q_OS_WIN
lang = "lang/en_US.qm";
#else
lang = "lang/en_US.ts";
#endif
}
else if(seletedText == "简体中文")
{
#ifdef Q_OS_WIN
lang = "lang/zh_CN.qm";
#else
lang = "lang/zh_CN.ts";
#endif
}
}
QTranslator* translator = new QTranslator(&w);
if(translator->load(lang.toString()))
{
a.installTranslator(translator);
settings->setValue("lang", lang);
}
else
{
QMessageBox::information(&w, "Error", "Can't load " + lang.toString() + " as translation file.");
}
delete settings;
w.initUI();
w.show(); w.show();
return a.exec(); return a.exec();
} }

@ -1,67 +0,0 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
pm3=new PM3Process;
connect(pm3,&PM3Process::readyRead,this,&MainWindow::refresh);
connect(ui->commandEdit,&QLineEdit::editingFinished,this,&MainWindow::sendMSG);
ui->portBox->addItem("");
foreach(QString port,pm3->findPort())
{
ui->portBox->addItem(port);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_connectButton_clicked()
{
QString port=ui->portBox->currentText();
if(port=="")
QMessageBox::information(NULL, "Info", "Plz choose a port first", QMessageBox::Ok);
else
qDebug()<<pm3->start(ui->PM3PathEdit->text(),port);
}
void MainWindow::on_sendButton_clicked()
{
qDebug()<<(ui->commandEdit->text().toLocal8Bit());
pm3->write((ui->commandEdit->text()+"\r\n").toLocal8Bit());
pm3->waitForBytesWritten(3000);
}
void MainWindow::refresh()
{
QByteArray btay=pm3->readLine();
while(btay!="")
{
qDebug()<<btay;
ui->outputEdit->insertPlainText(btay);
btay=pm3->readLine();
}
ui->outputEdit->moveCursor(QTextCursor::End);
}
void MainWindow::sendMSG()
{
if(ui->commandEdit->hasFocus())
on_sendButton_clicked();
}
void MainWindow::on_disconnectButton_clicked()
{
pm3->kill();
}
void MainWindow::on_clearButton_clicked()
{
ui->outputEdit->clear();
}

@ -1,38 +0,0 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QProcess>
#include <QDebug>
#include <QMessageBox>
#include "pm3process.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void refresh();
private slots:
void on_connectButton_clicked();
void on_sendButton_clicked();
void on_disconnectButton_clicked();
void on_clearButton_clicked();
void sendMSG();
private:
Ui::MainWindow *ui;
PM3Process* pm3;
};
#endif // MAINWINDOW_H

@ -1,146 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>310</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>450</width>
<height>300</height>
</size>
</property>
<property name="windowTitle">
<string>Proxmark3GUI</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Path:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="PM3PathEdit">
<property name="text">
<string>proxmark3</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="portBox"/>
</item>
<item>
<widget class="QPushButton" name="connectButton">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="disconnectButton">
<property name="text">
<string>Disconnect</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="funcTab">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Tab 1</string>
</attribute>
</widget>
<widget class="QWidget" name="rawTab">
<attribute name="title">
<string>RawCommand</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPlainTextEdit" name="outputEdit">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="sizeConstraint">
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QLineEdit" name="commandEdit"/>
</item>
<item>
<widget class="QPushButton" name="sendButton">
<property name="text">
<string>Send</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="text">
<string>ClearOutput</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>450</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

@ -0,0 +1,855 @@
#include "mifare.h"
Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent) : QObject(parent)
{
this->parent = parent;
util = addr;
this->ui = ui;
cardType = card_1k;
keyAList = new QStringList();
keyBList = new QStringList();
dataList = new QStringList();
data_clearKey(); // fill with blank Qstring
data_clearData(); // fill with blank Qstring
dataPattern = new QRegExp("([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}");
chkKeyPattern = new QRegExp("\\|\\d{3}\\|.+\\|.+\\|");
nestedKeyPattern = new QRegExp("\\|\\d{3}\\|.+\\|.+\\|.+\\|.+\\|");
}
QString Mifare::info(bool isRequiringOutput)
{
if(isRequiringOutput)
{
QString result = util->execCMDWithOutput("hf 14a info", 500);
qDebug() << result << result.indexOf(QRegExp(ui->MF_RW_dataEdit->text()), 0);
result.replace("UID :", "|");
result.replace("ATQA :", "|");
result.replace("SAK :", "|");
result.replace("TYPE :", "|");
QStringList lis = result.split("|");
if(lis.length() > 4)
{
qDebug() << lis[1] + lis[2] + lis[3];
return lis[1] + lis[2] + lis[3];
}
else
return "";
}
else
{
util->execCMD("hf 14a info");
ui->funcTab->setCurrentIndex(1);
return "";
}
}
void Mifare::chk()
{
QString result = util->execCMDWithOutput("hf mf chk *" + QString::number(cardType.type) + " ?", 1000 + cardType.type * 1000);
qDebug() << result;
int offset = 0;
QString tmp, tmp2;
for(int i = 0; i < cardType.sectors; i++)
{
offset = result.indexOf(*chkKeyPattern, offset);
tmp = result.mid(offset, 39).toUpper();
offset += 39;
qDebug() << tmp << offset;
tmp2 = tmp.mid(7, 12).trimmed();
if(tmp2 != "?")
keyAList->replace(i, tmp2);
tmp2 = tmp.mid(24, 12).trimmed();
if(tmp2 != "?")
keyBList->replace(i, tmp2);
}
data_syncWithKeyWidget();
}
void Mifare::nested()
{
QString result = util->execCMDWithOutput("hf mf nested " + QString::number(cardType.type) + " *");
int offset = 0;
QString tmp;
for(int i = 0; i < cardType.sectors; i++)
{
offset = result.indexOf(*nestedKeyPattern, offset);
tmp = result.mid(offset, 47).toUpper();
offset += 47;
if(tmp.at(23) == '1')
keyAList->replace(i, tmp.mid(7, 12).trimmed());
if(tmp.at(44) == '1')
keyBList->replace(i, tmp.mid(28, 12).trimmed());
}
data_syncWithKeyWidget();
}
void Mifare::hardnested()
{
MF_Attack_hardnestedDialog dialog(cardType.blocks);
connect(&dialog, &MF_Attack_hardnestedDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted)
ui->funcTab->setCurrentIndex(1);
}
void Mifare::sniff()
{
util->execCMD("hf mf sniff");
ui->funcTab->setCurrentIndex(1);
}
void Mifare::list()
{
util->execCMD("hf list mf");
ui->funcTab->setCurrentIndex(1);
}
void Mifare::read()
{
int waitTime = 300;
int currblk = ui->MF_RW_blockBox->currentText().toInt();
QString result = util->execCMDWithOutput("hf mf rdbl "
+ QString::number(currblk)
+ " "
+ ui->MF_RW_keyTypeBox->currentText()
+ " "
+ ui->MF_RW_keyEdit->text(), waitTime);
if(result.indexOf("isOk:01") != -1)
{
result = result.mid(result.indexOf(*dataPattern, 0), 47).toUpper();
if((currblk < 128 && ((currblk + 1) % 4 == 0)) || ((currblk + 1) % 8 == 0)) // process key block
{
if(ui->MF_RW_keyTypeBox->currentText() == "A")
{
for(int i = 0; i < 6; i++)
{
result = result.replace(i * 3, 2, ui->MF_RW_keyEdit->text().mid(i * 2, 2));
}
ui->MF_RW_dataEdit->setText(result);
QString tmpKey = result.right(18).replace(" ", "");
result = util->execCMDWithOutput("hf mf rdbl "
+ ui->MF_RW_keyTypeBox->currentText()
+ " B "
+ tmpKey, waitTime);
if(result.indexOf("isOk:01") == -1)
{
result = ui->MF_RW_dataEdit->text();
result = result.replace(30, 17, "?? ?? ?? ?? ?? ??");
ui->MF_RW_dataEdit->setText(result);
}
}
else
{
for(int i = 0; i < 6; i++)
{
result = result.replace(30 + i * 3, 2, ui->MF_RW_keyEdit->text().mid(i * 2, 2));
}
result = result.replace(0, 18, "?? ?? ?? ?? ?? ?? ");
ui->MF_RW_dataEdit->setText(result);
}
}
else
{
ui->MF_RW_dataEdit->setText(result);
}
}
}
void Mifare::readAll()
{
QString result;
bool isKeyAValid;
bool isKeyBValid;
const int waitTime = 150;
QString tmp;
int offset = 0;
for(int i = 0; i < cardType.sectors; i++)
{
result = "";
isKeyAValid = false;
isKeyBValid = false;
// check keys and read the first block of each sector
if(data_isKeyValid(keyAList->at(i)))
{
result = util->execCMDWithOutput("hf mf rdsc "
+ QString::number(i)
+ " A "
+ keyAList->at(i), waitTime);
qDebug() << result;
offset = result.indexOf("isOk:01");
if(offset != -1)
{
isKeyAValid = true;
for(int j = 0; j < cardType.blk[i]; j++)
{
offset = result.indexOf(*dataPattern, offset);
tmp = result.mid(offset, 47).toUpper();
offset += 47;
qDebug() << tmp;
tmp.replace(" ", "");
dataList->replace(cardType.blks[i] + j, tmp);
data_syncWithDataWidget(false, cardType.blks[i] + j);
}
}
}
if(data_isKeyValid(keyBList->at(i)))
{
result = util->execCMDWithOutput("hf mf rdsc "
+ QString::number(i)
+ " B "
+ keyBList->at(i), waitTime);
qDebug() << result;
offset = result.indexOf("isOk:01");
if(offset != -1)
{
isKeyBValid = true;
for(int j = 0; j < cardType.blk[i]; j++)
{
offset = result.indexOf(*dataPattern, offset);
tmp = result.mid(offset, 47).toUpper();
offset += 47;
qDebug() << tmp;
tmp.replace(" ", "");
dataList->replace(cardType.blks[i] + j, tmp);
data_syncWithDataWidget(false, cardType.blks[i] + j);
}
}
}
if(isKeyAValid || isKeyBValid)
{
// fill the MF_dataWidget with the known valid key
//
// check whether the MF_dataWidget contains the valid key,
// and fill MF_keyWidget(when you only have KeyA but the ReadBlock output contains the KeyB)
//
// the structure is not symmetric, since you cannot get KeyA from output
// this program will only process the provided KeyA(in MF_keyWidget)
result = dataList->at(cardType.blks[i] + cardType.blk[i] - 1);
if(isKeyAValid)
{
result.replace(0, 12, keyAList->at(i));
}
else
{
result = result.replace(0, 12, "????????????");
}
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
if(isKeyBValid)
{
result.replace(20, 12, keyBList->at(i));
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
data_syncWithDataWidget(false, cardType.blks[i] + cardType.blk[i] - 1);
}
else // now isKeyAValid == true, the output might contains the KeyB
{
QString tmpKey = dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12);
result = util->execCMDWithOutput("hf mf rdbl "
+ QString::number(cardType.blks[i] + cardType.blk[i] - 1)
+ " B "
+ tmpKey, waitTime);
if(result.indexOf("isOk:01") != -1)
{
keyBList->replace(i, tmpKey);
data_syncWithKeyWidget(false, i, false);
}
else
{
result = dataList->at(cardType.blks[i] + cardType.blk[i] - 1);
result = result.replace(20, 12, "????????????");
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
}
}
data_syncWithDataWidget(false, cardType.blks[i] + cardType.blk[i] - 1);
}
}
}
void Mifare::write()
{
int waitTime = 300;
QString result = util->execCMDWithOutput("hf mf wrbl "
+ ui->MF_RW_blockBox->currentText()
+ " "
+ ui->MF_RW_keyTypeBox->currentText()
+ " "
+ ui->MF_RW_keyEdit->text()
+ " "
+ ui->MF_RW_dataEdit->text().replace(" ", ""), waitTime);
if(result.indexOf("isOk:01") != -1)
{
QMessageBox::information(parent, tr("Info"), tr("Success!"));
}
else
{
QMessageBox::information(parent, tr("Info"), tr("Failed!"));
}
}
void Mifare::writeAll()
{
const int waitTime = 300;
QString result;
for(int i = 0; i < cardType.sectors; i++)
{
for(int j = 0; j < cardType.blk[i]; j++)
{
result = ""; // if the KeyA is invalid and the result is not empty, the KeyB will not be tested.
if(data_isDataValid(dataList->at(cardType.blks[i] + j)) != DATA_NOSPACE || dataList->at(cardType.blks[i] + j).contains('?'))
continue;
if(data_isKeyValid(keyAList->at(i)))
{
result = util->execCMDWithOutput("hf mf wrbl "
+ QString::number(cardType.blks[i] + j)
+ " A "
+ keyAList->at(i)
+ " "
+ dataList->at(cardType.blks[i] + j), waitTime);
}
qDebug() << i << j << result.indexOf("isOk:01") << data_isKeyValid(keyBList->at(i));
if(result.indexOf("isOk:01") == -1 && data_isKeyValid(keyBList->at(i)))
{
result = util->execCMDWithOutput("hf mf wrbl "
+ QString::number(cardType.blks[i] + j)
+ " B "
+ keyBList->at(i)
+ " "
+ dataList->at(cardType.blks[i] + j), waitTime);
}
}
}
}
void Mifare::readC()
{
int waitTime = 300;
int currblk = ui->MF_RW_blockBox->currentText().toInt();
QString result = util->execCMDWithOutput("hf mf cgetblk "
+ QString::number(currblk), waitTime);
if(result.indexOf("No chinese") == -1)
{
result = result.mid(result.indexOf(*dataPattern, 0), 47).toUpper();
ui->MF_RW_dataEdit->setText(result);
}
}
void Mifare::readAllC()
{
QString result;
const int waitTime = 150;
QString tmp;
int offset = 0;
for(int i = 0; i < cardType.sectors; i++)
{
result = util->execCMDWithOutput("hf mf cgetsc "
+ QString::number(i), waitTime);
qDebug() << result;
if(result.indexOf("No chinese") == -1)
{
offset = 0;
for(int j = 0; j < cardType.blk[i]; j++)
{
offset = result.indexOf(*dataPattern, offset);
tmp = result.mid(offset, 47).toUpper();
offset += 47;
qDebug() << tmp;
tmp.replace(" ", "");
dataList->replace(cardType.blks[i] + j, tmp);
data_syncWithDataWidget(false, cardType.blks[i] + j);
}
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));
data_syncWithKeyWidget(false, i, true);
data_syncWithKeyWidget(false, i, false);
}
}
}
void Mifare::writeC()
{
int waitTime = 150;
QString result = util->execCMDWithOutput("hf mf csetblk "
+ ui->MF_RW_blockBox->currentText()
+ " "
+ ui->MF_RW_dataEdit->text().replace(" ", ""), waitTime);
if(result.indexOf("No chinese") == -1)
{
QMessageBox::information(parent, tr("Info"), tr("Success!"));
}
else
{
QMessageBox::information(parent, tr("Info"), tr("Failed!"));
}
}
void Mifare::writeAllC()
{
const int waitTime = 150;
QString result;
for(int i = 0; i < cardType.sectors; i++)
{
for(int j = 0; j < cardType.blk[i]; j++)
{
result = ""; // if the KeyA is invalid and the result is not empty, the KeyB will not be tested.
if(data_isDataValid(dataList->at(cardType.blks[i] + j)) != DATA_NOSPACE || dataList->at(cardType.blks[i] + j).contains('?'))
continue;
result = util->execCMDWithOutput("hf mf csetblk "
+ QString::number(cardType.blks[i] + j)
+ " "
+ dataList->at(cardType.blks[i] + j), waitTime);
}
}
}
void Mifare::wipeC()
{
util->execCMD("hf mf cwipe "
+ QString::number(cardType.type)
+ " f");
ui->funcTab->setCurrentIndex(1);
}
void Mifare::setParameterC()
{
QString result = info(true);
if(result == "")
QMessageBox::information(parent, tr("Info"), tr("Failed to read card."));
else
{
QStringList lis = result.split("\r\n");
lis[0].replace(" ", "");
lis[1].replace(" ", "");
lis[2].replace(" ", "");
MF_UID_parameterDialog dialog(lis[0].toUpper(), lis[1].toUpper(), lis[2].mid(0, 2).toUpper());
connect(&dialog, &MF_UID_parameterDialog::sendCMD, util, &Util::execCMD);
if(dialog.exec() == QDialog::Accepted)
ui->funcTab->setCurrentIndex(1);
}
}
void Mifare::lockC()
{
util->execCMD("hf 14a raw -pa -b7 40");
util->execCMD("hf 14a raw -pa 43");
util->execCMD("hf 14a raw -pa E0 00 39 F7");
util->execCMD("hf 14a raw -pa E1 00 E1 EE");
util->execCMD("hf 14a raw -pa 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47");
util->execCMD("hf 14a raw 52");
}
void Mifare::dump()
{
util->execCMD("hf mf dump");
ui->funcTab->setCurrentIndex(1);
}
void Mifare::restore()
{
util->execCMD("hf mf restore");
ui->funcTab->setCurrentIndex(1);
}
void Mifare::data_syncWithDataWidget(bool syncAll, int block)
{
QString tmp;
if(syncAll)
{
for(int i = 0; i < cardType.blocks; i++)
{
tmp = "";
if(dataList->at(i) != "")
{
tmp += dataList->at(i).mid(0, 2);
for(int j = 1; j < 16; j++)
{
tmp += " ";
tmp += dataList->at(i).mid(j * 2, 2);
}
}
ui->MF_dataWidget->item(i, 2)->setText(tmp);
}
}
else
{
tmp = "";
if(dataList->at(block) != "")
{
tmp += dataList->at(block).mid(0, 2);
for(int j = 1; j < 16; j++)
{
tmp += " ";
tmp += dataList->at(block).mid(j * 2, 2);
}
}
ui->MF_dataWidget->item(block, 2)->setText(tmp);
}
}
void Mifare::data_syncWithKeyWidget(bool syncAll, int sector, bool isKeyA)
{
if(syncAll)
{
for(int i = 0; i < cardType.sectors; i++)
{
ui->MF_keyWidget->item(i, 1)->setText(keyAList->at(i));
ui->MF_keyWidget->item(i, 2)->setText(keyBList->at(i));
}
}
else
{
if(isKeyA)
ui->MF_keyWidget->item(sector, 1)->setText(keyAList->at(sector));
else
ui->MF_keyWidget->item(sector, 2)->setText(keyBList->at(sector));
}
}
void Mifare::data_clearData()
{
dataList->clear();
for(int i = 0; i < cardType.blocks; i++)
dataList->append("");
}
void Mifare::data_clearKey()
{
keyAList->clear();
keyBList->clear();
for(int i = 0; i < cardType.sectors; i++)
{
keyAList->append("");
keyBList->append("");
}
}
bool Mifare::data_isKeyValid(const QString& key)
{
if(key.length() != 12)
return false;
for(int i = 0; i < 12; i++)
{
if(!((key[i] >= '0' && key[i] <= '9') || (key[i] >= 'A' && key[i] <= 'F')))
return false;
}
return true;
}
Mifare::DataType Mifare::data_isDataValid(QString data) // "?" will not been processd there
{
if(data.length() == 47)
{
for(int i = 0; i < 47; i++)
{
if(i % 3 != 0)
{
if(!((data[i] >= '0' && data[i] <= '9') || (data[i] >= 'A' && data[i] <= 'F') || data[i] == '?'))
return DATA_INVALID;
}
else
{
if(data[i] != ' ')
return DATA_INVALID;
}
}
return DATA_WITHSPACE;
}
else if(data.length() == 32)
{
for(int i = 0; i < 32; i++)
{
if(!((data[i] >= '0' && data[i] <= '9') || (data[i] >= 'A' && data[i] <= 'F') || data[i] == '?'))
return DATA_INVALID;
}
return DATA_NOSPACE;
}
else
return DATA_INVALID;
}
Mifare::CardType Mifare::getCardType()
{
return cardType;
}
void Mifare::setCardType(int type)
{
if(type == 0 || type == 1 || type == 2 || type == 4)
{
if(type == 0)
cardType = card_mini;
else if(type == 1)
cardType = card_1k;
else if(type == 2)
cardType = card_2k;
else if(type == 4)
cardType = card_4k;
data_clearKey();
data_clearData();
}
}
bool Mifare::data_loadDataFile(const QString& filename)
{
QFile file(filename, this);
if(file.open(QIODevice::ReadOnly))
{
QByteArray buff;
buff = file.read(10000);
bool isBin = false;
for(int i = 0; i < cardType.blocks * 16; i++) // Detect the file type
{
// qDebug() << (unsigned char)buff[i];
if(!((buff[i] >= 'A' && buff[i] <= 'F') ||
(buff[i] >= 'a' && buff[i] <= 'f') ||
(buff[i] >= '0' && buff[i] <= '9') ||
buff[i] == '\n' ||
buff[i] == '\r'))
{
isBin = true;
break;
}
}
if(isBin)
{
if(file.size() < cardType.blocks * 16)
return false;
for(int i = 0; i < cardType.blocks; i++)
{
QString tmp = bin2text(buff, i, 16);
dataList->replace(i, tmp.toUpper());
}
}
else
{
QString tmp = buff.left(cardType.blocks * 34);
QStringList tmpList = tmp.split("\r\n");
for(int i = 0; i < cardType.blocks; i++)
{
dataList->replace(i, tmpList[i].toUpper());
qDebug() << tmpList[i];
}
}
file.close();
data_syncWithDataWidget();
return true;
}
else
{
return false;
}
}
bool Mifare::data_loadKeyFile(const QString& filename)
{
QFile file(filename, this);
if(file.open(QIODevice::ReadOnly))
{
QByteArray buff;
buff = file.read(10000);
bool isKey = file.size() <= cardType.sectors * 14;
if(isKey)
{
for(int i = 0; i < cardType.sectors; i++)
{
QString tmp = bin2text(buff, i, 12);
keyAList->replace(i, tmp.left(12).toUpper());
keyBList->replace(i, tmp.right(12).toUpper());
}
}
else
{
for(int i = 0; i < cardType.sectors; i++)
{
int blk = cardType.blks[i] + cardType.blk[i] - 1;
QString tmp = bin2text(buff, blk, 16);
keyAList->replace(i, tmp.left(12).toUpper());
keyBList->replace(i, tmp.right(12).toUpper());
}
}
file.close();
data_syncWithKeyWidget();
return true;
}
else
{
return false;
}
}
QString Mifare::bin2text(const QByteArray& buff, int i, int length)
{
QString ret = "";
char LByte, RByte;
char map[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
for(int j = 0; j < length; j++)
{
LByte = map[(unsigned char)buff[i * length + j] >> 4];
RByte = map[(unsigned char)buff[i * length + j] & 0xF];
ret += LByte;
ret += RByte;
}
qDebug() << ret;
return ret;
}
bool Mifare::data_saveDataFile(const QString& filename, bool isBin)
{
QFile file(filename, this);
if(file.open(QIODevice::WriteOnly))
{
QByteArray buff;
QChar tmp;
if(isBin)
{
for(int i = 0; i < cardType.blocks; i++)
{
for(int j = 0; j < 16; j++)
{
unsigned char Byt[2];
for(int k = 0; k < 2; k++)
{
tmp = dataList->at(i).at(j * 2 + k).toUpper();
if(tmp >= '0' && tmp <= '9')
Byt[k] = tmp.toLatin1() - '0';
else if(tmp >= 'A' && tmp <= 'F')
Byt[k] = tmp.toLatin1() - 'A' + 10;
}
buff += (Byt[0] << 4) | Byt[1];
}
}
}
else
{
for(int i = 0; i < cardType.blocks; i++)
{
buff += dataList->at(i);
buff += "\r\n";
}
}
bool ret = file.write(buff) != -1;
file.close();
return ret;
}
else
{
return false;
}
}
bool Mifare::data_saveKeyFile(const QString& filename, bool isBin)
{
QFile file(filename, this);
if(file.open(QIODevice::WriteOnly))
{
QByteArray buff;
QChar tmp;
if(isBin)
{
for(int i = 0; i < cardType.sectors; i++)
{
for(int j = 0; j < 6; j++)
{
unsigned char Byt[2];
for(int k = 0; k < 2; k++)
{
tmp = keyAList->at(i).at(j * 2 + k).toUpper();
if(tmp >= '0' && tmp <= '9')
Byt[k] = tmp.toLatin1() - '0';
else if(tmp >= 'A' && tmp <= 'F')
Byt[k] = tmp.toLatin1() - 'A' + 10;
}
buff += (Byt[0] << 4) | Byt[1];
}
for(int j = 0; j < 6; j++)
{
unsigned char Byt[2];
for(int k = 0; k < 2; k++)
{
tmp = keyBList->at(i).at(j * 2 + k).toUpper();
if(tmp >= '0' && tmp <= '9')
Byt[k] = tmp.toLatin1() - '0';
else if(tmp >= 'A' && tmp <= 'F')
Byt[k] = tmp.toLatin1() - 'A' + 10;
}
buff += (Byt[0] << 4) | Byt[1];
}
}
}
else
{
}
bool ret = file.write(buff) != -1;
file.close();
return ret;
}
else
{
return false;
}
}
void Mifare::data_key2Data()
{
for(int i = 0; i < cardType.sectors; i++)
{
QString tmp = "";
if(data_isKeyValid(keyAList->at(i)))
tmp += keyAList->at(i);
else
tmp += "????????????";
if(dataList->at(cardType.blks[i] + cardType.blk[i] - 1) == "")
tmp += "FF078069"; // default control bytes
else
tmp += dataList->at(cardType.blks[i] + cardType.blk[i] - 1).mid(12, 8);
if(data_isKeyValid(keyBList->at(i)))
tmp += keyBList->at(i);
else
tmp += "????????????";
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, tmp);
data_syncWithDataWidget();
}
}
void Mifare::data_data2Key()
{
for(int i = 0; i < cardType.sectors; i++)
{
if(dataList->at(cardType.blks[i] + cardType.blk[i] - 1) == "")
{
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));
}
data_syncWithKeyWidget();
}
}
void Mifare::data_setData(int block, const QString& data)
{
dataList->replace(block, data);
}
void Mifare::data_setKey(int sector, bool isKeyA, const QString& key)
{
if(isKeyA)
keyAList->replace(sector, key);
else
keyBList->replace(sector, key);
}

@ -0,0 +1,126 @@
#ifndef MIFARE_H
#define MIFARE_H
#include "common/util.h"
#include "ui_mainwindow.h"
#include "ui/mf_attack_hardnesteddialog.h"
#include "ui/mf_uid_parameterdialog.h"
#include <QObject>
#include <QString>
#include <QStringList>
#include <QRegExp>
#include <QMessageBox>
class Mifare : public QObject
{
Q_OBJECT
public:
explicit Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent = nullptr);
QString info(bool isRequiringOutput = false);
void chk();
void nested();
void hardnested();
void sniff();
void list();
void read();
void readAll();
void write();
void writeAll();
void dump();
void restore();
enum DataType
{
DATA_INVALID,
DATA_WITHSPACE,
DATA_NOSPACE,
};
struct CardType
{
int type;
int sectors;
int blocks;
int blk[40];
int blks[40];
};
const CardType card_mini =
{
0,
5,
20,
{4, 4, 4, 4, 4},
{0, 4, 8, 12, 16}
};
const CardType card_1k =
{
1,
16,
64,
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60}
};
const CardType card_2k =
{
2,
32,
128,
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4},
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124}
};
const CardType card_4k =
{
4,
40,
256,
{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 16, 16, 16, 16, 16, 16, 16, 16},
{0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, 96, 100, 104, 108, 112, 116, 120, 124, 128, 144, 160, 176, 192, 208, 224, 240}
};
void data_clearData();
void data_clearKey();
bool data_isKeyValid(const QString &key);
Mifare::DataType data_isDataValid(QString data);
void data_syncWithDataWidget(bool syncAll = true, int block = 0);
void data_syncWithKeyWidget(bool syncAll = true, int sector = 0, bool isKeyA = true);
CardType cardType;
Mifare::CardType getCardType();
void setCardType(int type);
void writeAllC();
void writeC();
void readAllC();
void readC();
void wipeC();
void setParameterC();
bool data_loadDataFile(const QString &filename);
bool data_loadKeyFile(const QString &filename);
bool data_saveDataFile(const QString& filename, bool isBin);
bool data_saveKeyFile(const QString &filename, bool isBin);
void data_key2Data();
void data_data2Key();
void data_setData(int block, const QString &data);
void data_setKey(int sector, bool isKeyA, const QString &key);
void lockC();
public slots:
signals:
private:
QWidget* parent;
Ui::MainWindow *ui;
Util* util;
QStringList* keyAList;
QStringList* keyBList;
QStringList* dataList;
QRegExp* dataPattern;
QRegExp* chkKeyPattern;
QRegExp* nestedKeyPattern;
QRegExp* UIDPattern;
QString bin2text(const QByteArray &buff, int start, int length);
};
#endif // MIFARE_H

@ -1,29 +0,0 @@
#include "pm3process.h"
PM3Process::PM3Process(QObject* parent): QProcess(parent)
{
setProcessChannelMode(PM3Process::MergedChannels);
}
QStringList PM3Process::findPort()
{
QSerialPort serial;
QStringList retList;
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
serial.setPort(info);
if(serial.open(QIODevice::ReadWrite))
{
retList<<info.portName();
serial.close();
}
}
return retList;
}
bool PM3Process::start(const QString path, const QString port)
{
// using "-f" option to make the client output flushed after every print.
QProcess::start(path, QStringList()<<port<<"-f",QProcess::Unbuffered|QProcess::ReadWrite);
return waitForStarted();
}

@ -1,19 +0,0 @@
#ifndef PM3PROCESS_H
#define PM3PROCESS_H
#include <QProcess>
#include <QString>
#include <QDebug>
#include <QtSerialPort/QSerialPortInfo>
#include <QtSerialPort/QSerialPort>
class PM3Process : public QProcess
{
Q_OBJECT
public:
explicit PM3Process(QObject* parent=nullptr);
bool start(const QString path, const QString port);
QStringList findPort();
};
#endif // PM3PROCESS_H

@ -0,0 +1,653 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->MF_simGroupBox->setVisible(false); // developing...
ui->MF_sniffGroupBox->setVisible(false); // developing...
myInfo = new QAction("wh201906", this);
connect(myInfo, &QAction::triggered, [ = ]() {
QDesktopServices::openUrl(QUrl("https://github.com/wh201906"));
});
this->addAction(myInfo);
pm3Thread = new QThread(this);
pm3 = new PM3Process(pm3Thread);
// pm3->moveToThread(pm3Thread);
// pm3->init();
pm3Thread->start();
pm3state = false;
util = new Util(this);
mifare = new Mifare(ui, util, this);
}
MainWindow::~MainWindow()
{
delete ui;
emit killPM3();
pm3Thread->exit(0);
pm3Thread->wait(5000);
delete pm3;
delete pm3Thread;
}
void MainWindow::initUI() // will be called by main.app
{
ui->retranslateUi(this);
uiInit();
signalInit();
setState(false);
}
// ******************** basic functions ********************
void MainWindow::on_PM3_refreshPortButton_clicked()
{
ui->PM3_portBox->clear();
ui->PM3_portBox->addItem("");
QSerialPort serial;
QStringList serialList;
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
qDebug() << info.isBusy() << info.isNull() << info.portName();
serial.setPort(info);
if(serial.open(QIODevice::ReadWrite))
{
serialList << info.portName();
serial.close();
}
}
foreach(QString port, serialList)
{
ui->PM3_portBox->addItem(port);
}
}
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
{
emit connectPM3(ui->PM3_pathEdit->text(), port);
}
}
void MainWindow::onPM3StateChanged(bool st, QString info)
{
pm3state = st;
setState(st);
if(st == true)
{
setStatusBar(PM3VersionBar, info);
setStatusBar(connectStatusBar, tr("Connected"));
}
else
{
setStatusBar(connectStatusBar, tr("Not Connected"));
}
}
void MainWindow::on_PM3_disconnectButton_clicked()
{
pm3state = false;
setState(false);
emit killPM3();
emit setSerialListener("", false);
setStatusBar(connectStatusBar, tr("Not Connected"));
}
void MainWindow::refreshOutput(const QString& output)
{
// qDebug() << "MainWindow::refresh:" << output;
ui->Raw_outputEdit->insertPlainText(output);
ui->Raw_outputEdit->moveCursor(QTextCursor::End);
}
void MainWindow::refreshCMD(const QString& cmd)
{
ui->Raw_CMDEdit->setText(cmd);
if(cmd != "" && (ui->Raw_CMDHistoryWidget->count() == 0 || ui->Raw_CMDHistoryWidget->item(ui->Raw_CMDHistoryWidget->count() - 1)->text() != cmd))
ui->Raw_CMDHistoryWidget->addItem(cmd);
}
// *********************************************************
// ******************** raw command ********************
void MainWindow::on_Raw_sendCMDButton_clicked()
{
util->execCMD(ui->Raw_CMDEdit->text());
refreshCMD(ui->Raw_CMDEdit->text());
}
void MainWindow::on_Raw_clearOutputButton_clicked()
{
ui->Raw_outputEdit->clear();
}
void MainWindow::on_Raw_CMDHistoryBox_stateChanged(int arg1)
{
if(arg1 == Qt::Checked)
{
ui->Raw_CMDHistoryWidget->setVisible(true);
ui->Raw_clearHistoryButton->setVisible(true);
ui->Raw_CMDHistoryBox->setText(tr("History:"));
}
else
{
ui->Raw_CMDHistoryWidget->setVisible(false);
ui->Raw_clearHistoryButton->setVisible(false);
ui->Raw_CMDHistoryBox->setText("");
}
}
void MainWindow::on_Raw_clearHistoryButton_clicked()
{
ui->Raw_CMDHistoryWidget->clear();
}
void MainWindow::on_Raw_CMDHistoryWidget_itemDoubleClicked(QListWidgetItem *item)
{
ui->Raw_CMDEdit->setText(item->text());
ui->Raw_CMDEdit->setFocus();
}
void MainWindow::sendMSG() // send command when pressing Enter
{
if(ui->Raw_CMDEdit->hasFocus())
on_Raw_sendCMDButton_clicked();
}
// *****************************************************
// ******************** mifare ********************
void MainWindow::MF_onTypeChanged(int id, bool st)
{
typeBtnGroup->blockSignals(true);
qDebug() << id << typeBtnGroup->checkedId();
if(!st)
{
int result = QMessageBox::question(this, tr("Info"), tr("When Changeing card type, the data and keys in this app will be cleard.") + "\n" + tr("Continue?"), QMessageBox::Yes | QMessageBox::No);
if(result == QMessageBox::Yes)
{
qDebug() << "Yes";
mifare->setCardType(typeBtnGroup->checkedId());
MF_widgetReset();
}
else
{
qDebug() << "No";
typeBtnGroup->button(id)->setChecked(true);
}
}
typeBtnGroup->blockSignals(false);
}
void MainWindow::on_MF_data2KeyBotton_clicked()
{
mifare->data_data2Key();
}
void MainWindow::on_MF_key2DataBotton_clicked()
{
mifare->data_key2Data();
}
void MainWindow::on_MF_fontButton_clicked()
{
bool isOK = false;
QFont font = QFontDialog::getFont(&isOK, ui->MF_keyWidget->font(), this, tr("Plz select the font of data widget and key widget"));
if(isOK)
{
ui->MF_keyWidget->setFont(font);
ui->MF_dataWidget->setFont(font);
}
}
void MainWindow::on_MF_dataWidget_itemChanged(QTableWidgetItem *item)
{
if(item->column() == 2)
{
QString data = item->text().replace(" ", "").toUpper();
if(data == "" || mifare->data_isDataValid(data) == Mifare::DATA_NOSPACE)
{
mifare->data_setData(item->row(), data);
}
else
{
QMessageBox::information(this, tr("Info"), tr("Data must consists of 32 Hex symbols(Whitespace is allowed)"));
}
mifare->data_syncWithDataWidget(false, item->row());
}
}
void MainWindow::on_MF_keyWidget_itemChanged(QTableWidgetItem *item)
{
if(item->column() == 1)
{
QString key = item->text().replace(" ", "").toUpper();
if(key == "" || mifare->data_isKeyValid(key))
{
mifare->data_setKey(item->row(), true, key);
}
else
{
QMessageBox::information(this, tr("Info"), tr("Key must consists of 12 Hex symbols(Whitespace is allowed)"));
}
mifare->data_syncWithKeyWidget(false, item->row(), true);
}
else if(item->column() == 2)
{
QString key = item->text().replace(" ", "");
if(key == "" || mifare->data_isKeyValid(key))
{
mifare->data_setKey(item->row(), false, key);
}
else
{
QMessageBox::information(this, tr("Info"), tr("Key must consists of 12 Hex symbols(Whitespace is allowed)"));
}
mifare->data_syncWithKeyWidget(false, item->row(), false);
}
}
void MainWindow::on_MF_File_loadButton_clicked()
{
QString title = "";
QString filename = "";
if(ui->MF_File_dataBox->isChecked())
{
title = tr("Plz select the data file:");
filename = QFileDialog::getOpenFileName(this, title, "./", tr("Binary Data Files(*.bin *.dump);;Text Data Files(*.txt *.eml);;All Files(*.*)"));
qDebug() << filename;
if(filename != "")
{
if(!mifare->data_loadDataFile(filename))
{
QMessageBox::information(this, tr("Info"), tr("Failed to open") + "\n" + filename);
}
}
}
else if(ui->MF_File_keyBox->isChecked())
{
title = tr("Plz select the key file:");
filename = QFileDialog::getOpenFileName(this, title, "./", tr("Binary Key Files(*.bin *.dump);;Binary Data Files(*.bin *.dump);;All Files(*.*)"));
qDebug() << filename;
if(filename != "")
{
if(!mifare->data_loadKeyFile(filename))
{
QMessageBox::information(this, tr("Info"), tr("Failed to open") + "\n" + filename);
}
}
}
}
void MainWindow::on_MF_File_saveButton_clicked()
{
QString title = "";
QString filename = "";
QString selectedType = "";
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);
qDebug() << filename;
if(filename != "")
{
if(!mifare->data_saveDataFile(filename, selectedType == "Binary Data Files(*.bin *.dump)"))
{
QMessageBox::information(this, tr("Info"), tr("Failed to save to") + "\n" + filename);
}
}
}
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);
qDebug() << filename;
if(filename != "")
{
if(!mifare->data_saveKeyFile(filename, selectedType == "Binary Key Files(*.bin *.dump)"))
{
QMessageBox::information(this, tr("Info"), tr("Failed to save to") + "\n" + filename);
}
}
}
qDebug() << filename << selectedType;
}
void MainWindow::on_MF_File_clearButton_clicked()
{
if(ui->MF_File_keyBox->isChecked())
{
mifare->data_clearKey();
mifare->data_syncWithKeyWidget();
}
else if(ui->MF_File_dataBox->isChecked())
{
mifare->data_clearData();
mifare->data_syncWithDataWidget();
}
}
void MainWindow::on_MF_Attack_infoButton_clicked()
{
mifare->info();
}
void MainWindow::on_MF_Attack_chkButton_clicked()
{
setState(false);
mifare->chk();
setState(true);
}
void MainWindow::on_MF_Attack_nestedButton_clicked()
{
setState(false);
mifare->nested();
setState(true);
}
void MainWindow::on_MF_Attack_hardnestedButton_clicked()
{
mifare->hardnested();
}
void MainWindow::on_MF_RW_readAllButton_clicked()
{
setState(false);
mifare->readAll();
setState(true);
}
void MainWindow::on_MF_RW_readBlockButton_clicked()
{
setState(false);
mifare->read();
setState(true);
}
void MainWindow::on_MF_RW_writeBlockButton_clicked()
{
setState(false);
mifare->write();
setState(true);
}
void MainWindow::on_MF_RW_writeAllButton_clicked()
{
setState(false);
mifare->writeAll();
setState(true);
}
void MainWindow::on_MF_RW_dumpButton_clicked()
{
mifare->dump();
}
void MainWindow::on_MF_RW_restoreButton_clicked()
{
mifare->restore();
}
void MainWindow::on_MF_UID_readAllButton_clicked()
{
setState(false);
mifare->readAllC();
setState(true);
}
void MainWindow::on_MF_UID_readBlockButton_clicked()
{
setState(false);
mifare->readC();
setState(true);
}
void MainWindow::on_MF_UID_writeAllButton_clicked()
{
setState(false);
mifare->writeAllC();
setState(true);
}
void MainWindow::on_MF_UID_writeBlockButton_clicked()
{
setState(false);
mifare->writeC();
setState(true);
}
void MainWindow::on_MF_UID_wipeButton_clicked()
{
mifare->wipeC();
}
void MainWindow::on_MF_UID_aboutUIDButton_clicked()
{
QString msg;
msg += tr(" Normally, the Block 0 of a typical Mifare card, which contains the UID, is locked during the manufacture. Users cannot write anything to Block 0 or set a new UID to a normal Mifare card.") + "\n";
msg += tr(" Chinese Magic Cards(aka UID Cards) are some special cards whose Block 0 are writeable. And you can change UID by writing to it.") + "\n";
msg += "\n";
msg += tr("There are two versions of Chinese Magic Cards, the Gen1 and the Gen2.") + "\n";
msg += tr(" Gen1:") + "\n" + tr(" also called UID card in China. It responses to some backdoor commands so you can access any blocks without password. The Proxmark3 has a bunch of related commands(csetblk, cgetblk, ...) to deal with this type of card, and my GUI also support these commands.") + "\n";
msg += tr(" Gen2:") + "\n" + tr(" doesn't response to the backdoor commands, which means that a reader cannot detect whether it is a Chinese Magic Card or not by sending backdoor commands.") + "\n";
msg += "\n";
msg += tr("There are some types of Chinese Magic Card Gen2.") + "\n";
msg += tr(" CUID Card:") + "\n" + tr(" the Block 0 is writeable, you can write to this block repeatedly by normal wrbl command.") + "\n";
msg += tr(" (hf mf wrbl 0 A FFFFFFFFFFFF <the data you want to write>)") + "\n";
msg += tr(" FUID Card:") + "\n" + tr(" you can only write to Block 0 once. After that, it seems like a typical Mifare card(Block 0 cannot be written to).") + "\n";
msg += tr(" (some readers might try changing the Block 0, which could detect the CUID Card. In that case, you should use FUID card.)") + "\n";
msg += tr(" UFUID Card:") + "\n" + tr(" It behaves like a CUID card(or UID card? I'm not sure) before you send some special command to lock it. Once it is locked, you cannot change its Block 0(just like a typical Mifare card).") + "\n";
msg += "\n";
msg += tr(" Seemingly, these Chinese Magic Cards are more easily to be compromised by Nested Attack(it takes little time to get an unknown key).") + "\n";
QMessageBox::information(this, tr("About UID Card"), msg);
}
void MainWindow::on_MF_UID_setParaButton_clicked()
{
setState(false);
mifare->setParameterC();
setState(true);
}
void MainWindow::on_MF_UID_lockButton_clicked()
{
mifare->lockC();
}
void MainWindow::on_MF_Sniff_sniffButton_clicked()
{
setState(false);
mifare->sniff();
setState(true);
}
void MainWindow::on_MF_Sniff_listButton_clicked()
{
mifare->list();
}
void MainWindow::MF_widgetReset()
{
int secs = mifare->cardType.sectors;
int blks = mifare->cardType.blocks;
ui->MF_RW_blockBox->clear();
ui->MF_keyWidget->setRowCount(secs);
ui->MF_dataWidget->setRowCount(blks);
for(int i = 0; i < blks; i++)
{
setTableItem(ui->MF_dataWidget, i, 0, "");
setTableItem(ui->MF_dataWidget, i, 1, QString::number(i));
setTableItem(ui->MF_dataWidget, i, 2, "");
ui->MF_RW_blockBox->addItem(QString::number(i));
}
for(int i = 0; i < secs; i++)
{
setTableItem(ui->MF_keyWidget, i, 0, QString::number(i));
setTableItem(ui->MF_keyWidget, i, 1, "");
setTableItem(ui->MF_keyWidget, i, 2, "");
setTableItem(ui->MF_dataWidget, mifare->cardType.blks[i], 0, QString::number(i));
}
}
// ************************************************
// ******************** other ********************
void MainWindow::uiInit()
{
connect(ui->Raw_CMDEdit, &QLineEdit::editingFinished, this, &MainWindow::sendMSG);
connectStatusBar = new QLabel(this);
programStatusBar = new QLabel(this);
PM3VersionBar = new QLabel(this);
setStatusBar(connectStatusBar, tr("Not Connected"));
setStatusBar(programStatusBar, tr("Idle"));
setStatusBar(PM3VersionBar, "");
ui->statusbar->addPermanentWidget(PM3VersionBar, 1);
ui->statusbar->addPermanentWidget(connectStatusBar, 1);
ui->statusbar->addPermanentWidget(programStatusBar, 1);
ui->MF_dataWidget->setColumnCount(3);
ui->MF_dataWidget->setHorizontalHeaderItem(0, new QTableWidgetItem(tr("Sec")));
ui->MF_dataWidget->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("Blk")));
ui->MF_dataWidget->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("Data")));
ui->MF_dataWidget->verticalHeader()->setVisible(false);
ui->MF_dataWidget->setColumnWidth(0, 35);
ui->MF_dataWidget->setColumnWidth(1, 35);
ui->MF_dataWidget->setColumnWidth(2, 430);
ui->MF_keyWidget->setColumnCount(3);
ui->MF_keyWidget->setHorizontalHeaderItem(0, new QTableWidgetItem(tr("Sec")));
ui->MF_keyWidget->setHorizontalHeaderItem(1, new QTableWidgetItem(tr("KeyA")));
ui->MF_keyWidget->setHorizontalHeaderItem(2, new QTableWidgetItem(tr("KeyB")));
ui->MF_keyWidget->verticalHeader()->setVisible(false);
ui->MF_keyWidget->setColumnWidth(0, 35);
ui->MF_keyWidget->setColumnWidth(1, 115);
ui->MF_keyWidget->setColumnWidth(2, 115);
MF_widgetReset();
typeBtnGroup = new QButtonGroup(this);
typeBtnGroup->addButton(ui->MF_Type_miniButton, 0);
typeBtnGroup->addButton(ui->MF_Type_1kButton, 1);
typeBtnGroup->addButton(ui->MF_Type_2kButton, 2);
typeBtnGroup->addButton(ui->MF_Type_4kButton, 4);
connect(typeBtnGroup, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), this, &MainWindow::MF_onTypeChanged);
ui->MF_keyWidget->installEventFilter(this);
ui->MF_dataWidget->installEventFilter(this);
on_Raw_CMDHistoryBox_stateChanged(Qt::Unchecked);
on_PM3_refreshPortButton_clicked();
}
void MainWindow::signalInit()
{
connect(pm3, &PM3Process::newOutput, util, &Util::processOutput);
connect(util, &Util::refreshOutput, this, &MainWindow::refreshOutput);
connect(this, &MainWindow::connectPM3, pm3, &PM3Process::connectPM3);
connect(pm3, &PM3Process::PM3StatedChanged, this, &MainWindow::onPM3StateChanged);
connect(this, &MainWindow::killPM3, pm3, &PM3Process::kill);
connect(util, &Util::write, pm3, &PM3Process::write);
}
void MainWindow::setStatusBar(QLabel* target, const QString & text)
{
if(target == PM3VersionBar)
target->setText(tr("HW Version:") + text);
else if(target == connectStatusBar)
target->setText(tr("PM3:") + text);
else if(target == programStatusBar)
target->setText(tr("State:") + text);
}
void MainWindow::setTableItem(QTableWidget* widget, int row, int column, const QString& text)
{
if(widget->item(row, column) == nullptr)
widget->setItem(row, column, new QTableWidgetItem());
widget->item(row, column)->setText(text);
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event) // drag support
{
if(event->type() == QEvent::DragEnter)
{
QDragEnterEvent* dragEvent = static_cast<QDragEnterEvent*>(event);
dragEvent->acceptProposedAction();
return true;
}
else if(event->type() == QEvent::Drop)
{
QDropEvent* dropEvent = static_cast<QDropEvent*>(event);
if(watched == ui->MF_keyWidget)
{
const QMimeData* mime = dropEvent->mimeData();
if(mime->hasUrls())
{
QList<QUrl> urls = mime->urls();
if(urls.length() == 1)
{
mifare->data_loadKeyFile(urls[0].toLocalFile());
return true;
}
}
}
else if(watched == ui->MF_dataWidget)
{
const QMimeData* mime = dropEvent->mimeData();
if(mime->hasUrls())
{
QList<QUrl> urls = mime->urls();
if(urls.length() == 1)
{
mifare->data_loadDataFile(urls[0].toLocalFile());
return true;
}
}
}
}
return QMainWindow::eventFilter(watched, event);
}
void MainWindow::setState(bool st)
{
if(!st && pm3state)
{
setStatusBar(programStatusBar, tr("Running"));
}
else
{
setStatusBar(programStatusBar, tr("Idle"));
}
ui->MF_attackGroupBox->setEnabled(st);
ui->MF_normalGroupBox->setEnabled(st);
ui->MF_UIDGroupBox->setEnabled(st);
ui->MF_simGroupBox->setEnabled(st);
ui->MF_sniffGroupBox->setEnabled(st);
ui->Raw_CMDEdit->setEnabled(st);
ui->Raw_sendCMDButton->setEnabled(st);
}
// ***********************************************

@ -0,0 +1,149 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include <QProcess>
#include <QDebug>
#include <QMessageBox>
#include <QListWidgetItem>
#include <QButtonGroup>
#include <QRadioButton>
#include <QFileDialog>
#include <QFontDialog>
#include <QtSerialPort/QSerialPortInfo>
#include <QtSerialPort/QSerialPort>
#include <QMimeData>
#include <QAction>
#include <QDesktopServices>
#include "common/pm3process.h"
#include "module/mifare.h"
#include "common/util.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void initUI();
bool eventFilter(QObject *watched, QEvent *event);
public slots:
void refreshOutput(const QString &output);
void refreshCMD(const QString &cmd);
void setStatusBar(QLabel* target, const QString & text);
void onPM3StateChanged(bool st, QString info);
void MF_onTypeChanged(int id, bool st);
private slots:
void on_PM3_connectButton_clicked();
void on_Raw_sendCMDButton_clicked();
void on_PM3_disconnectButton_clicked();
void on_Raw_clearOutputButton_clicked();
void sendMSG();
void on_PM3_refreshPortButton_clicked();
void on_Raw_CMDHistoryBox_stateChanged(int arg1);
void on_Raw_clearHistoryButton_clicked();
void on_Raw_CMDHistoryWidget_itemDoubleClicked(QListWidgetItem *item);
void on_MF_Attack_chkButton_clicked();
void on_MF_Attack_nestedButton_clicked();
void on_MF_Attack_hardnestedButton_clicked();
void on_MF_Sniff_sniffButton_clicked();
void on_MF_Sniff_listButton_clicked();
void on_MF_RW_readAllButton_clicked();
void on_MF_RW_readBlockButton_clicked();
void on_MF_RW_writeBlockButton_clicked();
void on_MF_Attack_infoButton_clicked();
void on_MF_RW_writeAllButton_clicked();
void on_MF_RW_dumpButton_clicked();
void on_MF_RW_restoreButton_clicked();
void on_MF_UID_readAllButton_clicked();
void on_MF_UID_readBlockButton_clicked();
void on_MF_UID_writeAllButton_clicked();
void on_MF_UID_writeBlockButton_clicked();
void on_MF_File_loadButton_clicked();
void on_MF_File_saveButton_clicked();
void on_MF_data2KeyBotton_clicked();
void on_MF_key2DataBotton_clicked();
void on_MF_dataWidget_itemChanged(QTableWidgetItem *item);
void on_MF_File_clearButton_clicked();
void on_MF_keyWidget_itemChanged(QTableWidgetItem *item);
void on_MF_fontButton_clicked();
void on_MF_UID_wipeButton_clicked();
void on_MF_UID_aboutUIDButton_clicked();
void on_MF_UID_setParaButton_clicked();
void on_MF_UID_lockButton_clicked();
private:
Ui::MainWindow* ui;
QButtonGroup* typeBtnGroup;
QLabel* connectStatusBar;
QLabel* programStatusBar;
QLabel* PM3VersionBar;
QAction* myInfo;
void uiInit();
PM3Process* pm3;
bool pm3state;
QThread* pm3Thread;
Mifare* mifare;
Util* util;
void signalInit();
void MF_widgetReset();
void setTableItem(QTableWidget *widget, int row, int column, const QString &text);
void setState(bool st);
signals:
void connectPM3(const QString path, const QString port);
void killPM3();
void setSerialListener(const QString &name, bool state);
};
#endif // MAINWINDOW_H

File diff suppressed because it is too large Load Diff

@ -0,0 +1,34 @@
#include "mf_attack_hardnesteddialog.h"
#include "ui_mf_attack_hardnesteddialog.h"
MF_Attack_hardnestedDialog::MF_Attack_hardnestedDialog(int blocks, 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));
}
}
MF_Attack_hardnestedDialog::~MF_Attack_hardnestedDialog()
{
delete ui;
}
void MF_Attack_hardnestedDialog::on_buttonBox_accepted()
{
emit sendCMD("hf mf hardnested "
+ ui->knownKeySectorBox->currentText()
+ " "
+ ui->knownKeyTypeBox->currentText()
+ " "
+ ui->knownKeyBox->text()
+ " "
+ ui->targetKeySectorBox->currentText()
+ " "
+ ui->targetKeyTypeBox->currentText());
}

@ -0,0 +1,27 @@
#ifndef MF_ATTACK_HARDNESTEDDIALOG_H
#define MF_ATTACK_HARDNESTEDDIALOG_H
#include <QDialog>
namespace Ui {
class MF_Attack_hardnestedDialog;
}
class MF_Attack_hardnestedDialog : public QDialog
{
Q_OBJECT
public:
explicit MF_Attack_hardnestedDialog(int blocks, QWidget *parent = nullptr);
~MF_Attack_hardnestedDialog();
private:
Ui::MF_Attack_hardnestedDialog *ui;
signals:
void sendCMD(QString cmd);
private slots:
void on_buttonBox_accepted();
};
#endif // MF_ATTACK_HARDNESTEDDIALOG_H

@ -0,0 +1,228 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MF_Attack_hardnestedDialog</class>
<widget class="QDialog" name="MF_Attack_hardnestedDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>287</width>
<height>173</height>
</rect>
</property>
<property name="windowTitle">
<string>Hardnested Attack</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Known Block:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Block:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="knownKeySectorBox">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="knownKeyTypeBox">
<property name="minimumSize">
<size>
<width>35</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>A</string>
</property>
</item>
<item>
<property name="text">
<string>B</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLineEdit" name="knownKeyBox">
<property name="font">
<font>
<family>Courier</family>
</font>
</property>
<property name="text">
<string notr="true">FFFFFFFFFFFF</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Target Block:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Block:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="targetKeySectorBox">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="targetKeyTypeBox">
<property name="minimumSize">
<size>
<width>35</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>35</width>
<height>16777215</height>
</size>
</property>
<item>
<property name="text">
<string>A</string>
</property>
</item>
<item>
<property name="text">
<string>B</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>31</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MF_Attack_hardnestedDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MF_Attack_hardnestedDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

@ -0,0 +1,27 @@
#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) :
QDialog(parent),
ui(new Ui::MF_UID_parameterDialog)
{
ui->setupUi(this);
ui->UIDLineEdit->setText(uid);
ui->ATQALineEdit->setText(atqa);
ui->SAKLineEdit->setText(sak);
}
MF_UID_parameterDialog::~MF_UID_parameterDialog()
{
delete ui;
}
void MF_UID_parameterDialog::on_buttonBox_accepted()
{
emit sendCMD("hf mf csetuid "
+ ui->UIDLineEdit->text()
+ " "
+ ui->ATQALineEdit->text()
+ " "
+ ui->SAKLineEdit->text());
}

@ -0,0 +1,26 @@
#ifndef MF_UID_PARAMETERDIALOG_H
#define MF_UID_PARAMETERDIALOG_H
#include <QDialog>
namespace Ui {
class MF_UID_parameterDialog;
}
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);
~MF_UID_parameterDialog();
private:
Ui::MF_UID_parameterDialog *ui;
signals:
void sendCMD(QString cmd);
private slots:
void on_buttonBox_accepted();
};
#endif // MF_UID_PARAMETERDIALOG_H

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MF_UID_parameterDialog</class>
<widget class="QDialog" name="MF_UID_parameterDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>205</width>
<height>186</height>
</rect>
</property>
<property name="windowTitle">
<string>Set Parameter</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="uIDLabel">
<property name="text">
<string>UID:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="UIDLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="ATQALabel">
<property name="text">
<string>ATQA:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="ATQALineEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="SAKLabel">
<property name="text">
<string>SAK:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="SAKLineEdit"/>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>MF_UID_parameterDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>MF_UID_parameterDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
Loading…
Cancel
Save