Приветствую всех!
Думаю, многим из вас доводилось слышать такое утверждение, что SIM-карта — по сути полноценный специализированный компьютер. А раз симка — это компьютер, то, очевидно, должен быть и софт для него. Как насчёт попробовать что-нибудь написать и заставить это работать прямо на карте? Давайте разбираться.



Итак, в сегодняшней статье поговорим про эту довольно редко упоминающуюся сторону сотовой связи. Узнаем, как писать приложения, чтобы они запускались на всех телефонах, от Nokia 3310 до последних айфонов. Попутно выясним, как загружать их в SIM-карты и насколько сложно это сделать, и, конечно же, напишем наш первый апплет. Традиционно будет много интересного.

Суть такова


По уже сложившейся традиции каждый год десятого января я выкатываю пост про сотовые сети. И если раньше я традиционно рассказывал про антенны, трансиверы, базовые станции, то в этот раз мы взглянем на достаточно редко рассматриваемую составляющую мобильной связи: SIM-карты и всё, что с ними связано.

Если вы хотя бы немного интересовались сотовой связью, то наверняка знаете, что симка — не просто чип EEPROM в виде карточки, а по сути полноценная система на чипе, имеющая собственные процессор, память, ПЗУ, периферийный контроллер и другие составляющие. И мне всегда было интересно, кто же всё-таки пишет софт, работающий на таком компьютере, как это вообще происходит и как он развёртывается на SIM. До этого всё моё знакомство с карточками ограничивалось лишь таковыми с магнитной полосой и (немного) бесконтактными EMV.


VasiliyLiGHT понимает, о чём я

Удивительно, но насчёт сим-карт толковой информации почему-то мало. Так что пришлось немало поковыряться, прежде чем получилось заставить всё это работать и суметь рассказать об этом миру.

Краткое введение в контактные смарт-карты


Если вы никогда в жизни не сталкивались с такими штуками, сейчас я вам по-быстрому о них расскажу.



Думаю, многие из вас замечали, что симка, будучи ещё не извлечённой из пластиковой карты, по размером в точности соответствует банковской карте (а любители ретро-телефонов вспомнят про полноразмерные карточки, применявшиеся в первых GSM-трубках). Точно такими же свойствами обладают карты доступа, электронные пропуска и многио чего ещё. Так вот, это неслучайно. SIM-карта — частный случай контактной смарт-карты, а практически все они соответствуют стандарту ISO7816. Он определяет распиновку карты, расположение чипа на ней, протокол обмена и многое другое.

При начале работы с картой считыватель активирует питание и подаёт сигнал сброса. В ответ на это карточка отсылает ATR (Answer to Reset) — строку байт, позволяющую хосту определить, что это за карта и что она делает. После установления соединения считыватель может общаться с картой при помощи команд APDU (Application Protocol Data Unit). Что это за команды и какие они передают данные, зависит от того, для чего предназначена карта и какие на ней есть приложения.

Что же это за приложения? Зависит от смарт-карты. Их можно поделить на два типа:

  • Native. Внутри стоит по сути обычный микроконтроллер (чаще всего это мелкий PIC с микросхемой памяти, так же может быть и какая-то дополнительная периферия типа криптопроцессора) с контроллером интерфейса ISO7816. Соответственно, программисту требуется вручную обрабатывать приходящие к нему APDU. Такими были первые симки, а также старые чиповые банковские карты по типу «Золотой короны» (они, к слову говоря, были на процессорном ядре MC68000). Эти смарт-карты тоже представляют некоторый интерес, но о них поговорим как-нибудь потом.
  • JavaCard. Эти экземпляры устроены куда сложнее. Они имеют в себе куда более мощное процессорное ядро, память со своей файловой системой и много чего ещё. Но что самое главное — на них запускается Java-машина (ввиду необходимости тотальной экономии ресурсов довольно серьёзно урезанная, если сравнивать с ПК, J2ME и другими девайсами), позволяющая писать приложения (апплеты, они же кардлеты) на куда более высокоуровневом языке. Эти приложения загружаются в память карты и вызываются оттуда хостом. При этом разработчику уже не нужно заниматься ерундой типа работы напрямую с контроллером интерфейса, здесь всё гораздо проще. Именно о таких картах мы и поговорим.

Приложения могут быть абсолютно любыми, на усмотрение разработчика. В некоторых областях есть свои стандарты, например, карты EMV. Для GSM такой тоже есть, и называется он STK.

SIM Toolkit




Для обывателя приложения SIM не ассоциируются ни с чем хорошим. Именно благодаря этой функции работает «меню SIM» в телефоне. Это тот самый раздел, где неловкое нажатие (особенно если телефон дали детям), и вот вы уже подписаны на кучу «занимательных фактов» 18+, анекдоты, какие-то новости и прочую ересь. Но, само собой, одним лишь меню функционал STK не ограничивается. Именно благодаря ему (точнее, одному из приложений) при вставке симки в новый телефон запрашивается конфигурация точек доступа для интернета, именно STK позволяет выводить всплывающие поверх экрана уведомления о новых услугах (чем одно время очень бесил Tele2), именно с его использованием написаны более низкоуровневые приложения, реализующие все остальные функции симки. Также установленные приложения могут вообще не иметь никакого отношения к сотовой связи, вот, например, работа с квалифицированной электронной подписью при помощи заранее заряженной симки. Нечто подобное могут предоставить имеющие контракт с оператором банки и иные организации. И, наконец, именно SIM Toolkit реализует основную функцию симки — хранение ключей и авторизацию в сети. Реализация STK одинакова для всех телефонов, поэтому для разработчика апплетов не имеет значения, в какую трубку вставлена симка. Как нетрудно догадаться, этим софтом мы сегодня и будем заниматься.

Что нужно, чтобы записать свой софт на симку?


Перейдём к самому главному: что же нужно, чтобы запустить своё приложение? До детального знакомства с данной темой я представлял, что там наверняка будет куча непреодолимых для обывателя нюансов типа так и не слитой документации под NDA или необходимости раздобыть какие-то спецкарты и не менее редкий софт для работы с ними, но, как оказалось, порог вхождения не самый высокий — понадобится знать Java на уровне чуть большем, чем «Hello, world!», иметь представление о том, что такое Python, и уметь работать с консолью в линуксе. Из железа понадобится раздобыть считыватель смарт-карт, а также симку с известными административными ключами. Само собой, для «рабочей» карты никто таких ключей не даст, а известны они лишь оператору, который её выдал. Поэтому, как и в опытах с LTE, понадобятся программируемые. Выбор их довольно таки уныл.



Первый вариант — уже упоминавшийся Gialer. Нужна именно версия с поддержкой JavaCard, базовая не подойдёт.



Второй вариант — не менее знаменитый в узких кругах Sysmocom. Их симки поддерживают JavaCard даже в самой дешёвой версии. Есть достаточно много различных их модификаций, подойдёт практически любая (кроме eSIM, конечно).
По сути в этом и есть вся сложность — достать подобные артефакты под силу далеко не каждому. Но у меня они есть, так что приступим к экспериментам.

Обзор оборудования


Найти такие карты оказалось сложновато. Но в итоге помог товарищ axilirator, за что ему огромная благодарность.



А вот и наша симка. Это довольно старая модель sysmoUSIM-SJS1. Она не имеет ряда функций, присущих новым симкам (в частности, в ней нет поддержки SUCI, нужной для работы 5G), но сейчас это не так важно.



Обратная сторона.



Считыватель смарт-карт и плата-переходник, всё те же, что и в прошлых опытах.



Также понадобятся телефоны, в которых мы будем тестировать нашу карточку. Вот, например, легендарный Siemens CX75.





А вот старенький смартфон ZTE.



Ещё немного трубок.

Ставим софт


Теперь очередь софта. Казалось бы, всё просто: скачиваем то, что было в тех инструкциях, выполняем команды, и в путь. Но, сами понимаете, будь оно так, не было бы и этой статьи. Osmocom советует скачать некий shadysim.py, но есть проблема: он очень старый и не обновлялся уже давно, чего не скажешь о зависимостях. Написанный ещё для Python2 скрипт собирает сотню ошибок при попытке его запустить и упорно оказывается работать. Можно, конечно, попробовать закинуть его на более старую систему и попробовать там, но есть способ лучше: один товарищ портировал его на Python3, где на момент написания статьи он отлично стартует. Поэтому будем пробовать. Само собой, для опытов понадобится машина с Linux. Я использовал Linux Mint, но подойдёт и любой другой дистрибутив.
Итак, ставим зависимости и клонируем пропатченный софт:

sudo apt-get install python3 python3-pip pcscd libpcsclite-dev pcsc-tools
pip3 install setuptools pyscard pycryptodome
git clone https://github.com/cheeriotb/osmocom-sim-tools

Далее очередь софта для разработки под JavaCard:

sudo apt-get install openjdk-11-jdk openjdk-11-jre ant
git clone https://gitea.osmocom.org/sim-card/hello-stk

Здесь мы накатываем JDK (обязательно JDK 11, с поздними версиями апплет не компилируется), а из репозитория Osmocom клонируем JavaCard SDK и тестовую программу.

Пишем первую программу


Ну что же, самое время попробовать что-то собрать и запустить! Итак, в папке HelloSTK находим HelloSTK.java, который имеет следующий вид:

package org.toorcamp.HelloSTK;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISOException;

import sim.toolkit.EnvelopeHandler;
import sim.toolkit.ProactiveHandler;
import sim.toolkit.ToolkitConstants;
import sim.toolkit.ToolkitException;
import sim.toolkit.ToolkitInterface;
import sim.toolkit.ToolkitRegistry;

public class HelloSTK extends Applet implements ToolkitInterface, ToolkitConstants {
	// DON'T DECLARE USELESS INSTANCE VARIABLES! They get saved to the EEPROM,
	// which has a limited number of write cycles.
	private byte helloMenuItem;
	
	static byte[] welcomeMsg = new byte[] { 'W', 'e', 'l', 'c', 'o', 'm', 'e', ' ',
                                            't', 'o', ' ', 'T', 'o', 'o', 'r', 'C',
                                            'a', 'm', 'p', ' ', '2', '0', '1', '2' };
	
	static byte[] menuItemText = new byte[] { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'S', 'T', 'K'};
	
	private HelloSTK() {
		// This is the interface to the STK applet registry (which is separate
		// from the JavaCard applet registry!)
		ToolkitRegistry reg = ToolkitRegistry.getEntry();
	
		// Define the applet Menu Entry
		helloMenuItem = reg.initMenuEntry(menuItemText, (short)0, (short)menuItemText.length,
				PRO_CMD_SELECT_ITEM, false, (byte)0, (short)0);
	}
	
	// This method is called by the card when the applet is installed. You must
	// instantiate your applet and register it here.
	public static void install(byte[] bArray, short bOffset, byte bLength) {
		HelloSTK applet = new HelloSTK();
		applet.register();
	}
	
	// This processes APDUs sent directly to the applet. For STK applets, this
	// interface isn't really used.
	public void process(APDU arg0) throws ISOException {
		// ignore the applet select command dispached to the process
		if (selectingApplet())
			return;
	}

	// This processes STK events.
	public void processToolkit(byte event) throws ToolkitException {
		EnvelopeHandler envHdlr = EnvelopeHandler.getTheHandler();

		if (event == EVENT_MENU_SELECTION) {
			byte selectedItemId = envHdlr.getItemIdentifier();

			if (selectedItemId == helloMenuItem) {
				showHello();
			}
		}
	}
	
	private void showHello() {
		ProactiveHandler proHdlr = ProactiveHandler.getTheHandler();
		proHdlr.initDisplayText((byte)0, DCS_8_BIT_DATA, welcomeMsg, (short)0, 
				(short)(welcomeMsg.length));
		proHdlr.send();
		return;
	}
}

Разберёмся, что тут происходит. Сам код лёгок для пониманию даже для тех, кто никогда не писал на Java, но кое-что я всё же опишу.

Сразу после того, как апплет оказался на карте, он не готов к работе. Перед этим его нужно зарегистрировать, для чего вызывается специальный метод register. Также имеется функция, обрабатывающая APDU, но в STK она почти не используется. И наконец самое главное: обработчик событий STK. В данном примере нет ничего особенного, просто отображение текста, если был выбран пункт меню.



Теперь собираем его командой ant.



После этого мы получим апплет (с расширением *.cap), готовый к закидыванию на карту.



Если при попытке сборки выдаётся ошибка, значит, у вас установлена более новая версия JDK, с которой скачанный JavaCard SDK несовместим. Чтобы выбрать нужную, вводим команду:

sudo update-alternatives --config java

Теперь остаётся только выбрать нужный из списка:



Мне неведомо, каким образом производится отладка коммерческих приложений для сим-карт, так как каких-либо эмуляторов SIM ToolKit я не нашёл. Есть, конечно, софт типа jCardSim, но поддержки STK он не имеет, её надо дописывать самостоятельно. Нечто более близкое к истине было в составе Gemalto Developer Suite, но в Web Archive софта не сохранилось, а все найденные на просторах ссылки вели либо на вирусы, либо на откровенный мусор вроде сайта informer.com. Конечно, я не настоящий сварщик джавист и, возможно, есть более актуальные способы отладки таких приложений, нежели проприетарное ПО десятилетней давности, так что если у кого-то есть такой софт и он готов им поделиться, то я обязательно дополню эту статью.

KIK, KIc и KID


Теперь разберёмся с самым интересным — с тем, как апплеты попадают в память симки. Происходит это при помощи защищённых пакетов — APDU особой структуры, которые посылает либо телефон (при конфигурации по воздуху), либо считыватель смарт-карт, куда вставлена симка. Для проведения каких-либо операций нужно знать административные ключи. У обычных симок они известны только оператору, поэтому использовать их нам не получится. Так что время узнать, как обстоят дела у программируемых. Если у вас симки Gialer, то конфигурация (а также установка апплетов) производится при помощи их софта, в случае с Sysmocom все данные присылают при заказе (о чём говорит надпись Key material has been sent to the e-mail address entered during webshop order на новых симках). Если ключей у вас нет, то получить их заново нельзя. Ещё, кстати, давным-давно Sysmocom продавал чуть дешевле свои симки без предоставления административных ключей. Такой вариант нам сегодня тоже не подойдёт, если у вас именно такие, то придётся заказать новые.

Связанных с этим важнейшим процессом ключей всего три:

  • KIc. Этот ключ — самый важный. Им шифруется содержимое защищённого пакета.
  • KID. Проверочный ключ, служит для выполнения трёх операций, именуемых RC/CC/DS (Redundancy Check/Cryptographic Checksum/Digital Signature).
  • KIK. Чем-то он напоминает KLK в платёжных терминалах (хотя и отличается от него по назначению). Этим ключом шифруются KIc и KID для их безопасной передачи. В новых версиях стандарта он называется DEK (Data Encryption Key).

Благодаря последнему ключу есть возможность загружать приложения и файлы по воздуху. То есть если у оператора изменятся какие-то настройки, он, обладая административными ключами, обновит эти данные в симке по сети, визит абонента для этого не требуется.
Процессов доступа к данным симки всего два — RFM (Remote File Management) и RAM (Remote Applet Management). В ходе первого производится добавление или изменение файлов в ФС карты, во втором — загружаются, устанавливаются или удаляются апплеты.



А вот и структура защищённого пакета.



Эти самые пакеты оператор может передавать через GPRS, USSD или служебные SMS. Для пользователя при этом всё абсолютно прозрачно, этот процесс для него незаметен.

Загружаем апплет


Теперь вернёмся к тому самому скрипту shadysim.py. Он-то и поможет нам загрузить наше приложение в память карточки.



Если запустить его без подключенного считывателя, то должна появиться ошибка вроде этой.



Втыкаем картридер в комп. Чтобы убедиться, что он работает, вводим:

pcsc_scan

Если проблем нет, он отобразится в списке доступных считывателей.
Теперь нужно воткнуть карту и выполнить следующую команду:

python3 shadysim.py --pcsc -l HelloSTK.cap -i HelloSTK.cap \
          --enable-sim-toolkit --module-aid d07002ca44900101 \
          --instance-aid d07002CA44900101 \
          --nonvolatile-memory-required 0100 \
          --volatile-memory-for-install 0100 \
          --max-menu-entry-text 15 \
          --max-menu-entries 05 --kic KIc1 \
          --kid KID1

Здесь имя файла — тот самый апплет, который нам нужен. Этот скрипт его сразу и загружает (то есть копирует апплет в память симки) и устанавливает (регистрирует и активирует его). Не менее важным параметром является AID — код приложения (Application ID), по которому его можно однозначно определить (его можно задать в файле build.xml, здесь при загрузке указываем его же). Если попробовать установить два приложения с одинаковыми AID, то карта выдаст ошибку. Само собой, KIc и KID нужно заменить на свои данные. У симки может быть несколько групп таких ключей, выбираем первую.

Не будет лишним напомнить, что все административные ключи и коды имеют свойства, аналогичные таковым у PIN и PIN2. Если неверно ввести какой-либо из них три раза, то карта либо сдохнет, либо потеряет часть своих функций (к примеру, если вы заблокируете ключ ADM, то больше никогда не сможете изменять IMSI, Ki, OPc и прочие подобные данные). Проверяйте правильность введённых данных перед тем, как что-то выполнять.

Итак, будем считать, что коды вы указали те. Выполняем команду, и, если нештатных ситуаций в процессе не возникло, в консоли должно будет появиться примерно следующее:



Время тестировать. Первое января, пятый час ночи. Город засыпает, мафия тоже хочет спать. Ну а пока что достаём симку и втыкаем её в телефон.



Включаем его, и, если апплет успешно установился, на телефоне должно будет стать активным меню SIM.





Ну что же, оно работает!



Точно так же можно вставить карточку в любой другой телефон и убедиться, что там всё тоже запускается.



И на третьем телефоне тоже. Всё потому, что приложение работает на самой симке, а телефон лишь посылает ему команды.

Удаляем апплет


Как я уже говорил ранее, нельзя накатить один апплет поверх другого. Поэтому для загрузки новой версии старый апплет надо снести.
И для начала получим список установленных приложений на карте:

python3 shadysim.py --pcsc --list-applets --kic KIC1 --kid KID1

После выполнения команды в консоли отобразится нечто вроде этого:



Последний AID в списке и есть наш HelloSTK. Выше идут системные приложения.

Удаляется он довольно просто:

python3 shadysim.py --pcsc -d AID   --kic KIC  --kid KID

Эта команда заставит апплет исчезнуть с карты.

Ошибки


Как известно, только в туториалах вроде этого весь код пишется шутя и работает с первого раза. Поэтому стоит поговорить и об ошибках.



Если после выполнения скрипта вы наблюдаете вот такую строчку в конце, значит, что-то пошло не так. Увы, мне не удалось найти детальную документацию о том, что значит каждый код ошибки (ни на сайте Osmocom, ни в руководстве от Sysmocom этого нет). Но некоторую закономерность удалось обнаружить:

  • 6985 — дублирующийся AID. Проще говоря — попытка установить апплет, который уже установлен. Устраняется сносом старого апплета и накатыванием нового.
  • 6A88 — отсутствующий AID. Обычно происходит при удалении апплета, которого нет.
  • 6A86 — ошибка в параметрах. Помогало переустановить апплет.
  • 6438 — вероятно, ошибка обмена. Выйти из неё удалось лишь при помощи переустановки апплета с использованием другого считывателя.

Если кто-то знает, где найти более детальное описание, буду рад с ним ознакомиться.

Что же в итоге?


Признаться, сам не ожидал, что сборка и загрузка простенького апплета окажутся таким муторным занятием. Но было очень увлекательно разбираться с этими картами, считывателями и софтом.

Простор для экспериментов здесь просто огромный, начиная с простеньких апплетов и заканчивая каким-нибудь текстовым квестом с менюшками, работающим полностью на симке. Пока разбирался, нашёл около десятка примеров разных приложений, работоспособных и не очень. Но о том, что же ещё примечательного можно написать для симки, поговорим уже в следующей статье.

Такие дела.



Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале



Ссылки:

Читайте также:

Комментарии (7)


  1. enamchuk
    10.01.2025 09:58

    Возможно ли из обычных SIM, которые операторы связи выдают абонентам, удалить приложение?


    1. gmini
      10.01.2025 09:58

      видимо, ключи надо, а они только у оператора


      1. MaFrance351 Автор
        10.01.2025 09:58

        Именно.


    1. Coppermine
      10.01.2025 09:58

      Если цель избавиться от навязчивых push-уведомлений от оператора и у Вас телефон на базе Android, то можно попробовать с помощью adb избавиться от пакета com.android.stk. Но это из категории вредных советов.


      1. grishkaa
        10.01.2025 09:58

        Конкретно — adb shell pm uninstall --user 0 com.android.stk. Я так делал, подтверждаю, работает.


      1. enamchuk
        10.01.2025 09:58

        Именно так и сделал.
        Но встречал и полезные SIM приложения, например, у оператора MCN там переключаются профили для международного роуминга, а у некоторых eSIM , выполненных в виде обычной SIM - возможность переключения профиля без использования спец.приложения.


  1. Rubilnik
    10.01.2025 09:58

    Я ожидал, что сейчас запустим doom на сим карте...