mirror of
https://github.com/wh201906/Proxmark3GUI.git
synced 2026-06-30 23:34:27 +08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b74ad1b0de | |||
| c72025787f | |||
| 784e627c0f | |||
| 9b175a4a93 | |||
| 58d2ba4eae | |||
| e2fb18970e | |||
| 184a9ed5f2 | |||
| 0738aff2bf | |||
| d466e5536b | |||
| b9da3e9209 | |||
| ee7aeda91e | |||
| 99bb58adf9 | |||
| 785fde6e2d | |||
| a9b03f081a | |||
| 0634e530b6 | |||
| e6be456cfa |
@@ -2,6 +2,12 @@
|
||||
|
||||
[中文](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
|
||||
|
||||
@@ -82,13 +82,18 @@ 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
|
||||
|
||||
Client Path must be path to pm3 console client like "/usr/local/bin/pm3/"
|
||||
|
||||

|
||||
|
||||
***
|
||||
|
||||
## Tutorial
|
||||
|
||||
[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)
|
||||
|
||||
***
|
||||
|
||||
## Change Log
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
<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>
|
||||
|
||||
@@ -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",
|
||||
"mifare classic": {
|
||||
"nested": {
|
||||
|
||||
@@ -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",
|
||||
"mifare classic": {
|
||||
"nested": {
|
||||
@@ -48,7 +48,8 @@
|
||||
"key B index": 4
|
||||
},
|
||||
"info": {
|
||||
"cmd": "hf 14a info"
|
||||
"cmd": "hf 14a info -nsv",
|
||||
"basic cmd": "hf 14a info"
|
||||
},
|
||||
"sniff": {
|
||||
"cmd": "hf sniff"
|
||||
@@ -238,4 +239,4 @@
|
||||
"t55x7 flag": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"//": "Based on Proxmark3 rrg repo v4.15864, commit 1f75adc",
|
||||
"//": "Based on Proxmark3 rrg repo v4.15864, commit 1f75adcf6d",
|
||||
"//": "You can change this file if the command format of client changes",
|
||||
"mifare classic": {
|
||||
"nested": {
|
||||
@@ -48,7 +48,8 @@
|
||||
"key B index": 4
|
||||
},
|
||||
"info": {
|
||||
"cmd": "hf 14a info"
|
||||
"cmd": "hf 14a info -nsv",
|
||||
"basic cmd": "hf 14a info"
|
||||
},
|
||||
"sniff": {
|
||||
"cmd": "hf sniff"
|
||||
|
||||
@@ -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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
[English](../../CHANGELOG.md)
|
||||
|
||||
### V0.2.8
|
||||
+ 支持冰人版客户端 v4.16717
|
||||
+ 修复若干Bug
|
||||
+ 便于在不同版本客户端之间切换
|
||||
+ 支持蓝牙及TCP连接
|
||||
|
||||
### V0.2.7
|
||||
+ 修复使用冰人版v4.15864时无法写入块0的问题
|
||||
+ 默认关闭Linux/macOS系统下对PM3硬件断连的检测
|
||||
|
||||
@@ -87,7 +87,8 @@ open Proxmark3GUI.app
|
||||
***
|
||||
## 教程
|
||||
[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硬件)
|
||||
***
|
||||
|
||||
## 更新日志
|
||||
|
||||
@@ -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`。如果选项中没有你所使用的客户端版本,可以尝试选择版本号相近的对应配置文件
|
||||
### 连接设备
|
||||
在“端口”当中选择需要连接的端口号,单击“连接”即可
|
||||
+412
-405
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+287
-279
File diff suppressed because it is too large
Load Diff
@@ -59,9 +59,9 @@ qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
VERSION = 0.2.7
|
||||
VERSION = 0.2.8
|
||||
QMAKE_TARGET_PRODUCT = "Proxmark3GUI"
|
||||
QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI"
|
||||
QMAKE_TARGET_DESCRIPTION = "A cross-platform GUI for Proxmark3 client"
|
||||
QMAKE_TARGET_COMPANY = "wh201906"
|
||||
|
||||
RESOURCES += \
|
||||
|
||||
@@ -22,6 +22,7 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
|
||||
QString result;
|
||||
Util::ClientType clientType;
|
||||
setRequiringOutput(true);
|
||||
QRegularExpression osPattern("(os:\\s+|OS\\.+\\s+)");
|
||||
|
||||
// stash for reconnect
|
||||
currPath = path;
|
||||
@@ -35,7 +36,7 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
|
||||
waitForReadyRead(10000);
|
||||
setRequiringOutput(false);
|
||||
result = *requiredOutput;
|
||||
if(result.indexOf("[=]") != -1)
|
||||
if(result.contains("[=]"))
|
||||
{
|
||||
clientType = Util::CLIENTTYPE_ICEMAN;
|
||||
setRequiringOutput(true);
|
||||
@@ -44,7 +45,8 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
|
||||
{
|
||||
waitForReadyRead(200);
|
||||
result += *requiredOutput;
|
||||
if(result.indexOf("os: ") != -1)
|
||||
// if(result.contains("os: "))
|
||||
if(osPattern.match(result).hasMatch())
|
||||
break;
|
||||
}
|
||||
setRequiringOutput(false);
|
||||
@@ -53,16 +55,21 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
|
||||
{
|
||||
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
|
||||
if(osPattern.match(result).hasMatch())
|
||||
{
|
||||
emit changeClientType(clientType);
|
||||
result = result.mid(result.indexOf("os: "));
|
||||
// result = result.mid(result.indexOf("os: "));
|
||||
QRegularExpressionMatch osMatch = osPattern.match(result);
|
||||
result = result.mid(osMatch.capturedStart());
|
||||
result = result.left(result.indexOf("\n"));
|
||||
result = result.mid(4, result.indexOf(" ", 4) - 4);
|
||||
// result = result.mid(4, result.indexOf(" ", 4) - 4);
|
||||
result = result.mid(osMatch.capturedLength(), result.indexOf(" ", osMatch.capturedLength()) - osMatch.capturedLength());
|
||||
emit PM3StatedChanged(true, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "unexpected output:" << (result.isEmpty() ? "(empty)" : result);
|
||||
emit HWConnectFailed();
|
||||
kill();
|
||||
}
|
||||
|
||||
@@ -151,6 +151,7 @@ void LF::syncWithUI()
|
||||
ui->LF_LFConf_averagingBox->setChecked(currLFConfig.averaging);
|
||||
ui->LF_LFConf_thresholdBox->setValue(currLFConfig.triggerThreshold);
|
||||
ui->LF_LFConf_skipsBox->setValue(currLFConfig.samplesToSkip);
|
||||
emit LFfreqConfChanged(currLFConfig.divisor, false);
|
||||
}
|
||||
|
||||
void LF::setConfigMap(const QVariantMap& configMap)
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ private:
|
||||
void syncWithUI();
|
||||
bool getLFConfig_helper(const QVariantMap& map, QString& str, int* result);
|
||||
signals:
|
||||
|
||||
void LFfreqConfChanged(int divisor, bool isCustomized);
|
||||
};
|
||||
|
||||
#endif // LF_H
|
||||
|
||||
+21
-1
@@ -102,7 +102,12 @@ QMap<QString, QString> Mifare::info(bool isRequiringOutput)
|
||||
QVariantMap config = configMap["info"].toMap();
|
||||
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");
|
||||
|
||||
for(auto line = lineList.begin(); line != lineList.end(); line++)
|
||||
@@ -1370,3 +1375,18 @@ quint16 Mifare::getTrailerBlockId(quint8 sectorId, qint8 cardTypeId)
|
||||
// other cardTypeId: use current cardtype(include default -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();
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ public:
|
||||
QString data_getUID();
|
||||
quint16 getTrailerBlockId(quint8 sectorId, qint8 cardTypeId = -1); // -1: use current cardtype
|
||||
void setConfigMap(const QVariantMap& configMap);
|
||||
QString getTraceSavePath();
|
||||
public slots:
|
||||
signals:
|
||||
|
||||
|
||||
+165
-31
@@ -43,6 +43,7 @@ MainWindow::MainWindow(QWidget *parent):
|
||||
mifare = new Mifare(ui, util, this);
|
||||
lf = new LF(ui, util, this);
|
||||
t55xxTab = new T55xxTab(util);
|
||||
connect(lf, &LF::LFfreqConfChanged, this, &MainWindow::onLFfreqConfChanged);
|
||||
connect(t55xxTab, &T55xxTab::setParentGUIState, this, &MainWindow::setState);
|
||||
ui->funcTab->insertTab(2, t55xxTab, tr("T55xx"));
|
||||
|
||||
@@ -158,8 +159,45 @@ void MainWindow::on_PM3_connectButton_clicked()
|
||||
{
|
||||
qDebug() << "Main:" << QThread::currentThread();
|
||||
|
||||
QString port = ui->PM3_portBox->currentData().toString();
|
||||
const QComboBox* portBox = ui->PM3_portBox;
|
||||
QString port;
|
||||
if(portBox->currentText() == portBox->itemText(portBox->currentIndex()))
|
||||
// in the list
|
||||
port = portBox->currentData().toString();
|
||||
else
|
||||
// not in the list
|
||||
port = portBox->currentText();
|
||||
qDebug() << "port:" << port;
|
||||
QString startArgs = ui->Set_Client_startArgsEdit->text();
|
||||
QString clientPath = ui->PM3_pathBox->currentText();
|
||||
QFileInfo clientFile(clientPath);
|
||||
bool clientExist = false;
|
||||
|
||||
QStringList extList = {""};
|
||||
#ifdef Q_OS_WIN
|
||||
if(clientFile.suffix().isEmpty())
|
||||
{
|
||||
QString pathExt = QProcessEnvironment::systemEnvironment().value("pathext");
|
||||
extList += pathExt.split(";", Qt::SkipEmptyParts);
|
||||
if(extList.size() == 1)
|
||||
extList += ".exe";
|
||||
}
|
||||
#endif
|
||||
for(const QString& ext : extList)
|
||||
{
|
||||
QFileInfo executable(clientFile.filePath() + ext);
|
||||
if(executable.isFile())
|
||||
{
|
||||
clientExist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!clientExist)
|
||||
{
|
||||
QMessageBox::information(this, tr("Info"), tr("The client path is invalid"), QMessageBox::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// on RRG repo, if no port is specified, the client will search the available port
|
||||
if(port == "" && startArgs.contains("<port>")) // has <port>, no port
|
||||
@@ -172,25 +210,29 @@ void MainWindow::on_PM3_connectButton_clicked()
|
||||
port = ""; // a symbol
|
||||
|
||||
QStringList args = startArgs.replace("<port>", port).split(' ');
|
||||
saveClientPath(ui->PM3_pathEdit->text());
|
||||
addClientPath(clientPath);
|
||||
|
||||
QProcess envSetProcess;
|
||||
QFileInfo envScriptPath(ui->Set_Client_envScriptEdit->text());
|
||||
if(envScriptPath.exists())
|
||||
QString envScriptPath = ui->Set_Client_envScriptEdit->text();
|
||||
if(envScriptPath.contains("<client dir>"))
|
||||
envScriptPath.replace("<client dir>", clientFile.absoluteDir().absolutePath());
|
||||
|
||||
QFileInfo envScript(envScriptPath);
|
||||
if(envScript.exists())
|
||||
{
|
||||
qDebug() << envScriptPath.absoluteFilePath();
|
||||
qDebug() << envScript.absoluteFilePath();
|
||||
// use the shell session to keep the environment then read it
|
||||
#ifdef Q_OS_WIN
|
||||
// cmd /c "<path>">>nul && set
|
||||
envSetProcess.start("cmd", {}, QProcess::Unbuffered | QProcess::ReadWrite | QProcess::Text);
|
||||
envSetProcess.write(QString("\"" + envScriptPath.absoluteFilePath() + "\">>nul\n").toLatin1());
|
||||
envSetProcess.write(QString("\"" + envScript.absoluteFilePath() + "\">>nul\n").toLatin1());
|
||||
envSetProcess.waitForReadyRead(10000);
|
||||
envSetProcess.readAll();
|
||||
envSetProcess.write("set\n");
|
||||
#else
|
||||
// need implementation(or test if space works)
|
||||
// sh -c '. "<path>">>/dev/null && env'
|
||||
envSetProcess.start("sh -c \' . \"" + envScriptPath.absoluteFilePath() + "\">>/dev/null && env");
|
||||
envSetProcess.start("sh -c \' . \"" + envScript.absoluteFilePath() + "\">>/dev/null && env");
|
||||
#endif
|
||||
envSetProcess.waitForReadyRead(10000);
|
||||
QString envSetResult = QString(envSetProcess.readAll());
|
||||
@@ -219,7 +261,7 @@ void MainWindow::on_PM3_connectButton_clicked()
|
||||
emit setWorkingDir(clientWorkingDir->absolutePath());
|
||||
|
||||
loadConfig();
|
||||
emit connectPM3(ui->PM3_pathEdit->text(), args);
|
||||
emit connectPM3(clientPath, args);
|
||||
if(port != "" && !keepClientActive)
|
||||
emit setSerialListener(port, true);
|
||||
else if(!keepClientActive)
|
||||
@@ -232,7 +274,7 @@ void MainWindow::onPM3ErrorOccurred(QProcess::ProcessError error)
|
||||
{
|
||||
qDebug() << "PM3 Error:" << error << pm3->errorString();
|
||||
if(error == QProcess::FailedToStart)
|
||||
QMessageBox::information(this, tr("Info"), tr("Failed to start the client"));
|
||||
QMessageBox::information(this, tr("Info"), tr("Failed to start the client") + "\n" + pm3->errorString());
|
||||
}
|
||||
|
||||
void MainWindow::onPM3HWConnectFailed()
|
||||
@@ -914,18 +956,31 @@ void MainWindow::on_MF_Sniff_loadButton_clicked() // use a tmp file to support c
|
||||
{
|
||||
QString title = "";
|
||||
QString filename = "";
|
||||
QString defaultExtension;
|
||||
QDir clientTracePath;
|
||||
|
||||
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
|
||||
defaultExtension = ".trc";
|
||||
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
|
||||
defaultExtension = ".trace";
|
||||
|
||||
QString userTraceSavePath = mifare->getTraceSavePath();
|
||||
if(userTraceSavePath.isEmpty())
|
||||
clientTracePath = *clientWorkingDir;
|
||||
else
|
||||
clientTracePath = QDir(userTraceSavePath); // For v4.16717 and later
|
||||
|
||||
title = tr("Plz select the trace file:");
|
||||
filename = QFileDialog::getOpenFileName(this, title, clientWorkingDir->absolutePath(), tr("Trace Files(*.trc)") + ";;" + tr("All Files(*.*)"));
|
||||
filename = QFileDialog::getOpenFileName(this, title, clientTracePath.absolutePath(), tr("Trace Files") + "(*" + defaultExtension + ")" + ";;" + tr("All Files(*.*)"));
|
||||
qDebug() << filename;
|
||||
if(filename != "")
|
||||
{
|
||||
QString tmpFile = "tmp" + QString::number(QDateTime::currentDateTime().toTime_t()) + ".trc";
|
||||
if(QFile::copy(filename, clientWorkingDir->absolutePath() + "/" + tmpFile))
|
||||
QString tmpFile = "tmp" + QString::number(QDateTime::currentDateTimeUtc().toTime_t()) + defaultExtension;
|
||||
if(QFile::copy(filename, clientTracePath.absolutePath() + "/" + tmpFile))
|
||||
{
|
||||
mifare->loadSniff(tmpFile);
|
||||
util->delay(3000);
|
||||
QFile::remove(clientWorkingDir->absolutePath() + "/" + tmpFile);
|
||||
QFile::remove(clientTracePath.absolutePath() + "/" + tmpFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -938,25 +993,41 @@ void MainWindow::on_MF_Sniff_saveButton_clicked()
|
||||
{
|
||||
QString title = "";
|
||||
QString filename = "";
|
||||
QString defaultExtension;
|
||||
QDir clientTracePath;
|
||||
|
||||
if(Util::getClientType() == Util::CLIENTTYPE_OFFICIAL)
|
||||
defaultExtension = ".trc";
|
||||
else if(Util::getClientType() == Util::CLIENTTYPE_ICEMAN)
|
||||
defaultExtension = ".trace";
|
||||
|
||||
QString userTraceSavePath = mifare->getTraceSavePath();
|
||||
if(userTraceSavePath.isEmpty())
|
||||
clientTracePath = *clientWorkingDir;
|
||||
else
|
||||
clientTracePath = QDir(userTraceSavePath); // For v4.16717 and later
|
||||
|
||||
title = tr("Plz select the location to save trace file:");
|
||||
filename = QFileDialog::getSaveFileName(this, title, clientWorkingDir->absolutePath(), tr("Trace Files(*.trc)"));
|
||||
filename = QFileDialog::getSaveFileName(this, title, clientTracePath.absolutePath(), tr("Trace Files") + "(*" + defaultExtension + ")");
|
||||
qDebug() << filename;
|
||||
if(filename != "")
|
||||
{
|
||||
QString tmpFile = "tmp" + QString::number(QDateTime::currentDateTime().toTime_t()) + ".trc";
|
||||
QString tmpFile = "tmp" + QString::number(QDateTime::currentDateTimeUtc().toTime_t()) + defaultExtension;
|
||||
mifare->saveSniff(tmpFile);
|
||||
for(int i = 0; i < 100; i++)
|
||||
{
|
||||
util->delay(100);
|
||||
if(QFile::exists(clientWorkingDir->absolutePath() + "/" + tmpFile))
|
||||
if(QFile::exists(clientTracePath.absolutePath() + "/" + tmpFile))
|
||||
break;
|
||||
}
|
||||
if(!QFile::copy(clientWorkingDir->absolutePath() + "/" + tmpFile, filename))
|
||||
// filename is not empty -> the user has chosen to overwrite the existing file
|
||||
if(QFile::exists(filename))
|
||||
QFile::remove(filename);
|
||||
if(!QFile::copy(clientTracePath.absolutePath() + "/" + tmpFile, filename))
|
||||
{
|
||||
QMessageBox::information(this, tr("Info"), tr("Failed to save to") + "\n" + filename);
|
||||
}
|
||||
QFile::remove(clientWorkingDir->absolutePath() + "/" + tmpFile);
|
||||
QFile::remove(clientTracePath.absolutePath() + "/" + tmpFile);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1090,9 +1161,7 @@ void MainWindow::uiInit()
|
||||
}
|
||||
settings->endGroup();
|
||||
|
||||
settings->beginGroup("Client_Path");
|
||||
ui->PM3_pathEdit->setText(settings->value("path", "proxmark3").toString());
|
||||
settings->endGroup();
|
||||
loadClientPathList();
|
||||
|
||||
ui->Set_Client_GUIWorkingDirLabel->setText(QDir::currentPath());
|
||||
|
||||
@@ -1118,13 +1187,17 @@ void MainWindow::uiInit()
|
||||
settings->endGroup();
|
||||
ui->Set_Client_keepClientActiveBox->setChecked(keepClientActive);
|
||||
|
||||
QDirIterator configFiles(":/config/");
|
||||
QDir configFiles(":/config/");
|
||||
configFiles.setSorting(QDir::Name);
|
||||
const QFileInfoList configFileList = configFiles.entryInfoList();
|
||||
ui->Set_Client_configFileBox->blockSignals(true);
|
||||
while(configFiles.hasNext())
|
||||
for(const auto& file : configFileList)
|
||||
{
|
||||
configFiles.next();
|
||||
ui->Set_Client_configFileBox->addItem(configFiles.fileName(), configFiles.filePath());
|
||||
ui->Set_Client_configFileBox->addItem(file.fileName(), file.filePath());
|
||||
}
|
||||
|
||||
// Use the last one as the default one
|
||||
ui->Set_Client_configFileBox->setCurrentIndex(ui->Set_Client_configFileBox->count() - 1);
|
||||
ui->Set_Client_configFileBox->addItem(tr("External file"), "(ext)");
|
||||
|
||||
int configId = -1;
|
||||
@@ -1331,10 +1404,67 @@ void MainWindow::on_GroupBox_clicked(bool checked)
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void MainWindow::saveClientPath(const QString& path)
|
||||
void MainWindow::addClientPath(const QString& path)
|
||||
{
|
||||
m_clientPathList.removeAll(path);
|
||||
m_clientPathList.prepend(path);
|
||||
while(m_clientPathList.size() > 32) // the maximum count of path items
|
||||
m_clientPathList.removeLast();
|
||||
// sync to the storage
|
||||
saveClientPathList();
|
||||
// sync to the UI
|
||||
loadClientPathList();
|
||||
}
|
||||
|
||||
void MainWindow::loadClientPathList()
|
||||
{
|
||||
m_clientPathList.clear();
|
||||
settings->beginGroup("Client_Path");
|
||||
int len = settings->beginReadArray("pathList");
|
||||
settings->endArray();
|
||||
if(settings->contains("path") && len == 0)
|
||||
{
|
||||
qDebug() << "Using old client path storage";
|
||||
m_clientPathList += settings->value("path", "proxmark3").toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
int arrayLen = settings->beginReadArray("pathList");
|
||||
for(int i = 0; i < arrayLen; i++)
|
||||
{
|
||||
settings->setArrayIndex(i);
|
||||
QString path = settings->value("path").toString();
|
||||
if(!path.isEmpty())
|
||||
m_clientPathList += path;
|
||||
}
|
||||
settings->endArray();
|
||||
}
|
||||
settings->endGroup();
|
||||
|
||||
ui->PM3_pathBox->clear();
|
||||
for(const QString& clientPath : qAsConst(m_clientPathList))
|
||||
ui->PM3_pathBox->addItem(clientPath);
|
||||
}
|
||||
|
||||
void MainWindow::saveClientPathList()
|
||||
{
|
||||
settings->beginGroup("Client_Path");
|
||||
settings->setValue("path", path);
|
||||
if(settings->contains("path"))
|
||||
{
|
||||
qDebug() << "Upgrading client path storage";
|
||||
QString oldPath = settings->value("path").toString();
|
||||
if(!oldPath.isEmpty() && !m_clientPathList.contains(oldPath))
|
||||
m_clientPathList.append(oldPath);
|
||||
settings->remove("path");
|
||||
}
|
||||
|
||||
settings->beginWriteArray("pathList");
|
||||
for(int i = 0; i < m_clientPathList.size(); i++)
|
||||
{
|
||||
settings->setArrayIndex(i);
|
||||
settings->setValue("path", m_clientPathList[i]);
|
||||
}
|
||||
settings->endArray();
|
||||
settings->endGroup();
|
||||
}
|
||||
// ***********************************************
|
||||
@@ -1411,16 +1541,20 @@ void MainWindow::on_LF_LFConf_freqSlider_valueChanged(int value)
|
||||
onLFfreqConfChanged(value, true);
|
||||
}
|
||||
|
||||
void MainWindow::onLFfreqConfChanged(int value, bool isCustomized)
|
||||
void MainWindow::onLFfreqConfChanged(int divisor, bool isCustomized)
|
||||
{
|
||||
ui->LF_LFConf_freqDivisorBox->blockSignals(true);
|
||||
ui->LF_LFConf_freqSlider->blockSignals(true);
|
||||
|
||||
if(isCustomized)
|
||||
ui->LF_LFConf_freqOtherButton->setChecked(true);
|
||||
ui->LF_LFConf_freqLabel->setText(tr("Actural Freq: ") + QString("%1kHz").arg(LF::divisor2Freq(value), 0, 'f', 3));
|
||||
ui->LF_LFConf_freqDivisorBox->setValue(value);
|
||||
ui->LF_LFConf_freqSlider->setValue(value);
|
||||
else if(divisor == 95)
|
||||
ui->LF_LFConf_freq125kButton->setChecked(true);
|
||||
else if(divisor == 88)
|
||||
ui->LF_LFConf_freq134kButton->setChecked(true);
|
||||
ui->LF_LFConf_freqLabel->setText(tr("Actural Freq: ") + QString("%1kHz").arg(LF::divisor2Freq(divisor), 0, 'f', 3));
|
||||
ui->LF_LFConf_freqDivisorBox->setValue(divisor);
|
||||
ui->LF_LFConf_freqSlider->setValue(divisor);
|
||||
|
||||
ui->LF_LFConf_freqDivisorBox->blockSignals(false);
|
||||
ui->LF_LFConf_freqSlider->blockSignals(false);
|
||||
|
||||
+7
-2
@@ -220,6 +220,8 @@ private slots:
|
||||
|
||||
void on_Set_UI_CMDFont_setButton_clicked();
|
||||
|
||||
void onLFfreqConfChanged(int divisor, bool isCustomized);
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui;
|
||||
QButtonGroup* MFCardTypeBtnGroup;
|
||||
@@ -260,11 +262,14 @@ private:
|
||||
|
||||
MF_trailerDecoderDialog* decDialog;
|
||||
|
||||
QStringList m_clientPathList;
|
||||
|
||||
void signalInit();
|
||||
void MF_widgetReset();
|
||||
void setTableItem(QTableWidget *widget, int row, int column, const QString& text);
|
||||
void saveClientPath(const QString& path);
|
||||
void onLFfreqConfChanged(int value, bool isCustomized);
|
||||
void addClientPath(const QString& path);
|
||||
void loadClientPathList();
|
||||
void saveClientPathList();
|
||||
void dockInit();
|
||||
void loadConfig();
|
||||
protected:
|
||||
|
||||
+16
-2
@@ -58,7 +58,17 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="PM3_pathEdit"/>
|
||||
<widget class="QComboBox" name="PM3_pathBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_18">
|
||||
@@ -84,6 +94,9 @@
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumContentsLength">
|
||||
<number>15</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -2714,7 +2727,8 @@ or the communication between a tag and a reader.</string>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>If the client requires some enviroment variables, you can make a script file(*.bat on Windows or *.sh on Linux) to configure them, then put the path of the script there.</string>
|
||||
<string>If the client requires some enviroment variables, you can make a script file(*.bat on Windows or *.sh on Linux) to configure them, then put the path of the script there.
|
||||
The "<client dir>" will be replaced by the directory of the "Client Path"</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
|
||||
Reference in New Issue
Block a user