2018-03-31

Android root Mount Protect Bypass

1. Android root Mount Protect Bypass

1.1. Oppo && Vivo

so easy… fork, fork, fork…

1.2. Huawei MT7 && LOWER

1.2.1. mount check

void submit_bio(int rw, struct bio *bio) {
  struct task_struct *tsk = current;

#ifdef CONFIG_HW_SYSTEM_WR_PROTECT
  char devname[BDEVNAME_SIZE] = {0};
#endif

  bio->bi_rw |= rw;

  /*
   * If it's a regular read/write or a barrier with data attached,
   * go through tPGOUT, count);
   } else {
   task_io_account_read(bio->bi_size);
   count_vm_events(PGPGIN, count);
   }

   #ifdef CONFIG_HW_SYSTEM_WR_PROTECT
   if (rw & WRITE) {
   memset(devname, 0x00, BDEVNAME_SIZE);
   bdevname(bio->bi_bdev, devname);

   /*
   * runmode=factory:send write request to mmc driver.
   * bootmode=recovery:send write request to mmc driver.
   * partition is mounted ro: file system will block write request.
   * root user: send write request to mmc driver.
   */
  if (((strstr(devname, PART_SYSTEM) != NULL) ||
       (strstr(devname, PART_MODEM) != NULL) ||
       (strstr(devname, PART_CUST) != NULL)) &&
      *ro_secure_debuggable) {
    // ...
  }
}
#endif
}
}

1.2.2. mount bypass:

if (ro_secure_debuggable) {
  if(*ro_secure_debuggable > KERNEL_ADDR) {
    ro_secure_debuggable_static = *ro_secure_debuggable;
    *ro_secure_debuggable_static = 0;
  } else {
    *ro_secure_debuggable = 0;
  }
 }

1.3. Huawei P10 && UPPER

1.3.1. mount check

void submit_bio(int rw, struct bio *bio)
{
  bio->bi_rw |= rw;

  /*
   * If it's a regular read/write or a barrier with data attached,
   * go through the normal accounting stuff before submission.
   */
  if (bio_has_data(bio)) {
    unsigned int count;

    if (unlikely(rw & REQ_WRITE_SAME))
      count = bdev_logical_block_size(bio->bi_bdev) >> 9;
    else
      count = bio_sectors(bio);

    if (rw & WRITE) {
      count_vm_events(PGPGOUT, count);
    } else {
      task_io_account_read(bio->bi_iter.bi_size);
      count_vm_events(PGPGIN, count);
    }

#ifdef CONFIG_HW_SYSTEM_WR_PROTECT
    if (should_trap_this_bio(rw, bio, count))
      return;
#endif
    // ...
  }
}


int should_trap_this_bio(int rw, struct bio *bio, unsigned int count)
{
  char *name;

  if (!(rw & WRITE))
    return 0;

  name = get_bio_part_name(bio);

  // ...

  if (likely(!is_protected_partition(name)))
    return 0;

  if ((NULL == ro_secure_debuggable) || (0 == *ro_secure_debuggable))
    return 0;
  // ...
}

static inline char *is_protected_partition(const char *name)
{
  int i;

  for (i = 0; protected_partitions[i]; i++) {
    if (!strncmp(name, protected_partitions[i],
                 strlen(protected_partitions[i]) + 1)) {
      return 1;
    }
  }

  return 0;
}

/*  system write protect flag, 0: disable(default) 1:enable */
static int *ro_secure_debuggable;

static char *protected_partitions[] = {
  "system",
  "system_a",
  "system_b",
  "cust",
  "cust_a",
  "cust_b",
  "vendor",
  "vendor_a",
  "vendor_b",
  "product",
  "product_a",
  "product_b",
  NULL,
};

1.3.2. mount bypass

使函数 should_trap_this_bio() 返回 0 即可


echo 0 > /proc/sys_wp_soft

HWVTR:/ # cat /proc/kallsyms | grep protected_partitions
ffffffc001185ff8 r protected_partitions

只读,不可写入,会崩溃

1.3.3. 缺陷

已有的绕过方案:保护实现位于 software_system_wp.c

重新刷机后发现 mount 后只能写入一次,第二次则失败!

'/dev/block/dm-0' is read-only

经过验证,是 dm-verity 的问题

patch fstab.hi3660 之后就可以正常 mount 以及写入 apk

与 emmc_system_wp.c 实现无关

重启后 apk 生效,与 system-less 模式无关

dm-verity 开启:
/dev/block/dm-0 /system ext4 ro,seclabel,relatime,discard,data=ordered 0 0

dm-verity 关闭:
/dev/block/bootdevice/by-name/system /system ext4 ro,seclabel,relatime,discard,data=ordered 0 0

Author: idhyt

Android Root Zap Framework

‎ 1. Warning 请遵守GPL开源协议, 请遵守法律法规, 本项目仅供学习和交流, 请勿用于非法用途! 道路千万条, 安全第一条, 行车不规范, 亲人两行泪. 2. Android Root Zap Frame...