如何使用nfcpy正确模拟带有特定服务码和块数据的FeliCa NFC标签?
看起来你在FeliCa标签模拟上卡到了最关键的细节——我之前用nfcpy做类似项目的时候也踩过这些坑,核心问题是FeliCa的身份识别参数和服务映射必须100%匹配原卡,我来一步步帮你解决:
先解决核心问题:如何让阅读器完全识别模拟的标签
阅读器不认模拟标签的第一原因,几乎都是身份参数不匹配,然后才是服务数据的问题,按以下步骤调整:
替换硬编码的IDM/PMM/System Code为原卡的真实值
你代码里写的idm, pmm, sys = '03FEFFE011223344', '01E0000000FFFF00', '12FC'是nfcpy的示例值,这是最大的问题!FeliCa阅读器首先会验证这三个参数,不一致直接跳过识别。
你可以从原卡的dump结果里找到这些值(原卡dump的开头应该有类似FeliCa IDm=XXXXX, PMm=XXXXX, System Code=XXXXX的内容),把它们替换成原卡的真实十六进制值。比如你dump里的System Code是8688和FE00,先优先匹配阅读器常用的那个系统码(比如8688),测试通过后再处理多系统码的情况。为每个捕获的服务码单独编写读写回调
你现在用的ndef_read/ndef_write是针对标准NDEF标签的,但你的原卡是自定义服务(比如0x1A88、0x4348这些非NDEF服务),通用的NDEF回调完全不适用。正确的做法是:- 把每个服务的块数据单独存起来(比如用列表对应每个块的16字节内容)
- 为每个服务写专属的read和write函数,返回对应块的捕获数据,同时遵循原卡的访问权限(比如原卡标注"write with key"的服务,write函数可以直接返回
False拒绝写入,除非你实现了密钥验证逻辑)
举个例子,针对你捕获的0x1A88服务:
# 从原卡dump中提取0x1A88服务的块数据 service_1A88_blocks = [ bytearray.fromhex("30313030303030303030303000003031"), # 块0000 bytearray.fromhex("00000000000000000000000000000000"), # 块0001 bytearray.fromhex("30303030303030303230323430343031"), # 块0002 bytearray.fromhex("32303333303333316330303030303030"), # 块0003 ] def service_1A88_read(block_number, rb, re): # rb是请求读取的块数量,拼接对应块的字节数据返回 response = b'' for i in range(rb): target_block = block_number + i if target_block < len(service_1A88_blocks): response += service_1A88_blocks[target_block] else: response += b'\x00' * 16 # 原卡空块的默认填充值 return response def service_1A88_write(block_number, block_data, wb, we): # 原卡该服务需要密钥才能写入,无密钥时拒绝操作 return False然后在
on_connect里添加这个服务:tag.add_service(0x1A88, service_1A88_read, service_1A88_write)用同样的方式处理其他服务(比如0x4348、0x50C8等)。
严格遵循原卡的访问权限
你dump里的服务有"read w/o key"、"write with key"等权限,在回调函数里要对应实现:- 无密钥可读的服务:直接返回对应块数据
- 需要密钥读写的服务:如果没实现密钥验证逻辑,读写函数可以返回
False拒绝操作,避免阅读器报错
针对你第二个问题:nfcpy里有没有遗漏的关键点?
有几个容易忽略的细节:
- 身份参数的完全一致性:再次强调,IDM、PMM、System Code必须和原卡完全一致,这是阅读器识别的第一关,之前的示例值必须替换。
- 服务码的类型无需额外配置:你dump里的Random Service和Cyclic Service,nfcpy的
add_service不需要额外指定类型,只要使用正确的服务码值即可。 - 避免通用NDEF回调的误用:你的原卡不是NDEF标签,所以不要用
ndef_data_area和通用的NDEF读写函数,必须为每个自定义服务写专属回调。
针对你第三个问题:有没有更好的库或方法?
如果nfcpy的FeliCa模拟确实满足不了需求(比如需要更底层的密钥处理),可以试试这些方案:
- libnfc + pynfc:libnfc是更底层的NFC库,pynfc是它的Python绑定,能实现更灵活的FeliCa模拟,但需要更多的底层开发(比如手动处理FeliCa的命令帧)。
- Sony官方FeliCa SDK:针对Sony阅读器(比如你的RC-S380)有官方的C语言SDK,能实现更完整的FeliCa功能,但需要写C代码或者用Python调用C扩展,复杂度较高。
- 优先调通nfcpy:其实nfcpy已经足够覆盖你的需求,只要把上面的细节调整正确,RC-S380也支持FeliCa模拟,所以优先解决当前代码的问题会更高效。
最后测试建议
调整完代码后,用你用来dump原卡的那个测试程序(就是调用tag.dump()的代码)来读取模拟的标签,对比dump结果和原卡的dump结果,确保所有服务码和块数据完全一致,这样阅读器就能识别为原卡了。
备注:内容来源于stack exchange,提问作者ちいらのちつもり

