安卓nfc模拟软件_模拟nfc软件「建议收藏」

安卓nfc模拟软件_模拟nfc软件「建议收藏」NFC模拟卡功能是工作后的第一个项目,当时完全没接触过android,别说是代码,就连用的手机也不是andorid,所以当时遇到的一些问题现在看起来很蠢,都是一些基础问题

NFC模拟卡功能是工作后的第一个项目,当时完全没接触过android,别说是代码,就连用的手机也不是andorid,所以当时遇到的一些问题现在看起来很蠢,都是一些基础问题。现在回头看实现当时需求的功能,可能1天的时间都用不到。

需求:让手机能当做门禁卡刷开小区、办公楼闸机。

目录

1 NFC基础知识

2 读取NFC卡内信息

3 修改手机NFC的uid

        3.1 确认原始状态

        3.2 尝试修改这个值

        3.3 配置文件修改

4 总结

问题1:无论给什么权限的app,都不能修改/vendor/etc/libnfc-nxp_RF.conf

问题2:avc权限问题

整体流程


1 NFC基础知识

NFC技术支持设备之间进行非接触式点对点的数据传输,可以在10cm距离内交换数据,属于一种非接触式识别和互联通信技术,通常在移动设备、消费类电子产品、智能硬件工具间进行近距离无线通信。

安卓nfc模拟软件_模拟nfc软件「建议收藏」
图片来源于网络

其工作分为三个模式:

  • 点对点模式(P2P mode)
    在此模式下,两台支持 NFC 的设备在短距离内直接通信。它用于安全支付、文件共享和设备配对等应用。
  • 卡模式(Card emulation)
    在此模式下,NFC 设备模拟一张非接触式智能卡。它允许设备与传统非接触式卡读卡器进行通信。例如,NFC 智能手机可以模拟一张交通卡,用于乘坐公共交通工具。以及本文提到的模拟门禁卡。
  • 读卡器模式(Reader/writer mode)
    在此模式下,NFC 设备充当读卡器或写入器,与非接触式智能卡或标签进行通信。例如,NFC 智能手机可以读取非接触式银行卡或门禁卡上的数据。

这个项目用到的模式就是卡模式和读卡器模式,先通过读卡器模式读取门禁卡上的数据,再写入手机中,然后进入卡模式,手机就可以当做门禁卡使用了。

标签:Tag,其中包含了少量的信息。具有不同的标准,执行不同的协议,不同类型的卡中可能包含不同类型的tag。

2 读取NFC卡内信息

android提供了原生接口实现此功能,使用读卡器模式,通过NFC.Adapter实现对tag等信息的读取。

读取中分为三个优先级:

  • NDEF.DISCOVERED
    此意图在以下情况下广播:检测到包含 NDEF(NFC 数据交换格式)消息的 NFC 标签或设备。检测到支持 NDEF 的 NFC 设备,但没有包含 NDEF 消息。
  • TECH_DISCOVERED
    检测到支持特定 NFC 技术的 NFC 标签或设备,无论是否包含 NDEF 消息。
  • TAG_DISCOVERED
    检测到任何类型的 NFC 标签,无论是否包含 NDEF 消息或支持特定 NFC 技术。

TAG_DISCOVERED 意图的优先级最高,其次是 TECH_DISCOVERED 意图,最后是NDEF.DISCOVERED 意图。这意味着如果同时检测到 NFC 标签和 NDEF 消息,则应用程序将首先收到 TAG_DISCOVERED 意图,然后是 TECH_DISCOVERED 意图,最后是 NDEF.DISCOVERED 意图。

在Manifest中注册意图:

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.NFCread">
        <activity android:name=".MainActivity"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
            </intent-filter>
            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />
        </activity>
    </application>

卡中包含了很多数据,对门禁卡功能有用的是什么呢?

        >>>tag中的uid,在非加密门禁卡中,仅比对此项是否与数据库中匹配。
可以理解为卡的“身份证”。 

读取uid信息,代码中的cardId变量:

 @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        String cardId = ByteArrayToHexString(tag.getId());

        Ndef ndef = Ndef.get(tag);
        if(ndef != null){
            msgg = "type:" + ndef.getType();
            msgg += "\nmaxsize:" + ndef.getMaxSize() + "bytes";
            readNfcTag(intent);
        }else{
            msgg = "no ndef message";
        }
        Toast.makeText(this ,"识别到新卡",Toast.LENGTH_LONG).show();
        content.setText(cardId + "\n" + msgg );
        Log.d("myNFC",cardId);
        Log.d("myNFC",intent.toString());
    }

    private void readNfcTag(Intent intent) {
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
            Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
                    NfcAdapter.EXTRA_NDEF_MESSAGES);
            NdefMessage msgs[] = null;
            int contentSize = 0;
            if (rawMsgs != null) {
                msgs = new NdefMessage[rawMsgs.length];
                for (int i = 0; i < rawMsgs.length; i++) {
                    msgs[i] = (NdefMessage) rawMsgs[i];
                    contentSize += msgs[i].toByteArray().length;
                }
            }
            try {
                if (msgs != null) {
                    NdefRecord record = msgs[0].getRecords()[0];
                    String textRecord = parseTextRecord(record);
                    msgg += "\ncontent:" + textRecord;
                    msgg += "\ncontentSize:" + contentSize + " bytes";
                }
            } catch (Exception e) {
            }
        }
    }

代码中读取的还有一些ndef信息,但后面也都没有用上了。下面是NDEF信息的解析函数:

    public static String parseTextRecord(NdefRecord ndefRecord) {
        /**
         * 判断数据是否为NDEF格式
         */
        //判断TNF
        if (ndefRecord.getTnf() != NdefRecord.TNF_WELL_KNOWN) {
            return null;
        }
        //判断可变的长度的类型
        if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
            return null;
        }
        try {
            //获得字节数组,然后进行分析
            byte[] payload = ndefRecord.getPayload();
            //下面开始NDEF文本数据第一个字节,状态字节
            //判断文本是基于UTF-8还是UTF-16的,取第一个字节"位与"上16进制的80,16进制的80也就是最高位是1,
            //其他位都是0,所以进行"位与"运算后就会保留最高位
            String textEncoding = ((payload[0] & 0x80) == 0) ? "UTF-8" : "UTF-16";
            //3f最高两位是0,第六位是1,所以进行"位与"运算后获得第六位
            int languageCodeLength = payload[0] & 0x3f;
            //下面开始NDEF文本数据第二个字节,语言编码
            //获得语言编码
            String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
            //下面开始NDEF文本数据后面的字节,解析出文本
            String textRecord = new String(payload, languageCodeLength + 1,
                    payload.length - languageCodeLength - 1, textEncoding);
            return textRecord;
        } catch (Exception e) {
            throw new IllegalArgumentException();
        }
    }

3 修改手机NFC的uid

        3.1 确认原始状态

安卓nfc模拟软件_模拟nfc软件「建议收藏」

换了几台设备,读出的uid各不相同,但有一个规律:08xxxxxx。

这是源于NFCC协议的缺省,未设置情况下是以08开头的8位16进制uid。

        3.2 尝试修改这个值

在代码中对找到对这个值进行设置的地方,位于:

/vendor/nxp/opensource/commonsys/external/libnfc-nci/xxxx/src/nfa/dm/nfa_dm_discover.c

通过
...
UINT8_TO_STREAM(p, NFC_PMID_LA_NFCID1)
...
可以对其进行设置。

问题:相当于将uid写死了。在后续的app中需要实现对这个uid的修改,如果在此修改则需要通过代码注入等方式,代价高。

        3.3 配置文件修改

寻找配置文件,在配置文件中修改对应的值。配置文件位于:

/vendor/etc/libnfc-nxp_RF.conf
//文件位置可能不同,主要是找到NXP_CORE_CONF变量的配置位置。

对应的uid字段:NXP_CORE_CONF配置如下:

NXP_CORE_CONF={ 20, 02, 2B, 0D,
18, 01, 01,
21, 01, 00,
28, 01, 01,
30, 01, 08,
31, 01, 03,
33, 04, DC, 2C, E3, 4E,
50, 01, 02,
54, 01, 06,
5B, 01, 02,
60, 01, 0E,
80, 01, 01,
81, 01, 01,
82, 01, 0E
}


最开始用的是下面这版配置:

# Add 58, 01, 74, for changing FWI while route IsoDep type-A to HCE:
#    Fix bug AlmId 26307, Jingdong pay is failure on Lakala T1 POS.
#    Default TB1 of HCE is 0x44. Change TB1 to 0x74,
#    then change FWT from 4.8ms to 38.7ms.
#    TB1: high nibble 4bits is FWI, low nibble 4bits is SFGI.
NXP_CORE_CONF={ 20, 02, 33, 11,
    18, 01, 01,
    21, 01, 00,
    28, 01, 00,
    30, 01, 08,
    31, 01, 03,
    32, 01, 20,
    33, 00,
    38, 01, 01,
    50, 01, 02,
    54, 01, 06,
    58, 01, 74,
    5B, 01, 00,
    80, 01, 01,
    81, 01, 01,
    82, 01, 0E,
    68, 01, 01,
    85, 01, 01
    }

但是会报错:
10-08 09:35:43.713   916  7462 D NxpHal  : phNxpNciHal_print_res_status: response status =STATUS_SYNTAX_ERROR
后面就修改掉了

其中33 , 04后跟的就是想要设置的uid。

安卓nfc模拟软件_模拟nfc软件「建议收藏」

4 总结

到此,跟NFC相关的技术内容其实就已经结束了,想要实现手机NFC模拟门禁卡,其实就是修改uid的配置。这种方式只针对最简单的非加密门禁卡。

但是当时做的时候,困难才刚刚开始。

问题1:无论给什么权限的app,都不能修改/vendor/etc/libnfc-nxp_RF.conf

看吧,这个问题真的很蠢,稍微了解一点android就会知道,vendor下的文件怎么可能给你乱搞。论Read-only-file system的含金量。当时又搞avc,又搞挂载,反正一顿操作hhh。

还出了一个乌龙:突然有一段时间能用了。猜猜是什么原因?

答案是想往手机里push文件,就需要root remount,这下好了,不是只读的了,当然就可以修改了,当时还以为解决了,白高兴半天。

但这也是为什么市面上第三方的NFC模拟卡软件都需要手机的root权限的原因,可能内部大多都是修改uid的这种逻辑。

如果不是源码开发,将手机root后,修改这个文件也可以实现NFC模拟卡功能。

因为是源码开发,后面修改:

vendor/nxp/opensource/halimpl/xxx/halimpl/hal/phNxpNciHal.cc
	
int phNxpNciHal_MinOpen (){
	
...
	
  setNxpRfConfigPath("/xxx/xxx/xxx/xxx/libnfc-nxp_RF.conf");

...
	
 
//以及
vendor/nxp/opensource/halimpl/xxx/halimpl/utils/phNxpConfig.cc 

...

char nxp_rf_config_path[256] =
	
        "/xxx/xxx/xxx/xxx/libnfc-nxp_RF.conf";

...

将系统读config的地方换到了可修改的位置,实现对uid的修改。

问题2:avc权限问题

这也是android源码开发比较常见的问题了,解决方案也很简单。

  • Step 1:抓取avc权限问题log
    adb logcat | grep "avc" > avc.txt
    
  • Step 2:使用工具audit2allow,执行audit2allow –i avc
    audit2allow –i avc
  • Step 3:可以输出对应需要的权限如下(例)
    #============= platform_app ==============
    allow platform_app nfc_service:service_manager find;
  • Step 4:找到对应.te文件
    find -name platform_app.te
  • Step 5:例中位于
    ./sepolicy/public/platform_app.te
  • Step 6:在其中加入上面的输出
    allow platform_app nfc_service:service_manager find;

重新编译就可以解决avc权限问题。

整体流程

安卓nfc模拟软件_模拟nfc软件「建议收藏」

今天的文章安卓nfc模拟软件_模拟nfc软件「建议收藏」分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/86589.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注