Merge pull request #1339 from Guilhem7/master
[RRG-proxmark3.git] / pm3
blob0aea8942c32643def8f82d4556511a4dbd14852f
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 # Devel mode: point to workdir pm3.py module
31 EVALENV+=" PYTHONPATH=$PM3PATH/client/src"
32 # try install dir
33 elif [ -x "$PM3PATH/proxmark3" ]; then
34 CLIENT="$PM3PATH/proxmark3"
35 EVALENV+=" PYTHONPATH=$PM3PATH/../share/proxmark3/pyscripts/"
36 # or /usr/[local/]lib/python3/dist-packages/pm3.py ?
37 else
38 # hope it's installed somehow, still not sure where fw images and pm3.py are...
39 CLIENT="proxmark3"
43 # LeakSanitizer suppressions
44 if [ -e .lsan_suppressions ]; then
45 EVALENV+=" LSAN_OPTIONS=suppressions=.lsan_suppressions"
47 if [ "$EVALENV" != "" ]; then
48 EVALENV="export $EVALENV"
50 PM3LIST=()
51 SHOWLIST=false
53 function get_pm3_list_Linux {
54 N=$1
55 PM3LIST=()
56 if [ ! -c "/dev/tty0" ]; then
57 echo >&2 "[!!] Script cannot access /dev/ttyXXX files, insufficient privileges"
58 exit 1
60 for DEV in $(find /dev/ttyACM* 2>/dev/null); do
61 if which udevadm >/dev/null; then
62 if udevadm info -q property -n "$DEV" | grep -q "ID_VENDOR=proxmark.org"; then
63 PM3LIST+=("$DEV")
64 if [ ${#PM3LIST[*]} -ge "$N" ]; then
65 return
68 else
69 if grep -q "proxmark.org" "/sys/class/tty/${DEV#/dev/}/../../../manufacturer" 2>/dev/null; then
70 PM3LIST+=("$DEV")
71 if [ ${#PM3LIST[*]} -ge "$N" ]; then
72 return
76 done
77 if $FINDBTDONGLE; then
78 # check if the HC-06-USB white dongle is present (still, that doesn't tell us if it's paired with a Proxmark3...)
79 for DEV in $(find /dev/ttyUSB* 2>/dev/null); do
80 if which udevadm >/dev/null; then
81 if udevadm info -q property -n "$DEV" | grep -q "ID_MODEL=CP2104_USB_to_UART_Bridge_Controller"; then
82 PM3LIST+=("$DEV")
83 if [ ${#PM3LIST[*]} -ge "$N" ]; then
84 return
87 else
88 if grep -q "DRIVER=cp210x" "/sys/class/tty/${DEV#/dev/}/../../uevent" 2>/dev/null; then
89 PM3LIST+=("$DEV")
90 if [ ${#PM3LIST[*]} -ge "$N" ]; then
91 return
95 done
97 if $FINDBTRFCOMM; then
98 # check if the MAC of a Proxmark3 was bound to a local rfcomm interface
99 # (on OSes without deprecated rfcomm and hcitool, the loop will be simply skipped)
100 for DEVMAC in $(rfcomm -a 2>/dev/null | grep " 20:19:0[45]" | sed 's/^\(.*\): \([0-9:]*\) .*/\1@\2/'); do
101 DEV=${DEVMAC/@*/}
102 MAC=${DEVMAC/*@/}
103 # check which are Proxmark3 and, side-effect, if they're actually present
104 if hcitool name "$MAC" | grep -q "PM3"; then
105 PM3LIST+=("/dev/$DEV")
106 if [ ${#PM3LIST[*]} -ge "$N" ]; then
107 return
110 done
112 if $FINDBTDIRECT; then
113 # check if the MAC of a Proxmark3 was registered in the known devices
114 for MAC in $(dbus-send --system --print-reply --type=method_call --dest='org.bluez' '/' org.freedesktop.DBus.ObjectManager.GetManagedObjects 2>/dev/null|\
115 awk '/"Address"/{getline;gsub(/"/,"",$3);a=$3}/Name/{getline;if (/PM3_RDV4/) print a}'); do
116 PM3LIST+=("bt:$MAC")
117 done
118 # we don't probe the device so there is no guarantee the device is actually present
122 function get_pm3_list_macOS {
123 N=$1
124 PM3LIST=()
125 for DEV in $(ioreg -r -c "IOUSBHostDevice" -l | awk -F '"' '
126 $2=="USB Vendor Name"{b=($4=="proxmark.org")}
127 b==1 && $2=="IODialinDevice"{print $4}'); do
128 PM3LIST+=("$DEV")
129 if [ ${#PM3LIST[*]} -ge "$N" ]; then
130 return
132 done
135 function get_pm3_list_Windows {
136 N=$1
137 PM3LIST=()
138 # Need to look for this first, the call to Win32_serialport "crashes" then native bt serial port. Don't ask why.
139 #BT direct SERIAL PORTS (COM)
140 if $FINDBTRFCOMM; then
141 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
142 DEV=${DEV/ */}
143 PM3LIST+=("$DEV")
144 if [ ${#PM3LIST[*]} -ge "$N" ]; then
145 return
147 done
150 # Normal SERIAL PORTS (COM)
151 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
152 DEV=${DEV/ */}
153 #prevent soft bricking when using pm3-flash-all on an outdated bootloader
154 if [ $(basename -- "$0") = "pm3-flash-all" ]; then
155 if [ ! $(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then
156 echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!"
157 exit 1
160 #Prioritise USB connections
161 PM3LIST=("$DEV" "${PM3LIST[@]}")
162 if [ ${#PM3LIST[*]} -ge "$N" ]; then
163 return
165 done
167 #white BT dongle SERIAL PORTS (COM)
168 if $FINDBTDONGLE; then
169 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
170 DEV=${DEV/ */}
171 PM3LIST+=("$DEV")
172 if [ ${#PM3LIST[*]} -ge "$N" ]; then
173 return
175 done
179 function get_pm3_list_WSL {
180 N=$1
181 PM3LIST=()
183 # Need to look for this first, the call to Win32_serialport "crashes" then native bt serial port. Don't ask why.
184 #BT direct SERIAL PORTS (COM)
185 if $FINDBTRFCOMM; then
186 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
187 # ttyS counterpart takes some more time to appear
188 if [ -e "$DEV" ]; then
189 PM3LIST+=("$DEV")
190 if [ ! -w "$DEV" ]; then
191 echo "[!] Let's give users read/write access to $DEV"
192 sudo chmod 666 "$DEV"
194 if [ ${#PM3LIST[*]} -ge "$N" ]; then
195 return
199 done
202 # Normal SERIAL PORTS (COM)
203 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 | tr -dc '[:print:]'); do
204 _comport=$DEV
205 DEV=$(echo $DEV | sed -nr 's#^COM([0-9]+)\b#/dev/ttyS\1#p')
206 # ttyS counterpart takes some more time to appear
207 if [ -e "$DEV" ]; then
208 #prevent soft bricking when using pm3-flash-all on an outdated bootloader
209 if [ $(basename -- "$0") = "pm3-flash-all" ]; then
210 if [ ! $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null | tr -dc '[:print:]') = "USB\VID_9AC4&PID_4B8F\ICEMAN" ]; then
211 echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!"
212 exit 1
215 #Prioritise USB connections
216 PM3LIST=("$DEV" "${PM3LIST[@]}")
217 if [ ! -w "$DEV" ]; then
218 echo "[!] Let's give users read/write access to $DEV"
219 sudo chmod 666 "$DEV"
221 if [ ${#PM3LIST[*]} -ge "$N" ]; then
222 return
225 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 Proxmark 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 else
295 ARGS+=("--image" "$1")
297 shift;
298 done
299 $CLIENT "${ARGS[@]}";
301 HELP() {
302 cat << EOF
303 Quick helper script for flashing a Proxmark device via USB
305 Description:
306 The usage is similar to the old proxmark3-flasher binary, except that the correct port name will be automatically guessed.
307 You can also specify a first option -n N to access the Nth Proxmark3 connected on USB.
308 If this doesn't work, you'll have to use manually the proxmark3 client, see "$CLIENT -h".
309 To see a list of available ports, use --list.
311 Usage:
312 $SCRIPT [-n <N>] [-b] image.elf [image.elf...]
313 $SCRIPT --list
315 Options:
316 -b Enable flashing of bootloader area (DANGEROUS)
318 Example:
319 $SCRIPT -b bootrom.elf fullimage.elf
322 elif [ "$SCRIPT" = "pm3-flash-all" ]; then
323 FINDBTDONGLE=false
324 FINDBTRFCOMM=false
325 FINDBTDIRECT=false
326 CMD() { $CLIENT "--port" "$1" "--flash" "--unlock-bootloader" "--image" "$BOOTIMAGE" "--image" "$FULLIMAGE"; }
327 HELP() {
328 cat << EOF
329 Quick helper script for flashing a Proxmark device via USB
331 Description:
332 The correct port name will be automatically guessed and the stock bootloader and firmware image will be flashed.
333 You can also specify a first option -n N to access the Nth Proxmark3 connected on USB.
334 If this doesn't work, you'll have to use manually the proxmark3 client, see "$CLIENT -h".
335 To see a list of available ports, use --list.
337 Usage:
338 $SCRIPT [-n <N>]
339 $SCRIPT --list
342 elif [ "$SCRIPT" = "pm3-flash-fullimage" ]; then
343 FINDBTDONGLE=false
344 FINDBTRFCOMM=false
345 FINDBTDIRECT=false
346 CMD() { $CLIENT "--port" "$1" "--flash" "--image" "$FULLIMAGE"; }
347 HELP() {
348 cat << EOF
349 Quick helper script for flashing a Proxmark device via USB
351 Description:
352 The correct port name will be automatically guessed and the stock firmware image will be flashed.
353 You can also specify a first option -n N to access the Nth Proxmark3 connected on USB.
354 If this doesn't work, you'll have to use manually the proxmark3 client, see "$CLIENT -h".
355 To see a list of available ports, use --list.
357 Usage:
358 $SCRIPT [-n <N>]
359 $SCRIPT --list
362 elif [ "$SCRIPT" = "pm3-flash-bootrom" ]; then
363 FINDBTDONGLE=false
364 FINDBTRFCOMM=false
365 FINDBTDIRECT=false
366 CMD() { $CLIENT "--port" "$1" "--flash" "--unlock-bootloader" "--image" "$BOOTIMAGE"; }
367 HELP() {
368 cat << EOF
369 Quick helper script for flashing a Proxmark device via USB
371 Description:
372 The correct port name will be automatically guessed and the stock bootloader will be flashed.
373 You can also specify a first option -n N to access the Nth Proxmark3 connected on USB.
374 If this doesn't work, you'll have to use manually the proxmark3 client, see "$CLIENT -h".
375 To see a list of available ports, use --list.
377 Usage:
378 $SCRIPT [-n <N>]
379 $SCRIPT --list
382 else
383 echo >&2 "[!!] Script ran under unknown name, abort: $SCRIPT"
384 exit 1
387 # priority to the help options
388 for ARG; do
389 if [ "$ARG" == "-h" ] || [ "$ARG" == "--help" ]; then
390 HELP
391 exit 0
393 if [ "$ARG" == "-hh" ] || [ "$ARG" == "--helpclient" ]; then
394 CMD "-h"
395 exit 0
397 done
399 # if offline, bypass the script and forward all other args
400 for ARG; do
401 shift
402 if [ "$ARG" == "-o" ] || [ "$ARG" == "--offline" ]; then
403 CMD "$@"
404 exit $?
406 set -- "$@" "$ARG"
407 done
409 # if a port is already provided, let's just run the command as such
410 for ARG; do
411 if [ "$ARG" == "-p" ]; then
412 CMD "$@"
413 exit $?
415 done
417 if [ "$1" == "--list" ]; then
418 shift
419 if [ "$1" != "" ]; then
420 echo >&2 "[!!] Option --list must be used alone"
421 exit 1
423 SHOWLIST=true
426 # Number of the proxmark3 we're interested in
428 if [ "$1" == "-n" ]; then
429 shift
430 if [ "$1" -ge 1 ] && [ "$1" -lt 10 ]; then
431 N=$1
432 shift
433 else
434 echo >&2 "[!!] Option -n requires a number between 1 and 9, got \"$1\""
435 exit 1
439 HOSTOS=$(uname | awk '{print toupper($0)}')
440 if [ "$HOSTOS" = "LINUX" ]; then
441 if uname -a|grep -q Microsoft; then
442 # First try finding it using the PATH environment variable
443 PSHEXE=$(which powershell.exe 2>/dev/null)
445 # If it fails (such as if WSLENV is not set), try using the default installation path
446 if [ -z "$PSHEXE" ]; then
447 PSHEXE=/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe
450 # Finally test if PowerShell is working
451 if ! "$PSHEXE" exit >/dev/null 2>&1; then
452 echo >&2 "[!!] Cannot run powershell.exe, are you sure your WSL is authorized to run Windows processes? (cf WSL interop flag)"
453 exit 1
456 GETPM3LIST=get_pm3_list_WSL
457 else
458 GETPM3LIST=get_pm3_list_Linux
460 elif [ "$HOSTOS" = "DARWIN" ]; then
461 GETPM3LIST=get_pm3_list_macOS
462 elif [[ "$HOSTOS" =~ MINGW(32|64)_NT* ]]; then
463 GETPM3LIST=get_pm3_list_Windows
464 else
465 echo >&2 "[!!] Host OS not recognized, abort: $HOSTOS"
466 exit 1
469 if $SHOWLIST; then
470 # Probe for up to 9 devs
471 $GETPM3LIST 9
472 if [ ${#PM3LIST} -lt 1 ]; then
473 echo >&2 "[!!] No port found"
474 exit 1
477 for DEV in "${PM3LIST[@]}"
479 echo "$n: $DEV"
480 n=$((n+1))
481 done
482 exit 0
485 # Wait till we get at least N proxmark3 devices
486 $GETPM3LIST "$N"
487 if [ ${#PM3LIST} -lt "$N" ]; then
488 echo >&2 "[=] Waiting for Proxmark3 to appear..."
490 while true; do
491 if [ ${#PM3LIST[*]} -ge "$N" ]; then
492 break
494 sleep .1
495 $GETPM3LIST "$N"
496 done
498 if [ ${#PM3LIST} -lt "$N" ]; then
499 HELP() {
500 cat << EOF
501 [!!] No port found, abort
503 [?] Hint: try '$SCRIPT --list' to see list of available ports, and use the -n command like below
504 [?] $SCRIPT [-n <N>]
508 HELP
509 exit 1
512 CMD "${PM3LIST[$((N-1))]}" "$@"
513 exit $?