Reading a SIM card phone book in Python
I already wrote a SIM phone book dumper program in 2004. This first version was in Perl and was presented in "SIM card phone book listing".
You can also find more advanced tools in articles with the SIM label, like cardpeek, monosim or PSSI.
I now present a version in Python using the PySCard wrapper.
Source code
The source code is in 2 parts: usim.py and usim_read.py files.
usim.py is:
#!/usr/bin/env python3 from smartcard.System import readers from smartcard.util import toBytes from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver debug = True def usim(reader_nb): # get all the available readers r = readers() print("Available readers:") for reader in r: print("-", reader) reader = r[reader_nb] print("Using:", reader) connection = reader.createConnection() if debug: observer = ConsoleCardConnectionObserver() connection.addObserver(observer) connection.connect() SELECT = "A0 A4 00 00 02 " GET_RESPONSE = "A0 C0 00 00 " # Select MF print("Select MF") data, sw1, sw2 = connection.transmit(toBytes(SELECT + "3F 00")) if sw1 != 0x9F: raise(Exception("Error")) # Select DF Telecom print("Select DF Telecom") data, sw1, sw2 = connection.transmit(toBytes(SELECT + "7F 10")) if sw1 != 0x9F: raise(Exception("Error")) # Select EF ADN print("Select EF ADN") data, sw1, sw2 = connection.transmit(toBytes(SELECT + "6F 3A")) if (sw1, sw2) != (0x9F, 0x0F): raise(Exception("Error")) # Get Response print("Get Response") data, sw1, sw2 = connection.transmit(toBytes(GET_RESPONSE) + [sw2]) if (sw1, sw2) != (0x90, 0x00): raise(Exception("Error")) size = data[-1] pin = None if pin: print(pin) pin = list(map(ord, pin)) padd(pin, 8) # Verify CHV VERIFY = "A0 20 00 01 08" cmd = toBytes(VERIFY) + pin data, sw1, sw2 = connection.transmit(cmd) if (sw1, sw2) != (0x90, 0x00): raise(Exception("Wrong PIN:" + pin)) return size, connection if __name__ == "__main__": usim(0)
usim_read.py is:
#!/usr/bin/env python3 from smartcard.util import toBytes, toASCIIString import usim def decode_record(record): """ decode_record(toBytes("43 75 73 74 6F 6D 65 72 20 43 61 72 65 FF 06 A1 80 00 07 70 00 FF FF FF FF FF FF FF")) >> ['Customer Care', '0800700700'] """ X = len(record) - 14 name = toASCIIString(record[0:X - 1]).replace("ÿ", "") # number of bytes for the phone number tel_size = record[X] phone = record[X + 2:X + tel_size + 1] decoded = "" for n in phone: hex = "%02X" % n high = hex[0] low = hex[1] decoded += low + high # if the number of digits is odd we suppress the padding if decoded[-1] == "F": decoded = decoded[:-1] phone = decoded return name, phone def usim_read(reader_nb): # Select the EF ADN (size, connection) = usim.usim(reader_nb) for nbr in range(1, 250): # Read record header = [0xA0, 0xB2] record_idx = nbr cmd = header + [record_idx, 0x04, size] data, sw1, sw2 = connection.transmit(cmd) if (sw1, sw2) != (0x90, 0x00): return name, phone = decode_record(data) if name != "": print(f"{record_idx}: Name: {name}, phone: {phone}") if __name__ == "__main__": import sys if 2 == len(sys.argv): reader_nb = int(sys.argv[1]) else: reader_nb = 0 usim_read(reader_nb)
Comments
The debug is enabled. So you can see the communication between the application
and the card.
You ned to change only one line to remove the APDU log if
needed.
The phone book record size is not fixed for all the SIM cards. The record size is returned in the last byte of the GET RESPONSE command after the SELECT EF (Elementary File) ADN (Abbreviated dialling numbers).
You can get more details about the EF ADN and the record coding in the document ETSI TS 131 102 V16.6.0 (2021-01) chapter "4.4.2.3 EF_ADN (Abbreviated dialling numbers)". It is important to note that ETSI (European Telecommunications Standards Institute) standards are public and free.
By default the first PC/SC reader is used. But you can select another reader by passing a number as argument to the program. We will use this feature later.
No PIN is defined and verified. I am using a
sysmocom sysmoUSIM-SJS1
card. This card has the user PIN disabled by default.
You can enable PIN
verification by defining a PIN in usim.py. The code is already present.
USIM (Universal Subscriber Identity Module) is a new application
introduced for GSM version 3 (3G) to replace/improve the SIM
(subscriber identity/identification) application. The code should work
the same with a SIM card or a USIM card (but untested).
Output
$ ./usim_read.py Available readers: - Gemalto PC Twin Reader Using: Gemalto PC Twin Reader connecting to Gemalto PC Twin Reader Select MF > A0 A4 00 00 02 3F 00 < [] 9F 22 Select DF Telecom > A0 A4 00 00 02 7F 10 < [] 9F 22 Select EF ADN > A0 A4 00 00 02 6F 3A < [] 9F 0F Get Response > A0 C0 00 00 0F < 00 00 21 34 6F 3A 04 00 11 FF 22 01 02 01 22 90 00 > A0 B2 01 04 22 < 4C 61 75 72 65 20 46 72 61 6E E7 6F 69 73 65 20 59 76 6F 6E 06 A1 24 66 85 10 22 FF FF FF FF FF FF FF 90 00 1: Name: Laure Francoise Yvo, phone: 4266580122 > A0 B2 02 04 22 < 4C 75 63 69 65 6E 6E 65 20 48 65 6C 65 6E 65 20 4C 75 63 69 06 A1 76 45 65 28 77 FF FF FF FF FF FF FF 90 00 2: Name: Lucienne Helene Luc, phone: 6754568277 > A0 B2 03 04 22 < 55 72 62 61 69 6E 20 47 69 6C 6C 65 73 20 4A 75 73 74 65 FF 06 A1 80 38 74 16 54 FF FF FF FF FF FF FF 90 00 3: Name: Urbain Gilles Juste, phone: 0883476145 > A0 B2 04 04 22 < 4A 65 72 6F 6D 65 20 50 61 73 63 61 6C 20 46 65 72 6E 61 6E 06 A1 80 53 42 10 86 FF FF FF FF FF FF FF 90 00 4: Name: Jerome Pascal Ferna, phone: 0835240168 [...]
The output is truncated. I do not want to include all the 255 phone numbers.
Note that the names and numbers are random. More on that later.
Conclusion
It is easy to dump the phone book from a SIM card.
The SIM phone book is very limited (no birthday, no email address). The real phone book is, in general, in the phone itself and synchronised using CardDav with a server like Nextcloud.