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
7 Likes

学习了:grinning:

先赞后看,紫薯布丁。

1 Like