11 Commits

Author SHA1 Message Date
wh201906 ce973fda96 V0.2.6
Update deploy/deploy.py
2022-11-25 01:10:37 +08:00
wh201906 2704b7cfc2 Update translations 2022-11-24 23:46:11 +08:00
wh201906 2b5c94974d Add support for rrg v4.15864
Add key result as comment in config files
Specify card size in hf mf dump/restore
Use regular expression to detect lf config text
Skip the useless waiting when hf mf nested detects the static nonce then
perform staticnested attack
2022-11-24 19:44:59 +08:00
wh201906 d8d9178ce8 Fix PM3 hardware detection 2022-11-24 01:34:25 +08:00
wh201906 9c89df4519 Misc
add config file to resource system
move language folder
2022-11-24 01:24:13 +08:00
wh201906 757fdcfc21 Misc
select available PM3 hardware port when updating the serial port list
remove extra empty lines in raw command output by replacing
appendPlainText() with insertPlainText() rather than starting the client
with QProcess::Text
2022-11-23 16:51:37 +08:00
wh201906 a9b19f92d6 More hints
For serial ports which look like PM3 hardware, show a '*' behind them.
Show message box if the GUI fails to connect to the hardware
2022-11-23 15:26:28 +08:00
wh201906 b2cb1ea8e7 Show current working directory of GUI in Settings 2022-11-23 14:16:51 +08:00
wh201906 da2f6ead6e Add feedback of failing to start the client
plus, make setRequiringOutput() matched in PM3Process::connectPM3()
2022-11-23 14:01:19 +08:00
wh201906 ef9972d24a Fix default lf config 2022-06-28 00:29:26 +08:00
wh201906 9dcd291894 Misc
Terminate the child thread properly
Optimize write logic
2022-03-21 15:45:31 +08:00
27 changed files with 1361 additions and 773 deletions
+14 -3
View File
@@ -2,15 +2,26 @@
[中文](doc/CHANGELOG/CHANGELOG_zh_CN.md)
### V0.2.6
+ Add support for Iceman/RRG repo v4.15864 [#37](https://github.com/wh201906/Proxmark3GUI/issues/37)
+ Optimize mifare classic block writing logic
+ Fix the default lf config
+ Add feedback for the GUI failing to start the client
+ Add feedback for the client failing to connect to PM3 hardware
+ Detect PM3 hardware when searching serial ports
+ Remove extra empty lines in raw command output
+ Use embedded config files
+ Remove the wait time between performing nested attack then switching to staticnested attack
### V0.2.5
+ Fix bug [#28](https://github.com/wh201906/Proxmark3GUI/issues/28)
+ Fix bug [#28](https://github.com/wh201906/Proxmark3GUI/issues/28)
### V0.2.4
+ Clone EM410x card to T55xx card
### V0.2.3
+ Fix bug [#27](https://github.com/wh201906/Proxmark3GUI/issues/27)
+ Try to support Non-ASCII path
+ Fix bug [#27](https://github.com/wh201906/Proxmark3GUI/issues/27)
+ Try to support Non-ASCII path
### V0.2.2
+ Load command format from external json file
-1
View File
@@ -58,7 +58,6 @@ Great thanks to him.
mkdir build && cd build
qmake ../src
make -j4 && make clean
cp -r ../config ./
./Proxmark3GUI
***
+7
View File
@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/config">
<file>config_official.json</file>
<file>config_rrgv4.13441.json</file>
<file>config_rrgv4.15864.json</file>
</qresource>
</RCC>
+38 -10
View File
@@ -10,6 +10,13 @@
"2k": "2",
"4k": "4"
},
"//": "|---|----------------|---|----------------|---| ",
"//": "|sec|key A |res|key B |res| ",
"//": "|---|----------------|---|----------------|---| ",
"//": "|000| ffffffffffff | 1 | ffffffffffff | 1 | ",
"//": "......",
"//": "|---|----------------|---|----------------|---| ",
"//": "",
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2,
"key B index": 4
@@ -22,6 +29,15 @@
"2k": "2",
"4k": "4"
},
"//": "|---|----------------|----------------| ",
"//": "|sec|key A |key B | ",
"//": "|---|----------------|----------------| ",
"//": "|000| ffffffffffff | ffffffffffff | ",
"//": "......",
"//": "|004| ? | ? | ",
"//": "......",
"//": "|---|----------------|----------------| ",
"//": " ",
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2,
"key B index": 3
@@ -39,10 +55,22 @@
"cmd": "hf list mf"
},
"dump": {
"cmd": "hf mf dump"
"cmd": "hf mf dump <card type>",
"card type": {
"mini": "0",
"1k": "1",
"2k": "2",
"4k": "4"
}
},
"restore": {
"cmd": "hf mf restore"
"cmd": "hf mf restore <card type>",
"card type": {
"mini": "0",
"1k": "1",
"2k": "2",
"4k": "4"
}
},
"emulator wipe": {
"cmd": "hf mf eclr"
@@ -192,14 +220,14 @@
"divisor cmd": "hw setlfdivisor <divisor>"
}
},
"t55xx":{
"clone em410x":{
"read":"lf search",
"successful read flag":"Valid EM410x ID",
"pattern":"EM TAG ID\\s*:\\s\\K[0-9a-fA-F]{10}",
"clone cmd":"lf em 410xwrite <id> <type>",
"t5555 flag":"0",
"t55x7 flag":"1"
"t55xx": {
"clone em410x": {
"read": "lf search",
"successful read flag": "Valid EM410x ID",
"pattern": "EM TAG ID\\s*:\\s\\K[0-9a-fA-F]{10}",
"clone cmd": "lf em 410xwrite <id> <type>",
"t5555 flag": "0",
"t55x7 flag": "1"
}
}
}
@@ -15,6 +15,13 @@
"A": "a",
"B": "b"
},
"//": "[+] |-----|----------------|---|----------------|---|",
"//": "[+] | Sec | key A |res| key B |res|",
"//": "[+] |-----|----------------|---|----------------|---|",
"//": "[+] | 000 | ffffffffffff | 1 | ffffffffffff | 1 |",
"//": "......",
"//": "[+] |-----|----------------|---|----------------|---|",
"//": "[+] ( 0:Failed / 1:Success )",
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2,
"key B index": 4
@@ -27,6 +34,15 @@
"2k": "2k",
"4k": "4k"
},
"//": "[+] |-----|----------------|---|----------------|---|",
"//": "[+] | Sec | key A |res| key B |res|",
"//": "[+] |-----|----------------|---|----------------|---|",
"//": "[+] | 000 | ffffffffffff | 1 | ffffffffffff | 1 |",
"//": "......",
"//": "[+] | 004 | ------------ | 0 | ------------ | 0 |",
"//": "......",
"//": "[+] |-----|----------------|---|----------------|---|",
"//": "[+] ( 0:Failed / 1:Success )",
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2,
"key B index": 4
@@ -44,10 +60,22 @@
"cmd": "trace list -t mf"
},
"dump": {
"cmd": "hf mf dump"
"cmd": "hf mf dump --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
}
},
"restore": {
"cmd": "hf mf restore"
"cmd": "hf mf restore --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
}
},
"emulator wipe": {
"cmd": "hf mf eclr"
@@ -200,14 +228,14 @@
"divisor cmd": "hw setlfdivisor -d <divisor>"
}
},
"t55xx":{
"clone em410x":{
"read":"lf em 410x reader",
"successful read flag":"EM 410x ID",
"pattern":"EM 410x ID\\s*\\K[0-9a-fA-F]{10}",
"clone cmd":"lf em 410x clone --id <id> <type>",
"t5555 flag":"--q5",
"t55x7 flag":""
"t55xx": {
"clone em410x": {
"read": "lf em 410x reader",
"successful read flag": "EM 410x ID",
"pattern": "EM 410x ID\\s*\\K[0-9a-fA-F]{10}",
"clone cmd": "lf em 410x clone --id <id> <type>",
"t5555 flag": "--q5",
"t55x7 flag": ""
}
}
}
+241
View File
@@ -0,0 +1,241 @@
{
"//": "Based on Proxmark3 rrg repo v4.15864, commit 1f75adc",
"//": "You can change this file if the command format of client changes",
"mifare classic": {
"nested": {
"cmd": "hf mf nested --<card type> --blk <block> -<key type> -k <key>",
"static cmd": "hf mf staticnested --<card type> --blk <block> -<key type> -k <key>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
},
"key type": {
"A": "a",
"B": "b"
},
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] Sec | Blk | key A |res| key B |res",
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] 000 | 003 | FFFFFFFFFFFF | 1 | FFFFFFFFFFFF | 1",
"//": "......",
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] ( 0:Failed / 1:Success )",
"key pattern": "\\s*\\d{3}\\s*\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*$",
"key A index": 2,
"key B index": 4
},
"check": {
"cmd": "hf mf chk --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
},
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] Sec | Blk | key A |res| key B |res",
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] 000 | 003 | FFFFFFFFFFFF | 1 | FFFFFFFFFFFF | 1",
"//": "......",
"//": "[+] 004 | 019 | ------------ | 0 | ------------ | 0",
"//": "......",
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] ( 0:Failed / 1:Success )",
"key pattern": "\\s*\\d{3}\\s*\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*$",
"key A index": 2,
"key B index": 4
},
"info": {
"cmd": "hf 14a info"
},
"sniff": {
"cmd": "hf sniff"
},
"sniff 14a": {
"cmd": "hf 14a sniff"
},
"list": {
"cmd": "trace list -t mf"
},
"dump": {
"cmd": "hf mf dump --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
}
},
"restore": {
"cmd": "hf mf restore --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
}
},
"emulator wipe": {
"cmd": "hf mf eclr"
},
"Magic Card wipe": {
"cmd": "hf mf cwipe"
},
"emulator read block": {
"cmd": "hf mf egetblk --blk <block>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read block": {
"cmd": "hf mf cgetblk --blk <block>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"normal read block": {
"cmd": "hf mf rdbl --blk <block> -<key type> -k <key>",
"key type": {
"A": "a",
"B": "b"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"darkside": {
"cmd": "hf mf darkside"
},
"save sniff": {
"cmd": "trace save -f <filename>"
},
"load sniff": {
"cmd": "trace load -f <filename>",
"show cmd": "trace list --buffer -t mf"
},
"hardnested": {
"cmd": "hf mf hardnested --blk <known key block> -<known key type> -k <known key> --tblk <target key block> --t<target key type>",
"known key type": {
"A": "a",
"B": "b"
},
"target key type": {
"A": "a",
"B": "b"
}
},
"normal read sector": {
"cmd": "hf mf rdsc --sec <sector> -<key type> -k <key>",
"key type": {
"A": "a",
"B": "b"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read sector": {
"cmd": "hf mf cgetsc --sec <sector>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"//": "When writing a block, if the result is not empty and doesn't contain the failed flag, the function will return true",
"normal write block": {
"cmd": "hf mf wrbl --blk <block> -<key type> -k <key> -d <data>",
"key type": {
"A": "a",
"B": "b"
},
"failed flag": [
"fail",
"error"
]
},
"Magic Card write block": {
"cmd": "hf mf csetblk --blk <block> -d <data>",
"failed flag": [
"fail",
"error"
]
},
"emulator write block": {
"cmd": "hf mf esetblk --blk <block> -d <data>"
},
"Magic Card lock": {
"cmd": "hf 14a raw ",
"sequence": [
"-ak -b 7 40",
"-ak 43",
"-ak E0 00 39 F7",
"-ak E1 00 E1 EE",
"-ak 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47",
"-a 52"
]
},
"Magic Card set parameter": {
"cmd": "hf mf csetuid --uid <uid> --atqa <atqa> --sak <sak>"
}
},
"lf": {
"read": {
"cmd": "lf read -v",
"show cmd": "data plot"
},
"sniff": {
"cmd": "lf sniff -v",
"show cmd": "data plot"
},
"search": {
"cmd": "lf search -u"
},
"tune": {
"cmd": "lf tune --divisor <divisor>"
},
"get config": {
"cmd": "hw status",
"field start": "LF Sampling config",
"field end": "\\[#\\] \\S",
"divisor": {
"flag": "divisor",
"pattern": "\\d+"
},
"bits per sample": {
"flag": "bits per sample",
"pattern": "\\d+"
},
"decimation": {
"flag": "decimation",
"pattern": "\\d+"
},
"averaging": {
"flag": "averaging",
"pattern": "\\d+",
"replace": {
"yes": "1",
"no": "0",
"Yes": "1",
"No": "0"
}
},
"trigger threshold": {
"flag": "trigger threshold",
"pattern": "\\d+"
},
"samples to skip": {
"flag": "samples to skip",
"pattern": "\\d+"
},
"//": "execute 'cmd' then find parameters between 'field stard' and 'field end'",
"//": "for each line, if the line doesn't have any flag, skip",
"//": "otherwise, delete characters before 'flag' and 'flag' itself, then use 'pattern' to get the parameter",
"//": "If 'replace' dict exists, replace all keys with respective values before getting parameters"
},
"set config": {
"cmd": "lf config --divisor <divisor> --bps <bits per sample> --dec <decimation> --avg <averaging> --trig <trigger threshold> --skip <samples to skip>",
"divisor cmd": "hw setlfdivisor -d <divisor>"
}
},
"t55xx": {
"clone em410x": {
"read": "lf em 410x reader",
"successful read flag": "EM 410x ID",
"pattern": "EM 410x ID\\s*\\K[0-9a-fA-F]{10}",
"clone cmd": "lf em 410x clone --id <id> <type>",
"t5555 flag": "--q5",
"t55x7 flag": ""
}
}
}
+45 -22
View File
@@ -1,17 +1,19 @@
import os, sys, shutil
from win32api import GetFileVersionInfo
from json import load
from re import fullmatch, IGNORECASE
from re import fullmatch, sub, IGNORECASE
compressDirList = []
def getPEVersion(fname):
try:
fileInfo = GetFileVersionInfo(fname, '\\')
version = "V%d.%d.%d" % (fileInfo['FileVersionMS'] / 65536,
fileInfo['FileVersionMS'] % 65536,
fileInfo['FileVersionLS'] / 65536)
fileInfo = GetFileVersionInfo(fname, "\\")
version = "V%d.%d.%d" % (
fileInfo["FileVersionMS"] / 65536,
fileInfo["FileVersionMS"] % 65536,
fileInfo["FileVersionLS"] / 65536,
)
except Exception:
print("Cannot get version number of", fname)
return version
@@ -19,7 +21,7 @@ def getPEVersion(fname):
os.chdir(sys.path[0])
print("Current Directory:", os.getcwd())
targetName = os.path.abspath(os.getcwd()).split('\\')[-2]
targetName = os.path.abspath(os.getcwd()).split("\\")[-2]
print("Target Name", targetName)
src32Dir = ""
@@ -63,11 +65,6 @@ elif not os.path.exists(dst32Dir):
print(dst32Dir, "doesn't exist, creating...")
shutil.copytree("./32", dst32Dir)
shutil.copyfile(src32Path, dst32Path)
configPath = dst32Dir + "/config"
if os.path.exists(configPath):
print(configPath, "exists, replacing...")
shutil.rmtree(configPath)
shutil.copytree("../config", configPath)
compressDirList.append(dst32Dir)
if os.path.exists(dst64Dir) and os.path.exists(dst64Path):
@@ -77,19 +74,23 @@ elif not os.path.exists(dst64Dir):
print(dst64Dir, "doesn't exist, creating...")
shutil.copytree("./64", dst64Dir)
shutil.copyfile(src64Path, dst64Path)
configPath = dst64Dir + "/config"
if os.path.exists(configPath):
print(configPath, "exists, replacing...")
shutil.rmtree(configPath)
shutil.copytree("../config", configPath)
compressDirList.append(dst64Dir)
# TODO: GUI+client
clientList = [
"official-v3.1.0", "rrg_other-v4.13441", "rrg_other-v4.14434",
"rrg_other-v4.14831"
"official-v3.1.0",
"rrg_other-v4.13441",
"rrg_other-v4.14434",
"rrg_other-v4.14831",
"rrg_other-v4.15864",
]
configList = []
for config in os.listdir("../config"):
configPath = os.path.join("../config", config)
if os.path.isfile(configPath) and config.endswith(".json"):
configList.append(config)
def generateClient(clientName):
global compressDirList
@@ -105,12 +106,34 @@ def generateClient(clientName):
shutil.copytree(clientSrcDir, clientDstDir)
shutil.copytree(dst64Dir, clientDstGUIDir)
if "official" in clientName:
shutil.copyfile("./client/GUIsettings_Official.ini",
clientDstGUIDir + "/GUIsettings.ini")
shutil.copyfile(
"./client/GUIsettings_Official.ini", clientDstGUIDir + "/GUIsettings.ini"
)
elif "rrg" in clientName:
shutil.copyfile("./client/GUIsettings_RRG.ini",
clientDstGUIDir + "/GUIsettings.ini")
shutil.copyfile(
"./client/GUIsettings_RRG.ini", clientDstGUIDir + "/GUIsettings.ini"
)
# Use exactly matched configFile if possible
version = clientName[clientName.find("v") :]
for config in configList:
if version in config:
print("Find matched config file", config)
with open(
clientDstGUIDir + "/GUIsettings.ini", "r", encoding="utf-8"
) as f:
data = f.read()
data = sub(
"configFile=:/config/.+\\.json",
"configFile=:/config/" + config,
data,
)
with open(
clientDstGUIDir + "/GUIsettings.ini", "w", encoding="utf-8"
) as f:
f.write(data)
compressDirList.append(clientDstDir)
return clientDstDir
for cl in clientList:
+11
View File
@@ -2,6 +2,17 @@
[English](../../CHANGELOG.md)
### V0.2.6
+ 支持冰人版客户端 v4.15864 [#37](https://github.com/wh201906/Proxmark3GUI/issues/37)
+ 优化Mifare Classic卡写卡逻辑
+ 修复lf config默认配置
+ 添加客户端无法启动的提示
+ 添加PM3硬件连接失败的提示
+ 为PM3对应串口添加提示,并自动选中
+ 修复原始指令框中有多余空行的问题
+ 内嵌不同客户端的配置文件
+ 去除从nested attack切换到staticnested attack的等待时间
### V0.2.5
+ 修复 [#28](https://github.com/wh201906/Proxmark3GUI/issues/28)
-1
View File
@@ -57,7 +57,6 @@ release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客
mkdir build && cd build
qmake ../src
make -j4 && make clean
cp -r ../config ./
./Proxmark3GUI
***
BIN
View File
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,3 @@
[Languages]
en_US=English
zh_CN=简体中文
ext=Load from external file
Binary file not shown.
File diff suppressed because it is too large Load Diff
+5 -4
View File
@@ -51,18 +51,19 @@ FORMS += \
ui/mf_attack_hardnesteddialog.ui
TRANSLATIONS += \
i18n/zh_CN.ts \
i18n/en_US.ts
../i18n/zh_CN.ts \
../i18n/en_US.ts
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
VERSION = 0.2.5
VERSION = 0.2.6
QMAKE_TARGET_PRODUCT = "Proxmark3GUI"
QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI"
QMAKE_TARGET_COMPANY = "wh201906"
RESOURCES += \
i18n/language.qrc
../i18n/language.qrc \
../config/config.qrc
+9 -1
View File
@@ -13,6 +13,8 @@ PM3Process::PM3Process(QThread* thread, QObject* parent): QProcess(parent)
connect(serialListener, &QTimer::timeout, this, &PM3Process::onTimeout);
connect(this, &PM3Process::readyRead, this, &PM3Process::onReadyRead);
portInfo = nullptr;
qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError");
}
void PM3Process::connectPM3(const QString& path, const QStringList args)
@@ -26,7 +28,8 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
currArgs = args;
// using "-f" option to make the client output flushed after every print.
start(path, args, QProcess::Unbuffered | QProcess::ReadWrite | QProcess::Text);
// single '\r' might appear. Don't use QProcess::Text there or '\r' is ignored.
start(path, args, QProcess::Unbuffered | QProcess::ReadWrite);
if(waitForStarted(10000))
{
waitForReadyRead(10000);
@@ -59,8 +62,13 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
emit PM3StatedChanged(true, result);
}
else
{
emit HWConnectFailed();
kill();
}
}
setRequiringOutput(false);
}
void PM3Process::reconnectPM3()
+1
View File
@@ -48,6 +48,7 @@ signals:
void PM3StatedChanged(bool st, const QString& info = "");
void newOutput(const QString& output);
void changeClientType(Util::ClientType);
void HWConnectFailed();
};
#endif // PM3PROCESS_H
+17 -5
View File
@@ -119,17 +119,29 @@ bool Util::chooseLanguage(QSettings* guiSettings, QMainWindow* window)
QStringList langList = langSettings->allKeys();
for(int i = 0; i < langList.size(); i++)
langMap.insert(langSettings->value(langList[i]).toString(), langList[i]);
langMap.insert(tr("Load from external file"), "(ext)");
langSettings->endGroup();
delete langSettings;
bool isOk = false;
QString selectedText = QInputDialog::getItem(window, "", "Choose a language:", langMap.keys(), 0, false, &isOk);
if(isOk)
QString selectedText = QInputDialog::getItem(window, "", tr("Choose a language:"), langMap.keys(), 0, false, &isOk);
if(!isOk)
return false;
if(langMap[selectedText] == "(ext)")
{
guiSettings->beginGroup("lang");
guiSettings->setValue("language", langMap[selectedText]);
QString extPath = QFileDialog::getOpenFileName(nullptr, tr("Select the translation file:"));
if(extPath.isEmpty())
return false;
guiSettings->beginGroup("language");
guiSettings->setValue("extPath", extPath);
guiSettings->endGroup();
guiSettings->sync();
}
guiSettings->beginGroup("language");
guiSettings->setValue("name", langMap[selectedText]);
guiSettings->endGroup();
guiSettings->sync();
return isOk;
}
+1
View File
@@ -13,6 +13,7 @@
#include <QSettings>
#include <QMainWindow>
#include <QInputDialog>
#include <QFileDialog>
#include <QDockWidget>
#include "ui_mainwindow.h"
BIN
View File
Binary file not shown.
+16 -15
View File
@@ -27,33 +27,34 @@ int main(int argc, char *argv[])
QSettings* settings = new QSettings("GUIsettings.ini", QSettings::IniFormat);
settings->setIniCodec("UTF-8");
settings->beginGroup("lang");
QString currLang = settings->value("language", "").toString();
settings->beginGroup("language");
QString languageFile = settings->value("extPath").toString();
QString languageName = settings->value("name").toString();
settings->endGroup();
if(currLang == "")
if(languageName == "")
{
if(Util::chooseLanguage(settings, &w))
{
settings->beginGroup("lang");
currLang = settings->value("language", "").toString();
settings->beginGroup("language");
languageName = settings->value("name").toString();
settings->endGroup();
}
else
currLang = "en_US";
languageName = "en_US";
}
if(languageName == "(ext)")
{
settings->beginGroup("language");
languageFile = settings->value("extPath").toString();
settings->endGroup();
}
if(currLang == "ext")
currLang = QFileDialog::getOpenFileName(nullptr, "Select the translation file:");
else
currLang = ":/i18n/" + currLang + ".qm";
languageFile = ":/i18n/" + languageName + ".qm";
QTranslator* translator = new QTranslator(&w);
if(translator->load(currLang))
{
if(translator->load(languageFile))
a.installTranslator(translator);
}
else
{
QMessageBox::information(&w, "Error", "Can't load " + currLang + " as translation file.");
}
QMessageBox::information(&w, "Error", "Can't load " + languageFile + " as translation file.");
delete settings;
w.initUI();
w.show();
+4 -2
View File
@@ -81,8 +81,10 @@ void LF::getLFConfig()
QVariantMap config = configMap["get config"].toMap();
QString cmd = config["cmd"].toString();
result = util->execCMDWithOutput(cmd, 400);
start = result.indexOf(config["field start"].toString());
end = result.indexOf(config["field end"].toString());
reMatch = QRegularExpression(config["field start"].toString(), QRegularExpression::MultilineOption).match(result);
start = reMatch.hasMatch() ? reMatch.capturedEnd() : 0;
reMatch = QRegularExpression(config["field end"].toString(), QRegularExpression::MultilineOption).match(result, start);
end = reMatch.hasMatch() ? reMatch.capturedStart() : result.length();
result = result.mid(start, end - start);
#if (QT_VERSION <= QT_VERSION_CHECK(5,14,0))
resultList = result.split("\n", QString::SkipEmptyParts);
+16 -6
View File
@@ -130,7 +130,7 @@ void Mifare::chk()
QString cmd = config["cmd"].toString();
int keyAindex = config["key A index"].toInt();
int keyBindex = config["key B index"].toInt();
QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString());
QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString(), QRegularExpression::MultilineOption);
cmd.replace("<card type>", config["card type"].toMap()[cardType.typeText].toString());
result = util->execCMDWithOutput(
@@ -169,7 +169,7 @@ void Mifare::nested(bool isStaticNested)
cmd = config["cmd"].toString();
int keyAindex = config["key A index"].toInt();
int keyBindex = config["key B index"].toInt();
QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString());
QRegularExpression keyPattern = QRegularExpression(config["key pattern"].toString(), QRegularExpression::MultilineOption);
QRegularExpressionMatch reMatch;
QString result;
int offset = 0;
@@ -212,7 +212,7 @@ void Mifare::nested(bool isStaticNested)
}
result = util->execCMDWithOutput(
cmd,
Util::ReturnTrigger(15000, {"Can't found", "Can't authenticate", keyPattern_res->pattern()}),
Util::ReturnTrigger(15000, {"Quit", "Can't found", "Can't authenticate", keyPattern_res->pattern()}),
true);
if(result.contains("static") && !isStaticNested)
@@ -691,10 +691,14 @@ void Mifare::writeSelected(TargetType targetType)
{
result = _writeblk(item, KEY_B, keyBList->at(data_b2s(item)), dataList->at(item), TARGET_MIFARE);
}
if(!result)
if(!result && keyAList->at(data_b2s(item)) != "FFFFFFFFFFFF")
{
result = _writeblk(item, KEY_A, "FFFFFFFFFFFF", dataList->at(item), TARGET_MIFARE);
}
if(!result && keyBList->at(data_b2s(item)) != "FFFFFFFFFFFF") // for access bits like "80 f7 87", the block can only be written with keyB
{
result = _writeblk(item, KEY_B, "FFFFFFFFFFFF", dataList->at(item), TARGET_MIFARE);
}
}
else // key doesn't matter when writing to Chinese Magic Card and Emulator Memory
{
@@ -743,14 +747,20 @@ void Mifare::writeSelected(TargetType targetType)
void Mifare::dump()
{
QVariantMap config = configMap["dump"].toMap();
util->execCMD(config["cmd"].toString());
QString cmd = config["cmd"].toString();
if(cmd.contains("<card type>"))
cmd.replace("<card type>", config["card type"].toMap()[cardType.typeText].toString());
util->execCMD(cmd);
Util::gotoRawTab();
}
void Mifare::restore()
{
QVariantMap config = configMap["restore"].toMap();
util->execCMD(config["cmd"].toString());
QString cmd = config["cmd"].toString();
if(cmd.contains("<card type>"))
cmd.replace("<card type>", config["card type"].toMap()[cardType.typeText].toString());
util->execCMD(cmd);
Util::gotoRawTab();
}
+85 -9
View File
@@ -2,6 +2,7 @@
#include "ui_mainwindow.h"
#include <QJsonDocument>
#include <QDirIterator>
MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent)
@@ -30,7 +31,9 @@ MainWindow::MainWindow(QWidget *parent):
settings->setIniCodec("UTF-8");
pm3Thread = new QThread(this);
connect(QApplication::instance(), &QApplication::aboutToQuit, pm3Thread, &QThread::quit);
pm3 = new PM3Process(pm3Thread);
connect(pm3Thread, &QThread::finished, pm3, &PM3Process::deleteLater);
pm3Thread->start();
pm3state = false;
clientWorkingDir = new QDir;
@@ -77,7 +80,11 @@ MainWindow::~MainWindow()
void MainWindow::loadConfig()
{
QFile configList(ui->Set_Client_configPathEdit->text());
QString filename = ui->Set_Client_configFileBox->currentData().toString();
if(filename == "(ext)")
filename = ui->Set_Client_configPathEdit->text();
qDebug() << "config file:" << filename;
QFile configList(filename);
if(!configList.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::information(this, tr("Info"), tr("Failed to load config file"));
@@ -104,18 +111,46 @@ void MainWindow::initUI() // will be called by main.app
void MainWindow::on_portSearchTimer_timeout()
{
QStringList newPortList;
QStringList newPortList; // for actural port name
QStringList newPortNameList; // for display name
const QString hint = " *";
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
// qDebug() << info.isBusy() << info.isNull() << info.portName() << info.description();
// qDebug() << info.isNull() << info.portName() << info.description() << info.serialNumber() << info.manufacturer();
if(!info.isNull())
newPortList << info.portName();
{
QString idString = (info.description() + info.serialNumber() + info.manufacturer()).toLower();
QString portName = info.portName();
newPortList << portName;
if(info.hasVendorIdentifier() && info.hasProductIdentifier())
{
quint16 vid = info.vendorIdentifier();
quint16 pid = info.productIdentifier();
if(vid == 0x9AC4 && pid == 0x4B8F)
portName += hint;
else if(vid == 0x2D2D && pid == 0x504D)
portName += hint;
}
else if(idString.contains("proxmark") || idString.contains("iceman"))
portName += hint;
newPortNameList << portName;
}
}
if(newPortList != portList) // update PM3_portBox when available ports changed
{
portList = newPortList;
ui->PM3_portBox->clear();
ui->PM3_portBox->addItems(portList);
int selectId = -1;
for(int i = 0; i < portList.size(); i++)
{
ui->PM3_portBox->addItem(newPortNameList[i], newPortList[i]);
if(selectId == -1 && newPortNameList[i].endsWith(hint))
selectId = i;
}
if(selectId != -1)
ui->PM3_portBox->setCurrentIndex(selectId);
}
}
@@ -123,7 +158,7 @@ void MainWindow::on_PM3_connectButton_clicked()
{
qDebug() << "Main:" << QThread::currentThread();
QString port = ui->PM3_portBox->currentText();
QString port = ui->PM3_portBox->currentData().toString();
QString startArgs = ui->Set_Client_startArgsEdit->text();
// on RRG repo, if no port is specified, the client will search the available port
@@ -193,6 +228,18 @@ void MainWindow::on_PM3_connectButton_clicked()
envSetProcess.kill();
}
void MainWindow::onPM3ErrorOccurred(QProcess::ProcessError error)
{
qDebug() << "PM3 Error:" << error << pm3->errorString();
if(error == QProcess::FailedToStart)
QMessageBox::information(this, tr("Info"), tr("Failed to start the client"));
}
void MainWindow::onPM3HWConnectFailed()
{
QMessageBox::information(this, tr("Info"), tr("Failed to connect to the hardware"));
}
void MainWindow::onPM3StateChanged(bool st, const QString& info)
{
pm3state = st;
@@ -220,7 +267,8 @@ void MainWindow::on_PM3_disconnectButton_clicked()
void MainWindow::refreshOutput(const QString& output)
{
// qDebug() << "MainWindow::refresh:" << output;
ui->Raw_outputEdit->appendPlainText(output);
ui->Raw_outputEdit->moveCursor(QTextCursor::End);
ui->Raw_outputEdit->insertPlainText(output);
ui->Raw_outputEdit->moveCursor(QTextCursor::End);
}
@@ -1054,6 +1102,8 @@ void MainWindow::uiInit()
ui->PM3_pathEdit->setText(settings->value("path", "proxmark3").toString());
settings->endGroup();
ui->Set_Client_GUIWorkingDirLabel->setText(QDir::currentPath());
settings->beginGroup("Client_Args");
ui->Set_Client_startArgsEdit->setText(settings->value("args", "<port> -f").toString());
settings->endGroup();
@@ -1068,11 +1118,27 @@ void MainWindow::uiInit()
ui->Set_Client_keepClientActiveBox->setChecked(keepClientActive);
settings->endGroup();
QDirIterator configFiles(":/config/");
ui->Set_Client_configFileBox->blockSignals(true);
while(configFiles.hasNext())
{
configFiles.next();
ui->Set_Client_configFileBox->addItem(configFiles.fileName(), configFiles.filePath());
}
ui->Set_Client_configFileBox->addItem(tr("External file"), "(ext)");
int configId = -1;
settings->beginGroup("Client_Env");
ui->Set_Client_envScriptEdit->setText(settings->value("scriptPath").toString());
ui->Set_Client_workingDirEdit->setText(settings->value("workingDir", "../data").toString());
ui->Set_Client_configPathEdit->setText(settings->value("configPath", "config.json").toString());
configId = ui->Set_Client_configFileBox->findData(settings->value("configFile"));
ui->Set_Client_configPathEdit->setText(settings->value("extConfigFilePath", "config.json").toString());
settings->endGroup();
if(configId != -1)
ui->Set_Client_configFileBox->setCurrentIndex(configId);
ui->Set_Client_configFileBox->blockSignals(false);
on_Set_Client_configFileBox_currentIndexChanged(ui->Set_Client_configFileBox->currentIndex());
ui->MF_RW_keyTypeBox->addItem("A", Mifare::KEY_A);
ui->MF_RW_keyTypeBox->addItem("B", Mifare::KEY_B);
@@ -1091,6 +1157,8 @@ void MainWindow::signalInit()
connect(this, &MainWindow::reconnectPM3, pm3, &PM3Process::reconnectPM3);
connect(pm3, &PM3Process::PM3StatedChanged, this, &MainWindow::onPM3StateChanged);
connect(pm3, &PM3Process::PM3StatedChanged, util, &Util::setRunningState);
connect(pm3, &PM3Process::errorOccurred, this, &MainWindow::onPM3ErrorOccurred);
connect(pm3, &PM3Process::HWConnectFailed, this, &MainWindow::onPM3HWConnectFailed);
connect(this, &MainWindow::killPM3, pm3, &PM3Process::killPM3);
connect(this, &MainWindow::setProcEnv, pm3, &PM3Process::setProcEnv);
connect(this, &MainWindow::setWorkingDir, pm3, &PM3Process::setWorkingDir);
@@ -1274,7 +1342,7 @@ void MainWindow::on_Set_Client_workingDirEdit_editingFinished()
void MainWindow::on_Set_Client_configPathEdit_editingFinished()
{
settings->beginGroup("Client_Env");
settings->setValue("configPath", ui->Set_Client_configPathEdit->text());
settings->setValue("extConfigFilePath", ui->Set_Client_configPathEdit->text());
settings->endGroup();
}
@@ -1412,3 +1480,11 @@ void MainWindow::on_LF_LFConf_resetButton_clicked()
setState(true);
}
void MainWindow::on_Set_Client_configFileBox_currentIndexChanged(int index)
{
ui->Set_Client_configPathEdit->setVisible(ui->Set_Client_configFileBox->itemData(index).toString() == "(ext)");
settings->beginGroup("Client_Env");
settings->setValue("configFile", ui->Set_Client_configFileBox->currentData());
settings->endGroup();
}
+6 -1
View File
@@ -51,7 +51,7 @@ public:
~MainWindow();
void initUI();
bool eventFilter(QObject *watched, QEvent *event);
bool eventFilter(QObject *watched, QEvent *event) override;
public slots:
void refreshOutput(const QString& output);
void refreshCMD(const QString& cmd);
@@ -60,6 +60,8 @@ public slots:
void MF_onMFCardTypeChanged(int id, bool st);
void on_Raw_keyPressed(QObject *obj_addr, QEvent &event);
void on_MF_keyWidget_resized(QObject *obj_addr, QEvent &event);
void onPM3ErrorOccurred(QProcess::ProcessError error);
void onPM3HWConnectFailed();
private slots:
void on_PM3_connectButton_clicked();
@@ -207,6 +209,9 @@ private slots:
void on_Set_Client_configPathEdit_editingFinished();
void setState(bool st);
void on_Set_Client_configFileBox_currentIndexChanged(int index);
private:
Ui::MainWindow* ui;
QButtonGroup* MFCardTypeBtnGroup;
+44 -3
View File
@@ -1454,8 +1454,8 @@ When setting the freq, the &quot;hw setlfdivisor&quot; will also be called.</str
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="LF_LFConf_averagingBox">
<property name="text">
<string/>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
@@ -2650,6 +2650,23 @@ or the communication between a tag and a reader.</string>
<string>Client</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QLabel" name="label_65">
<property name="text">
<string>GUI working directory:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="Set_Client_GUIWorkingDirLabel"/>
</item>
<item>
<widget class="Line" name="line_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="text">
@@ -2746,10 +2763,34 @@ or the communication between a tag and a reader.</string>
<item>
<widget class="QLabel" name="label_63">
<property name="text">
<string>Config file path(Reconnect to apply):</string>
<string>Config file(Reconnect to apply):</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
<widget class="QComboBox" name="Set_Client_configFileBox">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_13">
<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>
<widget class="QLineEdit" name="Set_Client_configPathEdit">
<property name="text">