14 Commits

Author SHA1 Message Date
wh201906 ce973fda96 V0.2.6
Update deploy/deploy.py
2022-11-25 01:10:37 +08:00
wh201906 2704b7cfc2 Update translations 2022-11-24 23:46:11 +08:00
wh201906 2b5c94974d Add support for rrg v4.15864
Add key result as comment in config files
Specify card size in hf mf dump/restore
Use regular expression to detect lf config text
Skip the useless waiting when hf mf nested detects the static nonce then
perform staticnested attack
2022-11-24 19:44:59 +08:00
wh201906 d8d9178ce8 Fix PM3 hardware detection 2022-11-24 01:34:25 +08:00
wh201906 9c89df4519 Misc
add config file to resource system
move language folder
2022-11-24 01:24:13 +08:00
wh201906 757fdcfc21 Misc
select available PM3 hardware port when updating the serial port list
remove extra empty lines in raw command output by replacing
appendPlainText() with insertPlainText() rather than starting the client
with QProcess::Text
2022-11-23 16:51:37 +08:00
wh201906 a9b19f92d6 More hints
For serial ports which look like PM3 hardware, show a '*' behind them.
Show message box if the GUI fails to connect to the hardware
2022-11-23 15:26:28 +08:00
wh201906 b2cb1ea8e7 Show current working directory of GUI in Settings 2022-11-23 14:16:51 +08:00
wh201906 da2f6ead6e Add feedback of failing to start the client
plus, make setRequiringOutput() matched in PM3Process::connectPM3()
2022-11-23 14:01:19 +08:00
wh201906 ef9972d24a Fix default lf config 2022-06-28 00:29:26 +08:00
wh201906 9dcd291894 Misc
Terminate the child thread properly
Optimize write logic
2022-03-21 15:45:31 +08:00
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
30 changed files with 1601 additions and 862 deletions
+72
View File
@@ -0,0 +1,72 @@
# Change Log
[中文](doc/CHANGELOG/CHANGELOG_zh_CN.md)
### V0.2.6
+ Add support for Iceman/RRG repo v4.15864 [#37](https://github.com/wh201906/Proxmark3GUI/issues/37)
+ Optimize mifare classic block writing logic
+ Fix the default lf config
+ Add feedback for the GUI failing to start the client
+ Add feedback for the client failing to connect to PM3 hardware
+ Detect PM3 hardware when searching serial ports
+ Remove extra empty lines in raw command output
+ Use embedded config files
+ Remove the wait time between performing nested attack then switching to staticnested attack
### V0.2.5
+ Fix bug [#28](https://github.com/wh201906/Proxmark3GUI/issues/28)
### 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.
+2 -57
View File
@@ -58,7 +58,6 @@ Great thanks to him.
mkdir build && cd build mkdir build && cd build
qmake ../src qmake ../src
make -j4 && make clean make -j4 && make clean
cp -r ../config ./
./Proxmark3GUI ./Proxmark3GUI
*** ***
@@ -68,59 +67,5 @@ Great thanks to him.
[2.Edit Mifare Classic data](doc/tutorial/Edit_Mifare_Classic_data/Edit_Mifare_Classic_data.md)(Proxmark3 hardware is not necessary) [2.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.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.
+7
View File
@@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/config">
<file>config_official.json</file>
<file>config_rrgv4.13441.json</file>
<file>config_rrgv4.15864.json</file>
</qresource>
</RCC>
+38 -10
View File
@@ -10,6 +10,13 @@
"2k": "2", "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"
@@ -192,14 +220,14 @@
"divisor cmd": "hw setlfdivisor <divisor>" "divisor cmd": "hw setlfdivisor <divisor>"
} }
}, },
"t55xx":{ "t55xx": {
"clone em410x":{ "clone em410x": {
"read":"lf search", "read": "lf search",
"successful read flag":"Valid EM410x ID", "successful read flag": "Valid EM410x ID",
"pattern":"EM TAG ID\\s*:\\s\\K[0-9a-fA-F]{10}", "pattern": "EM TAG ID\\s*:\\s\\K[0-9a-fA-F]{10}",
"clone cmd":"lf em 410xwrite <id> <type>", "clone cmd": "lf em 410xwrite <id> <type>",
"t5555 flag":"0", "t5555 flag": "0",
"t55x7 flag":"1" "t55x7 flag": "1"
} }
} }
} }
@@ -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,6 +34,15 @@
"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
@@ -44,10 +60,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"
@@ -200,14 +228,14 @@
"divisor cmd": "hw setlfdivisor -d <divisor>" "divisor cmd": "hw setlfdivisor -d <divisor>"
} }
}, },
"t55xx":{ "t55xx": {
"clone em410x":{ "clone em410x": {
"read":"lf em 410x reader", "read": "lf em 410x reader",
"successful read flag":"EM 410x ID", "successful read flag": "EM 410x ID",
"pattern":"EM 410x ID\\s*\\K[0-9a-fA-F]{10}", "pattern": "EM 410x ID\\s*\\K[0-9a-fA-F]{10}",
"clone cmd":"lf em 410x clone --id <id> <type>", "clone cmd": "lf em 410x clone --id <id> <type>",
"t5555 flag":"--q5", "t5555 flag": "--q5",
"t55x7 flag":"" "t55x7 flag": ""
} }
} }
} }
+241
View File
@@ -0,0 +1,241 @@
{
"//": "Based on Proxmark3 rrg repo v4.15864, commit 1f75adc",
"//": "You can change this file if the command format of client changes",
"mifare classic": {
"nested": {
"cmd": "hf mf nested --<card type> --blk <block> -<key type> -k <key>",
"static cmd": "hf mf staticnested --<card type> --blk <block> -<key type> -k <key>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
},
"key type": {
"A": "a",
"B": "b"
},
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] Sec | Blk | key A |res| key B |res",
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] 000 | 003 | FFFFFFFFFFFF | 1 | FFFFFFFFFFFF | 1",
"//": "......",
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] ( 0:Failed / 1:Success )",
"key pattern": "\\s*\\d{3}\\s*\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*$",
"key A index": 2,
"key B index": 4
},
"check": {
"cmd": "hf mf chk --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
},
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] Sec | Blk | key A |res| key B |res",
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] 000 | 003 | FFFFFFFFFFFF | 1 | FFFFFFFFFFFF | 1",
"//": "......",
"//": "[+] 004 | 019 | ------------ | 0 | ------------ | 0",
"//": "......",
"//": "[+] -----+-----+--------------+---+--------------+----",
"//": "[+] ( 0:Failed / 1:Success )",
"key pattern": "\\s*\\d{3}\\s*\\|\\s*\\d{3}\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*\\|\\s*.+?\\s*$",
"key A index": 2,
"key B index": 4
},
"info": {
"cmd": "hf 14a info"
},
"sniff": {
"cmd": "hf sniff"
},
"sniff 14a": {
"cmd": "hf 14a sniff"
},
"list": {
"cmd": "trace list -t mf"
},
"dump": {
"cmd": "hf mf dump --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
}
},
"restore": {
"cmd": "hf mf restore --<card type>",
"card type": {
"mini": "mini",
"1k": "1k",
"2k": "2k",
"4k": "4k"
}
},
"emulator wipe": {
"cmd": "hf mf eclr"
},
"Magic Card wipe": {
"cmd": "hf mf cwipe"
},
"emulator read block": {
"cmd": "hf mf egetblk --blk <block>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read block": {
"cmd": "hf mf cgetblk --blk <block>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"normal read block": {
"cmd": "hf mf rdbl --blk <block> -<key type> -k <key>",
"key type": {
"A": "a",
"B": "b"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"darkside": {
"cmd": "hf mf darkside"
},
"save sniff": {
"cmd": "trace save -f <filename>"
},
"load sniff": {
"cmd": "trace load -f <filename>",
"show cmd": "trace list --buffer -t mf"
},
"hardnested": {
"cmd": "hf mf hardnested --blk <known key block> -<known key type> -k <known key> --tblk <target key block> --t<target key type>",
"known key type": {
"A": "a",
"B": "b"
},
"target key type": {
"A": "a",
"B": "b"
}
},
"normal read sector": {
"cmd": "hf mf rdsc --sec <sector> -<key type> -k <key>",
"key type": {
"A": "a",
"B": "b"
},
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"Magic Card read sector": {
"cmd": "hf mf cgetsc --sec <sector>",
"data pattern": "([0-9a-fA-F]{2} ){15}[0-9a-fA-F]{2}"
},
"//": "When writing a block, if the result is not empty and doesn't contain the failed flag, the function will return true",
"normal write block": {
"cmd": "hf mf wrbl --blk <block> -<key type> -k <key> -d <data>",
"key type": {
"A": "a",
"B": "b"
},
"failed flag": [
"fail",
"error"
]
},
"Magic Card write block": {
"cmd": "hf mf csetblk --blk <block> -d <data>",
"failed flag": [
"fail",
"error"
]
},
"emulator write block": {
"cmd": "hf mf esetblk --blk <block> -d <data>"
},
"Magic Card lock": {
"cmd": "hf 14a raw ",
"sequence": [
"-ak -b 7 40",
"-ak 43",
"-ak E0 00 39 F7",
"-ak E1 00 E1 EE",
"-ak 85 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 18 47",
"-a 52"
]
},
"Magic Card set parameter": {
"cmd": "hf mf csetuid --uid <uid> --atqa <atqa> --sak <sak>"
}
},
"lf": {
"read": {
"cmd": "lf read -v",
"show cmd": "data plot"
},
"sniff": {
"cmd": "lf sniff -v",
"show cmd": "data plot"
},
"search": {
"cmd": "lf search -u"
},
"tune": {
"cmd": "lf tune --divisor <divisor>"
},
"get config": {
"cmd": "hw status",
"field start": "LF Sampling config",
"field end": "\\[#\\] \\S",
"divisor": {
"flag": "divisor",
"pattern": "\\d+"
},
"bits per sample": {
"flag": "bits per sample",
"pattern": "\\d+"
},
"decimation": {
"flag": "decimation",
"pattern": "\\d+"
},
"averaging": {
"flag": "averaging",
"pattern": "\\d+",
"replace": {
"yes": "1",
"no": "0",
"Yes": "1",
"No": "0"
}
},
"trigger threshold": {
"flag": "trigger threshold",
"pattern": "\\d+"
},
"samples to skip": {
"flag": "samples to skip",
"pattern": "\\d+"
},
"//": "execute 'cmd' then find parameters between 'field stard' and 'field end'",
"//": "for each line, if the line doesn't have any flag, skip",
"//": "otherwise, delete characters before 'flag' and 'flag' itself, then use 'pattern' to get the parameter",
"//": "If 'replace' dict exists, replace all keys with respective values before getting parameters"
},
"set config": {
"cmd": "lf config --divisor <divisor> --bps <bits per sample> --dec <decimation> --avg <averaging> --trig <trigger threshold> --skip <samples to skip>",
"divisor cmd": "hw setlfdivisor -d <divisor>"
}
},
"t55xx": {
"clone em410x": {
"read": "lf em 410x reader",
"successful read flag": "EM 410x ID",
"pattern": "EM 410x ID\\s*\\K[0-9a-fA-F]{10}",
"clone cmd": "lf em 410x clone --id <id> <type>",
"t5555 flag": "--q5",
"t55x7 flag": ""
}
}
}
+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)
+72
View File
@@ -0,0 +1,72 @@
# 更新日志
[English](../../CHANGELOG.md)
### V0.2.6
+ 支持冰人版客户端 v4.15864 [#37](https://github.com/wh201906/Proxmark3GUI/issues/37)
+ 优化Mifare Classic卡写卡逻辑
+ 修复lf config默认配置
+ 添加客户端无法启动的提示
+ 添加PM3硬件连接失败的提示
+ 为PM3对应串口添加提示,并自动选中
+ 修复原始指令框中有多余空行的问题
+ 内嵌不同客户端的配置文件
+ 去除从nested attack切换到staticnested attack的等待时间
### V0.2.5
+ 修复 [#28](https://github.com/wh201906/Proxmark3GUI/issues/28)
### 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
+ 一个带串口选择框的实验版本
+2 -56
View File
@@ -57,7 +57,6 @@ release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客
mkdir build && cd build mkdir build && cd build
qmake ../src qmake ../src
make -j4 && make clean make -j4 && make clean
cp -r ../config ./
./Proxmark3GUI ./Proxmark3GUI
*** ***
@@ -65,59 +64,6 @@ release页面中有含客户端的GUI。这个GUI也可以搭配你自己的客
[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.编辑Mifare(IC)卡数据](../tutorial/Edit_Mifare_Classic_data/Edit_Mifare_Classic_data_zh_CN.md)(无需PM3硬件)
*** ***
## 更新日志:
### V0.2.4 ## 更新日志
+ 复制EM410x卡(一种常见的低频ID卡) [更新日志](../CHANGELOG/CHANGELOG_zh_CN.md)
### 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
+ 一个带串口选择框的实验版本
+2 -2
View File
@@ -27,10 +27,10 @@
(4) Go to "Settings" panel. Input the config file path which matching the client you use. (4) Go to "Settings" panel. Input the config file path which matching the client you use.
![](configpath.png) ![](configpath.png)
(5) If setup.bat is required, input the script path in the "Preload script path" editbox. (5) If setup.bat is required, input the script path in the "Preload script path" editbox.
![](preloadpath.png) ![](preloadpath.png)
(6) If using RRG/Iceman repo, input "-p \<port\> -f" in the "Start arguments" editbox. (6) If using RRG/Iceman repo, input "-p \<port\> -f" in the "Start arguments" editbox.
![](args.png) ![](args.png)
*** ***
BIN
View File
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,3 @@
[Languages] [Languages]
en_US=English en_US=English
zh_CN=简体中文 zh_CN=简体中文
ext=Load from external file
Binary file not shown.
File diff suppressed because it is too large Load Diff
+5 -4
View File
@@ -51,18 +51,19 @@ FORMS += \
ui/mf_attack_hardnesteddialog.ui ui/mf_attack_hardnesteddialog.ui
TRANSLATIONS += \ TRANSLATIONS += \
i18n/zh_CN.ts \ ../i18n/zh_CN.ts \
i18n/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.4 VERSION = 0.2.6
QMAKE_TARGET_PRODUCT = "Proxmark3GUI" QMAKE_TARGET_PRODUCT = "Proxmark3GUI"
QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI" QMAKE_TARGET_DESCRIPTION = "Proxmark3GUI"
QMAKE_TARGET_COMPANY = "wh201906" QMAKE_TARGET_COMPANY = "wh201906"
RESOURCES += \ RESOURCES += \
i18n/language.qrc ../i18n/language.qrc \
../config/config.qrc
+9 -1
View File
@@ -13,6 +13,8 @@ PM3Process::PM3Process(QThread* thread, QObject* parent): QProcess(parent)
connect(serialListener, &QTimer::timeout, this, &PM3Process::onTimeout); connect(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,7 +28,8 @@ 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);
@@ -59,8 +62,13 @@ void PM3Process::connectPM3(const QString& path, const QStringList args)
emit PM3StatedChanged(true, result); emit PM3StatedChanged(true, result);
} }
else else
{
emit HWConnectFailed();
kill(); kill();
}
} }
setRequiringOutput(false);
} }
void PM3Process::reconnectPM3() void PM3Process::reconnectPM3()
+1
View File
@@ -48,6 +48,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
+17 -5
View File
@@ -119,17 +119,29 @@ bool Util::chooseLanguage(QSettings* guiSettings, QMainWindow* window)
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(nullptr, 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->endGroup();
guiSettings->sync();
} }
guiSettings->beginGroup("language");
guiSettings->setValue("name", langMap[selectedText]);
guiSettings->endGroup();
guiSettings->sync();
return isOk; return isOk;
} }
+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"
BIN
View File
Binary file not shown.
+16 -15
View File
@@ -27,33 +27,34 @@ int main(int argc, char *argv[])
QSettings* settings = new QSettings("GUIsettings.ini", QSettings::IniFormat); QSettings* settings = new QSettings("GUIsettings.ini", QSettings::IniFormat);
settings->setIniCodec("UTF-8"); settings->setIniCodec("UTF-8");
settings->beginGroup("lang"); settings->beginGroup("language");
QString currLang = settings->value("language", "").toString(); QString languageFile = settings->value("extPath").toString();
QString languageName = settings->value("name").toString();
settings->endGroup(); settings->endGroup();
if(currLang == "") if(languageName == "")
{ {
if(Util::chooseLanguage(settings, &w)) if(Util::chooseLanguage(settings, &w))
{ {
settings->beginGroup("lang"); settings->beginGroup("language");
currLang = settings->value("language", "").toString(); languageName = settings->value("name").toString();
settings->endGroup(); settings->endGroup();
} }
else else
currLang = "en_US"; languageName = "en_US";
}
if(languageName == "(ext)")
{
settings->beginGroup("language");
languageFile = settings->value("extPath").toString();
settings->endGroup();
} }
if(currLang == "ext")
currLang = QFileDialog::getOpenFileName(nullptr, "Select the translation file:");
else else
currLang = ":/i18n/" + currLang + ".qm"; languageFile = ":/i18n/" + languageName + ".qm";
QTranslator* translator = new QTranslator(&w); QTranslator* translator = new QTranslator(&w);
if(translator->load(currLang)) if(translator->load(languageFile))
{
a.installTranslator(translator); a.installTranslator(translator);
}
else else
{ QMessageBox::information(&w, "Error", "Can't load " + languageFile + " as translation file.");
QMessageBox::information(&w, "Error", "Can't load " + currLang + " as translation file.");
}
delete settings; delete settings;
w.initUI(); w.initUI();
w.show(); w.show();
+4 -2
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);
+16 -6
View File
@@ -130,7 +130,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(
@@ -169,7 +169,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;
@@ -212,7 +212,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)
@@ -691,10 +691,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
{ {
@@ -743,14 +747,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();
} }
+86 -10
View File
@@ -2,6 +2,7 @@
#include "ui_mainwindow.h" #include "ui_mainwindow.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <QDirIterator>
MainWindow::MainWindow(QWidget *parent): MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent) QMainWindow(parent)
@@ -30,7 +31,9 @@ MainWindow::MainWindow(QWidget *parent):
settings->setIniCodec("UTF-8"); settings->setIniCodec("UTF-8");
pm3Thread = new QThread(this); pm3Thread = new QThread(this);
connect(QApplication::instance(), &QApplication::aboutToQuit, pm3Thread, &QThread::quit);
pm3 = new PM3Process(pm3Thread); pm3 = new PM3Process(pm3Thread);
connect(pm3Thread, &QThread::finished, pm3, &PM3Process::deleteLater);
pm3Thread->start(); pm3Thread->start();
pm3state = false; pm3state = false;
clientWorkingDir = new QDir; clientWorkingDir = new QDir;
@@ -77,7 +80,11 @@ MainWindow::~MainWindow()
void MainWindow::loadConfig() void MainWindow::loadConfig()
{ {
QFile configList(ui->Set_Client_configPathEdit->text()); QString filename = ui->Set_Client_configFileBox->currentData().toString();
if(filename == "(ext)")
filename = ui->Set_Client_configPathEdit->text();
qDebug() << "config file:" << filename;
QFile configList(filename);
if(!configList.open(QFile::ReadOnly | QFile::Text)) if(!configList.open(QFile::ReadOnly | QFile::Text))
{ {
QMessageBox::information(this, tr("Info"), tr("Failed to load config file")); QMessageBox::information(this, tr("Info"), tr("Failed to load config file"));
@@ -104,18 +111,46 @@ void MainWindow::initUI() // will be called by main.app
void MainWindow::on_portSearchTimer_timeout() void MainWindow::on_portSearchTimer_timeout()
{ {
QStringList newPortList; QStringList newPortList; // for actural port name
QStringList newPortNameList; // for display name
const QString hint = " *";
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{ {
// qDebug() << info.isBusy() << info.isNull() << info.portName() << info.description(); // qDebug() << info.isNull() << info.portName() << info.description() << info.serialNumber() << info.manufacturer();
if(!info.isNull()) if(!info.isNull())
newPortList << info.portName(); {
QString idString = (info.description() + info.serialNumber() + info.manufacturer()).toLower();
QString portName = info.portName();
newPortList << portName;
if(info.hasVendorIdentifier() && info.hasProductIdentifier())
{
quint16 vid = info.vendorIdentifier();
quint16 pid = info.productIdentifier();
if(vid == 0x9AC4 && pid == 0x4B8F)
portName += hint;
else if(vid == 0x2D2D && pid == 0x504D)
portName += hint;
}
else if(idString.contains("proxmark") || idString.contains("iceman"))
portName += hint;
newPortNameList << portName;
}
} }
if(newPortList != portList) // update PM3_portBox when available ports changed if(newPortList != portList) // update PM3_portBox when available ports changed
{ {
portList = newPortList; portList = newPortList;
ui->PM3_portBox->clear(); ui->PM3_portBox->clear();
ui->PM3_portBox->addItems(portList); int selectId = -1;
for(int i = 0; i < portList.size(); i++)
{
ui->PM3_portBox->addItem(newPortNameList[i], newPortList[i]);
if(selectId == -1 && newPortNameList[i].endsWith(hint))
selectId = i;
}
if(selectId != -1)
ui->PM3_portBox->setCurrentIndex(selectId);
} }
} }
@@ -123,7 +158,7 @@ void MainWindow::on_PM3_connectButton_clicked()
{ {
qDebug() << "Main:" << QThread::currentThread(); qDebug() << "Main:" << QThread::currentThread();
QString port = ui->PM3_portBox->currentText(); QString port = ui->PM3_portBox->currentData().toString();
QString startArgs = ui->Set_Client_startArgsEdit->text(); QString startArgs = ui->Set_Client_startArgsEdit->text();
// on RRG repo, if no port is specified, the client will search the available port // on RRG repo, if no port is specified, the client will search the available port
@@ -193,6 +228,18 @@ void MainWindow::on_PM3_connectButton_clicked()
envSetProcess.kill(); envSetProcess.kill();
} }
void MainWindow::onPM3ErrorOccurred(QProcess::ProcessError error)
{
qDebug() << "PM3 Error:" << error << pm3->errorString();
if(error == QProcess::FailedToStart)
QMessageBox::information(this, tr("Info"), tr("Failed to start the client"));
}
void MainWindow::onPM3HWConnectFailed()
{
QMessageBox::information(this, tr("Info"), tr("Failed to connect to the hardware"));
}
void MainWindow::onPM3StateChanged(bool st, const QString& info) void MainWindow::onPM3StateChanged(bool st, const QString& info)
{ {
pm3state = st; pm3state = st;
@@ -220,7 +267,8 @@ void MainWindow::on_PM3_disconnectButton_clicked()
void MainWindow::refreshOutput(const QString& output) void MainWindow::refreshOutput(const QString& output)
{ {
// qDebug() << "MainWindow::refresh:" << output; // qDebug() << "MainWindow::refresh:" << output;
ui->Raw_outputEdit->appendPlainText(output); ui->Raw_outputEdit->moveCursor(QTextCursor::End);
ui->Raw_outputEdit->insertPlainText(output);
ui->Raw_outputEdit->moveCursor(QTextCursor::End); ui->Raw_outputEdit->moveCursor(QTextCursor::End);
} }
@@ -715,7 +763,7 @@ void MainWindow::on_MF_File_clearButton_clicked()
mifare->data_clearKey(); mifare->data_clearKey();
mifare->data_syncWithKeyWidget(); mifare->data_syncWithKeyWidget();
} }
else if(ui->MF_File_keyButton->isChecked()) else if(ui->MF_File_dataButton->isChecked())
{ {
mifare->data_clearData(); mifare->data_clearData();
mifare->data_syncWithDataWidget(); mifare->data_syncWithDataWidget();
@@ -1054,6 +1102,8 @@ void MainWindow::uiInit()
ui->PM3_pathEdit->setText(settings->value("path", "proxmark3").toString()); ui->PM3_pathEdit->setText(settings->value("path", "proxmark3").toString());
settings->endGroup(); settings->endGroup();
ui->Set_Client_GUIWorkingDirLabel->setText(QDir::currentPath());
settings->beginGroup("Client_Args"); settings->beginGroup("Client_Args");
ui->Set_Client_startArgsEdit->setText(settings->value("args", "<port> -f").toString()); ui->Set_Client_startArgsEdit->setText(settings->value("args", "<port> -f").toString());
settings->endGroup(); settings->endGroup();
@@ -1068,11 +1118,27 @@ void MainWindow::uiInit()
ui->Set_Client_keepClientActiveBox->setChecked(keepClientActive); ui->Set_Client_keepClientActiveBox->setChecked(keepClientActive);
settings->endGroup(); settings->endGroup();
QDirIterator configFiles(":/config/");
ui->Set_Client_configFileBox->blockSignals(true);
while(configFiles.hasNext())
{
configFiles.next();
ui->Set_Client_configFileBox->addItem(configFiles.fileName(), configFiles.filePath());
}
ui->Set_Client_configFileBox->addItem(tr("External file"), "(ext)");
int configId = -1;
settings->beginGroup("Client_Env"); settings->beginGroup("Client_Env");
ui->Set_Client_envScriptEdit->setText(settings->value("scriptPath").toString()); ui->Set_Client_envScriptEdit->setText(settings->value("scriptPath").toString());
ui->Set_Client_workingDirEdit->setText(settings->value("workingDir", "../data").toString()); ui->Set_Client_workingDirEdit->setText(settings->value("workingDir", "../data").toString());
ui->Set_Client_configPathEdit->setText(settings->value("configPath", "config.json").toString()); configId = ui->Set_Client_configFileBox->findData(settings->value("configFile"));
ui->Set_Client_configPathEdit->setText(settings->value("extConfigFilePath", "config.json").toString());
settings->endGroup(); settings->endGroup();
if(configId != -1)
ui->Set_Client_configFileBox->setCurrentIndex(configId);
ui->Set_Client_configFileBox->blockSignals(false);
on_Set_Client_configFileBox_currentIndexChanged(ui->Set_Client_configFileBox->currentIndex());
ui->MF_RW_keyTypeBox->addItem("A", Mifare::KEY_A); ui->MF_RW_keyTypeBox->addItem("A", Mifare::KEY_A);
ui->MF_RW_keyTypeBox->addItem("B", Mifare::KEY_B); ui->MF_RW_keyTypeBox->addItem("B", Mifare::KEY_B);
@@ -1091,6 +1157,8 @@ void MainWindow::signalInit()
connect(this, &MainWindow::reconnectPM3, pm3, &PM3Process::reconnectPM3); connect(this, &MainWindow::reconnectPM3, pm3, &PM3Process::reconnectPM3);
connect(pm3, &PM3Process::PM3StatedChanged, this, &MainWindow::onPM3StateChanged); connect(pm3, &PM3Process::PM3StatedChanged, this, &MainWindow::onPM3StateChanged);
connect(pm3, &PM3Process::PM3StatedChanged, util, &Util::setRunningState); connect(pm3, &PM3Process::PM3StatedChanged, util, &Util::setRunningState);
connect(pm3, &PM3Process::errorOccurred, this, &MainWindow::onPM3ErrorOccurred);
connect(pm3, &PM3Process::HWConnectFailed, this, &MainWindow::onPM3HWConnectFailed);
connect(this, &MainWindow::killPM3, pm3, &PM3Process::killPM3); connect(this, &MainWindow::killPM3, pm3, &PM3Process::killPM3);
connect(this, &MainWindow::setProcEnv, pm3, &PM3Process::setProcEnv); connect(this, &MainWindow::setProcEnv, pm3, &PM3Process::setProcEnv);
connect(this, &MainWindow::setWorkingDir, pm3, &PM3Process::setWorkingDir); connect(this, &MainWindow::setWorkingDir, pm3, &PM3Process::setWorkingDir);
@@ -1274,7 +1342,7 @@ void MainWindow::on_Set_Client_workingDirEdit_editingFinished()
void MainWindow::on_Set_Client_configPathEdit_editingFinished() void MainWindow::on_Set_Client_configPathEdit_editingFinished()
{ {
settings->beginGroup("Client_Env"); settings->beginGroup("Client_Env");
settings->setValue("configPath", ui->Set_Client_configPathEdit->text()); settings->setValue("extConfigFilePath", ui->Set_Client_configPathEdit->text());
settings->endGroup(); settings->endGroup();
} }
@@ -1412,3 +1480,11 @@ void MainWindow::on_LF_LFConf_resetButton_clicked()
setState(true); setState(true);
} }
void MainWindow::on_Set_Client_configFileBox_currentIndexChanged(int index)
{
ui->Set_Client_configPathEdit->setVisible(ui->Set_Client_configFileBox->itemData(index).toString() == "(ext)");
settings->beginGroup("Client_Env");
settings->setValue("configFile", ui->Set_Client_configFileBox->currentData());
settings->endGroup();
}
+6 -1
View File
@@ -51,7 +51,7 @@ public:
~MainWindow(); ~MainWindow();
void initUI(); void initUI();
bool eventFilter(QObject *watched, QEvent *event); bool eventFilter(QObject *watched, QEvent *event) override;
public slots: public slots:
void refreshOutput(const QString& output); void refreshOutput(const QString& output);
void refreshCMD(const QString& cmd); void refreshCMD(const QString& cmd);
@@ -60,6 +60,8 @@ public slots:
void MF_onMFCardTypeChanged(int id, bool st); void MF_onMFCardTypeChanged(int id, bool st);
void on_Raw_keyPressed(QObject *obj_addr, QEvent &event); void on_Raw_keyPressed(QObject *obj_addr, QEvent &event);
void on_MF_keyWidget_resized(QObject *obj_addr, QEvent &event); void on_MF_keyWidget_resized(QObject *obj_addr, QEvent &event);
void onPM3ErrorOccurred(QProcess::ProcessError error);
void onPM3HWConnectFailed();
private slots: private slots:
void on_PM3_connectButton_clicked(); void on_PM3_connectButton_clicked();
@@ -207,6 +209,9 @@ private slots:
void on_Set_Client_configPathEdit_editingFinished(); void on_Set_Client_configPathEdit_editingFinished();
void setState(bool st); void setState(bool st);
void on_Set_Client_configFileBox_currentIndexChanged(int index);
private: private:
Ui::MainWindow* ui; Ui::MainWindow* ui;
QButtonGroup* MFCardTypeBtnGroup; QButtonGroup* MFCardTypeBtnGroup;
+44 -3
View File
@@ -1454,8 +1454,8 @@ When setting the freq, the &quot;hw setlfdivisor&quot; will also be called.</str
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QCheckBox" name="LF_LFConf_averagingBox"> <widget class="QCheckBox" name="LF_LFConf_averagingBox">
<property name="text"> <property name="checked">
<string/> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
@@ -2650,6 +2650,23 @@ or the communication between a tag and a reader.</string>
<string>Client</string> <string>Client</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_10"> <layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<widget class="QLabel" name="label_65">
<property name="text">
<string>GUI working directory:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="Set_Client_GUIWorkingDirLabel"/>
</item>
<item>
<widget class="Line" name="line_9">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item> <item>
<widget class="QLabel" name="label_11"> <widget class="QLabel" name="label_11">
<property name="text"> <property name="text">
@@ -2746,10 +2763,34 @@ or the communication between a tag and a reader.</string>
<item> <item>
<widget class="QLabel" name="label_63"> <widget class="QLabel" name="label_63">
<property name="text"> <property name="text">
<string>Config file path(Reconnect to apply):</string> <string>Config file(Reconnect to apply):</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
<widget class="QComboBox" name="Set_Client_configFileBox">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_13">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item> <item>
<widget class="QLineEdit" name="Set_Client_configPathEdit"> <widget class="QLineEdit" name="Set_Client_configPathEdit">
<property name="text"> <property name="text">