57 Commits

Author SHA1 Message Date
Self Not Found 695f963991 More general build steps for Linux
Tested on Ubuntu 18.04.6 and 23.10.1
2023-11-03 23:32:55 +08:00
Self Not Found 38c7916715 Merge pull request #54 from setime/workaround-ubuntu-22_04
Workaround to get the GUI working on Ubuntu 22.04
2023-10-29 02:27:54 +08:00
setime 687c27672f Workaround to get the GUI working on Ubuntu 22.04 2023-10-28 19:12:59 +02:00
wh201906 e2fb18970e V0.2.8 2023-06-27 21:54:21 +08:00
wh201906 184a9ed5f2 Fix saving/loading trace(sniff) files
Fix file extension for RRG repo
Fix overwriting existing file
Add support for RRG v4.16717(path in prefs)
2023-06-27 21:09:08 +08:00
wh201906 0738aff2bf Check 125k/134k radiobutton when getting lf config 2023-06-27 17:46:25 +08:00
wh201906 d466e5536b Show more information when running card info 2023-06-27 17:32:41 +08:00
wh201906 b9da3e9209 Add support for RRG v4.16717
Change the order and the default option of config files
2023-06-27 17:16:50 +08:00
wh201906 ee7aeda91e Fix a bug in finding client
In commit e6be456cfa, I uses QFileInfo::exists() to check if the client
exists. However, it doesn't work for client with extensions in
environment variable %PATHEXT% when specifying the path without
extension
2023-06-06 20:04:52 +08:00
wh201906 99bb58adf9 Fix the user input for "Port"
Port can be something not listed in the combobox, like
tcp:192.168.xxx.xxx:xxxxx(25 characters)
bt:aa:bb:cc:dd:ee:ff(20 characters)
2023-06-04 19:10:03 +08:00
wh201906 785fde6e2d Add tutorial for ProxSpace 2023-06-04 18:41:30 +08:00
wh201906 a9b03f081a Remember different client paths(max num:32)
Helpful for me
2023-06-04 02:25:46 +08:00
wh201906 0634e530b6 Use QString::contains() 2023-06-04 00:57:09 +08:00
wh201906 e6be456cfa Add <client dir> for preload script path 2023-06-04 00:53:15 +08:00
wh201906 aee621c196 V0.2.7 2023-02-26 13:12:33 +08:00
wh201906 b788d6a15f Misc work in translation
Update translations
Fix the translation in t55xxtab
(QTranslator must be created before wigets)
Reduce unnecessary translations
2023-02-26 12:33:15 +08:00
wh201906 92d704bc96 Update README
Remove introduction of Iceman/RRG repo
(It is the default repo of this GUI now)
Update build instructions
2023-02-26 09:45:04 +08:00
wh201906 d671266797 Replace replace(xxx, "") with remove(xxx) 2023-02-26 09:43:54 +08:00
wh201906 5a26cd1936 Fix nested setting groups 2023-02-26 00:49:39 +08:00
wh201906 5b84e58ecb UI: More configurable items
Code part
Fonts, opacity and theme are configurable now
Add dark theme for night owls
2023-02-19 00:19:07 +08:00
wh201906 29bac475b5 Add QDarkStyleSheet for Dark/Light theme
Stylesheet is from https://github.com/ColinDuquesnoy/QDarkStyleSheet
2023-02-19 00:17:33 +08:00
wh201906 6926b2f170 UI: More configurable items
UI part
2023-02-18 15:25:40 +08:00
wh201906 aaf6e52a12 Add URLs for releases and reporting bugs 2023-02-14 00:40:11 +08:00
wh201906 b3001e71b7 Disable disconnection detection on Linux/macOS 2023-02-13 09:49:56 +08:00
wh201906 a7e112f124 Better Trailer Decoder
Fix the decoding of isKeyBReadable
Show every Access Bits
Show isKeyBReadable
Add comment for the decoding process
Better UI
Remove unnecessary debug output
2023-02-13 09:27:38 +08:00
wh201906 c2d3248b68 Add --force for hf mf wrbl(v4.15864)
Otherwise writing to trailer block and block 0 won't work
2023-02-12 22:57:50 +08:00
wh201906 2723abd260 Update README
Add download links from SourceForge
Remove unnecessary steps in macOS building instructions
2022-11-25 13:36:03 +08:00
wh201906 9aff432b1b Merge branch 'dev' 2022-11-25 01:27:09 +08:00
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 3c6d5e4d82 Update README 2022-09-12 22:36:21 +08:00
wh201906 8105aba254 Merge pull request #33 from rzhq/macos_build
added documents for macOS build
2022-07-14 10:54:32 +08:00
rzhq ebf1980af5 added documents for macOS build 2022-07-14 11:04:41 +10:00
wh201906 fd0f9c081f Merge pull request #32 from zxkmm/master
English translate correction/更正一些英文翻译
2022-06-28 00:32:33 +08:00
wh201906 ef9972d24a Fix default lf config 2022-06-28 00:29:26 +08:00
zxkmm 8739dde6a2 Update zh_CN.ts
corrected typo
2022-06-10 18:31:51 +08:00
zxkmm 2e1e8a0ae5 Update en_US.ts
corrected typo
2022-06-10 18:31:13 +08:00
zxkmm 9b206d6828 Update mifare.cpp
corrected typo
2022-06-10 18:30:06 +08:00
zxkmm 3b1092304c Update en_US.ts 2022-06-10 18:25:43 +08:00
zxkmm 924178dffa Update zh_CN.ts
corrected typo
2022-06-10 18:24:46 +08:00
zxkmm 953e686785 Update mifare.cpp
corrected typo
2022-06-10 18:22:14 +08:00
wh201906 a2d63b5cdc Update tutorial 2022-04-03 15:55:03 +08:00
wh201906 9dcd291894 Misc
Terminate the child thread properly
Optimize write logic
2022-03-21 15:45:31 +08:00
wh201906 ff3a43a4a6 V0.2.5 2022-03-13 20:37:47 +08:00
wh201906 5a0f0d3e3e Fix bug #28
Add deploy helper(unfinished)
2022-03-12 20:26:34 +08:00
wh201906 d60f636881 Merge branch 'dev' 2022-03-01 18:55:49 +08:00
wh201906 ae932778ce V0.2.4 2022-03-01 18:52:04 +08:00
wh201906 1e728c891c EM410x clone support 2022-03-01 18:47:33 +08:00
wh201906 f86cba8d56 New project structure
Load translation file in the executable.
2022-03-01 11:13:07 +08:00
wh201906 b319f9fbe1 Fix a UI bug
The dock widget will take as much space as it could get now
2022-01-31 00:58:57 +08:00
481 changed files with 8783 additions and 1661 deletions
+2 -72
View File
@@ -1,72 +1,2 @@
# This file is used to ignore files which are generated /build*
# ---------------------------------------------------------------------------- /data
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
+88
View File
@@ -0,0 +1,88 @@
# Change Log
[中文](doc/CHANGELOG/CHANGELOG_zh_CN.md)
### V0.2.8
+ Add support for Iceman/RRG repo v4.16717
+ Fix some bugs
+ Make it easier for testing this GUI across multiple clients
+ Add support for Bluetooth and TCP connection
### V0.2.7
+ Fix writing to Block 0 failure when using with RRG repo v4.15864
+ Disable disconnection detection on Linux/macOS by default
+ Fix a little bug in the config file
+ Fix the Trailer Decoder
+ Show more details in the Trailer Decoder
+ Add dark theme(from https://github.com/ColinDuquesnoy/QDarkStyleSheet)
+ Add support for customizable theme, opacity and fonts
+ Fix translations
### 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)
### 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
### V0.2.2
+ Load command format from external json file
+ Fix bug [#20](https://github.com/wh201906/Proxmark3GUI/issues/20), [#21](https://github.com/wh201906/Proxmark3GUI/issues/21), [#22](https://github.com/wh201906/Proxmark3GUI/issues/22)
+ Support Iceman/RRG repo v4.13441
### V0.2.1
+ Optimize MIFARE Classic reading logic
+ Fix bug [#16](https://github.com/wh201906/Proxmark3GUI/issues/16)
+ Fix bug [#15](https://github.com/wh201906/Proxmark3GUI/issues/15) partially (the path can contain spaces now)
### V0.2
+ Use Dock widget for more flexible layout
+ Support basic LF commands
+ Fix a bug in RawCommand tab
### V0.1.4
+ Optimize performance
+ Optimize UI
+ Search available ports automatically
+ Add High-DPI support
+ Support configuring environment variables by script
(Useful when the client requires specific environment variables)
+ All functions are compatible with Iceman/RRG repo(tested on v4.9237)
+ Support specifying client working directory
+ Fix some bugs
### V0.1.3
+ Fix Trailer Decoder
+ Add feedback when writing selected blocks
### V0.1.2
+ Optimize read logic
+ Make UI Customizable
+ Save client path automatically
+ Add Trailer Decoder(Deprecated, plz use V0.1.3 or higher version)
+ Support read/write selected blocks
+ Support a few Iceman functions
+ Fix some bugs
### V0.1.1
+ Complete Mifare module(support simulate and sniff)
### V0.1
+ Able to deal with Mifare card and related files
### V0.0.1
+ a dumb version with a useless GUI and a serial choose box.
+51 -77
View File
@@ -1,7 +1,10 @@
# Proxmark3GUI # Proxmark3GUI
![downloads](https://img.shields.io/github/downloads/wh201906/Proxmark3GUI/total) [![downloads](https://img.shields.io/github/downloads/wh201906/Proxmark3GUI/total?label=GitHub%20release%20downloads)](https://github.com/wh201906/Proxmark3GUI/releases)
[![downloads](https://img.shields.io/sourceforge/dt/proxmark3gui.svg?label=SourceForge%20downloads)](https://sourceforge.net/projects/proxmark3gui/)
A cross-platform GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) client A cross-platform GUI for [Proxmark3](https://github.com/Proxmark/proxmark3)/[Proxmark3 Iceman fork](https://github.com/RfidResearchGroup/proxmark3) client
(The [orignal Proxmark3 repo](https://github.com/Proxmark/proxmark3) has been unmaintained for a long time. I personally suggest using the [Proxmark3 Iceman fork](https://github.com/RfidResearchGroup/proxmark3))
[中文介绍](doc/README/README_zh_CN.md) [中文介绍](doc/README/README_zh_CN.md)
@@ -32,13 +35,6 @@ A cross-platform GUI for [Proxmark3](https://github.com/Proxmark/proxmark3) clie
*** ***
## About Iceman fork/repo
The [Iceman fork/repo](https://github.com/RfidResearchGroup/proxmark3) has more powerful functions. These guys even developed a new hardware called Proxmark3 RDV4 with smart card support. But the official repo and the Iceman repo is not fully compatible.
This GUI is compatible with Iceman/RRG repo(tested on v4.13441)
***
## About Compiled Windows clients ## About Compiled Windows clients
A cool guy [Gator96100](https://github.com/Gator96100) creates [ProxSpace](https://github.com/Gator96100/ProxSpace) and makes it possible to compile both the firmware and the client on Windows. A cool guy [Gator96100](https://github.com/Gator96100) creates [ProxSpace](https://github.com/Gator96100/ProxSpace) and makes it possible to compile both the firmware and the client on Windows.
@@ -48,79 +44,57 @@ Great thanks to him.
*** ***
## Build on Linux ## Download binaries for Windows
You can download pre-built Windows binaries in [release](https://github.com/wh201906/Proxmark3GUI/releases) page
`Vx.x.x-win64.7z` only contains the GUI
`Vx.x.x-win64-xxxxxxx.7z` contains the GUI and corresponding client. You just need to open `Vx.x.x-win64-xxxxxxx\GUI\Proxmark3GUI.exe`
cd ~ You can also download them in SourceForge
sudo apt-get update [![Download Proxmark3GUI](https://a.fsdn.com/con/app/sf-download-button)](https://sourceforge.net/projects/proxmark3gui/files/latest/download)
sudo apt-get install qt5-default libqt5serialport5 libqt5serialport5-dev
git clone https://github.com/wh201906/Proxmark3GUI.git --depth=1 ## Build on Linux
cd Proxmark3GUI ```bash
mkdir build cd ~
cd build # sudo add-apt-repository universe
qmake ../ sudo apt-get update
make # sudo apt-get install git build-essential
make clean sudo apt-get install qtbase5-dev qt5-qmake libqt5serialport5-dev
cp -r ../lang ./ git clone https://github.com/wh201906/Proxmark3GUI.git --depth=1
cp -r ../config ./ cd Proxmark3GUI
./Proxmark3GUI mkdir build && cd build
export QT_SELECT=qt5
qmake ../src
make -j4 && make clean
./Proxmark3GUI
```
## Build on macOS
```zsh
cd ~
brew update
brew install qt@5
brew link qt5 --force
git clone https://github.com/wh201906/Proxmark3GUI.git --depth=1
cd Proxmark3GUI
mkdir build && cd build
qmake ../src
make -j4 && make clean
open Proxmark3GUI.app
```
> In order for the GUI to connect to the device in macOS, you'd need to tweak the settings a little bit
![macOS_settings](doc/README/macOS_settings.png)
*** ***
## Tutorial ## Tutorial
[1.Quickstart](doc/tutorial/Quickstart/quickstart.md) [1.Quickstart](doc/tutorial/Quickstart/quickstart.md)
[2.Edit Mifare Classic data](doc/tutorial/Edit_Mifare_Classic_data/Edit_Mifare_Classic_data.md)(Proxmark3 hardware is not necessary) [2.Work with ProxSpace](doc/tutorial/Work_With_ProxSpace/work_with_proxspace.md)
[3.Edit Mifare Classic data](doc/tutorial/Edit_Mifare_Classic_data/Edit_Mifare_Classic_data.md)(Proxmark3 hardware is not necessary)
*** ***
## Update Log: ## Change Log
[Change Log](CHANGELOG.md)
### V0.2.3
+ 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
+ Fix bug [#20](https://github.com/wh201906/Proxmark3GUI/issues/20), [#21](https://github.com/wh201906/Proxmark3GUI/issues/21), [#22](https://github.com/wh201906/Proxmark3GUI/issues/22)
+ Support Iceman/RRG repo v4.13441
### V0.2.1
+ Optimize MIFARE Classic reading logic
+ Fix bug [#16](https://github.com/wh201906/Proxmark3GUI/issues/16)
+ Fix bug [#15](https://github.com/wh201906/Proxmark3GUI/issues/15) partially (the path can contain spaces now)
### V0.2
+ Use Dock widget for more flexible layout
+ Support basic LF commands
+ Fix a bug in RawCommand tab
### V0.1.4
+ Optimize performance
+ Optimize UI
+ Search available ports automatically
+ Add High-DPI support
+ Support configuring environment variables by script
(Useful when the client requires specific environment variables)
+ All functions are compatible with Iceman/RRG repo(tested on v4.9237)
+ Support specifying client working directory
+ Fix some bugs
### V0.1.3
+ Fix Trailer Decoder
+ Add feedback when writing selected blocks
### V0.1.2
+ Optimize read logic
+ Make UI Customizable
+ Save client path automatically
+ Add Trailer Decoder(Deprecated, plz use V0.1.3 or higher version)
+ Support read/write selected blocks
+ Support a few Iceman functions
+ Fix some bugs
### V0.1.1
+ Complete Mifare module(support simulate and sniff)
### V0.1
+ Able to deal with Mifare card and related files
### V0.0.1
+ a dumb version with a useless GUI and a serial choose box.
+8
View File
@@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/config">
<file>config_official.json</file>
<file>config_rrgv4.13441.json</file>
<file>config_rrgv4.15864.json</file>
<file>config_rrgv4.16717.json</file>
</qresource>
</RCC>
+41 -3
View File
@@ -1,5 +1,5 @@
{ {
"//": "Based on Proxmark3 official repo v3.1.0, commit 6116334", "//": "Based on Proxmark3 official repo v3.1.0, commit 6116334485",
"//": "You can change this file if the command format of client changes", "//": "You can change this file if the command format of client changes",
"mifare classic": { "mifare classic": {
"nested": { "nested": {
@@ -10,6 +10,13 @@
"2k": "2", "2k": "2",
"4k": "4" "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 pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2, "key A index": 2,
"key B index": 4 "key B index": 4
@@ -22,6 +29,15 @@
"2k": "2", "2k": "2",
"4k": "4" "4k": "4"
}, },
"//": "|---|----------------|----------------| ",
"//": "|sec|key A |key B | ",
"//": "|---|----------------|----------------| ",
"//": "|000| ffffffffffff | ffffffffffff | ",
"//": "......",
"//": "|004| ? | ? | ",
"//": "......",
"//": "|---|----------------|----------------| ",
"//": " ",
"key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|", "key pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2, "key A index": 2,
"key B index": 3 "key B index": 3
@@ -39,10 +55,22 @@
"cmd": "hf list mf" "cmd": "hf list mf"
}, },
"dump": { "dump": {
"cmd": "hf mf dump" "cmd": "hf mf dump <card type>",
"card type": {
"mini": "0",
"1k": "1",
"2k": "2",
"4k": "4"
}
}, },
"restore": { "restore": {
"cmd": "hf mf restore" "cmd": "hf mf restore <card type>",
"card type": {
"mini": "0",
"1k": "1",
"2k": "2",
"4k": "4"
}
}, },
"emulator wipe": { "emulator wipe": {
"cmd": "hf mf eclr" "cmd": "hf mf eclr"
@@ -191,5 +219,15 @@
"cmd": "lf config q <divisor> b <bits per sample> d <decimation> a <averaging> t <trigger threshold> s <samples to skip>", "cmd": "lf config q <divisor> b <bits per sample> d <decimation> a <averaging> t <trigger threshold> s <samples to skip>",
"divisor cmd": "hw setlfdivisor <divisor>" "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"
}
} }
} }
@@ -1,5 +1,5 @@
{ {
"//": "Based on Proxmark3 rrg repo v4.13441, commit 35ddebc", "//": "Based on Proxmark3 rrg repo v4.13441, commit 35ddebc03c",
"//": "You can change this file if the command format of client changes", "//": "You can change this file if the command format of client changes",
"mifare classic": { "mifare classic": {
"nested": { "nested": {
@@ -15,6 +15,13 @@
"A": "a", "A": "a",
"B": "b" "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 pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2, "key A index": 2,
"key B index": 4 "key B index": 4
@@ -27,12 +34,22 @@
"2k": "2k", "2k": "2k",
"4k": "4k" "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 pattern": "\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|",
"key A index": 2, "key A index": 2,
"key B index": 4 "key B index": 4
}, },
"info": { "info": {
"cmd": "hf 14a info" "cmd": "hf 14a info -nsv",
"basic cmd": "hf 14a info"
}, },
"sniff": { "sniff": {
"cmd": "hf sniff" "cmd": "hf sniff"
@@ -44,10 +61,22 @@
"cmd": "trace list -t mf" "cmd": "trace list -t mf"
}, },
"dump": { "dump": {
"cmd": "hf mf dump" "cmd": "hf mf dump --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
}
}, },
"restore": { "restore": {
"cmd": "hf mf restore" "cmd": "hf mf restore --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
}
}, },
"emulator wipe": { "emulator wipe": {
"cmd": "hf mf eclr" "cmd": "hf mf eclr"
@@ -199,5 +228,15 @@
"cmd": "lf config --divisor <divisor> --bps <bits per sample> --dec <decimation> --avg <averaging> --trig <trigger threshold> --skip <samples to skip>", "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>" "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": ""
}
} }
} }
+242
View File
@@ -0,0 +1,242 @@
{
"//": "Based on Proxmark3 rrg repo v4.15864, commit 1f75adcf6d",
"//": "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 -nsv",
"basic 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> --force",
"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": ""
}
}
}
+244
View File
@@ -0,0 +1,244 @@
{
"//": "Based on Proxmark3 rrg repo v4.16717, commit adfebd6510",
"//": "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 -nsv",
"basic 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> --force",
"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>",
"path cmd":"prefs show",
"path pattern":"trace save path\\.+\\s*(.+)$"
},
"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> --force",
"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": ""
}
}
}
+5
View File
@@ -0,0 +1,5 @@
/V*-*
/V*-*/
/32/
/64/
/client/
+3
View File
@@ -0,0 +1,3 @@
# Deploy helper
Just for generating Github release
Useless for general users
+151
View File
@@ -0,0 +1,151 @@
import os, sys, shutil
from win32api import GetFileVersionInfo
from json import load
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,
)
except Exception:
print("Cannot get version number of", fname)
return version
os.chdir(sys.path[0])
print("Current Directory:", os.getcwd())
targetName = os.path.abspath(os.getcwd()).split("\\")[-2]
print("Target Name", targetName)
src32Dir = ""
src64Dir = ""
dirList = os.listdir("../")
for i in dirList:
if not os.path.isdir("../" + i):
continue
if not i.startswith("build"):
continue
if i.endswith("32_bit-Release"):
src32Dir = "../" + i
elif i.endswith("64_bit-Release"):
src64Dir = "../" + i
src32Path = src32Dir + "/release/" + targetName + ".exe"
src64Path = src64Dir + "/release/" + targetName + ".exe"
print("Target Files:")
print(src32Path)
print(src64Path)
ver32 = getPEVersion(src32Path)
ver64 = getPEVersion(src64Path)
print("Versions:")
print("win32:", ver32)
print("win64:", ver64)
if ver32 != ver64:
print("WARNING!")
print("Version names are not the same!")
dst32Dir = "./" + ver32 + "-win32"
dst64Dir = "./" + ver64 + "-win64"
dst32Path = dst32Dir + "/" + targetName + ".exe"
dst64Path = dst64Dir + "/" + targetName + ".exe"
if os.path.exists(dst32Dir) and os.path.exists(dst32Path):
print(dst32Path, "exists, replacing...")
os.remove(dst32Path)
elif not os.path.exists(dst32Dir):
print(dst32Dir, "doesn't exist, creating...")
shutil.copytree("./32", dst32Dir)
shutil.copyfile(src32Path, dst32Path)
compressDirList.append(dst32Dir)
if os.path.exists(dst64Dir) and os.path.exists(dst64Path):
print(dst64Path, "exists, replacing...")
os.remove(dst64Path)
elif not os.path.exists(dst64Dir):
print(dst64Dir, "doesn't exist, creating...")
shutil.copytree("./64", dst64Dir)
shutil.copyfile(src64Path, dst64Path)
compressDirList.append(dst64Dir)
# TODO: GUI+client
clientList = [
"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
clientSrcDir = "./client/" + clientName
clientDstDir = "./" + ver64 + "-win64-" + clientName
clientDstGUIDir = clientDstDir + "/GUI"
if os.path.exists(clientDstDir) and os.path.exists(clientDstGUIDir):
print(clientDstGUIDir, "exists, replacing...")
shutil.rmtree(clientDstGUIDir)
elif not os.path.exists(clientDstDir):
print(clientDstDir, "doesn't exist, creating...")
shutil.copytree(clientSrcDir, clientDstDir)
shutil.copytree(dst64Dir, clientDstGUIDir)
if "official" in clientName:
shutil.copyfile(
"./client/GUIsettings_Official.ini", clientDstGUIDir + "/GUIsettings.ini"
)
elif "rrg" in clientName:
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:
generateClient(cl)
use7z = input("Compress?(y/N)")
if fullmatch("yes|y", use7z, IGNORECASE):
print(compressDirList)
for it in compressDirList:
archivePath = it + ".7z"
if os.path.exists(archivePath):
print(archivePath, "exists, replacing...")
os.remove(archivePath)
os.system("7z a -t7z -mmt8 -mx9 " + archivePath + " " + it)
+88
View File
@@ -0,0 +1,88 @@
# 更新日志
[English](../../CHANGELOG.md)
### V0.2.8
+ 支持冰人版客户端 v4.16717
+ 修复若干Bug
+ 便于在不同版本客户端之间切换
+ 支持蓝牙及TCP连接
### V0.2.7
+ 修复使用冰人版v4.15864时无法写入块0的问题
+ 默认关闭Linux/macOS系统下对PM3硬件断连的检测
+ 修复配置文件中的小Bug
+ 修复访问控制位解码器
+ 在访问控制位解码器中显示更多细节
+ 添加暗黑主题(源于https://github.com/ColinDuquesnoy/QDarkStyleSheet)
+ 支持自定义主题,透明度,字体
+ 修复若干翻译问题
### 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)
### V0.2.4
+ 复制EM410x卡(一种常见的低频ID卡)
### V0.2.3
+ 修复 [#27](https://github.com/wh201906/Proxmark3GUI/issues/27)
+ 尝试支持中文启动路径
### V0.2.2
+ 从外部文件加载客户端命令格式
+ 修复 [#20](https://github.com/wh201906/Proxmark3GUI/issues/20), [#21](https://github.com/wh201906/Proxmark3GUI/issues/21), [#22](https://github.com/wh201906/Proxmark3GUI/issues/22)
+ 兼容冰人版客户端 v4.13441
### V0.2.1
+ 优化MIFARE Classic读卡逻辑
+ 修复 [#16](https://github.com/wh201906/Proxmark3GUI/issues/16) (配合新版RRG固件时无法读取扇区数据)
+ 修复 [#15](https://github.com/wh201906/Proxmark3GUI/issues/15) (路径中支持空格)
### V0.2
+ 使用浮动窗口,界面配置更加灵活
+ 支持部分低频命令
+ 修复原始命令选项卡中的一个Bug
### V0.1.4
+ 优化性能
+ 优化用户界面
+ 自动搜索可用端口
+ 支持高分屏
+ 可通过外部脚本配置环境变量
(在客户端需要配置环境变量时很有用)
+ 全功能兼容冰人版(在v4.9237上测试通过)
+ 支持指定客户端工作路径
+ 修复部分bug
### V0.1.3
+ 修复访问控制位解码器
+ 写多个块时显示写入结果
### V0.1.2
+ 优化读卡逻辑
+ UI自定义
+ 自动保存客户端路径
+ 添加访问控制位解码器(也可用于自己构造访问控制位)(有bug,请使用V0.1.3或更高版本)
+ 支持仅读写选中块
+ 支持部分冰人功能
+ 修复部分bug
### V0.1.1
+ 完成整个Mifare模块(支持模拟卡和嗅探功能)
### V0.1
+ 支持处理Mifare卡片及相关数据文件
### V0.0.1
+ 一个带串口选择框的实验版本
+50 -76
View File
@@ -1,7 +1,10 @@
# Proxmark3GUI # Proxmark3GUI
![downloads](https://img.shields.io/github/downloads/wh201906/Proxmark3GUI/total) [![downloads](https://img.shields.io/github/downloads/wh201906/Proxmark3GUI/total?label=GitHub%E4%B8%8B%E8%BD%BD%E9%87%8F)](https://github.com/wh201906/Proxmark3GUI/releases)
[![downloads](https://img.shields.io/sourceforge/dt/proxmark3gui.svg?label=SourceForge%E4%B8%8B%E8%BD%BD%E9%87%8F)](https://sourceforge.net/projects/proxmark3gui/)
一个自制的[Proxmark3](https://github.com/Proxmark/proxmark3) GUI,可在Windows/Linux系统下运行 一个自制的[Proxmark3](https://github.com/Proxmark/proxmark3) GUI,可在Windows/Linux/macOS系统下运行,支持[官方版](https://github.com/Proxmark/proxmark3)/[冰人版](https://github.com/RfidResearchGroup/proxmark3)客户端和固件
(目前[官方版](https://github.com/Proxmark/proxmark3)已停更超过一年,推荐使用[冰人版](https://github.com/RfidResearchGroup/proxmark3)固件和客户端)
[English](../../README.md) [English](../../README.md)
@@ -28,13 +31,7 @@
## 预览图 ## 预览图
![preview](preview_zh_CN.png) ![preview](preview_zh_CN.png)
[更多预览](../preview/previews.md) [更多预览](../preview/previews.md)
***
## 关于冰人版
[冰人版](https://github.com/RfidResearchGroup/proxmark3)(Iceman/RRG)的客户端和固件更新更为激进,相比官方版具有更多的功能
此GUI所有功能均兼容冰人版(在v4.13441上测试通过)
*** ***
@@ -47,77 +44,54 @@ release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客
*** ***
## 在Linux系统下编译 ## 下载Windows版本
[release](https://github.com/wh201906/Proxmark3GUI/releases) 页面当中包含了编译好的Windows程序,解压后即可使用
`Vx.x.x-win64.7z`是不带客户端的纯GUI程序,可配合已有的客户端使用
`Vx.x.x-win64-xxxxxxx.7z`包含了对应的客户端,打开`Vx.x.x-win64-xxxxxxx\GUI\Proxmark3GUI.exe`即可使用
cd ~ SourceForge平台上也可下载
sudo apt-get update [![Download Proxmark3GUI](https://a.fsdn.com/con/app/sf-download-button)](https://sourceforge.net/projects/proxmark3gui/files/latest/download)
sudo apt-get install qt5-default libqt5serialport5 libqt5serialport5-dev
git clone https://github.com/wh201906/Proxmark3GUI.git --depth=1 ## 在Linux系统下编译
cd Proxmark3GUI ```bash
mkdir build cd ~
cd build # sudo add-apt-repository universe
qmake ../ sudo apt-get update
make # sudo apt-get install git build-essential
make clean sudo apt-get install qtbase5-dev qt5-qmake libqt5serialport5-dev
cp -r ../lang ./ git clone https://github.com/wh201906/Proxmark3GUI.git --depth=1
cp -r ../config ./ cd Proxmark3GUI
./Proxmark3GUI mkdir build && cd build
export QT_SELECT=qt5
qmake ../src
make -j4 && make clean
./Proxmark3GUI
```
## 在macOS系统下编译
```zsh
cd ~
brew update
brew install qt@5
brew link qt5 --force
git clone https://github.com/wh201906/Proxmark3GUI.git --depth=1
cd Proxmark3GUI
mkdir build && cd build
qmake ../src
make -j4 && make clean
open Proxmark3GUI.app
```
> 为使GUI在macOS下正确连接设备,需要更改一些设置
![macOS_settings](macOS_settings.png)
*** ***
## 教程 ## 教程
[1.快速上手](../tutorial/Quickstart/quickstart_zh_CN.md) [1.快速上手](../tutorial/Quickstart/quickstart_zh_CN.md)
[2.编辑Mifare(IC)卡数据](../tutorial/Edit_Mifare_Classic_data/Edit_Mifare_Classic_data_zh_CN.md)(无需PM3硬件) [2.使用ProxSpace编译的客户端](../tutorial/Work_With_ProxSpace/work_with_proxspace_zh_CN.md)
[3.编辑Mifare(IC)卡数据](../tutorial/Edit_Mifare_Classic_data/Edit_Mifare_Classic_data_zh_CN.md)(无需PM3硬件)
*** ***
## 更新日志:
### V0.2.3 ## 更新日志
+ 修复 [#27](https://github.com/wh201906/Proxmark3GUI/issues/27) [更新日志](../CHANGELOG/CHANGELOG_zh_CN.md)
+ 尝试支持中文启动路径
### V0.2.2
+ 从外部文件加载客户端命令格式
+ 修复 [#20](https://github.com/wh201906/Proxmark3GUI/issues/20), [#21](https://github.com/wh201906/Proxmark3GUI/issues/21), [#22](https://github.com/wh201906/Proxmark3GUI/issues/22)
+ 兼容冰人版客户端 v4.13441
### V0.2.1
+ 优化MIFARE Classic读卡逻辑
+ 修复 [#16](https://github.com/wh201906/Proxmark3GUI/issues/16) (配合新版RRG固件时无法读取扇区数据)
+ 修复 [#15](https://github.com/wh201906/Proxmark3GUI/issues/15) (路径中支持空格)
### V0.2
+ 使用浮动窗口,界面配置更加灵活
+ 支持部分低频命令
+ 修复原始命令选项卡中的一个Bug
### V0.1.4
+ 优化性能
+ 优化用户界面
+ 自动搜索可用端口
+ 支持高分屏
+ 可通过外部脚本配置环境变量
(在客户端需要配置环境变量时很有用)
+ 全功能兼容冰人版(在v4.9237上测试通过)
+ 支持指定客户端工作路径
+ 修复部分bug
### V0.1.3
+ 修复访问控制位解码器
+ 写多个块时显示写入结果
### V0.1.2
+ 优化读卡逻辑
+ UI自定义
+ 自动保存客户端路径
+ 添加访问控制位解码器(也可用于自己构造访问控制位)(有bug,请使用V0.1.3或更高版本)
+ 支持仅读写选中块
+ 支持部分冰人功能
+ 修复部分bug
### V0.1.1
+ 完成整个Mifare模块(支持模拟卡和嗅探功能)
### V0.1
+ 支持处理Mifare卡片及相关数据文件
### V0.0.1
+ 一个带串口选择框的实验版本
Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

+22 -1
View File
@@ -41,5 +41,26 @@
(3) You might need to change "\<port\>" to "/dev/\<port\>" in "Settings"->"Start arguments" editbox (3) You might need to change "\<port\>" to "/dev/\<port\>" in "Settings"->"Start arguments" editbox
![](args_linux.png) ![](args_linux.png)
(4) If you are using Raspbian(Raspberry OS), you might need to check "Keep the client active even the PM3 hardware is disconnected." in the "Steeings" panel (4) If you are using Raspbian(Raspberry OS), you might need to check "Keep the client active even the PM3 hardware is disconnected." in the "Settings" panel
![](keep.png) ![](keep.png)
## About preload script
The client might refer to some environment variables to load dependencies
For example, the RRG client on Windows requires these environment variables
```
QT_PLUGIN_PATH=<client path>\libs\
QT_QPA_PLATFORM_PLUGIN_PATH=<client path>\libs\
PATH=<client path>\libs\;<client path>\libs\shell\;<old PATH variable>
MSYSTEM=MINGW64
```
So the GUI will run "\<client path\>\\setup.bat" before loading the client, which will set the environment variables to the client properly. The script will not affect the system environment variables.
The contents of setup.bat are as follows
```
@echo off
set "HOME=%~dp0"
set "QT_PLUGIN_PATH=%HOME%\libs\"
set "QT_QPA_PLATFORM_PLUGIN_PATH=%QT_PLUGIN_PATH%"
set "PATH=%QT_PLUGIN_PATH%;%QT_PLUGIN_PATH%shell\;%PATH%"
set MSYSTEM=MINGW64
```
You can write your own script by referring to it if you need other client, then input the script path in the "Preload script path" editbox.
@@ -47,3 +47,25 @@
(4) 若使用树莓派Raspbian系统且连接成功若干秒后PM3会自动断开,则需要在“设置”面板中勾选“在PM3断开后保持客户端运行” (4) 若使用树莓派Raspbian系统且连接成功若干秒后PM3会自动断开,则需要在“设置”面板中勾选“在PM3断开后保持客户端运行”
![](keep_zh_CN.png) ![](keep_zh_CN.png)
## 预加载脚本
客户端在运行时可能需要使用某些环境变量以解决依赖问题
例如,Windows平台下的冰人客户端运行时需要以下环境变量
```
QT_PLUGIN_PATH=<客户端路径>\libs\
QT_QPA_PLATFORM_PLUGIN_PATH=<客户端路径>\libs\
PATH=<客户端路径>\libs\;<客户端路径>\libs\shell\;<原PATH变量>
MSYSTEM=MINGW64
```
因此,GUI会在加载客户端之前先运行"\<客户端路径\>\\setup.bat",从而在加载客户端时使用正确的环境变量。这些设置不会影响系统环境变量,仅对客户端本身有效
setup.bat的内容如下
```
@echo off
set "HOME=%~dp0"
set "QT_PLUGIN_PATH=%HOME%\libs\"
set "QT_QPA_PLATFORM_PLUGIN_PATH=%QT_PLUGIN_PATH%"
set "PATH=%QT_PLUGIN_PATH%;%QT_PLUGIN_PATH%shell\;%PATH%"
set MSYSTEM=MINGW64
```
如果需要使用其它客户端,你可以参考此文件编写自己的脚本,然后将其填入“预加载脚本路径”当中
@@ -0,0 +1,81 @@
# Work with ProxSpace
[中文教程](work_with_proxspace_zh_CN.md)
This GUI supports clients built from ProxSpace, making it easier to use the latest client with this GUI.
## 1. Set up ProxSpace
Please refer to this tutorial to set up ProxSpace and compile Proxmark3 client:
https://github.com/Gator96100/ProxSpace/blob/HEAD/README.md
After that, you will get a folder structure like this:
```
.
├── autobuild.bat
├── msys2
│   ├── autorebase.bat
│   └── ......
├── pm3
│   └── proxmark3
│   ├── client
│   ├── ......
│   ├── pm3
│   ├── README.md
│   └── ......
├── README.md
├── runme64.bat
└── setup
└── ......
```
The proxmark3 repository is located in `./pm3/proxmark3`
## 2. Download GUI
You can download prebuilt binaries there.
[Prebuilt binaries](../../../README.md#download-binaries-for-windows)
Please download a version without the client, like `V0.2.7-win64.7z`.
After downloading, extract it to a path without non-ASCII characters and spaces. Plus, the target folder should not be the same as the proxmark3 repository.
For example, if you extract it to ./pm3/GUI/, you will get a folder structure like this:
```
.
├── autobuild.bat
├── msys2
│   ├── autorebase.bat
│   └── ......
├── pm3
│   ├── GUI
│   │   └── V0.2.7-win64
│   │   ├── plugins
│   │   ├── Proxmark3GUI.exe
│   │   └── ......
│   └── proxmark3
│   ├── client
│   ├── ......
│   ├── pm3
│   ├── README.md
│   └── ......
├── README.md
├── runme64.bat
└── setup
└── ......
```
## 3. Run the GUI in ProxSpace
Double-click `./runme64.bat` to run the ProxSpace. Now the working directory is `./pm3`.
In the terminal of ProxSpace, run `cd GUI` to go to the `./pm3/GUI`, then run `./V0.2.7-win64/Proxmark3GUI.exe` to open the GUI.
***
**Note:** You can run the GUI in your preferred folder, but please avoid running it in the same directory as the GUI itself, otherwise it will cause errors when loading the client.
Using the directory structure above as an example, you can first run `cd /pm3` to set the working directory to `/pm3`, then run `./V0.2.7-win64/Proxmark3GUI.exe` to open the GUI.
However, you should not first run `cd /pm3/GUI/V0.2.7-win64` and then run `./Proxmark3GUI.exe`.
## 4. Connect to the device in GUI
## Specify the Client Path
Using the directory structure above as an example, assuming the current working directory is `./pm3/GUI`, and the client path is `./pm3/proxmark3/client/proxmark3.exe`, you need to enter `../proxmark3/client/proxmark3.exe` in the `Client Path`.
## Clear the Preload Script Path
The GUI is launched in ProxSpace so it includes the necessary environment variables for the client, there is no need to use any preload script.
## Select the Config File
Depending on the client version, you need to select the corresponding config file. For example, select `config_official.json` for the official client, and select `config_rrgv4.15864.json` for the rrg version v4.15864. If your client version is not listed, try selecting the config file with a similar version number.
## Connect to the Device
Select the port number of the PM3 hardware, then click `Connect`.
@@ -0,0 +1,77 @@
# 使用ProxSpace编译的客户端
[English](work_with_proxspace.md)
此GUI可以和ProxSpace编译出来的客户端配合运行,满足一部分用户使用最新版客户端的需求
## 1. 搭建ProxSpace环境
请参考此教程搭建ProxSpace环境并编译proxmark3客户端:
https://github.com/Gator96100/ProxSpace/blob/HEAD/README.md
搭建完成后,你将会获得如下的目录结构:
```
.
├── autobuild.bat
├── msys2
│   ├── autorebase.bat
│   └── ......
├── pm3
│   └── proxmark3
│   ├── client
│   ├── ......
│   ├── pm3
│   ├── README.md
│   └── ......
├── README.md
├── runme64.bat
└── setup
└── ......
```
其中proxmark3仓库位于 `./pm3/proxmark3`
## 2. 下载GUI
你可以在此处下载编译好的客户端
[预编译客户端](../../README/README_zh_CN.md#关于预编译windows客户端)
下载时请选择不含客户端的版本,例如`V0.2.7-win64.7z`
下载后请将其解压到不含中文字符和空格的路径中,同时要确保GUI文件和proxmark3仓库不位于同一文件夹下
以解压到`./pm3/GUI/`为例,你将会获得如下的目录结构
```
.
├── autobuild.bat
├── msys2
│   ├── autorebase.bat
│   └── ......
├── pm3
│   ├── GUI
│   │   └── V0.2.7-win64
│   │   ├── plugins
│   │   ├── Proxmark3GUI.exe
│   │   └── ......
│   └── proxmark3
│   ├── client
│   ├── ......
│   ├── pm3
│   ├── README.md
│   └── ......
├── README.md
├── runme64.bat
└── setup
└── ......
```
## 3. 从ProxSpace运行GUI
双击`./runme64.bat`运行ProxSpace环境,此时工作目录位于`./pm3`
在新弹出的终端中运行`cd GUI`来到`./pm3/GUI/`目录下,然后运行`./V0.2.7-win64/Proxmark3GUI.exe`,此时的GUI将会包含客户端运行所需要的所有环境变量
***
**请注意**,你可以在你喜欢的工作目录下运行GUI,但请不要在GUI文件所在目录下运行,否则加载客户端时会出错
以上面的目录结构为例,你可以先运行`cd /pm3`将工作目录设为`/pm3`,然后运行`./V0.2.7-win64/Proxmark3GUI.exe`来打开GUI
但是你不能先运行`cd /pm3/GUI/V0.2.7-win64`,然后运行`./Proxmark3GUI.exe`,否则之后无法正确加载客户端
## 4. 从GUI连接设备
### 填写客户端路径
以上面的目录结构为例,假设此时的工作目录为`./pm3/GUI`,而客户端路径为`./pm3/proxmark3/client/proxmark3.exe`,则需要在客户端路径里面填写`../proxmark3/client/proxmark3.exe`
### 清空预加载脚本路径
因为GUI是从ProxSpace中启动的,本身已包含客户端所需的环境变量,因此不需要使用任何预加载脚本
### 选择(客户端)配置文件
根据客户端版本的不同,你需要选择对应的配置文件。例如official版本对应`config_official.json`rrg版本号v4.15864对应`config_rrgv4.15864.json`。如果选项中没有你所使用的客户端版本,可以尝试选择版本号相近的对应配置文件
### 连接设备
在“端口”当中选择需要连接的端口号,单击“连接”即可
BIN
View File
Binary file not shown.
File diff suppressed because it is too large Load Diff
+7
View File
@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/i18n">
<file>en_US.qm</file>
<file>languages.ini</file>
<file>zh_CN.qm</file>
</qresource>
</RCC>
+3
View File
@@ -0,0 +1,3 @@
[Languages]
en_US=English
zh_CN=简体中文
Binary file not shown.
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
-3
View File
@@ -1,3 +0,0 @@
[Languages]
en_US=English
zh_CN=简体中文
-63
View File
@@ -1,63 +0,0 @@
#include "ui/mainwindow.h"
#include <QApplication>
#include <QSettings>
#include <QTranslator>
#include <QMessageBox>
#include <QTextCodec>
#include <QDir>
int main(int argc, char *argv[])
{
// A trick to handle non-ascii path
// The application cannot find the plugins when the path contains non ascii characters.
// However, the plugins will be load after creating MainWindow(or QApplication?).
// QDir will handle the path correctly.
QDir* pluginDir = new QDir;
if(pluginDir->cd("plugins")) // has plugins folder
{
qputenv("QT_PLUGIN_PATH", pluginDir->absolutePath().toLocal8Bit());
}
delete pluginDir;
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QDir *langPath = new QDir();
QApplication a(argc, argv);
MainWindow w;
QSettings* settings = new QSettings("GUIsettings.ini", QSettings::IniFormat);
settings->setIniCodec("UTF-8");
settings->beginGroup("lang");
QString currLang = settings->value("language", "").toString();
settings->endGroup();
if(currLang == "")
{
if(Util::chooseLanguage(settings, &w))
{
settings->beginGroup("lang");
currLang = settings->value("language", "").toString();
settings->endGroup();
}
else
currLang = "en_US";
}
currLang += ".qm";
langPath->cd("lang");
QTranslator* translator = new QTranslator(&w);
if(translator->load(currLang, langPath->absolutePath()))
{
a.installTranslator(translator);
}
else
{
QMessageBox::information(&w, "Error", "Can't load " + currLang + " as translation file.");
}
delete settings;
delete langPath;
w.initUI();
w.show();
return a.exec();
}
+72
View File
@@ -0,0 +1,72 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe
+13 -4
View File
@@ -22,6 +22,7 @@ SOURCES += \
common/util.cpp \ common/util.cpp \
module/lf.cpp \ module/lf.cpp \
module/mifare.cpp \ module/mifare.cpp \
module/t55xxtab.cpp \
ui/mf_trailerdecoderdialog.cpp \ ui/mf_trailerdecoderdialog.cpp \
ui/mf_sim_simdialog.cpp \ ui/mf_sim_simdialog.cpp \
ui/mf_uid_parameterdialog.cpp \ ui/mf_uid_parameterdialog.cpp \
@@ -34,6 +35,7 @@ HEADERS += \
common/util.h \ common/util.h \
module/lf.h \ module/lf.h \
module/mifare.h \ module/mifare.h \
module/t55xxtab.h \
ui/mf_trailerdecoderdialog.h \ ui/mf_trailerdecoderdialog.h \
ui/mf_sim_simdialog.h \ ui/mf_sim_simdialog.h \
ui/mf_uid_parameterdialog.h \ ui/mf_uid_parameterdialog.h \
@@ -41,6 +43,7 @@ HEADERS += \
ui/mf_attack_hardnesteddialog.h \ ui/mf_attack_hardnesteddialog.h \
FORMS += \ FORMS += \
ui/t55xxtab.ui \
ui/mf_trailerdecoderdialog.ui \ ui/mf_trailerdecoderdialog.ui \
ui/mf_sim_simdialog.ui \ ui/mf_sim_simdialog.ui \
ui/mf_uid_parameterdialog.ui \ ui/mf_uid_parameterdialog.ui \
@@ -48,15 +51,21 @@ FORMS += \
ui/mf_attack_hardnesteddialog.ui ui/mf_attack_hardnesteddialog.ui
TRANSLATIONS += \ TRANSLATIONS += \
lang/zh_CN.ts \ ../i18n/zh_CN.ts \
lang/en_US.ts ../i18n/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.2.3 VERSION = 0.2.8
QMAKE_TARGET_PRODUCT = "Proxmark3GUI" QMAKE_TARGET_PRODUCT = "Proxmark3GUI"
QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI" QMAKE_TARGET_DESCRIPTION = "A cross-platform GUI for Proxmark3 client"
QMAKE_TARGET_COMPANY = "wh201906" QMAKE_TARGET_COMPANY = "wh201906"
RESOURCES += \
../i18n/language.qrc \
../config/config.qrc \
qdarkstyle/dark/darkstyle.qrc \
qdarkstyle/light/lightstyle.qrc
@@ -13,6 +13,8 @@ PM3Process::PM3Process(QThread* thread, QObject* parent): QProcess(parent)
connect(serialListener, &QTimer::timeout, this, &PM3Process::onTimeout); connect(serialListener, &QTimer::timeout, this, &PM3Process::onTimeout);
connect(this, &PM3Process::readyRead, this, &PM3Process::onReadyRead); connect(this, &PM3Process::readyRead, this, &PM3Process::onReadyRead);
portInfo = nullptr; portInfo = nullptr;
qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError");
} }
void PM3Process::connectPM3(const QString& path, const QStringList args) void PM3Process::connectPM3(const QString& path, const QStringList args)
@@ -26,31 +28,32 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
currArgs = args; currArgs = args;
// using "-f" option to make the client output flushed after every print. // 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)) if(waitForStarted(10000))
{ {
waitForReadyRead(10000); waitForReadyRead(10000);
setRequiringOutput(false); setRequiringOutput(false);
result = *requiredOutput; result = *requiredOutput;
if(result.indexOf("[=]") != -1) // Workaround for wayland system, e.g. Ubuntu 22.04
// The issue is that the warning is read and nothing else, hence the process is killed.
if(result.contains("Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome. Use QT_QPA_PLATFORM=wayland to run on Wayland anyway."))
{
setRequiringOutput(true);
readWaitForConnection(&result);
}
if(result.contains("[=]"))
{ {
clientType = Util::CLIENTTYPE_ICEMAN; clientType = Util::CLIENTTYPE_ICEMAN;
setRequiringOutput(true); setRequiringOutput(true);
write("hw version\n"); write("hw version\n");
for(int i = 0; i < 50; i++) readWaitForConnection(&result);
{
waitForReadyRead(200);
result += *requiredOutput;
if(result.indexOf("os: ") != -1)
break;
}
setRequiringOutput(false);
} }
else else
{ {
clientType = Util::CLIENTTYPE_OFFICIAL; clientType = Util::CLIENTTYPE_OFFICIAL;
} }
if(result.indexOf("os: ") != -1) // make sure the PM3 is connected if(result.contains("os: ")) // make sure the PM3 is connected
{ {
emit changeClientType(clientType); emit changeClientType(clientType);
result = result.mid(result.indexOf("os: ")); result = result.mid(result.indexOf("os: "));
@@ -59,8 +62,26 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
emit PM3StatedChanged(true, result); emit PM3StatedChanged(true, result);
} }
else else
{
qDebug() << "unexpected output:" << (result.isEmpty() ? "(empty)" : result);
emit HWConnectFailed();
kill(); kill();
} }
}
setRequiringOutput(false);
}
void PM3Process::readWaitForConnection(QString *result)
{
for(int i = 0; i < 50; i++)
{
waitForReadyRead(200);
(*result) += *requiredOutput;
if(result->contains("os: "))
break;
}
setRequiringOutput(false);
} }
void PM3Process::reconnectPM3() void PM3Process::reconnectPM3()
@@ -38,6 +38,7 @@ private:
bool isRequiringOutput; bool isRequiringOutput;
QString* requiredOutput; // It only works in this class now QString* requiredOutput; // It only works in this class now
void setRequiringOutput(bool st);// It only works in this class now void setRequiringOutput(bool st);// It only works in this class now
void readWaitForConnection(QString *result);
QTimer* serialListener; QTimer* serialListener;
QSerialPortInfo* portInfo; QSerialPortInfo* portInfo;
QString currPath; QString currPath;
@@ -48,6 +49,7 @@ signals:
void PM3StatedChanged(bool st, const QString& info = ""); void PM3StatedChanged(bool st, const QString& info = "");
void newOutput(const QString& output); void newOutput(const QString& output);
void changeClientType(Util::ClientType); void changeClientType(Util::ClientType);
void HWConnectFailed();
}; };
#endif // PM3PROCESS_H #endif // PM3PROCESS_H
+25 -7
View File
@@ -78,7 +78,13 @@ QString Util::execCMDWithOutput(const QString& cmd, ReturnTrigger trigger, bool
} }
} }
isRequiringOutput = false; isRequiringOutput = false;
return (isResultFound || trigger.expectedOutputs.isEmpty() || rawOutput ? *requiredOutput : "");
// For functions without expected outputs in the return trigger, the result is the raw output.
// For functions with expected outputs in the return trigger,
// if rawOutput=true, the result is the raw output,
// otherwise, if the raw output contains one of the expected outputs, the result is the raw output,
// otherwise, the result is empty(as a failed flag).
return (trigger.expectedOutputs.isEmpty() || isResultFound || rawOutput ? *requiredOutput : "");
} }
void Util::delay(unsigned int msec) void Util::delay(unsigned int msec)
@@ -106,24 +112,36 @@ void Util::setRunningState(bool st)
bool Util::chooseLanguage(QSettings* guiSettings, QMainWindow* window) bool Util::chooseLanguage(QSettings* guiSettings, QMainWindow* window)
{ {
// make sure the GUISettings is not in any group // make sure the GUISettings is not in any group
QSettings* langSettings = new QSettings("lang/languages.ini", QSettings::IniFormat); QSettings* langSettings = new QSettings(":/i18n/languages.ini", QSettings::IniFormat);
QMap<QString, QString> langMap; QMap<QString, QString> langMap;
langSettings->setIniCodec("UTF-8"); langSettings->setIniCodec("UTF-8");
langSettings->beginGroup("Languages"); langSettings->beginGroup("Languages");
QStringList langList = langSettings->allKeys(); QStringList langList = langSettings->allKeys();
for(int i = 0; i < langList.size(); i++) for(int i = 0; i < langList.size(); i++)
langMap.insert(langSettings->value(langList[i]).toString(), langList[i]); langMap.insert(langSettings->value(langList[i]).toString(), langList[i]);
langMap.insert(tr("Load from external file"), "(ext)");
langSettings->endGroup(); langSettings->endGroup();
delete langSettings; delete langSettings;
bool isOk = false; bool isOk = false;
QString selectedText = QInputDialog::getItem(window, "", "Choose a language:", langMap.keys(), 0, false, &isOk); QString selectedText = QInputDialog::getItem(window, "", tr("Choose a language:"), langMap.keys(), 0, false, &isOk);
if(isOk) if(!isOk)
return false;
if(langMap[selectedText] == "(ext)")
{ {
guiSettings->beginGroup("lang"); QString extPath = QFileDialog::getOpenFileName(window, tr("Select the translation file:"));
guiSettings->setValue("language", langMap[selectedText]); if(extPath.isEmpty())
return false;
guiSettings->beginGroup("language");
guiSettings->setValue("extPath", extPath);
guiSettings->endGroup();
}
guiSettings->beginGroup("language");
guiSettings->setValue("name", langMap[selectedText]);
guiSettings->endGroup(); guiSettings->endGroup();
guiSettings->sync(); guiSettings->sync();
}
return isOk; return isOk;
} }
+2 -1
View File
@@ -13,6 +13,7 @@
#include <QSettings> #include <QSettings>
#include <QMainWindow> #include <QMainWindow>
#include <QInputDialog> #include <QInputDialog>
#include <QFileDialog>
#include <QDockWidget> #include <QDockWidget>
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
@@ -58,7 +59,7 @@ public:
static ClientType getClientType(); static ClientType getClientType();
static int rawTabIndex; static int rawTabIndex;
static QDockWidget* rawDockPtr; static QDockWidget* rawDockPtr;
static bool chooseLanguage(QSettings *guiSettings, QMainWindow *window); static bool chooseLanguage(QSettings *guiSettings, QMainWindow *window = nullptr);
public slots: public slots:
void processOutput(const QString& output); void processOutput(const QString& output);
static void setClientType(Util::ClientType clientType); static void setClientType(Util::ClientType clientType);
+97
View File
@@ -0,0 +1,97 @@
#include "ui/mainwindow.h"
#include <QApplication>
#include <QSettings>
#include <QTranslator>
#include <QMessageBox>
#include <QTextCodec>
#include <QDir>
int main(int argc, char *argv[])
{
// A trick to handle non-ascii path
// The application cannot find the plugins when the path contains non ascii characters.
// However, the plugins will be load after creating MainWindow(or QApplication?).
// QDir will handle the path correctly.
QDir* pluginDir = new QDir;
if(pluginDir->cd("plugins")) // has plugins folder
{
qputenv("QT_PLUGIN_PATH", pluginDir->absolutePath().toLocal8Bit());
}
delete pluginDir;
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
QApplication a(argc, argv);
QSettings* settings = new QSettings("GUIsettings.ini", QSettings::IniFormat);
settings->setIniCodec("UTF-8");
settings->beginGroup("language");
QString languageFile = settings->value("extPath").toString();
QString languageName = settings->value("name").toString();
settings->endGroup();
settings->beginGroup("UI");
QString theme = settings->value("Theme_Name").toString();
settings->endGroup();
if(languageName == "")
{
if(Util::chooseLanguage(settings))
{
settings->beginGroup("language");
languageName = settings->value("name").toString();
settings->endGroup();
}
else
languageName = "en_US";
}
if(languageName == "(ext)")
{
settings->beginGroup("language");
languageFile = settings->value("extPath").toString();
settings->endGroup();
}
else
languageFile = ":/i18n/" + languageName + ".qm";
// Note that the translator must be created before the application's widgets.
QTranslator* translator = new QTranslator();
if(translator->load(languageFile))
a.installTranslator(translator);
else
QMessageBox::information(nullptr, "Error", "Can't load " + languageFile + " as translation file.");
QFile* themeFile = new QFile();
QTextStream* themeStream = new QTextStream();
QString qssString = a.styleSheet(); // default behavior
if(theme == "(none)")
;
else if(theme == "qdss_dark")
{
themeFile->setFileName(":/qdarkstyle/dark/darkstyle.qss");
themeFile->open(QFile::ReadOnly | QFile::Text);
themeStream->setDevice(themeFile);
qssString = themeStream->readAll();
}
else if(theme == "qdss_light")
{
themeFile->setFileName(":/qdarkstyle/light/lightstyle.qss");
themeFile->open(QFile::ReadOnly | QFile::Text);
themeStream->setDevice(themeFile);
qssString = themeStream->readAll();
}
a.setStyleSheet(qssString);
delete themeFile;
delete themeStream;
themeFile = nullptr;
themeStream = nullptr;
delete settings;
settings = nullptr;
MainWindow w;
w.initUI();
w.show();
return a.exec();
}
+5 -3
View File
@@ -81,8 +81,10 @@ void LF::getLFConfig()
QVariantMap config = configMap["get config"].toMap(); QVariantMap config = configMap["get config"].toMap();
QString cmd = config["cmd"].toString(); QString cmd = config["cmd"].toString();
result = util->execCMDWithOutput(cmd, 400); result = util->execCMDWithOutput(cmd, 400);
start = result.indexOf(config["field start"].toString()); reMatch = QRegularExpression(config["field start"].toString(), QRegularExpression::MultilineOption).match(result);
end = result.indexOf(config["field end"].toString()); 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); result = result.mid(start, end - start);
#if (QT_VERSION <= QT_VERSION_CHECK(5,14,0)) #if (QT_VERSION <= QT_VERSION_CHECK(5,14,0))
resultList = result.split("\n", QString::SkipEmptyParts); resultList = result.split("\n", QString::SkipEmptyParts);
@@ -149,10 +151,10 @@ void LF::syncWithUI()
ui->LF_LFConf_averagingBox->setChecked(currLFConfig.averaging); ui->LF_LFConf_averagingBox->setChecked(currLFConfig.averaging);
ui->LF_LFConf_thresholdBox->setValue(currLFConfig.triggerThreshold); ui->LF_LFConf_thresholdBox->setValue(currLFConfig.triggerThreshold);
ui->LF_LFConf_skipsBox->setValue(currLFConfig.samplesToSkip); ui->LF_LFConf_skipsBox->setValue(currLFConfig.samplesToSkip);
emit LFfreqConfChanged(currLFConfig.divisor, false);
} }
void LF::setConfigMap(const QVariantMap& configMap) void LF::setConfigMap(const QVariantMap& configMap)
{ {
this->configMap = configMap; this->configMap = configMap;
qDebug() << configMap;
} }
+1 -1
View File
@@ -53,7 +53,7 @@ private:
void syncWithUI(); void syncWithUI();
bool getLFConfig_helper(const QVariantMap& map, QString& str, int* result); bool getLFConfig_helper(const QVariantMap& map, QString& str, int* result);
signals: signals:
void LFfreqConfChanged(int divisor, bool isCustomized);
}; };
#endif // LF_H #endif // LF_H
+77 -38
View File
@@ -40,36 +40,39 @@ const Mifare::CardType Mifare::card_4k =
const Mifare::AccessType Mifare::dataCondition[8][4] = const Mifare::AccessType Mifare::dataCondition[8][4] =
{ {
{ACC_KEY_AB, ACC_KEY_AB, ACC_KEY_AB, ACC_KEY_AB}, // {read, write, increment, decrement/transfer/restore}
{ACC_KEY_AB, ACC_KEY_B, ACC_NEVER, ACC_NEVER}, {ACC_KEY_AB, ACC_KEY_AB, ACC_KEY_AB, ACC_KEY_AB}, // {C3x, C2x, C1x} = 0
{ACC_KEY_AB, ACC_NEVER, ACC_NEVER, ACC_NEVER}, {ACC_KEY_AB, ACC_KEY_B, ACC_NEVER, ACC_NEVER}, // {C3x, C2x, C1x} = 1
{ACC_KEY_AB, ACC_KEY_B, ACC_KEY_B, ACC_KEY_AB}, {ACC_KEY_AB, ACC_NEVER, ACC_NEVER, ACC_NEVER}, // {C3x, C2x, C1x} = 2
{ACC_KEY_AB, ACC_NEVER, ACC_NEVER, ACC_KEY_AB}, {ACC_KEY_AB, ACC_KEY_B, ACC_KEY_B, ACC_KEY_AB}, // {C3x, C2x, C1x} = 3
{ACC_KEY_B, ACC_NEVER, ACC_NEVER, ACC_NEVER}, {ACC_KEY_AB, ACC_NEVER, ACC_NEVER, ACC_KEY_AB}, // {C3x, C2x, C1x} = 4
{ACC_KEY_B, ACC_KEY_B, ACC_NEVER, ACC_NEVER}, {ACC_KEY_B, ACC_NEVER, ACC_NEVER, ACC_NEVER}, // {C3x, C2x, C1x} = 5
{ACC_NEVER, ACC_NEVER, ACC_NEVER, ACC_NEVER}, {ACC_KEY_B, ACC_KEY_B, ACC_NEVER, ACC_NEVER}, // {C3x, C2x, C1x} = 6
{ACC_NEVER, ACC_NEVER, ACC_NEVER, ACC_NEVER}, // {C3x, C2x, C1x} = 7
}; };
const Mifare::AccessType Mifare::trailerReadCondition[8][3] = const Mifare::AccessType Mifare::trailerReadCondition[8][3] =
{ {
{ACC_NEVER, ACC_KEY_A, ACC_KEY_A}, // {KEYA, Access bits, KEYB}
{ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, {ACC_NEVER, ACC_KEY_A, ACC_KEY_A}, // {C33, C23, C13} = 0
{ACC_NEVER, ACC_KEY_A, ACC_KEY_A}, {ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, // {C33, C23, C13} = 1
{ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, {ACC_NEVER, ACC_KEY_A, ACC_KEY_A}, // {C33, C23, C13} = 2
{ACC_NEVER, ACC_KEY_A, ACC_KEY_A}, {ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, // {C33, C23, C13} = 3
{ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, {ACC_NEVER, ACC_KEY_A, ACC_KEY_A}, // {C33, C23, C13} = 4
{ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, {ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, // {C33, C23, C13} = 5
{ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, {ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, // {C33, C23, C13} = 6
{ACC_NEVER, ACC_KEY_AB, ACC_NEVER}, // {C33, C23, C13} = 7
}; };
const Mifare::AccessType Mifare::trailerWriteCondition[8][3] = const Mifare::AccessType Mifare::trailerWriteCondition[8][3] =
{ {
{ACC_KEY_A, ACC_NEVER, ACC_KEY_A}, // {KEYA, Access bits, KEYB}
{ACC_KEY_B, ACC_NEVER, ACC_KEY_B}, {ACC_KEY_A, ACC_NEVER, ACC_KEY_A}, // {C33, C23, C13} = 0
{ACC_NEVER, ACC_NEVER, ACC_NEVER}, {ACC_KEY_B, ACC_NEVER, ACC_KEY_B}, // {C33, C23, C13} = 1
{ACC_NEVER, ACC_NEVER, ACC_NEVER}, {ACC_NEVER, ACC_NEVER, ACC_NEVER}, // {C33, C23, C13} = 2
{ACC_KEY_A, ACC_KEY_A, ACC_KEY_A}, {ACC_NEVER, ACC_NEVER, ACC_NEVER}, // {C33, C23, C13} = 3
{ACC_NEVER, ACC_KEY_B, ACC_NEVER}, {ACC_KEY_A, ACC_KEY_A, ACC_KEY_A}, // {C33, C23, C13} = 4
{ACC_KEY_B, ACC_KEY_B, ACC_KEY_B}, {ACC_NEVER, ACC_KEY_B, ACC_NEVER}, // {C33, C23, C13} = 5
{ACC_NEVER, ACC_NEVER, ACC_NEVER}, {ACC_KEY_B, ACC_KEY_B, ACC_KEY_B}, // {C33, C23, C13} = 6
{ACC_NEVER, ACC_NEVER, ACC_NEVER}, // {C33, C23, C13} = 7
}; };
Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent): QObject(parent) Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent): QObject(parent)
@@ -91,7 +94,6 @@ Mifare::Mifare(Ui::MainWindow *ui, Util *addr, QWidget *parent): QObject(parent)
void Mifare::setConfigMap(const QVariantMap& configMap) void Mifare::setConfigMap(const QVariantMap& configMap)
{ {
this->configMap = configMap; this->configMap = configMap;
qDebug() << configMap;
} }
QMap<QString, QString> Mifare::info(bool isRequiringOutput) QMap<QString, QString> Mifare::info(bool isRequiringOutput)
@@ -100,17 +102,22 @@ QMap<QString, QString> Mifare::info(bool isRequiringOutput)
QVariantMap config = configMap["info"].toMap(); QVariantMap config = configMap["info"].toMap();
if(isRequiringOutput) if(isRequiringOutput)
{ {
QString result = util->execCMDWithOutput(config["cmd"].toString(), 500); QString cmd = config["basic cmd"].toString();
// for official client
if(cmd.isEmpty())
cmd = config["cmd"].toString();
QString result = util->execCMDWithOutput(cmd, 500);
QStringList lineList = result.split("\n"); QStringList lineList = result.split("\n");
for(auto line = lineList.begin(); line != lineList.end(); line++) for(auto line = lineList.begin(); line != lineList.end(); line++)
{ {
if(line->contains("UID")) if(line->contains("UID"))
map["UID"] = line->replace("UID", "").replace(QRegularExpression("[^0-9a-fA-F]"), "").trimmed(); map["UID"] = line->remove("UID").remove(QRegularExpression("[^0-9a-fA-F]")).trimmed();
else if(line->contains("ATQA")) else if(line->contains("ATQA"))
map["ATQA"] = line->replace("ATQA", "").replace(QRegularExpression("[^0-9a-fA-F]"), "").trimmed(); map["ATQA"] = line->remove("ATQA").remove(QRegularExpression("[^0-9a-fA-F]")).trimmed();
else if(line->contains("SAK")) else if(line->contains("SAK"))
map["SAK"] = line->replace("SAK", "").replace(QRegularExpression("\\[.+?\\]"), "").replace(QRegularExpression("[^0-9a-fA-F]"), "").trimmed(); map["SAK"] = line->remove("SAK").remove(QRegularExpression("\\[.+?\\]")).remove(QRegularExpression("[^0-9a-fA-F]")).trimmed();
} }
} }
else else
@@ -131,7 +138,7 @@ void Mifare::chk()
QString cmd = config["cmd"].toString(); QString cmd = config["cmd"].toString();
int keyAindex = config["key A index"].toInt(); int keyAindex = config["key A index"].toInt();
int keyBindex = config["key B 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()); cmd.replace("<card type>", config["card type"].toMap()[cardType.typeText].toString());
result = util->execCMDWithOutput( result = util->execCMDWithOutput(
@@ -170,7 +177,7 @@ void Mifare::nested(bool isStaticNested)
cmd = config["cmd"].toString(); cmd = config["cmd"].toString();
int keyAindex = config["key A index"].toInt(); int keyAindex = config["key A index"].toInt();
int keyBindex = config["key B 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; QRegularExpressionMatch reMatch;
QString result; QString result;
int offset = 0; int offset = 0;
@@ -213,7 +220,7 @@ void Mifare::nested(bool isStaticNested)
} }
result = util->execCMDWithOutput( result = util->execCMDWithOutput(
cmd, 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); true);
if(result.contains("static") && !isStaticNested) if(result.contains("static") && !isStaticNested)
@@ -640,7 +647,7 @@ void Mifare::writeOne(TargetType targetType)
bool isSuccessful = _writeblk(blockId, keyType, ui->MF_RW_keyEdit->text().toUpper(), ui->MF_RW_dataEdit->text(), targetType); bool isSuccessful = _writeblk(blockId, keyType, ui->MF_RW_keyEdit->text().toUpper(), ui->MF_RW_dataEdit->text(), targetType);
if(isSuccessful) if(isSuccessful)
{ {
QMessageBox::information(parent, tr("Info"), tr("Success!")); QMessageBox::information(parent, tr("Info"), tr("Succeed!"));
} }
else else
{ {
@@ -692,10 +699,14 @@ void Mifare::writeSelected(TargetType targetType)
{ {
result = _writeblk(item, KEY_B, keyBList->at(data_b2s(item)), dataList->at(item), TARGET_MIFARE); 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); 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 else // key doesn't matter when writing to Chinese Magic Card and Emulator Memory
{ {
@@ -707,7 +718,7 @@ void Mifare::writeSelected(TargetType targetType)
} }
} }
if(failedBlocks.size() == 0) if(failedBlocks.size() == 0)
QMessageBox::information(parent, tr("Info"), tr("Successful!")); QMessageBox::information(parent, tr("Info"), tr("Succeed!"));
else else
{ {
QString suffix = ""; QString suffix = "";
@@ -744,14 +755,20 @@ void Mifare::writeSelected(TargetType targetType)
void Mifare::dump() void Mifare::dump()
{ {
QVariantMap config = configMap["dump"].toMap(); 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(); Util::gotoRawTab();
} }
void Mifare::restore() void Mifare::restore()
{ {
QVariantMap config = configMap["restore"].toMap(); 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(); Util::gotoRawTab();
} }
@@ -1303,9 +1320,13 @@ bool Mifare::data_isACBitsValid(const QString& text, QList<quint8>* returnHalfBy
QList<quint8> halfBytes; QList<quint8> halfBytes;
for(int i = 0; i < 6; i++) for(int i = 0; i < 6; i++)
{ {
// 6 7 8
// AB CD EF->
// {0xA, 0xB, 0xC, 0xD, 0xE, 0xF}
// {~C2x, ~C1x, C1x, ~C3x, C3, C2}
halfBytes.append((val >> ((5 - i) * 4)) & 0xf); halfBytes.append((val >> ((5 - i) * 4)) & 0xf);
} }
qDebug() << val; // qDebug() << val;
if((~halfBytes[0] & 0xf) == halfBytes[5] && (~halfBytes[1] & 0xf) == halfBytes[2] && (~halfBytes[3] & 0xf) == halfBytes[4]) if((~halfBytes[0] & 0xf) == halfBytes[5] && (~halfBytes[1] & 0xf) == halfBytes[2] && (~halfBytes[3] & 0xf) == halfBytes[4])
{ {
if(returnHalfBytes != nullptr) if(returnHalfBytes != nullptr)
@@ -1321,9 +1342,12 @@ QList<quint8> Mifare::data_getACBits(const QString& text) //return empty QList i
QList<quint8> halfBytes, result; QList<quint8> halfBytes, result;
if(data_isACBitsValid(text, &halfBytes)) if(data_isACBitsValid(text, &halfBytes))
{ {
// data in halfbits:
// {~C2x, ~C1x, C1x, ~C3x, C3, C2}
for(int i = 0; i < 4; i++) for(int i = 0; i < 4; i++)
{ {
result.append((((halfBytes[4] >> i) & 1) << 2) | (((halfBytes[5] >> i) & 1) << 1) | (((halfBytes[2] >> i) & 1) << 0)); result.append((((halfBytes[4] >> i) & 1) << 2) | (((halfBytes[5] >> i) & 1) << 1) | (((halfBytes[2] >> i) & 1) << 0));
// {Cx0, Cx1, Cx2, Cx3} (Cx0={C30, C20, C10})
} }
} }
return result; return result;
@@ -1351,3 +1375,18 @@ quint16 Mifare::getTrailerBlockId(quint8 sectorId, qint8 cardTypeId)
// other cardTypeId: use current cardtype(include default -1) // other cardTypeId: use current cardtype(include default -1)
return (cardType.blks[sectorId] + cardType.blk[sectorId] - 1); return (cardType.blks[sectorId] + cardType.blk[sectorId] - 1);
} }
QString Mifare::getTraceSavePath()
{
QVariantMap config = configMap["save sniff"].toMap();
QString pathCmd = config["path cmd"].toString();
QString patternText = config["path pattern"].toString();
QRegularExpression pattern = QRegularExpression(patternText, QRegularExpression::MultilineOption);
if(pathCmd.isEmpty() || patternText.isEmpty())
return QString();
QString result = util->execCMDWithOutput(pathCmd, 500);
QRegularExpressionMatch reMatch = pattern.match(result);
if(!reMatch.hasMatch())
return QString();
return reMatch.captured(1).trimmed();
}
+1
View File
@@ -115,6 +115,7 @@ public:
QString data_getUID(); QString data_getUID();
quint16 getTrailerBlockId(quint8 sectorId, qint8 cardTypeId = -1); // -1: use current cardtype quint16 getTrailerBlockId(quint8 sectorId, qint8 cardTypeId = -1); // -1: use current cardtype
void setConfigMap(const QVariantMap& configMap); void setConfigMap(const QVariantMap& configMap);
QString getTraceSavePath();
public slots: public slots:
signals: signals:
+68
View File
@@ -0,0 +1,68 @@
#include "t55xxtab.h"
#include "ui_t55xxtab.h"
T55xxTab::T55xxTab(Util *addr, QWidget *parent) :
QWidget(parent),
ui(new Ui::T55xxTab)
{
ui->setupUi(this);
util = addr;
}
T55xxTab::~T55xxTab()
{
delete ui;
}
void T55xxTab::setConfigMap(const QVariantMap &configMap)
{
this->configMap = configMap;
}
void T55xxTab::setGUIState(bool st)
{
ui->cloneGroupBox->setEnabled(st);
emit setParentGUIState(st);
}
void T55xxTab::on_Clone_EM410xReadButton_clicked()
{
setGUIState(false);
QVariantMap config = configMap["clone em410x"].toMap();
QString result;
QRegularExpressionMatch reMatch;
result = util->execCMDWithOutput(
config["read"].toString(),
Util::ReturnTrigger(6000, {config["successful read flag"].toString()}));
if(result.isEmpty())
{
setGUIState(true);
return;
}
reMatch = QRegularExpression(config["pattern"].toString()).match(result);
ui->Clone_EM410xIDEdit->setText(reMatch.captured());
setGUIState(true);
}
void T55xxTab::on_Clone_EM410xCloneButton_clicked()
{
if(ui->Clone_EM410xIDEdit->text().isEmpty())
return;
setGUIState(false);
QVariantMap config = configMap["clone em410x"].toMap();
QString cmd = config["clone cmd"].toString();
cmd.replace("<id>", ui->Clone_EM410xIDEdit->text());
if(ui->Clone_T5555Button->isChecked())
cmd.replace("<type>", config["t5555 flag"].toString());
else
cmd.replace("<type>", config["t55x7 flag"].toString());
util->execCMD(cmd);
Util::gotoRawTab();
setGUIState(true);
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef T55XXTAB_H
#define T55XXTAB_H
#include "common/util.h"
#include <QWidget>
namespace Ui
{
class T55xxTab;
}
class T55xxTab : public QWidget
{
Q_OBJECT
public:
explicit T55xxTab(Util *addr, QWidget *parent = nullptr);
~T55xxTab();
void setConfigMap(const QVariantMap& configMap);
private slots:
void on_Clone_EM410xReadButton_clicked();
void on_Clone_EM410xCloneButton_clicked();
private:
Ui::T55xxTab *ui;
Util* util;
QVariantMap configMap;
void setGUIState(bool st);
signals:
void setParentGUIState(bool st);
};
#endif // T55XXTAB_H
+1
View File
@@ -0,0 +1 @@
From commit 6ff5fdf of [QDarkStyleSheet](https://github.com/ColinDuquesnoy/QDarkStyleSheet)
+216
View File
@@ -0,0 +1,216 @@
<RCC warning="WARNING! File created programmatically. All changes made in this file will be lost!">
<qresource prefix="qss_icons/dark">
<file>rc/arrow_down.png</file>
<file>rc/arrow_down@2x.png</file>
<file>rc/arrow_down_disabled.png</file>
<file>rc/arrow_down_disabled@2x.png</file>
<file>rc/arrow_down_focus.png</file>
<file>rc/arrow_down_focus@2x.png</file>
<file>rc/arrow_down_pressed.png</file>
<file>rc/arrow_down_pressed@2x.png</file>
<file>rc/arrow_left.png</file>
<file>rc/arrow_left@2x.png</file>
<file>rc/arrow_left_disabled.png</file>
<file>rc/arrow_left_disabled@2x.png</file>
<file>rc/arrow_left_focus.png</file>
<file>rc/arrow_left_focus@2x.png</file>
<file>rc/arrow_left_pressed.png</file>
<file>rc/arrow_left_pressed@2x.png</file>
<file>rc/arrow_right.png</file>
<file>rc/arrow_right@2x.png</file>
<file>rc/arrow_right_disabled.png</file>
<file>rc/arrow_right_disabled@2x.png</file>
<file>rc/arrow_right_focus.png</file>
<file>rc/arrow_right_focus@2x.png</file>
<file>rc/arrow_right_pressed.png</file>
<file>rc/arrow_right_pressed@2x.png</file>
<file>rc/arrow_up.png</file>
<file>rc/arrow_up@2x.png</file>
<file>rc/arrow_up_disabled.png</file>
<file>rc/arrow_up_disabled@2x.png</file>
<file>rc/arrow_up_focus.png</file>
<file>rc/arrow_up_focus@2x.png</file>
<file>rc/arrow_up_pressed.png</file>
<file>rc/arrow_up_pressed@2x.png</file>
<file>rc/base_icon.png</file>
<file>rc/base_icon@2x.png</file>
<file>rc/base_icon_disabled.png</file>
<file>rc/base_icon_disabled@2x.png</file>
<file>rc/base_icon_focus.png</file>
<file>rc/base_icon_focus@2x.png</file>
<file>rc/base_icon_pressed.png</file>
<file>rc/base_icon_pressed@2x.png</file>
<file>rc/branch_closed.png</file>
<file>rc/branch_closed@2x.png</file>
<file>rc/branch_closed_disabled.png</file>
<file>rc/branch_closed_disabled@2x.png</file>
<file>rc/branch_closed_focus.png</file>
<file>rc/branch_closed_focus@2x.png</file>
<file>rc/branch_closed_pressed.png</file>
<file>rc/branch_closed_pressed@2x.png</file>
<file>rc/branch_end.png</file>
<file>rc/branch_end@2x.png</file>
<file>rc/branch_end_disabled.png</file>
<file>rc/branch_end_disabled@2x.png</file>
<file>rc/branch_end_focus.png</file>
<file>rc/branch_end_focus@2x.png</file>
<file>rc/branch_end_pressed.png</file>
<file>rc/branch_end_pressed@2x.png</file>
<file>rc/branch_line.png</file>
<file>rc/branch_line@2x.png</file>
<file>rc/branch_line_disabled.png</file>
<file>rc/branch_line_disabled@2x.png</file>
<file>rc/branch_line_focus.png</file>
<file>rc/branch_line_focus@2x.png</file>
<file>rc/branch_line_pressed.png</file>
<file>rc/branch_line_pressed@2x.png</file>
<file>rc/branch_more.png</file>
<file>rc/branch_more@2x.png</file>
<file>rc/branch_more_disabled.png</file>
<file>rc/branch_more_disabled@2x.png</file>
<file>rc/branch_more_focus.png</file>
<file>rc/branch_more_focus@2x.png</file>
<file>rc/branch_more_pressed.png</file>
<file>rc/branch_more_pressed@2x.png</file>
<file>rc/branch_open.png</file>
<file>rc/branch_open@2x.png</file>
<file>rc/branch_open_disabled.png</file>
<file>rc/branch_open_disabled@2x.png</file>
<file>rc/branch_open_focus.png</file>
<file>rc/branch_open_focus@2x.png</file>
<file>rc/branch_open_pressed.png</file>
<file>rc/branch_open_pressed@2x.png</file>
<file>rc/checkbox_checked.png</file>
<file>rc/checkbox_checked@2x.png</file>
<file>rc/checkbox_checked_disabled.png</file>
<file>rc/checkbox_checked_disabled@2x.png</file>
<file>rc/checkbox_checked_focus.png</file>
<file>rc/checkbox_checked_focus@2x.png</file>
<file>rc/checkbox_checked_pressed.png</file>
<file>rc/checkbox_checked_pressed@2x.png</file>
<file>rc/checkbox_indeterminate.png</file>
<file>rc/checkbox_indeterminate@2x.png</file>
<file>rc/checkbox_indeterminate_disabled.png</file>
<file>rc/checkbox_indeterminate_disabled@2x.png</file>
<file>rc/checkbox_indeterminate_focus.png</file>
<file>rc/checkbox_indeterminate_focus@2x.png</file>
<file>rc/checkbox_indeterminate_pressed.png</file>
<file>rc/checkbox_indeterminate_pressed@2x.png</file>
<file>rc/checkbox_unchecked.png</file>
<file>rc/checkbox_unchecked@2x.png</file>
<file>rc/checkbox_unchecked_disabled.png</file>
<file>rc/checkbox_unchecked_disabled@2x.png</file>
<file>rc/checkbox_unchecked_focus.png</file>
<file>rc/checkbox_unchecked_focus@2x.png</file>
<file>rc/checkbox_unchecked_pressed.png</file>
<file>rc/checkbox_unchecked_pressed@2x.png</file>
<file>rc/line_horizontal.png</file>
<file>rc/line_horizontal@2x.png</file>
<file>rc/line_horizontal_disabled.png</file>
<file>rc/line_horizontal_disabled@2x.png</file>
<file>rc/line_horizontal_focus.png</file>
<file>rc/line_horizontal_focus@2x.png</file>
<file>rc/line_horizontal_pressed.png</file>
<file>rc/line_horizontal_pressed@2x.png</file>
<file>rc/line_vertical.png</file>
<file>rc/line_vertical@2x.png</file>
<file>rc/line_vertical_disabled.png</file>
<file>rc/line_vertical_disabled@2x.png</file>
<file>rc/line_vertical_focus.png</file>
<file>rc/line_vertical_focus@2x.png</file>
<file>rc/line_vertical_pressed.png</file>
<file>rc/line_vertical_pressed@2x.png</file>
<file>rc/radio_checked.png</file>
<file>rc/radio_checked@2x.png</file>
<file>rc/radio_checked_disabled.png</file>
<file>rc/radio_checked_disabled@2x.png</file>
<file>rc/radio_checked_focus.png</file>
<file>rc/radio_checked_focus@2x.png</file>
<file>rc/radio_checked_pressed.png</file>
<file>rc/radio_checked_pressed@2x.png</file>
<file>rc/radio_unchecked.png</file>
<file>rc/radio_unchecked@2x.png</file>
<file>rc/radio_unchecked_disabled.png</file>
<file>rc/radio_unchecked_disabled@2x.png</file>
<file>rc/radio_unchecked_focus.png</file>
<file>rc/radio_unchecked_focus@2x.png</file>
<file>rc/radio_unchecked_pressed.png</file>
<file>rc/radio_unchecked_pressed@2x.png</file>
<file>rc/toolbar_move_horizontal.png</file>
<file>rc/toolbar_move_horizontal@2x.png</file>
<file>rc/toolbar_move_horizontal_disabled.png</file>
<file>rc/toolbar_move_horizontal_disabled@2x.png</file>
<file>rc/toolbar_move_horizontal_focus.png</file>
<file>rc/toolbar_move_horizontal_focus@2x.png</file>
<file>rc/toolbar_move_horizontal_pressed.png</file>
<file>rc/toolbar_move_horizontal_pressed@2x.png</file>
<file>rc/toolbar_move_vertical.png</file>
<file>rc/toolbar_move_vertical@2x.png</file>
<file>rc/toolbar_move_vertical_disabled.png</file>
<file>rc/toolbar_move_vertical_disabled@2x.png</file>
<file>rc/toolbar_move_vertical_focus.png</file>
<file>rc/toolbar_move_vertical_focus@2x.png</file>
<file>rc/toolbar_move_vertical_pressed.png</file>
<file>rc/toolbar_move_vertical_pressed@2x.png</file>
<file>rc/toolbar_separator_horizontal.png</file>
<file>rc/toolbar_separator_horizontal@2x.png</file>
<file>rc/toolbar_separator_horizontal_disabled.png</file>
<file>rc/toolbar_separator_horizontal_disabled@2x.png</file>
<file>rc/toolbar_separator_horizontal_focus.png</file>
<file>rc/toolbar_separator_horizontal_focus@2x.png</file>
<file>rc/toolbar_separator_horizontal_pressed.png</file>
<file>rc/toolbar_separator_horizontal_pressed@2x.png</file>
<file>rc/toolbar_separator_vertical.png</file>
<file>rc/toolbar_separator_vertical@2x.png</file>
<file>rc/toolbar_separator_vertical_disabled.png</file>
<file>rc/toolbar_separator_vertical_disabled@2x.png</file>
<file>rc/toolbar_separator_vertical_focus.png</file>
<file>rc/toolbar_separator_vertical_focus@2x.png</file>
<file>rc/toolbar_separator_vertical_pressed.png</file>
<file>rc/toolbar_separator_vertical_pressed@2x.png</file>
<file>rc/transparent.png</file>
<file>rc/transparent@2x.png</file>
<file>rc/transparent_disabled.png</file>
<file>rc/transparent_disabled@2x.png</file>
<file>rc/transparent_focus.png</file>
<file>rc/transparent_focus@2x.png</file>
<file>rc/transparent_pressed.png</file>
<file>rc/transparent_pressed@2x.png</file>
<file>rc/window_close.png</file>
<file>rc/window_close@2x.png</file>
<file>rc/window_close_disabled.png</file>
<file>rc/window_close_disabled@2x.png</file>
<file>rc/window_close_focus.png</file>
<file>rc/window_close_focus@2x.png</file>
<file>rc/window_close_pressed.png</file>
<file>rc/window_close_pressed@2x.png</file>
<file>rc/window_grip.png</file>
<file>rc/window_grip@2x.png</file>
<file>rc/window_grip_disabled.png</file>
<file>rc/window_grip_disabled@2x.png</file>
<file>rc/window_grip_focus.png</file>
<file>rc/window_grip_focus@2x.png</file>
<file>rc/window_grip_pressed.png</file>
<file>rc/window_grip_pressed@2x.png</file>
<file>rc/window_minimize.png</file>
<file>rc/window_minimize@2x.png</file>
<file>rc/window_minimize_disabled.png</file>
<file>rc/window_minimize_disabled@2x.png</file>
<file>rc/window_minimize_focus.png</file>
<file>rc/window_minimize_focus@2x.png</file>
<file>rc/window_minimize_pressed.png</file>
<file>rc/window_minimize_pressed@2x.png</file>
<file>rc/window_undock.png</file>
<file>rc/window_undock@2x.png</file>
<file>rc/window_undock_disabled.png</file>
<file>rc/window_undock_disabled@2x.png</file>
<file>rc/window_undock_focus.png</file>
<file>rc/window_undock_focus@2x.png</file>
<file>rc/window_undock_pressed.png</file>
<file>rc/window_undock_pressed@2x.png</file>
</qresource>
<qresource prefix="qdarkstyle/dark">
<file>darkstyle.qss</file>
</qresource>
</RCC>
File diff suppressed because it is too large Load Diff
+1
View File
@@ -0,0 +1 @@
Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Some files were not shown because too many files have changed in this diff Show More