当前位置:主页 > 保定科技 > 文章内容

usdt自动充值(www.caibao.it):DA14531芯片固件逆向系列(2)- 操作系统底层机制剖析

日期:2021-02-24 浏览:

USDT自动充值

菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

概述

DA145x软件平台利用了由Riviera Waves允许的小型高效实时内核,内核提供以下功效:

  1. 义务建立和状态转换。
  2. 义务之间的新闻交流。
  3. 计时器治理。
  4. 动态内存分配。
  5. BLE事宜的调剂和处置

基础数据结构

本节主要剖析Riviera Waves系统中常用的一些数据结构

co_list链表实现

数据结构

co_list就是一个单向链表,DA145x代码内里会使用co_list来存放种种数据,好比新闻数据.

焦点的数据结构如下

//链表中的节点
struct co_list_hdr
{
    /// 指向下一个链表节点
    struct co_list_hdr *next;
};

/// 链表头的结构
struct co_list
{
    // 链表头节点
    struct co_list_hdr *first;
    // 链表尾节点
    struct co_list_hdr *last;

    // 链表中的节点个数
    uint32_t cnt;
    // 链表中最多节点数
    uint32_t maxcnt;
    // 链表中最少节点数
    uint32_t mincnt;
};

co_list示意链表头,存放了整个链表的一些元数据,链表节点为co_list_hdr,应用程序使用co_list时会在其特定结构体内部嵌入co_list_hdr和co_list。

链表初始化

co_list_init用于初始化一个链表

void __fastcall co_list_init(struct co_list *list)
{
  list->first = 0;
  list->last = 0;
  list->cnt = 0;
  list->maxcnt = 0;
  list->mincnt = -1;
}

插入节点

co_list_push_back用于将节点list_hdr插入到链表list的尾部

void __fastcall co_list_push_back(struct co_list *list, struct co_list_hdr *list_hdr)
{
  uint32_t cnt; // r1

  if ( list->first )
  {
    list->last->next = list_hdr;
  }
  else
  {
    list->first = list_hdr;
  }
  list->last = list_hdr;
  list_hdr->next = 0;
  cnt = list->cnt   1;
  list->cnt = cnt;
  if ( list->maxcnt < cnt )
  {
    list->maxcnt = cnt;
  }
}
  1. 若是list->first为空,就把list_hdr放到链表头list->first,否则就把该list_hdr放到最后一个节点的末尾
  2. 最后更新list->lastlist->cnt

co_list_push_front用于将节点list_hdr插入到链表list的头部

void __fastcall co_list_push_front(struct co_list *list, struct co_list_hdr *list_hdr)
{
  co_list_hdr *v2; // r2
  uint32_t v3; // r1

  v2 = list->first;
  if ( !list->first )
  {
    list->last = list_hdr;
  }
  list_hdr->next = v2;
  list->first = list_hdr;
  v3 = list->cnt   1;
  list->cnt = v3;
  if ( list->maxcnt < v3 )
  {
    list->maxcnt = v3;
  }
}

逻辑类似,就是把list_hdr放到链表list->first,然后修正list中相关的字段

节点出链表

co_list_pop_front将头节点出链表

struct co_list_hdr *__fastcall co_list_pop_front(struct co_list *list)
{
  struct co_list_hdr *item; // r1
  co_list_hdr *v2; // r2
  uint32_t v3; // r2

  item = list->first;
  if ( list->first )
  {
    v2 = item->next;
    list->first = item->next;
    if ( !v2 )
    {
      list->last = 0;
    }
    v3 = list->cnt - 1;
    list->cnt = v3;
    if ( list->mincnt > v3 )
    {
      list->mincnt = v3;
    }
  }
  return item;
}

就是把list->first的元素取出,然后修改list的相关信息。

取出节点

co_list_extract函数用于在list中取出从list_hdr最先的nb_following个节点。

bool __fastcall co_list_extract(struct co_list *list, struct co_list_hdr *list_hdr, int nb_following)
{
  bool has_found; // r5
  co_list_hdr *pre; // r4
  co_list_hdr *cur; // r3
  co_list_hdr *new_next; // r1
  uint32_t v7; // r1

  has_found = 0;
  pre = 0;
  for ( cur = list->first; cur; cur = cur->next )
  {
    if ( cur == list_hdr )                      // 首先找到 list_hdr 节点
    {
      has_found = 1;
      while ( nb_following > 0 )                // 从list_hdr最先取出nb_following个节点
      {
        cur = cur->next;
        --nb_following;  // 若是 nb_following 跨越链表长度,就会空指针...
        --list->cnt;
      }
      new_next = cur->next;
      if ( pre )                                // list_hdr最先的nb_following个节点出链表
      {
        pre->next = new_next;
      }
      else
      {
        list->first = new_next;
      }
      if ( list->last == cur )
      {
        list->last = pre;
      }
      v7 = list->cnt - 1;
      list->cnt = v7;
      if ( list->mincnt > v7 )
      {
        list->mincnt = v7;
      }
      return has_found;
    }
    pre = cur;
  }
  return has_found;
}

主要逻辑就是找到list_hdr节点cur,然后从cur最先取出nb_following个节点。

查找节点

co_list_find就是遍历链表找到list_hdr节点

bool __fastcall co_list_find(struct co_list *list, struct co_list_hdr *list_hdr)
{
  do
  {
    list = list->first;
  }
  while ( list != list_hdr && list );
  return list == list_hdr;
}

链表合并

co_list_merge把两个链表合并为一个链表,现实就是把list2的元素挂在list1的末尾

void __fastcall co_list_merge(struct co_list *list1, struct co_list *list2)
{
  list1->last->next = list2->first;
  list1->last = list2->last;
  list2->first = 0;
  list1->cnt  = list2->cnt;
  list2->cnt = 0;
}

事宜调剂机制

Riviera Waves中实现了事宜调剂机制,一个义务可以在处置完事情后,通知特定的事宜处置函数去举行详细的事物处置。

相关API实现

本节主要剖析事宜调剂相关函数的实现

ke_event_init

该函数主要就是初始化了一个全局变量

void ke_event_init()
{
  memset(p_ke_event_table, 0, sizeof(ke_event_table_struct));
}

p_ke_event_table指向一个全局的事宜调剂治理结构,经由逆向剖析其结构体界说如下

struct ke_event_table_struct
{
  int pending_event_bits;
  int callback_list[6];
};

其中pending_event_bits其中的一些bit用于示意特定的事宜是否已经处于pending状态守候系统处置。

callback_list示意每个事宜的处置函数的地址

ke_event_callback_set

该函数现实就是向系统注册 event_type 事宜对应的处置函数, event_type最大为5,及系总共支持6个事宜。

uint8_t __fastcall ke_event_callback_set(uint8_t event_type, void (*p_callback)(void))
{
  unsigned int idx; // r2
  uint8_t result; // r0

  idx = event_type;
  result = 3;
  if ( idx < 6 )
  {
    p_ke_event_table->callback_list[idx] = p_callback;
    result = 0;
  }
  return result;
}

ke_event_schedule

ke_event_schedule会检查p_ke_event_table->pending_event_bits中所有事宜的状态,若是事宜对应的bit为1,就挪用对应的回调函数,要害代码如下

unsigned int ke_event_schedule()
{

  v0 = p_ke_event_table;
  while ( 1 )  // 检查所有事宜的状态
  {
    result = v0->pending_event_bits;
    // 凭据pending_event_bits找到对应的回调函数
    event_callback = *(v0->callback_list   ((4 * (31 - v3)) & 0x3FF));
    if ( event_callback )
    {
      event_callback(); // 挪用事宜的回调函数
    }

ke_event_schedule会在系统运行的特定时机被挪用,好比定时器或者某些义务自动挪用来让系统处置事宜。

,

usdt支付接口

菜宝钱包(caibao.it)是使用TRC-20协议的Usdt第三方支付平台,Usdt收款平台、Usdt自动充提平台、usdt跑分平台。免费提供入金通道、Usdt钱包支付接口、Usdt自动充值接口、Usdt无需实名寄售回收。菜宝Usdt钱包一键生成Usdt钱包、一键调用API接口、一键无实名出售Usdt。

,

此外该函数不会设置事宜对应的bit,所以在事宜的处置函数,若是事宜获得处置要挪用ke_event_clear设置对应事宜的bit为0.

ke_event_clear

设置某个事宜的状态位为0.

bool __fastcall ke_event_clear(unsigned int event)
{
  unsigned int v1; // r1
  _BOOL4 result; // r0

  v1 = __get_CPSR();
  _R2 = 1;
  __asm { MSR.W           PRIMASK, R2 }
  if ( event < 6 )
  {
    p_ke_event_table->pending_event_bits &= ~(1 << event);
  }
  result = v1 != 0;
  __asm { MSR.W           PRIMASK, R0 }
  return result;
}

ke_event_set

设置某个事宜的状态位为1,即通知系统该事宜需要处置,ke_event_schedule函数中会挪用事宜对应的回调函数来处置事宜。

bool __fastcall ke_event_set(unsigned int a1)
{
  unsigned int v1; // r1
  _BOOL4 result; // r0

  v1 = __get_CPSR();
  _R2 = 1;
  __asm { MSR.W           PRIMASK, R2 }
  if ( a1 < 6 )
  {
    p_ke_event_table->pending_event_bits |= 1 << a1;
  }
  result = v1 != 0;
  __asm { MSR.W           PRIMASK, R0 }
  return result;
}

系统注册的事宜处置函数

通过查看ke_event_callback_set的交织引用和参数可以知道系统中注册的事宜号及其回调函数的信息如下

https://github.com/hac425xxx/BLE-DA145XX/blob/main/argument_tracker.py,L556

addr: 0x7F08BB2, event: 0x5, callback: lld_evt_deffered_elt_handler @ 0x7F08A6E
addr: 0x7F09CCE, event: 0x0, callback: llm_encryption_done @ 0x7F02744
addr: 0x7F0E5C2, event: 0x3, callback: event_3_callback_func @ 0x7F0E58E
addr: 0x7F0E956, event: 0x4, callback: event_4_callback_func @ 0x7F0E87C
addr: 0x7F1CDEC, event: 0x1, callback: event_1_callback_func @ 0x7F1CCDE
addr: 0x7F1D06C, event: 0x2, callback: event_2_callback_func @ 0x7F1CFFA

义务治理机制

Riviera Waves中实现了义务治理机制,用户可以建立自己的义务来处置特定的事宜

义务ID由两个部门组成,高8字节为义务的IDX,低8字节为义务的类型,界说如下

/// Task Identifier. Composed by the task type and the task index.
typedef uint16_t ke_task_id_t;

/// Builds the task identifier from the type and the index of that task.
,define KE_BUILD_ID(type, index) ( (ke_task_id_t)(((index) << 8)|(type)) )

/// Retrieves task type from task id.
,define KE_TYPE_GET(ke_task_id) ((ke_task_id) & 0xFF)

/// Retrieves task index number from task id.
,define KE_IDX_GET(ke_task_id) (((ke_task_id) >> 8) & 0xFF)

ke_task_create用于建立一个义务,现实就是把义务描述符放到全局义务数组的特定位置

uint8_t __fastcall ke_task_create(uint8_t task_type, const struct ke_task_desc *p_task_desc)
{
  idx = task_type;

  if ( idx < 26 )
  {
    if ( p_task_desc_table_0[idx] )
    {
      result = 4;
    }
    else
    {
      p_task_desc_table_0[idx] = p_task_desc;
    }

义务描述符的结构如下

/// Task descriptor grouping all information required by the kernel for the scheduling.
struct ke_task_desc
{
    /// Pointer to the state handler table (one element for each state).
    const struct ke_state_handler* state_handler;
    /// Pointer to the default state handler (element parsed after the current state).
    const struct ke_state_handler* default_handler;
    /// Pointer to the state table (one element for each instance).
    ke_state_t* state;
    /// Maximum number of states in the task.
    uint16_t state_max;
    /// Maximum index of supported instances of the task.
    uint16_t idx_max;
};

state是一个数组,用于示意当前task处于哪些状态,state_max为state数组的巨细

开发者可以使用ke_state_set设置task->state的值

void __fastcall ke_state_set(const ke_task_id_t id, const ke_state_t state_id)
{
  int state_idx; // r4
  ke_task_desc *task; // r2
  ke_state_t *v4; // r2

  state_idx = HIBYTE(id);
  task = 0;
  if ( id < 0x1Au )
  {
    task = p_task_desc_table_0[id];
  }
  if ( task->idx_max > state_idx )
  {
    v4 = &task->state[state_idx];
    if ( *v4 != state_id )
    {
      *v4 = state_id;
      notify_handle_saved_msg(id);              // 通知内核去处置queue_saved中的新闻
    }
  }
}

这个表主要在get_msg_handler函数中被使用,用于义务的状态机。

系统中的义务列表

call ke_task_create on llc_init 0x7F02CBE, task_struct: 0x7F1F1E8
call ke_task_create on lld_init 0x7F06E1E, task_struct: 0x7F1F540
call ke_task_create on llm_init 0x7F09CC6, task_struct: 0x7F1F578
call ke_task_create on gtl_init_func 0x7F0E322, task_struct: 0x7F1F7F0
call ke_task_create on gattc_init 0x7F125BE, task_struct: 0x7F1FE44
call ke_task_create on gattm_init 0x7F13824, task_struct: 0x7F1FF40
call ke_task_create on l2cc_init 0x7F13B7A, task_struct: 0x7F1FFE0
call ke_task_create on gapc_init 0x7F1567C, task_struct: 0x7F2004C
call ke_task_create on gapm_init 0x7F176D4, task_struct: 0x7F201B4

新闻调剂机制

申请新闻

函数通过ke_msg_alloc申请新闻,入参分别为新闻ID,目的task_id, 源task_id以及新闻参数的长度。

void *__fastcall ke_msg_alloc(const ke_msg_id_t id, const ke_task_id_t dest_id, const ke_task_id_t src_id, const uint16_t param_len)
{
  size_t v6; // r4
  ke_msg *msg; // r0
  uint32_t *v9; // r5

  v6 = param_len;
  msg = ke_malloc(param_len   16, 2);  // 申请内存
  msg->hdr.next = -1;
  msg->saved = 0;
  msg->id = id;
  msg->dest_id = dest_id;
  msg->src_id = src_id;
  msg->param_len = v6;
  v9 = msg->param;
  memset(msg->param, 0, v6);
  return v9;
}

返回值是一个ke_msg结构体的param部门

struct ke_msg
{
  struct co_list_hdr hdr;  // 链表头,用于后面把新闻挂载到co_list链表中
  uint32_t saved;
  ke_msg_id_t id;
  ke_task_id_t dest_id;
  ke_task_id_t src_id;
  uint16_t param_len;  // param 的长度
  uint32_t param[1];
};

新闻释放

ke_msg_free直接使用 ke_free 释放内存。

int __fastcall ke_msg_free(int a1)
{
  return ke_free(a1);
}

ke_msg_free的入参是 ke_msg*,然则ke_msg_alloc返回是ke_msgparam,所以在使用ke_msg_free很有可能泛起指针没有减0x10(ke_msg头部的巨细)的情形。

新闻发送

ke_msg_send用于将特定新闻发送到目的义务去处置

bool __fastcall ke_msg_send(int param)
{
  ke_msg *msg_hdr; // r1
  unsigned int v2; // r4

  msg_hdr = (param - 16);
  v2 = __get_CPSR();
  _R0 = 1;
  __asm { MSR.W           PRIMASK, R0 }         // 关闭中止
  co_list_push_back(&p_ke_env->queue_sent, &msg_hdr->hdr);
  _R0 = v2 != 0;
  __asm { MSR.W           PRIMASK, R0 }         // 恢复中止
  return ke_event_set(1u);
}

主要逻辑就是把msg_hdr放到p_ke_env->queue_sent链表的末尾,p_ke_env指向ke_envke_env是一个全局变量,其结构如下

/// Kernel environment definition
struct ke_env_tag
{
    /// Queue of sent messages but not yet delivered to receiver
    struct co_list queue_sent;
    /// Queue of messages delivered but not consumed by receiver
    struct co_list queue_saved;
    /// Queue of timers
    struct co_list queue_timer;

    ,if (KE_MEM_RW)
    /// Root pointer = pointer to first element of heap linked lists
    struct mblock_free * heap[KE_MEM_BLOCK_MAX];
    /// Size of heaps
    uint16_t heap_size[KE_MEM_BLOCK_MAX];

    ,if (KE_PROFILING)
    /// Size of heap used
    uint16_t heap_used[KE_MEM_BLOCK_MAX];
    /// Maximum heap memory used
    uint32_t max_heap_used;
    ,endif //KE_PROFILING
    ,endif //KE_MEM_RW
};

可以看的结构体头部是queue_sent,类型为co_list,这个行列用于存放发送的的新闻,queue_sent中新闻会在后面新闻调剂时,找到对应的新闻处置函数举行处置。

ke_msg_send就是把要发送的新闻放到ke_envqueue_sent发送行列中。

新闻挂载到queue_sent链表后会挪用ke_event_set通知内核,1号事宜触发,然后在事宜处置函数中会去挪用新闻对应的处置函数去处置新闻。

新闻处置

ke_task_init_func函数内里注册了1号事宜的处置函数

int ke_task_init_func()
{
  memset(p_task_desc_table_0, 0, 0x68u);
  return ke_event_callback_set(1u, 0x07F1CCDF);
}

0x07F1CCDF处的函数的要害代码为

int event_1_callback_func()
{
  // 从发送行列中取出一个新闻
  msg = co_list_pop_front(&p_ke_env_->queue_sent);
  if ( msg && !ke_is_free(msg) )
  {
    custom_msg_handler = *custom_msg_handlers_1;
    if ( *custom_msg_handlers_1 )
    {
      // 首先在 custom_msg_handlers 内里搜索新闻处置函数
      for ( i = 0; ;   i )
      {
        handler = &custom_msg_handler[i];       
        if ( !handler->func )
        {
          break;
        }
        if ( msg->dest_id == custom_msg_handler[i].task_id )
        {
          msg_id = msg->id;
          if ( msg_id == handler->id || msg_id == dv_0xFFFF )
          {
            msg_handle_func = custom_msg_handler[i].func;
            if ( !msg_handle_func )
            {
              break;                            // 若是匹配就挪用回调函数处置
            }
            goto trigger_callback_func;
          }
        }
      }
    }
    msg_handle_func = get_msg_handler(msg->id, msg->dest_id);
    if ( msg_handle_func )
    {
trigger_callback_func:
      msg_handle_result = msg_handle_func(msg->id, msg->param, msg->dest_id, msg->src_id);
      if ( msg_handle_result )
      {
        if ( msg_handle_result != 1 && msg_handle_result == 2 )
        {
          // 处置结果为2,msg保存到queue_saved链表
          msg->saved = 1;
          co_list_push_back(&p_ke_env_->queue_saved, &msg->hdr);
        }
        goto out;
      }
    }
    ke_msg_free(msg);                           // 若是新闻处置乐成就把msg释放
  }
out:
  if ( !p_ke_env_->queue_sent.first )           // 若是queue_sent链表为空,消灭 event ,1 事宜
  {
    ke_event_clear(1u);
  }
  return result;
}

代码逻辑为

  1. p_ke_env_->queue_sent取出一个新闻msg
  2. 凭据msg->idcustom_msg_handlers 内里搜索新闻处置函数,若是能找到就挪用新闻处置函数。
  3. 否则挪用get_msg_handler凭据msg->idmsg->dest_id去目的义务描述符内里搜索处置函数
  4. 找到处置函数msg_handle_func后,挪用msg_handle_func对新闻举行处置
  5. 若是msg_handle_func返回值为0示意新闻处置完毕,后面会使用ke_msg_free释放新闻的内存,若是返回值为2,就会把新闻放到p_ke_env_->queue_saved链表中
  6. 最后函数会判断queue_sent链表若是没有未处置的新闻,就会把 1 号事宜消灭。

总结

本文主要对Riviera Waves系统中的一些要害API、事情机制举行先容。