欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]SecureROM 分析笔记

[原创]SecureROM 分析笔记

SecureROM 分析笔记

这是我在分析 SecureROM 时随手记得笔记。

  • 软件环境:基于泄露的 iBoot 的源码,所涉及的二进制是基于源码编译的。
  • 硬件环境:T8010。

SecureROM 的功能概览

从下面的简化版的启动流程图上可以看出 SecureROM 的功能相对比较单一:

Form From:https://xerub.github.io/ios/iboot/2018/05/10/de-rebus-antiquis.html

                    NAND/Normal  +------+     +-------+

                   ------------> | LLB  | --> | iBoot | --> OS

    +-----------+ /              +------+     +-------+

    | SecureROM |<

    +-----------+ \              +------+     +-------+

                   ------------> | iBSS | --> | iBEC  | --> Restore

                    USB/DFU      +------+     +-------+

  • 进行基本的外设及内存初始化。
  • 枚举预设的块设备,寻找启动设备,加载 LLB。
  • 如果无法找到启动设备或者相关针脚指示要进入 DFU(Device Firmware Update) 模式,则加载 iBSS。

Start 函数

__text:0000000100000000 start

__text:0000000100000000 

__text:0000000100000000                 ADRP            X0, #start

__text:0000000100000004                 ADD             X0, X0, #start@PAGEOFF

__text:0000000100000008                 LDR             X1, =start

__text:000000010000000C                 BL              platform_start

__text:0000000100000010                 CMP             X1, X0

__text:0000000100000014                 B.EQ            loc_10000003C

__text:0000000100000018                 MOV             X30, X1

__text:000000010000001C                 LDR             X2, =handlers

__text:0000000100000020                 LDR             X3, =start

__text:0000000100000024                 SUB             X2, X2, X3

__text:0000000100000028

__text:0000000100000028 loc_100000028

__text:0000000100000028                 LDP             X3, X4, [X0],#0x10

__text:000000010000002C                 STP             X3, X4, [X1],#0x10

__text:0000000100000030                 SUBS            X2, X2, #0x10

__text:0000000100000034                 B.NE            loc_100000028

__text:0000000100000038                 RET

如上的反汇编结果是 start 的起始部分,这部分的主要功能是:确定 SecureROM 是否被加载到固定地址 0x100000000。如果在指定地址,则执行真正的功能代码 loc_10000003C。如果不是,则将返回地址设置到 0x100000000,并返回。platform_start 的汇编代码如下:

__text:0000000100009730 platform_start

__text:0000000100009730                 MRS             X2, S3_3_C15_C7_0

__text:0000000100009734                 ORR             X2, X2, #2

__text:0000000100009738                 MSR             S3_3_C15_C7_0, X2

__text:000000010000973C

__text:000000010000973C loc_10000973C

__text:000000010000973C                 MRS             X2, S3_3_C15_C7_0

__text:0000000100009740                 AND             X2, X2, #0x8000000000000000

__text:0000000100009744                 CBZ             X2, loc_10000973C

__text:0000000100009748                 RET

__text:0000000100009748 ; End of function platform_start

start 函数主要功能的反编译结果如下:

void start()

{

...

    __asm { MSR             DAIFSET, #0XF }

    _WriteStatusReg(ARM64_SYSREG(3, 0, 12, 0, 0), exception_vector_base);

    for ( i = 0x1800A8000LL; i != 0x1800AC000LL; i += 16LL )

    {

      *i = 0LL;

      *(i + 8) = 0LL;

    }

    for ( j = 0x1800A0000LL; j != 0x1800A8000LL; j += 16LL )

    {

      *j = 0LL;

      *(j + 8) = 0LL;

    }

    __asm { MSR             SPSEL, #0 }

    v13 = 0x100020000LL;

    v14 = &interrupt_stack_top;

    if ( &interrupt_stack_top != 0x100020000LL )

    {

      do

      {

        v15 = *v13;

        v16 = *(v13 + 8);

        v13 += 16LL;

        v14->handler = v15;

        v14->arg = v16;

        v14 = (v14 + 16);

      }

      while ( v14 != handlers );

    }

    v17 = handlers;

    do

    {

      v17->handler = 0LL;

      v17->arg = 0LL;

      v17 = (v17 + 16);

    }

    while ( v17 != &random_pool[12] );

    do

    {

      LODWORD(v17->handler) = 0;

      v17 = (v17 + 4);

    }

    while ( v17 < 0x180089448LL );

    interrupt_stack_top = 0x1800AC000LL;

    v18 = boot_handoff_trampoline;

    v19 = 0x1800AC000LL;

    do

    {

      v20 = *v18;

      v21 = *(v18 + 1);

      v18 = (v18 + 16);

      *v19 = v20;

      *(v19 + 8) = v21;

      v19 += 16LL;

    }

    while ( v18 < apcie_set_s3e_mode );

}

功能包括:设置中断向量表,初始化相关的内存,设置栈。执行完初始化后,start 函数也是通过设置返回地址的方式跳到 main 函数执行。

Main 函数

main 函数的反编译结果如下:

int __cdecl main()

{

  arch_cpu_init(0);

  printf("\nSecureROM start\n");

  printf("setting up initial clock configuration\n");

  platform_init_setup_clocks();

  printf("setting up internal memory\n");

  platform_init_internal_mem();

  printf("setting up default pin configuration\n");

  platform_init_hwpins();

  force_dfu = platform_get_force_dfu();

  request_dfu2 = 0LL;

  if ( platform_get_request_dfu1() )

    request_dfu2 = platform_get_request_dfu2();

  sys_init();

  sys_init_stack_cookie();

  printf("doing early platform hardware init\n");

  platform_early_init();

  printf("\n\n%s for %s\n", "SecureROM", "d10si");

  printf("%s\n", "localbuild...Proteas...ARM64_a99cbd3_dirty...2019/08/01-14:04:30");

  printf("%s\n", "DEBUG");

  printf("doing platform hardware init\n");

  platform_init();

  printf("Checking for Force DFU Mode Pin: %x / %x\n", force_dfu, request_dfu2);

  if ( force_dfu )

    force_dfu = platform_get_usb_cable_connected();

  printf("Checking for Force DFU Mode request pins: %x / %x\n", force_dfu, request_dfu2);

  if ( !force_dfu && request_dfu2 && platform_get_usb_cable_connected() )

  {

    v2 = system_time();

    while ( platform_get_request_dfu1()

         && platform_get_request_dfu2()

         && platform_get_usb_cable_connected()

         && !time_has_elapsed(v2, 0x5B8D80uLL) )

      task_sleep(0x186A0uLL);

    v3 = system_time();

    while ( 1 )

    {

      if ( platform_get_request_dfu1() || !platform_get_request_dfu2() || !platform_get_usb_cable_connected() )

        goto LABEL_21;

      if ( time_has_elapsed(v3, 0x5B8D80uLL) )

        break;

      task_sleep(0x186A0uLL);

    }

    printf("Force DFU: %x\n", 1LL);

  }

  else

  {

LABEL_21:

    printf("Force DFU: %x\n", force_dfu);

    if ( !force_dfu )

    {

      index0 = 0;

      goto LABEL_24;

    }

  }

  index0 = -1;

LABEL_24:

  index = index0;

  while ( 1 )

  {

    if ( !platform_get_boot_device(index, &boot_device, &boot_flag, &boot_arg) )

    {

      printf("No valid boot device, resetting.\n");

      platform_reset(0);

    }

    boot_flag2 = boot_flag;

    printf("boot_selected: boot_device: %08x, boot_flag: %08x, boot_arg: %08x\n", boot_device, boot_flag, boot_arg);

    platform_enable_boot_interface(1, boot_device, boot_arg);

    security_init(1);

    if ( boot_device == BOOT_DEVICE_USBDFU )

    {

      platform_set_dfu_status(1);

      v15 = getDFUImage(0x1800B0000LL, 0x100000);

      if ( v15 & 0x80000000 )

      {

        v16 = "fatal DFU download error";

LABEL_40:

        printf(v16);

        goto LABEL_41;

      }

      if ( v15 > 0x100000 )

        panic("boot_selected", "load overflow");

      v13 = v15;

      v12 = image_create_from_memory(0x1800B0000LL, v15, 0);

      if ( !v12 )

      {

        v16 = "failed to create image from DFU download\n";

        goto LABEL_40;

      }

      printf("loaded image from USB-DFU\n");

      v14 = 'ibss';

    }

    else

    {

      if ( boot_device == BOOT_DEVICE_NVME )

      {

        dev_name = "nvme_firmware0";

      }

      else

      {

        if ( boot_device != BOOT_DEVICE_SPI )

          goto LABEL_41;

        printf("SPI NOR boot selected\n");

        flash_nor_init(boot_arg);

        dev_name = "nor0";

      }

      v11 = lookup_image_in_bdev(dev_name, v9);

      v12 = v11;

      if ( !v11 )

        goto LABEL_41;

      v13 = LODWORD(v11->next);

      v14 = 'illb';

    }

    types = v14;

    load_len = v13;

    load_addr = 0x1800B0000LL;

    v12->imageOptions |= (2 * (boot_flag2 & 1)) ^ 0xB;

    if ( !image_load(v12, &types, 1u, 0LL, &load_addr, &load_len) )

    {

      image_free(v12);

      platform_enable_boot_interface(0, boot_device, boot_arg);

      security_consolidate_environment();       // demote

      security_sidp_seal_rom_manifest();

      printf("executing image...\n");

      prepare_and_jump(BOOT_UNKNOWN, 0x1800B0000LL, 0LL);

    }

    printf("image load failed\n");

    image_free(v12);

LABEL_41:

    platform_enable_boot_interface(0, boot_device, boot_arg);

    printf("failed to load from selected boot device\n");

    if ( !(index0 & 0x80000000) )

      ++index;

  }

}

从上面的代码中可以看到 main 函数的主要功能可以依据是否进入 DFU 进行分割:

  1. 如果需要进入 DFU 模式,则初始化 USB,等待 Client 发送 iBSS。 在收到 Client 发送的 iBSS 后,验证其签名的合法性。如果签名合法,则执行 iBSS。
  2. 如果不需要进入 DFU 模式,则查找启动设备,并从启动设备中寻找 LLB,并验证 LLB 的签名合法性。如果签名合法,则执行 LLB。如果没法找到启动设备,platform_get_boot_device 会返回 BOOT_DEVICE_USBDFU 即:同样会进入 DFU 模式。
  3. 其它:image_load 函数会校验 img4 的类型及合法性。

Reference

  1. iBoot Source Code

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功