深入探索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(应用标识符),相当于系统的"目录表"。读取流程如下:

  1. 发送SELECT EFDIR指令
  2. 解析响应获取record结构和数量
  3. 遍历record查找目标AID
  4. 用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采用三级安全机制保护敏感文件:

  1. ALW (Always):无需认证
  2. PIN :需要用户输入PIN码
  3. 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代码。

更多推荐