#!/usr/bin/env python3 import usb.core import usb.util import sys import time # needed for sleep() import traceback # Exception timeout # Sniffed Phone to SIM card communication: # phone < sim : ATR # phone > sim : A0 A4 00 00 02 (Select File) # phone < sim : A4 (INS repeated) # phone > sim : 7F 02 (= ??) # phone < sim : 9F 16 (9F: success, can deliver 0x16 (=22) byte) # phone > sim : ?? (A0 C0 00 00 16) # phone < sim : C0 (INS repeated) # phone < sim : 00 00 00 00 7F 20 02 00 00 00 00 00 09 91 00 17 04 00 83 8A (data of length 22) # phone < sim : 90 00 (OK, everything went fine) # phone ? sim : 00 (??) # SuperSIM ATR # atr= [0x3B, 0x9A, 0x94, 0x00, 0x92, 0x02, 0x75, 0x93, 0x11, 0x00, 0x01, 0x02, 0x02, 0x19] # Faster sysmocom SIM #atr = [0x3B, 0x99, 0x18, 0x00, 0x11, 0x88, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x60] atr = [0x3B, 0x99, 0x11, 0x00, 0x11, 0x88, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x60] RESP_OK = [0x60, 0x00] def find_dev(): dev = usb.core.find(idVendor=0x03eb, idProduct=0x6004) if dev is None: raise ValueError("Device not found") else: print("Found device") return dev def find_eps(dev): dev.set_configuration(3) cfg = dev.get_active_configuration() print("Active config: ") print(cfg) intf = cfg[(0,0)] ep_in = usb.util.find_descriptor( intf, custom_match = \ lambda e: \ usb.util.endpoint_direction(e.bEndpointAddress) == \ usb.util.ENDPOINT_IN) assert ep_in is not None ep_out = usb.util.find_descriptor( intf, custom_match = \ lambda e: \ usb.util.endpoint_direction(e.bEndpointAddress) == \ usb.util.ENDPOINT_OUT) assert ep_out is not None print("****") print(ep_in) print(ep_out) return (ep_in, ep_out) WAIT_RST = 0 WAIT_CMD = 1 def handle_wait_rst(dev): # ATR handling print("Handle ATR") arr = dev.read(PHONE_INT, 64, 300) # Notification endpoint # print("arr: ", arr) c=arr.pop() # print(c) if c == ord('R'): # We received a Reset, so we send ATR written = dev.write(PHONE_DATAOUT, atr, 1000) print("Written ATR of size: ") print(written) state = WAIT_CMD; return state def handle_wait_cmd(dev): # Read phone request print("Wait cmd") cmd = dev.read(PHONE_DATAIN, 64, 1000) print("Received request!: ") print("".join("%02x " % b for b in cmd)) return send_response(dev, cmd); handle_msg_funcs = { WAIT_RST: handle_wait_rst, WAIT_CMD: handle_wait_cmd } def handle_phone_request(dev, state): if state == WAIT_CMD: try: state = handle_msg_funcs[WAIT_RST](dev) except usb.USBError as e: print(e) state = handle_msg_funcs[state](dev) return state INS = 1 CNT = 4 PHONE_DATAOUT = 0x04 PHONE_DATAIN = 0x85 PHONE_INT = 0x86 def send_response(dev, cmd): # FIXME: We could get data of length 5 as well! Implement another distinct criteria! state = WAIT_CMD if len(cmd) == 5: # Received cmd from phone if cmd[INS] == 0xA4: resp = [cmd[INS]] # Respond with INS byte elif cmd[INS] == 0xC0: data = [0x00, 0x00, 0x00, 0x00, 0x7F, 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x91, 0x00, 0x17, 0x04, 0x00, 0x83, 0x8A, 0x83, 0x8A] SW = [0x90, 0x00] resp = [cmd[INS]] + data + SW # Respond with INS byte #state = WAIT_RST else: print("Unknown cmd") resp = [0x60, 0x00] elif len(cmd) == 2: resp = [0x9F, 0x16] else: resp = [0x60, 0x00] written = dev.write(PHONE_DATAOUT, resp, 10000); if written > 0: print("Bytes written:") print(written) print("Cmd, resp: ") print("".join("%02x " % b for b in cmd)) print("".join("%02x " % b for b in resp)) return state def emulate_sim(): dev = find_dev() state = WAIT_RST; while True: try: state = handle_phone_request(dev, state) except usb.USBError as e: # print e pass