原创] 初探安卓隐藏Bootloader锁

初探安卓隐藏Bootloader锁https://bbs.kanxue.com/thread-278445.htm 做完硬件断点记录器后就开始研究如何隐藏Android的Bootloader锁了,当然最近没啥兴趣继续研究了,把目前为止的思路发出来 首先想到的一个方向是要先spoof安卓Setting里的oemlock status 收集所需信息 在aoxpxref网站上搜索 bootloader unlocked 看到一个可疑的文件 /frameworks/base/core/java/android/service/oemlock/OemLockManager.java xref 找到 /frameworks/base/services/core/java/com/android/server/oemlock/OemLockService.java 看到函数 1 2 3 4 5 6 7 8 9 10 11 12 13 private static final String FLASH_LOCK_PROP = "ro.boot.flash.locked"; private static final String FLASH_LOCK_UNLOCKED = "0" public boolean isDeviceOemUnlocked() { enforceOemUnlockReadPermission(); String locked = SystemProperties.get(FLASH_LOCK_PROP); switch (locked) { case FLASH_LOCK_UNLOCKED: return true; default: return false; } } 可以看到Setting检测的是系统属性 ro.boot.flash.locked 来判断Bootloader是否解锁 AOSP搜索ro.boot.flash.locked,发现/system/core/init/init.cpp 有初始化该属性值的代码 1 2 3 4 5 6 7 8 static void export_oem_lock_status() { if (!android::base::GetBoolProperty("ro.oem_unlock_supported", false)) { return; } SetProperty( "ro.boot.flash.locked", android::base::GetProperty("ro.boot.verifiedbootstate", "") == "orange" ? "0" : "1"); } ro.boot.flash.locked 的值是受到 ro.boot.verifiedbootstate 的值影响 google搜了一下后面的这个属性,发现这个属性可能的值有red,orange,yellow,green 看到一个隐藏bl锁的github项目 https://github.com/topjohnwu/Magisk/blob/3c04dab47274e9bbbfb3ddd1fcf71c929c8ed0c0/native/jni/magiskhide/hide_policy.cpp#L12 看到替换表 1 2 3 4 5 6 7 8 9 10 11 12 13 static const char *prop_key[] = { "ro.boot.vbmeta.device_state", "ro.boot.verifiedbootstate", "ro.boot.flash.locked", "ro.boot.veritymode", "ro.boot.warranty_bit", "ro.warranty_bit", "ro.debuggable", "ro.secure", "ro.build.type", "ro.build.tags", "ro.vendor.boot.warranty_bit", "ro.vendor.warranty_bit", "vendor.boot.vbmeta.device_state", nullptr }; static const char *prop_val[] = { "locked", "green", "1", "enforcing", "0", "0", "0", "1", "user", "release-keys", "0", "0", "locked", nullptr }; 可以确定green是bl未解锁,还有一个 ro.boot.vbmeta.device_state 要改成locked状态,实机看这个属性解锁bl状态下是unlocked,除了前三个之外其他属性解bl之后没变 还有 googleplay service 的验证 https://developer.android.com/training/safetynet/attestation https://developer.android.com/google/play/integrity/overview 对应的解决方案是 https://github.com/kdrag0n/safetynet-fix 这个问题不大,国内又不用googleplay service 总结需要修改的信息 按照上述总结一下,隐藏bl锁需要修改以下属性 Property Value ro.boot.flash.locked 1 ro.boot.verifiedbootstate green ro.boot.vbmeta.device_state locked 寻找修改Property的方法 Java层最终会调用native_get方法获取Property的值 顺着native_get 找到函数__system_property_find 这个是用户层标准的获取property值的函数,来自libc.so,往下翻就是android property系统的实现了,可以看这篇文章 https://bbs.kanxue.com/thread-274100.htm 进用户层初始化property service的地方 /system/core/init/property_service.cpp 找到函数 PropertyInit 从名字猜测这是init进程初始化系统基本property值的地方,ProcessBootconfig和ProcessKernelCmdline最后是通过读取/proc/bootconfig和/proc/cmdline调用_system_property_add来设置ro.boot.verifiedbootstate和ro.boot.vbmeta.device_state的值 cat一下这两个设备文件,确实有相关信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 adb shell su -c cat /proc/bootconfig androidboot.hardware = "qcom" androidboot.memcg = "1" androidboot.usbcontroller = "a600000.dwc3" androidboot.bootdevice = "1d84000.ufshc" androidboot.boot_devices = "soc/1d84000.ufshc" androidboot.prjname = "22803" androidboot.startupmode = "pwrkey" androidboot.mode = "normal" androidboot.product.hardware.sku = "0" androidboot.hw_region_id = "1" androidboot.serialno = "xxxxxxx" androidboot.baseband = "msm" androidboot.dtbo_idx = "12" androidboot.dtb_idx = "1" androidboot.force_normal_boot = "0" androidboot.fstab_suffix = "default" androidboot.verifiedbootstate = "orange" androidboot.keymaster = "1" androidboot.vbmeta.device = "PARTUUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" androidboot.vbmeta.avb_version = "1.0" androidboot.vbmeta.device_state = "unlocked" androidboot.vbmeta.hash_alg = "sha256" androidboot.vbmeta.size = "23232" androidboot.vbmeta.digest = "xxxxx" androidboot.vbmeta.invalidate_on_error = "yes" androidboot.veritymode = "enforcing" androidboot.slot_suffix = "_a" 我想到了三个思路 在内核层修改/proc/bootconfig和/proc/cmdline的内容 对_system_property_add下硬件断点,回调里修改value的参数 修改/dev/properties/u:object_r:bootloader_prop:s0里的信息 第一个思路 kernel版本 5.10.168 路径/common/fs/proc/bootconfig.c 中的proc_boot_config_init 函数初始化了/proc/bootconfig的输出,顺着全局变量 xbc_data 找到系统获取bootconfig的地方/common/init/main.c -> setup_bootconfig , 可以看到bootconfig是从initrd里拿的 将返回的data copy进全局变量,然后由驱动打印出来看到数据 1 2 www1@www1s-Mac-mini ~ % adb shell su -c dmesg | grep "\[+" [ 0.278576] [+] androidboot.hardware=qcom\x0aandroidboot.memcg=1\x0aandroidboot.usbcontroller=a600000.dwc3\x0a\x0aandroidboot.bootdevice=1d84000.ufshc\x0aandroidboot.boot_devices=soc/1d84000.ufshc\x0aandroidboot.prjname=22803\x0aandroidboot.startupmode=hard_reset\x0aandroidboot.mode=normal\x0aandroidboot.product.hardware.sku=0\x0aandroidboot.hw_region_id=1\x0aandroidboot.serialno=xxxxxxxx\x0aandroidboot.baseband=msm\x0aandroidboot.dtbo_idx=12\x0aandroidboot.dtb_idx=1\x0aandroidboot.force_normal_boot=0\x0aandroidboot.fstab_suffix=default\x0a\x0aandroidboot.verifiedbootstate=orange\x0aandroidboot.keymaster=1\x0aandroidboot.vbmeta.device=PARTUUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\x0aandroidboot.vbmeta.avb_version=1.0\x0aandroidboot.vbmeta.device_state=unlocked\x0aandroidboot.vbmeta.hash_alg=sha256\x0aandroidboot.vbmeta.size=23232\x0aandroidboot.vbmeta.digest=xxxxxxxxxxxxx\x0aandroidboot.vbmeta.invalidate_on_error=yes\x0aandroidboot.veritymode=enforcing\x0aandroidboot.slot_suffix=_a\x0a\x0d 尝试文本替换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 void regen_bootcfg(char* buffer) { char * pos; pos = strstr(buffer, "verifiedbootstate=orange"); if(pos) { memcpy(pos,"verifiedbootstate=green\n",24); } pos = strstr(buffer, "vbmeta.device_state=unlocked"); if(pos) { memcpy(pos,"vbmeta.device_state=locked\n\n",28); } pos = strstr(buffer, "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"); if(pos) { memcpy(pos,"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx1",36); } } 实验发现替换 uuid 和 vbmeta.device_state 系统正常启动,一旦修改 verifiedbootstate 系统就无法启动了,第一个思路就结束在这里了 第二个思路 先说结果: 成功了!!!!!! 安卓的linker使用的是mmap映射的elf文件,hook do_mmap的返回处,判断pgoff和filepath就能拦截到init进程加载libc.so,在这个时机里对_system_property_add函数下execute hook, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 void rwhandler_hidebl_mmap_callback(unsigned long addr,struct file *file) { char fullpath[1024]; char *path = d_path(&file->f_path, fullpath, 1024); if( path && !strcmp(path,"/system/lib64/bootstrap/libc.so") && current->pid == 1) { rwhandler_start_debug(); rwhandler_set_hbp(1,addr+0x90430,4,HW_BREAKPOINT_X); printk("task = %s file = %s addr = %llX\r\n",current->comm,path,addr); } } hook回调里对参数进行简单处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 static const char *hide_props[]={"ro.boot.verifiedbootstate","ro.boot.vbmeta.device_state",NULL}; static char *hide_value[]={"green","locked",NULL}; static bool hidebl_hbpcallback(struct perf_event *bp, struct perf_sample_data *data, struct pt_regs *regs) { if(current->pid == 1) { char key[100]; unsigned long keyaddr = regs->regs[0]; unsigned long varaddr = regs->regs[2]; memset(key, 0, 100); printk("[+] init hit pc = %llX x0 = %llX x1 = %llX\r\n", regs->pc,regs->regs[0],regs->regs[1]); keyaddr &= 0xFFFFFFFFFFFFFF; varaddr &= 0xFFFFFFFFFFFFFF; if(rwhandler_read_memory( 1, (unsigned long)keyaddr, key, 99)>0) { char value[100]; memset(value, 0, 100); printk("[+] value = %llX\r\n",*(uint64_t*)key); printk("[+] init key = %s\r\n",key); if(rwhandler_read_memory( 1, (unsigned long)varaddr, value, 99)>0) { int idx = 0; printk("[+] init value = %s\r\n",value); while(hide_props[idx]) { if(!strcmp(key,hide_props[idx])) { if(rwhandler_do_ptrace_write(1, varaddr, hide_value[idx], strlen(hide_value[idx])+1)) { regs->regs[3]=strlen(hide_value[idx]); } break; } idx++; } } } return true; } return false; }; 修改成功 成功 Spoof Setting 结尾 第三个方法暂时没试过,感兴趣的可以试试看 有空就把第二个思路用kprobe来实现hook,包装成驱动连带硬件断点记录器分别开源到github上 刚入坑安卓,如有不对的地方或者有其他方法检测bl锁请大佬们在评论区指出!!! [培训]科锐软件逆向50期预科班报名即将截止,速来!!! 50期正式班报名火爆招生中!!!

留言

這個網誌中的熱門文章

⚡️有用的鏈接⚡️

DeepNude 2.0 – Deepnude AI算法一键脱衣,绿色破解版,免费下载

15 種 SMS 激活服務 - 通過 SMS 激活的號碼(免費和付費)