一张SIM卡里到底装了什么?用Wireshark抓包和Python脚本,带你解密USIM的文件系统
深入探索USIM卡文件系统:从APDU指令到Python解析实战
当你把手机卡插入设备时,这个指甲盖大小的芯片内部正在运行一个完整的微型数据库系统。作为移动通信的身份凭证,USIM卡远比普通用户想象的复杂——它包含超过200种结构化文件,存储着从基本身份信息到网络配置参数的各类数据。本文将带你用技术手段揭开这层神秘面纱。
1. USIM卡通信基础:APDU协议与文件系统架构
USIM卡本质上是一个符合ISO/IEC 7816标准的智能卡,其核心通信协议是应用协议数据单元(APDU)。这种指令-响应模式的交互,构成了我们与卡内文件系统对话的基础语言。
典型的APDU指令结构如下:
# SELECT命令示例 CLA = 0xA0 # 指令类 INS = 0xA4 # 指令码(SELECT) P1 = 0x00 # 参数1(选择文件) P2 = 0x00 # 参数2(返回FCP模板) Lc = 0x02 # 数据长度 Data = [0x3F, 0x00] # 主目录MF的标识符卡内文件系统采用树状结构组织:
- MF(Master File):根目录,固定标识符3F00
- ADF(Application DF):应用专属目录(如USIM ADF)
- EF(Elementary File):实际数据文件
关键入口文件EFDIR记录了所有应用的AID(应用标识符),相当于系统的"目录表"。读取流程如下:
- 发送SELECT EFDIR指令
- 解析响应获取record结构和数量
- 遍历record查找目标AID
- 用AID激活对应应用
2. 核心文件解析实战:IMSI与网络列表
2.1 EFIMSI:国际移动用户标识
IMSI是用户在全球移动网络中的唯一身份证,其二进制结构解析示例:
def parse_imsi(raw_data): # 第一个字节包含长度和编码指示 length = raw_data[0] & 0x0F digits = [] # 后续每字节存储两个BCD数字 for byte in raw_data[1:1+length]: digits.append(str(byte & 0x0F)) digits.append(str((byte >> 4) & 0x0F)) # 去除填充位并组合 imsi = ''.join(digits[:length*2-1]) return { 'MCC': imsi[:3], 'MNC': imsi[3:5] if len(imsi[3:5]) == 2 else imsi[3:6], 'MSIN': imsi[5:] }典型响应数据解析对照表:
| 字节位置 | 值(Hex) | 含义 |
|---|---|---|
| 0 | 08 | IMSI长度8字节 |
| 1 | 09 | 数字9和0(倒序) |
| 2 | 21 | 数字1和2 |
| 3 | 43 | 数字3和4 |
| 4-8 | ... | 后续MSIN部分 |
2.2 EFFPLMN:禁用网络列表
运营商通过此文件阻止设备接入异常网络,其记录格式解析要点:
- 每个PLMN占3字节:MCC(2字节)+MNC(1字节)
- 列表以FF FF FF标记结束
- 状态字节指示禁止原因(0x00=常规禁止)
使用Wireshark捕获的典型APDU交换流程:
# 请求 >> A0 A4 00 00 02 6F 7B << 9F 0F # 返回文件大小 >> A0 B0 00 00 0F << 01 02 03 04 05 06 FF FF FF 90 00 # 实际数据+状态字3. 高级文件操作与安全机制
3.1 文件访问权限控制
USIM采用三级安全机制保护敏感文件:
- ALW(Always):无需认证
- PIN:需要用户输入PIN码
- ADM:运营商级密钥控制
常见权限组合示例:
| 文件 | 读权限 | 更新权限 |
|---|---|---|
| EFIMSI | PIN | ADM |
| EFFPLMN | ALW | ADM |
| EFKEYS | ADM | ADM |
3.2 二进制解析技巧
处理TLV(标签-长度-值)格式文件的Python示例:
def parse_tlv(data): result = {} while len(data) > 2: tag = data[0] length = data[1] value = data[2:2+length] result[tag] = value data = data[2+length:] return result # 解析EFLOCI(位置信息) raw = bytes.fromhex('06 04 12 34 56 78 07 01 01') print(parse_tlv(raw)) # 输出: {6: b'\x124Vx', 7: b'\x01'}4. 构建自动化诊断工具
结合PySIM库实现批量文件读取的完整示例:
from pysim import sim def dump_usim_files(card): essential_files = { 'IMSI': '6F07', 'PLMNwAcT': '6F60', 'FPLMN': '6F7B', 'AD': '6FAD' } results = {} for name, fid in essential_files.items(): try: data = card.read_binary(fid) results[name] = parse_file(name, data) except Exception as e: print(f"读取{fid}失败: {str(e)}") return results # 实际使用 with sim.Reader() as reader: card = reader.connect() print(dump_usim_files(card))典型输出结构:
{ "IMSI": { "MCC": "460", "MNC": "01", "MSIN": "123456789" }, "FPLMN": [ {"MCC": "001", "MNC": "01"}, {"MCC": "310", "MNC": "260"} ] }在真实项目中,这类工具可以帮助快速诊断SIM卡配置问题。曾遇到一个案例:用户在国际漫游时无法注册网络,最终通过脚本比对发现是EFFPLMN列表中意外包含了当地合法运营商的PLMN代码。
