Merge branch 'master' of github.com:RfidResearchGroup/proxmark3
[RRG-proxmark3.git] / pm3
blob80aad83d8bca50ea2cd26c7568d8797daa284e31
1 #!/usr/bin/env bash
3 # Usage: run option -h to get help
5 # BT auto detection
6 # Shall we look for white HC-06-USB dongle ?
7 FINDBTDONGLE=true
8 # Shall we look for rfcomm interface ?
9 FINDBTRFCOMM=true
10 # Shall we look for registered BT device ? (Linux only)
11 FINDBTDIRECT=true
13 PM3PATH=$(dirname "$0")
14 EVALENV=""
15 FULLIMAGE="fullimage.elf"
16 BOOTIMAGE="bootrom.elf"
18 #Skip check if --list is used
19 if [ ! "$1" == "--list" ]; then
20 # try pm3 dirs in current repo workdir
21 if [ -d "$PM3PATH/client/" ]; then
22 if [ -x "$PM3PATH/client/proxmark3" ]; then
23 CLIENT="$PM3PATH/client/proxmark3"
24 elif [ -x "$PM3PATH/client/build/proxmark3" ]; then
25 CLIENT="$PM3PATH/client/build/proxmark3"
26 else
27 echo >&2 "[!!] In devel workdir but no executable found, did you compile it?"
28 exit 1
30 # try install dir
31 elif [ -x "$PM3PATH/proxmark3" ]; then
32 CLIENT="$PM3PATH/proxmark3"
33 else
34 # hope it's installed somehow, still not sure where fw images and pm3.py are...
35 CLIENT="proxmark3"
39 # LeakSanitizer suppressions
40 if [ -e .lsan_suppressions ]; then
41 EVALENV+=" LSAN_OPTIONS=suppressions=.lsan_suppressions"
43 if [ "$EVALENV" != "" ]; then
44 EVALENV="export $EVALENV"
46 PM3LIST=()
47 SHOWLIST=false
49 function get_pm3_list_Linux {
50 N=$1
51 PM3LIST=()
52 if [ ! -c "/dev/tty0" ]; then
53 echo >&2 "[!!] Script cannot access /dev/ttyXXX files, insufficient privileges"
54 exit 1
56 for DEV in $(find /dev/ttyACM* 2>/dev/null); do
57 if command -v udevadm >/dev/null; then
58 # WSL1 detection
59 if udevadm info -q property -n "$DEV" | grep -q "ID_VENDOR=proxmark.org"; then
60 PM3LIST+=("$DEV")
61 if [ ${#PM3LIST[*]} -ge "$N" ]; then
62 return
66 # WSL2 with usbipd detection - doesn't report same things as WSL1
67 if grep -q "proxmark.org" "/sys/class/tty/${DEV#/dev/}/../../../manufacturer" 2>/dev/null; then
68 if echo "${PM3LIST[*]}" | grep -qv "${DEV}"; then
69 PM3LIST+=("$DEV")
70 if [ ${#PM3LIST[*]} -ge "$N" ]; then
71 return
75 done
76 if $FINDBTDONGLE; then
77 # check if the HC-06-USB white dongle is present (still, that doesn't tell us if it's paired with a Proxmark3...)
78 for DEV in $(find /dev/ttyUSB* 2>/dev/null); do
79 if command -v udevadm >/dev/null; then
80 if udevadm info -q property -n "$DEV" | grep -q "ID_MODEL=CP2104_USB_to_UART_Bridge_Controller"; then
81 PM3LIST+=("$DEV")
82 if [ ${#PM3LIST[*]} -ge "$N" ]; then
83 return
86 else
87 if grep -q "DRIVER=cp210x" "/sys/class/tty/${DEV#/dev/}/../../uevent" 2>/dev/null; then
88 PM3LIST+=("$DEV")
89 if [ ${#PM3LIST[*]} -ge "$N" ]; then
90 return
94 done
96 if $FINDBTRFCOMM; then
97 # check if the MAC of a Proxmark3 was bound to a local rfcomm interface
98 # (on OSes without deprecated rfcomm and hcitool, the loop will be simply skipped)
99 for DEVMAC in $(rfcomm -a 2>/dev/null | grep " 20:19:0[45]" | sed 's/^\(.*\): \([0-9:]*\) .*/\1@\2/'); do
100 DEV=${DEVMAC/@*/}
101 MAC=${DEVMAC/*@/}
102 # check which are Proxmark3 and, side-effect, if they're actually present
103 if hcitool name "$MAC" | grep -q "PM3"; then
104 PM3LIST+=("/dev/$DEV")
105 if [ ${#PM3LIST[*]} -ge "$N" ]; then
106 return
109 done
111 if $FINDBTDIRECT; then
112 # check if the MAC of a Proxmark3 was registered in the known devices
113 for MAC in $(dbus-send --system --print-reply --type=method_call --dest='org.bluez' '/' org.freedesktop.DBus.ObjectManager.GetManagedObjects 2>/dev/null|\
114 awk '/"Address"/{getline;gsub(/"/,"",$3);a=$3}/Name/{getline;if (/PM3_RDV4/ || /Proxmark3 SE/) print a}'); do
115 PM3LIST+=("bt:$MAC")
116 done
117 # we don't probe the device so there is no guarantee the device is actually present
121 function get_pm3_list_macOS {
122 N=$1
123 PM3LIST=()
124 for DEV in $(ioreg -r -c "IOUSBHostDevice" -l | awk -F '"' '
125 $2=="USB Vendor Name"{b=($4=="proxmark.org")}
126 b==1 && $2=="IODialinDevice"{print $4}'); do
127 PM3LIST+=("$DEV")
128 if [ ${#PM3LIST[*]} -ge "$N" ]; then
129 return
131 done
134 function get_pm3_list_Windows {
135 N=$1
136 PM3LIST=()
138 # Normal SERIAL PORTS (COM)
139 for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%' Or PNPDeviceID LIKE '%VID_2D2D&PID_504D%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
140 DEV=${DEV/ */}
141 #prevent soft bricking when using pm3-flash-all on an outdated bootloader
142 if [ $(basename -- "$0") = "pm3-flash-all" ]; then
143 line=$(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}');
144 if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then
145 echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!"
146 exit 1
149 PM3LIST+=("$DEV")
150 if [ ${#PM3LIST[*]} -ge "$N" ]; then
151 return
153 done
155 #BT direct SERIAL PORTS (COM)
156 if $FINDBTRFCOMM; then
157 for DEV in $(wmic /locale:ms_409 path Win32_PnPEntity Where "Caption LIKE '%Bluetooth%(COM%'" Get Name 2> /dev/null | awk -b 'match($0,/(COM[0-9]+)/,m){print m[1]}'); do
158 DEV=${DEV/ */}
159 PM3LIST+=("$DEV")
160 if [ ${#PM3LIST[*]} -ge "$N" ]; then
161 return
163 done
166 #white BT dongle SERIAL PORTS (COM)
167 if $FINDBTDONGLE; then
168 for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_10C4&PID_EA60%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do
169 DEV=${DEV/ */}
170 PM3LIST+=("$DEV")
171 if [ ${#PM3LIST[*]} -ge "$N" ]; then
172 return
174 done
178 function get_pm3_list_WSL {
179 N=$1
180 PM3LIST=()
182 # Normal SERIAL PORTS (COM)
183 for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.PNPDeviceID -like '*VID_9AC4&PID_4B8F*' -or \$_.PNPDeviceID -like '*VID_2D2D&PID_504D*'} | Select -expandproperty DeviceID" 2>/dev/null); do
184 DEV=$(echo $DEV | tr -dc '[:print:]')
185 _comport=$DEV
186 DEV=$(echo $DEV | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p')
187 # ttyS counterpart takes some more time to appear
188 if [ -e "$DEV" ]; then
190 #prevent soft bricking when using pm3-flash-all on an outdated bootloader
191 if [ $(basename -- "$0") = "pm3-flash-all" ]; then
192 line=$($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null | tr -dc '[:print:]');
193 if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then
194 echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!"
195 exit 1
198 PM3LIST+=("$DEV")
199 if [ ! -w "$DEV" ]; then
200 echo "[!] Let's give users read/write access to $DEV"
201 sudo chmod 666 "$DEV"
203 if [ ${#PM3LIST[*]} -ge "$N" ]; then
204 return
207 done
209 #BT direct SERIAL PORTS (COM)
210 if $FINDBTRFCOMM; then
211 for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_PnPEntity | Where-Object Caption -like 'Standard Serial over Bluetooth link (COM*' | Select Name" 2> /dev/null | sed -nr 's#.*\bCOM([0-9]+)\b.*#/dev/ttyS\1#p'); do
212 # ttyS counterpart takes some more time to appear
213 if [ -e "$DEV" ]; then
214 PM3LIST+=("$DEV")
215 if [ ! -w "$DEV" ]; then
216 echo "[!] Let's give users read/write access to $DEV"
217 sudo chmod 666 "$DEV"
219 if [ ${#PM3LIST[*]} -ge "$N" ]; then
220 return
224 done
227 #white BT dongle SERIAL PORTS (COM)
228 if $FINDBTDONGLE; then
229 for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_10C4&PID_EA60*' | Select DeviceID" 2>/dev/null | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p'); do
230 # ttyS counterpart takes some more time to appear
231 if [ -e "$DEV" ]; then
232 PM3LIST+=("$DEV")
233 if [ ! -w "$DEV" ]; then
234 echo "[!] Let's give users read/write access to $DEV"
235 sudo chmod 666 "$DEV"
237 if [ ${#PM3LIST[*]} -ge "$N" ]; then
238 return
242 done
246 SCRIPT=$(basename -- "$0")
248 if [ "$SCRIPT" = "pm3" ]; then
249 CMD() { eval "$EVALENV"; $CLIENT "$@"; }
250 HELP() {
251 cat << EOF
253 Quick helper script for proxmark3 client when working with a Proxmark3 device
255 Description:
256 The usage is the same as for the proxmark3 client, with the following differences:
257 * the correct port name will be automatically guessed;
258 * the script will wait for a Proxmark3 to be connected (same as option -w of the client).
259 You can also specify a first option -n N to access the Nth Proxmark3 connected.
260 To see a list of available ports, use --list.
262 Usage:
263 $SCRIPT [-n <N>] [<any other proxmark3 client option>]
264 $SCRIPT [--list] [-h|--help] [-hh|--helpclient]
265 $SCRIPT [-o|--offline]
268 Arguments:
269 -h/--help this help
270 -hh/--helpclient proxmark3 client help (the script will forward these options)
271 --list list all detected com ports
272 -n <N> connect device referred to the N:th number on the --list output
273 -o/--offline shortcut to use directly the proxmark3 client without guessing ports
275 Samples:
276 ./$SCRIPT -- Auto detect/ select com port in the following order BT, USB/CDC, BT DONGLE
277 ./$SCRIPT -p /dev/ttyACM0 -- connect to port /dev/ttyACM0
278 ./$SCRIPT -n 2 -- use second item from the --list output
279 ./$SCRIPT -c 'lf search' -i -- run command and stay in client once completed
284 elif [ "$SCRIPT" = "pm3-flash" ]; then
285 FINDBTDONGLE=false
286 FINDBTRFCOMM=false
287 FINDBTDIRECT=false
288 CMD() {
289 ARGS=("--port" "$1" "--flash")
290 shift;
291 while [ "$1" != "" ]; do
292 if [ "$1" == "-b" ]; then
293 ARGS+=("--unlock-bootloader")
294 elif [ "$1" == "--force" ]; then
295 ARGS+=("--force")
296 else
297 ARGS+=("--image" "$1")
299 shift;
300 done
301 $CLIENT "${ARGS[@]}";
303 HELP() {
304 cat << EOF
305 Quick helper script for flashing a Proxmark3 device via USB
307 Description:
308 The usage is similar to the old proxmark3-flasher binary, except that the correct port name will be automatically guessed.
309 You can also specify a first option -n N to access the Nth Proxmark3 connected on USB.
310 If this doesn't work, you'll have to use manually the proxmark3 client, see "$CLIENT -h".
311 To see a list of available ports, use --list.
313 Usage:
314 $SCRIPT [-n <N>] [-b] image.elf [image.elf...]
315 $SCRIPT --list
317 Options:
318 -b Enable flashing of bootloader area (DANGEROUS)
320 Example:
321 $SCRIPT -b bootrom.elf fullimage.elf
324 elif [ "$SCRIPT" = "pm3-flash-all" ]; then
325 FINDBTDONGLE=false
326 FINDBTRFCOMM=false
327 FINDBTDIRECT=false
330 CMD() {
331 ARGS=("--port" "$1" "--flash" "--unlock-bootloader" "--image" "$BOOTIMAGE" "--image" "$FULLIMAGE")
332 shift;
333 while [ "$1" != "" ]; do
334 if [ "$1" == "--force" ]; then
335 ARGS+=("--force")
337 shift;
338 done
339 $CLIENT "${ARGS[@]}";
341 HELP() {
342 cat << EOF
343 Quick helper script for flashing a Proxmark3 device via USB
345 Description:
346 The correct port name will be automatically guessed and the stock bootloader and firmware image will be flashed.
347 You can also specify a first option -n N to access the Nth Proxmark3 connected on USB.
348 If this doesn't work, you'll have to use manually the proxmark3 client, see "$CLIENT -h".
349 To see a list of available ports, use --list.
351 Usage:
352 $SCRIPT [-n <N>]
353 $SCRIPT --list
356 elif [ "$SCRIPT" = "pm3-flash-fullimage" ]; then
357 FINDBTDONGLE=false
358 FINDBTRFCOMM=false
359 FINDBTDIRECT=false
360 CMD() {
361 ARGS=("--port" "$1" "--flash" "--image" "$FULLIMAGE")
362 shift;
363 while [ "$1" != "" ]; do
364 if [ "$1" == "--force" ]; then
365 ARGS+=("--force")
367 shift;
368 done
369 $CLIENT "${ARGS[@]}";
371 HELP() {
372 cat << EOF
373 Quick helper script for flashing a Proxmark3 device via USB
375 Description:
376 The correct port name will be automatically guessed and the stock firmware image will be flashed.
377 You can also specify a first option -n N to access the Nth Proxmark3 connected on USB.
378 If this doesn't work, you'll have to use manually the proxmark3 client, see "$CLIENT -h".
379 To see a list of available ports, use --list.
381 Usage:
382 $SCRIPT [-n <N>]
383 $SCRIPT --list
386 elif [ "$SCRIPT" = "pm3-flash-bootrom" ]; then
387 FINDBTDONGLE=false
388 FINDBTRFCOMM=false
389 FINDBTDIRECT=false
390 CMD() {
391 ARGS=("--port" "$1" "--flash" "--unlock-bootloader" "--image" "$BOOTIMAGE")
392 shift;
393 while [ "$1" != "" ]; do
394 if [ "$1" == "--force" ]; then
395 ARGS+=("--force")
397 shift;
398 done
399 $CLIENT "${ARGS[@]}";
401 HELP() {
402 cat << EOF
403 Quick helper script for flashing a Proxmark3 device via USB
405 Description:
406 The correct port name will be automatically guessed and the stock bootloader will be flashed.
407 You can also specify a first option -n N to access the Nth Proxmark3 connected on USB.
408 If this doesn't work, you'll have to use manually the proxmark3 client, see "$CLIENT -h".
409 To see a list of available ports, use --list.
411 Usage:
412 $SCRIPT [-n <N>]
413 $SCRIPT --list
416 else
417 echo >&2 "[!!] Script ran under unknown name, abort: $SCRIPT"
418 exit 1
421 # priority to the help options
422 for ARG; do
423 if [ "$ARG" == "-h" ] || [ "$ARG" == "--help" ]; then
424 HELP
425 exit 0
427 if [ "$ARG" == "-hh" ] || [ "$ARG" == "--helpclient" ]; then
428 CMD "-h"
429 exit 0
431 done
433 # if offline, bypass the script and forward all other args
434 for ARG; do
435 shift
436 if [ "$ARG" == "-o" ] || [ "$ARG" == "--offline" ]; then
437 CMD "$@"
438 exit $?
440 set -- "$@" "$ARG"
441 done
443 # if a port is already provided, let's just run the command as such
444 for ARG; do
445 shift
446 if [ "$ARG" == "-p" ]; then
447 CMD "$@"
448 exit $?
450 set -- "$@" "$ARG"
451 done
453 if [ "$1" == "--list" ]; then
454 shift
455 if [ "$1" != "" ]; then
456 echo >&2 "[!!] Option --list must be used alone"
457 exit 1
459 SHOWLIST=true
462 # Number of the Proxmark3 we're interested in
464 if [ "$1" == "-n" ]; then
465 shift
466 if [ "$1" -ge 1 ] && [ "$1" -lt 10 ]; then
467 N=$1
468 shift
469 else
470 echo >&2 "[!!] Option -n requires a number between 1 and 9, got \"$1\""
471 exit 1
475 HOSTOS=$(uname | awk '{print toupper($0)}')
476 if [ "$HOSTOS" = "LINUX" ]; then
477 # Detect when running under WSL1 (but exclude WSL2)
478 if uname -a | grep -qi Microsoft && uname -a | grep -qvi WSL2; then
479 # First try finding it using the PATH environment variable
480 PSHEXE=$(command -v powershell.exe 2>/dev/null)
482 # If it fails (such as if WSLENV is not set), try using the default installation path
483 if [ -z "$PSHEXE" ]; then
484 PSHEXE=/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe
487 # Finally test if PowerShell is working
488 if ! "$PSHEXE" exit >/dev/null 2>&1; then
489 echo >&2 "[!!] Cannot run powershell.exe, are you sure your WSL is authorized to run Windows processes? (cf WSL interop flag)"
490 exit 1
493 GETPM3LIST=get_pm3_list_WSL
494 else
495 GETPM3LIST=get_pm3_list_Linux
497 elif [ "$HOSTOS" = "DARWIN" ]; then
498 GETPM3LIST=get_pm3_list_macOS
499 elif [[ "$HOSTOS" =~ MINGW(32|64)_NT* ]]; then
500 GETPM3LIST=get_pm3_list_Windows
501 else
502 echo >&2 "[!!] Host OS not recognized, abort: $HOSTOS"
503 exit 1
506 if $SHOWLIST; then
507 # Probe for up to 9 devs
508 $GETPM3LIST 9
509 if [ ${#PM3LIST} -lt 1 ]; then
510 echo >&2 "[!!] No port found"
511 exit 1
514 for DEV in "${PM3LIST[@]}"
516 echo "$n: $DEV"
517 n=$((n+1))
518 done
519 exit 0
522 # Wait till we get at least N Proxmark3 devices
523 $GETPM3LIST "$N"
524 if [ ${#PM3LIST} -lt "$N" ]; then
525 echo >&2 "[=] Waiting for Proxmark3 to appear..."
527 while true; do
528 if [ ${#PM3LIST[*]} -ge "$N" ]; then
529 break
531 sleep .1
532 $GETPM3LIST "$N"
533 done
535 if [ ${#PM3LIST} -lt "$N" ]; then
536 HELP() {
537 cat << EOF
538 [!!] No port found, abort
540 [?] Hint: try '$SCRIPT --list' to see list of available ports, and use the -n command like below
541 [?] $SCRIPT [-n <N>]
545 HELP
546 exit 1
549 CMD "${PM3LIST[$((N-1))]}" "$@"
550 exit $?