pip3 install pyusb
Python:
from typing import Generator, Iterable, Tuple
from time import sleep, time
from sys import argv
from usb.core import find as find_device, USBTimeoutError
class Reader:
def __init__(self) -> None:
self.esc = b"\x1b"
print('[?] Looking for device')
self.device = find_device(
find_all=False, idVendor=0x0801, idProduct=0x0003
)
if self.device is None:
print('[-] Device is not found')
exit(0)
print('[+] Device is online')
if self.device.is_kernel_driver_active(0):
print('[+] Disabling drivers')
self.device.detach_kernel_driver(0)
print('[+] Driver disabled')
try:
print('[+] Setting up configuration')
self.device.set_configuration()
print('[+] Resetting driver')
self.device.reset()
except Exception as e:
print('[-] Error while setting up:', e)
exit(0)
print('[+] All setups done')
def _make_header(self, ssequ: bool, eof_sequ: bool, length: int) -> bytes:
if length < 0 or length > 63:
raise ValueError("Len must be a non-negative number no mo than 63")
header = length
if ssequ:
header |= 0b10000000
if eof_sequ:
header |= 0b01000000
return bytes([header])
def _encapsulate_message(
self, message: bytes
) -> Generator[bytes, bytes, None]:
idx = 0
while idx < len(message):
payload = message[idx:idx+63]
header = self._make_header(
idx == 0, len(message) - idx < 64, len(payload)
)
padding = b"\0" * (63 - len(payload))
yield header + payload + padding
idx += 63
def _send_packet(self, packet: bytes) -> None:
self.device.ctrl_transfer(
0x21, 9, wValue=0x0300, wIndex=0, data_or_wLength=packet
)
def _recv_packet(self, buff: int, timeout: int) -> bytes:
try:
return bytes(self.device.read(0x81, buff, timeout))
except USBTimeoutError:
self.device.reset()
return b'timeout'
except Exception as e:
print('Error:', e)
self.device.reset()
return b''
def recv_message(
self, buff: int = 1024, timeout: int = 500, nocheck: bool = False
) -> bytes:
message = b''
retries = 0
while True:
if retries == 14:
print('[!] Operation timeout')
return message
packet = self._recv_packet(buff, timeout)
if packet == b'timeout':
retries += 1
continue
if not packet and not message:
return b''
elif nocheck:
return packet
payload_length = packet[0] & 0b00111111
payload = packet[1:1+payload_length]
message = message + payload
if packet[0] & 0b01000000:
break
return message
def send_message(self, message: bytes, reset: bool = True) -> None:
if reset:
self.device.reset()
for packet in self._encapsulate_message(message):
self._send_packet(packet)
def read_tracks(self) -> Tuple[bytes, bytes, bytes]:
print('[!] Please swipe card')
self.send_message(self.esc + b"r")
ret = self.recv_message(nocheck=True)
if not ret:
return (b'', b'', b'')
print('[+] Extraction T1&T2')
with open('FILE', 'wb') as file:
print('Saved in temp:', ret)
file.write(ret)
with open('FILE', 'rb') as file:
print('Readed fftemp:', file.read())
track1 = ret[
ret.index(b'\x1b\x01')+3:ret.index(b'\x1b\x02')
].replace(b'\x3f', b'')
track2 = ret[
ret.index(b'\x1b\x02')+2:ret.index(b'\x1b\x03')
].replace(b'\x3f', b'')
track3 = ret[ret.index(b'\x1b\x03'):].replace(b'\x3f', b'')
self.device.reset()
return (track1, track2, track3)
def write(self, tracks: Tuple[bytes, bytes, bytes]) -> bool:
if len(tracks) != 2 and len(tracks) != 3:
print('[-] Write error. You must have 2-3 tracks to write')
return False
self.send_message(self.esc+b'w')
data = self.esc+b's' # Section 9; <ESC>w<ESC>s[DATA]
for i in range(1, len(tracks)+1, 1):
data += self.esc+i.to_bytes(1, 'little')+tracks[i-1]
# <ESC><Track NO><STR>
data += b'\x3f\x1c' # Ending Field: ?<FS>
print('[+] Swipe card for write')
self.send_message(data, False)
sleep(2)
answ = self.recv_message(nocheck=True)
print('Data:', data)
print('Answer:', answ)
return True
def get_firmware_version(self) -> bytes:
self.send_message(self.esc + b"v")
ret = self.recv_message()
assert ret[0:1] == self.esc
return ret[1:]
def set_hi_co(self) -> bytes:
self.send_message(self.esc + b"x")
ret = self.recv_message()
assert ret[0:1] == self.esc
return ret[1:]
def set_low_co(self) -> bytes:
self.send_message(self.esc + b"y")
ret = self.recv_message()
assert ret[0:1] == self.esc
return ret[1:]
def get_hi_low_co_status(self) -> None:
self.send_message(self.esc + b"d")
ret = self.recv_message()
assert ret[0:1] == self.esc
print(f'Current status: {"Low" if ret[1:] == b"l" else "Hi"}-Co')
def get_device_model(self) -> bytes:
self.send_message(self.esc + b"t")
ret = self.recv_message()
assert ret[0:1] == self.esc
return ret[1:]
def save_to_file(self, tracks: Iterable[bytes]) -> None:
with open(f'{int(time()*1000)}.tracks', 'wb') as tfile:
tfile.write(b'\n'.join(tracks))
def write_from_file(self, filename: str = 'FILE') -> bool:
tracks = []
with open(filename, 'rb') as file:
for line in file:
print('Track:', line)
tracks.append(line.strip())
self.write((tracks[0], tracks[1], tracks[2]))
return True
def compare(self) -> None:
print('[!] Reading first card data...')
c1t1, c1t2, c1t3 = self.read_tracks()
print('[+] First card readed go to second card...')
c2t1, c2t2, c2t3 = self.read_tracks()
assert c1t1 == c2t1, "First track not match"
assert c1t2 == c2t2, "Second track not match"
assert c1t3 == c2t3, "Third track not match"
print('[+] Passed. Both cards have same data.')
def earse(self, tracks: Tuple[bool, bool, bool]) -> bool:
code = 0
if all(tracks):
code = 7
if tracks[1]:
code += 2
if tracks[2]:
code += 4
data = self.esc+b'c'+bin(code)
print(data)
return False
print('[!] Swipe card for earse')
self.send_message(data)
ret = self.recv_message()
print(ret)
return True
if __name__ == '__main__':
valid_cmd = ('r', 'rs', 'w', 'c', 'e')
if len(argv) < 2:
print('[!] No command exiting')
exit(0)
elif argv[1] not in valid_cmd:
print(f'[?] Unknown command: {argv[1]}; Valid: {valid_cmd}')
exit(0)
msrx = Reader()
msrx.set_hi_co()
if argv[1] == 'c':
msrx.compare()
elif argv[1] == 'e':
msrx.earse((True, True, True))
elif argv[1] == 'r' or argv[1] == 'rs':
tracks = msrx.read_tracks()
print('Tracks:', tracks)
if argv[1] == 'rs':
msrx.save_to_file(tracks)
elif argv[1] == 'w':
if len(argv) != 3:
print('[!] main.py w FILENAME')
exit(0)
msrx.write_from_file(argv[2])
Последнее редактирование: