mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
Added native output grabbing for Python and Lua: less hacky than output_grabber.py, should work on ProxSpace as well
This commit is contained in:
parent
83f6e2b56b
commit
369c5bb5db
23 changed files with 387 additions and 198 deletions
|
@ -19,7 +19,6 @@ import time
|
|||
import subprocess
|
||||
import argparse
|
||||
import pm3
|
||||
from output_grabber import OutputGrabber
|
||||
# optional color support
|
||||
try:
|
||||
# pip install ansicolors
|
||||
|
@ -49,14 +48,6 @@ for tool, bin in tools.items():
|
|||
if not os.path.isfile(bin):
|
||||
if os.path.isfile(bin + ".exe"):
|
||||
tools[tool] = bin + ".exe"
|
||||
|
||||
print(f"Native Windows/ProxSpace detected.")
|
||||
print(f"Currently, our Python output grabbing does not work properly on this environment.")
|
||||
print(f"Use WSL or Linux.")
|
||||
# cf https://stackoverflow.com/questions/52373180/python-on-windows-handle-invalid-when-redirecting-stdout-writing-to-file
|
||||
# for ref : https://docs.python.org/3/c-api/init_config.html#c.PyConfig.legacy_windows_stdio
|
||||
exit()
|
||||
|
||||
else:
|
||||
print(f"Cannot find {bin}, abort!")
|
||||
exit()
|
||||
|
@ -69,27 +60,24 @@ parser.add_argument('-d', '--debug', action='store_true', help='Enable debug mod
|
|||
args = parser.parse_args()
|
||||
|
||||
start_time = time.time()
|
||||
out = OutputGrabber()
|
||||
p = pm3.pm3()
|
||||
|
||||
restore_color = False
|
||||
with out:
|
||||
p.console("prefs get color")
|
||||
p.console("prefs set color --off")
|
||||
for line in out.captured_output.split('\n'):
|
||||
p.console("prefs get color")
|
||||
p.console("prefs set color --off")
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
if "ansi" in line:
|
||||
restore_color = True
|
||||
with out:
|
||||
p.console("hf 14a read")
|
||||
p.console("hf 14a read")
|
||||
uid = None
|
||||
for line in out.captured_output.split('\n'):
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
if "UID:" in line:
|
||||
uid = int(line[10:].replace(' ', ''), 16)
|
||||
if uid is None:
|
||||
print("Card not found")
|
||||
if restore_color:
|
||||
with out:
|
||||
p.console("prefs set color --ansi")
|
||||
p.console("prefs set color --ansi")
|
||||
_ = p.grabbed_output
|
||||
exit()
|
||||
print("UID: " + color(f"{uid:08X}", fg="green"))
|
||||
|
||||
|
@ -102,9 +90,8 @@ def print_key(sec, key_type, key):
|
|||
found_keys = [["", ""] for _ in range(NUM_SECTORS)]
|
||||
if not args.no_init_check:
|
||||
print("Checking default keys...")
|
||||
with out:
|
||||
p.console("hf mf fchk")
|
||||
for line in out.captured_output.split('\n'):
|
||||
p.console("hf mf fchk")
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
if "[+] 0" in line:
|
||||
res = [x.strip() for x in line.split('|')]
|
||||
sec = int(res[0][4:])
|
||||
|
@ -119,18 +106,17 @@ nt = [["", ""] for _ in range(NUM_SECTORS)]
|
|||
nt_enc = [["", ""] for _ in range(NUM_SECTORS)]
|
||||
par_err = [["", ""] for _ in range(NUM_SECTORS)]
|
||||
print("Getting nonces...")
|
||||
with out:
|
||||
for sec in range(NUM_SECTORS):
|
||||
blk = sec * 4
|
||||
if found_keys[sec][0] == "" or found_keys[sec][1] == "":
|
||||
# Even if one key already found, we'll need both nt
|
||||
for key_type in [0, 1]:
|
||||
cmd = f"hf mf isen -n1 --blk {blk} -c {key_type+4} --key {BACKDOOR_RF08S}"
|
||||
p.console(cmd)
|
||||
cmd += f" --c2 {key_type}"
|
||||
p.console(cmd)
|
||||
for sec in range(NUM_SECTORS):
|
||||
blk = sec * 4
|
||||
if found_keys[sec][0] == "" or found_keys[sec][1] == "":
|
||||
# Even if one key already found, we'll need both nt
|
||||
for key_type in [0, 1]:
|
||||
cmd = f"hf mf isen -n1 --blk {blk} -c {key_type+4} --key {BACKDOOR_RF08S}"
|
||||
p.console(cmd)
|
||||
cmd += f" --c2 {key_type}"
|
||||
p.console(cmd)
|
||||
print("Processing traces...")
|
||||
for line in out.captured_output.split('\n'):
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
if "nested cmd: 64" in line or "nested cmd: 65" in line:
|
||||
sec = int(line[24:26], 16)//4
|
||||
key_type = int(line[21:23], 16) - 0x64
|
||||
|
@ -232,9 +218,8 @@ for sec in range(NUM_SECTORS):
|
|||
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
||||
if args.debug:
|
||||
print(cmd)
|
||||
with out:
|
||||
p.console(cmd)
|
||||
for line in out.captured_output.split('\n'):
|
||||
p.console(cmd)
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
if "aborted via keyboard" in line:
|
||||
abort = True
|
||||
if "found:" in line:
|
||||
|
@ -259,9 +244,8 @@ for sec in range(NUM_SECTORS):
|
|||
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
||||
if args.debug:
|
||||
print(cmd)
|
||||
with out:
|
||||
p.console(cmd)
|
||||
for line in out.captured_output.split('\n'):
|
||||
p.console(cmd)
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
if "aborted via keyboard" in line:
|
||||
abort = True
|
||||
if "found:" in line:
|
||||
|
@ -281,9 +265,8 @@ for sec in range(NUM_SECTORS):
|
|||
cmd = f"hf mf fchk --blk {sec * 4} -{kt} -f {dic} --no-default"
|
||||
if args.debug:
|
||||
print(cmd)
|
||||
with out:
|
||||
p.console(cmd)
|
||||
for line in out.captured_output.split('\n'):
|
||||
p.console(cmd)
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
if "aborted via keyboard" in line:
|
||||
abort = True
|
||||
if "found:" in line:
|
||||
|
@ -324,9 +307,8 @@ for sec in range(NUM_SECTORS):
|
|||
cmd += f" -k {k}"
|
||||
if args.debug:
|
||||
print(cmd)
|
||||
with out:
|
||||
p.console(cmd)
|
||||
for line in out.captured_output.split('\n'):
|
||||
p.console(cmd)
|
||||
for line in p.grabbed_output.split('\n'):
|
||||
if "aborted via keyboard" in line:
|
||||
abort = True
|
||||
if "found:" in line:
|
||||
|
@ -338,8 +320,8 @@ for sec in range(NUM_SECTORS):
|
|||
if abort:
|
||||
break
|
||||
if restore_color:
|
||||
with out:
|
||||
p.console("prefs set color --ansi")
|
||||
p.console("prefs set color --ansi")
|
||||
_ = p.grabbed_output
|
||||
|
||||
if abort:
|
||||
print("Brute-forcing phase aborted via keyboard!")
|
||||
|
@ -389,10 +371,7 @@ else:
|
|||
cmd = f"hf mf fchk -f keys_{uid:08x}.dic --no-default --dump"
|
||||
if args.debug:
|
||||
print(cmd)
|
||||
with out:
|
||||
p.console(cmd)
|
||||
for line in out.captured_output.split('\n'):
|
||||
print(line)
|
||||
p.console(cmd, passthru = True)
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
minutes = int(elapsed_time // 60)
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
# From https://stackoverflow.com/a/29834357
|
||||
class OutputGrabber(object):
|
||||
"""
|
||||
Class used to grab standard output or another stream.
|
||||
"""
|
||||
escape_char = "\b"
|
||||
|
||||
def __init__(self, stream=None, threaded=False):
|
||||
self.origstream = stream
|
||||
self.threaded = threaded
|
||||
if self.origstream is None:
|
||||
self.origstream = sys.stdout
|
||||
self.origstreamfd = self.origstream.fileno()
|
||||
self.captured_output = ""
|
||||
|
||||
def __enter__(self):
|
||||
self.start()
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.stop()
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Start capturing the stream data.
|
||||
"""
|
||||
self.captured_output = ""
|
||||
# Create a pipe so the stream can be captured:
|
||||
self.pipe_out, self.pipe_in = os.pipe()
|
||||
# Save a copy of the stream:
|
||||
self.streamfd = os.dup(self.origstreamfd)
|
||||
# Replace the original stream with our write pipe:
|
||||
os.dup2(self.pipe_in, self.origstreamfd)
|
||||
if self.threaded:
|
||||
# Start thread that will read the stream:
|
||||
self.workerThread = threading.Thread(target=self.readOutput)
|
||||
self.workerThread.start()
|
||||
# Make sure that the thread is running and os.read() has executed:
|
||||
time.sleep(0.01)
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop capturing the stream data and save the text in `captured_output`.
|
||||
"""
|
||||
# Print the escape character to make the readOutput method stop:
|
||||
self.origstream.write(self.escape_char)
|
||||
# Flush the stream to make sure all our data goes in before
|
||||
# the escape character:
|
||||
self.origstream.flush()
|
||||
if self.threaded:
|
||||
# wait until the thread finishes so we are sure that
|
||||
# we have until the last character:
|
||||
self.workerThread.join()
|
||||
else:
|
||||
self.readOutput()
|
||||
# Close the pipe:
|
||||
os.close(self.pipe_in)
|
||||
os.close(self.pipe_out)
|
||||
# Restore the original stream:
|
||||
os.dup2(self.streamfd, self.origstreamfd)
|
||||
# Close the duplicate stream:
|
||||
os.close(self.streamfd)
|
||||
|
||||
def readOutput(self):
|
||||
"""
|
||||
Read the stream data (one byte at a time)
|
||||
and save the text in `captured_output`.
|
||||
"""
|
||||
while True:
|
||||
char = os.read(self.pipe_out,1).decode(self.origstream.encoding, errors='replace')
|
||||
if not char or self.escape_char in char:
|
||||
break
|
||||
self.captured_output += char
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("This is a library, don't use it as a script")
|
|
@ -1,13 +1,10 @@
|
|||
# This file was automatically generated by SWIG (http://www.swig.org).
|
||||
# Version 4.0.2
|
||||
# This file was automatically generated by SWIG (https://www.swig.org).
|
||||
# Version 4.2.1
|
||||
#
|
||||
# Do not make changes to this file unless you know what you are doing--modify
|
||||
# Do not make changes to this file unless you know what you are doing - modify
|
||||
# the SWIG interface file instead.
|
||||
|
||||
from sys import version_info as _swig_python_version_info
|
||||
if _swig_python_version_info < (2, 7, 0):
|
||||
raise RuntimeError("Python 2.7 or later required")
|
||||
|
||||
# Import the low-level C/C++ module
|
||||
if __package__ or "." in __name__:
|
||||
from . import _pm3
|
||||
|
@ -29,10 +26,10 @@ def _swig_repr(self):
|
|||
|
||||
def _swig_setattr_nondynamic_instance_variable(set):
|
||||
def set_instance_attr(self, name, value):
|
||||
if name == "thisown":
|
||||
self.this.own(value)
|
||||
elif name == "this":
|
||||
if name == "this":
|
||||
set(self, name, value)
|
||||
elif name == "thisown":
|
||||
self.this.own(value)
|
||||
elif hasattr(self, name) and isinstance(getattr(type(self), name), property):
|
||||
set(self, name, value)
|
||||
else:
|
||||
|
@ -69,9 +66,10 @@ class pm3(object):
|
|||
_pm3.pm3_swiginit(self, _pm3.new_pm3(*args))
|
||||
__swig_destroy__ = _pm3.delete_pm3
|
||||
|
||||
def console(self, cmd):
|
||||
return _pm3.pm3_console(self, cmd)
|
||||
def console(self, cmd, passthru=False):
|
||||
return _pm3.pm3_console(self, cmd, passthru)
|
||||
name = property(_pm3.pm3_name_get)
|
||||
grabbed_output = property(_pm3.pm3_grabbed_output_get)
|
||||
|
||||
# Register pm3 in _pm3:
|
||||
_pm3.pm3_swigregister(pm3)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue