0%

1. 加密方案整理

1.1. 简介

Android上加密方案分为全磁盘加密(FDE)/文件加密(FBE)/元数据加密(METADATA)
均是针对userdata分区进行加密, 与其他分区并无关系.
本篇主要介绍下这三种加密方式硬件加密的实现框架

1.2. 判断机器采用何种加密方式

最直观的方式是可以通过分区表fstab来区分
未加密/fde加密/fbe加密/metadata加密

1
2
3
/dev/block/bootdevice/by-name/userdata     /data           ext4    noatime,nosuid,nodev,barrier=1,data=ordered,noauto_da_alloc     wait,check,encryptable=footer
/dev/block/bootdevice/by-name/userdata /data ext4 noatime,nosuid,nodev,barrier=1,noauto_da_alloc,discard latemount,wait,check,fileencryption=ice,wrappedkey,quota,reservedsize=128M
/dev/block/bootdevice/by-name/userdata /data ext4 noatime,nosuid,nodev,barrier=1,noauto_da_alloc,discard latemount,wait,check,fileencryption=ice,wrappedkey,keydirectory=/metadata/vold/metadata_encryption,quota,reservedsize=128M

当前版本中最常见的是fbe加密的机型.

代码中判断是否加密:

1
2
3
StorageManager.isEncrypted()
StorageManager.isFileEncryptedNativeOnly()
StorageManager.isBlockEncrypted()

native 层多是通过FstabEntry来判断是何种加密方式

阅读全文 »

vnote_backup_file_826537664 /home/mi/Documents/backup/VnoteBook/OTA相关/动态分区机型fastbootd使用.md

动态分区机型fastbootd使用

fastbootd简介

在动态分区机型上bootloader的fastboot不能烧写动态分区的镜像, 需要使用recovery子系统下的fastbootd来进行用户空间的烧写镜像的工作

fastbootd是recovery子系统下的一个native进程, 由init fork出来. 具体实现方式类似于adbd.
包括进程创建, 驱动通道, 与init的协作都与adbd一致, 是属于借助usb的config配置实现的功能.
因此不能同时启用adb和fastboot模式, 因为这两个独占同一个通道.

fastbootd命令

Command Description Available when device is OEM locked
getvar is-userspace Return yes Yes
getvar
is-logical:
Return yes if the given partition is a
logical partition, no otherwise
Yes
getvar super-partition-name MUST return super for a device
launching with logical partitions
Yes
create-logical-partition
Create a logical partition with the
given name and size
No
delete-logical-partition
Delete the given logical partition No
resize-logical-partition
Resize the logical partition to the new
size without changing its contents
No
update-super Similar to flash super, except rather
than flashing raw data to the super
partition, this will ensure that all
partitions within the downloaded
image are created
No
getvar max-download-size Return the maximum size of an image
that can be downloaded in bytes in
hex
Yes
getvar partition-type
Return file system type: ext4, f2fs,
raw
Yes
flash partition_name filename Flash the partition through a series of
download and flash fastboot
protocol commands
No
reboot bootloader Reboot into bootloader mode Yes
reboot fastboot Reboot back into fastbootd mode Yes

安装最新的fastboot工具

platform-tools获取最新的fastboot和adb的工具

  • linux下替换
    解压后得到platform-tools 目录
阅读全文 »

设备bootloader上锁状态下1217无法工作问题分析

背景

前面讲到r上6月份升级基线后, 因KM TA date support的升级导致recovery下无法正常使用解密服务.

当时的方案是配置recovery vbmeta区域的 prop --prop com.android.build.boot.security_patch:2020-06-05
从而在bootimg_hdr不支持识别date 信息的情况下, 可以在reocovery模式下bootloader能够读到天的信息, 并传给KM TA.

新问题

最近测试在复测该问题时, 发现手机bootloader上锁状态下, 无法执行1217功能. 因此需要重新分析下这个问题的原因.

locked 状态下的调试

debug abl的方法

locked状态下的限制

首先, 小米机器locked 状态有如下限制:

阅读全文 »

1. 开机log相关

1.1. 抓取log的方式

1.1.1. 通过rec overy抓取ota的log

1
2
3
4
5
6
7
8
9
10
11
12
@startuml
-设置
-系统更新
-菜单(重启到recovery)
note right
稳定版本需要连续点击logo
才会出现菜单项
end note
-系统重启到recovery模式
-选择连接小米助手
- pc端执行 adb pull /cache/ .
@enduml

1.1.1.1. 抓取的log分析

/cache/recovery/下面是ota升级相关的log日志
/cache/mqsas下是重启到recovery模式前主系统最后保存的日志

1.1.2. 主系统的日志

如果adb 可以连接, 可查看的log信息
`adblog

`cat

阅读全文 »

添加配置, 设置.
launch脚本

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
{
// 使用 IntelliSense 了解相关属性.
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/bin/main",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceRoot}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"preLaunchTask": "Build",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

其中的task脚本

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
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"taskname": "build",
"label": "Build",
"command": "g++-5",
"args": [
"-g",
"-Wall",
"-std=c++14",
"${file}",
"-lpthread",
"-o",
"${workspaceRoot}/bin/main"
],
"problemMatcher": {
"owner": "cpp",
"fileLocation": "absolute",
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "Run",
"type": "shell",
"dependsOn": "Build",
"command": "${workspaceRoot}/bin/main",
"args": [],
"presentation": {
"reveal": "always",
"focus": true
},
"problemMatcher": [],
"group": {
"kind": "test",
"isDefault": true
}
}
]
}
}

其中build部分可以替换为makefile. 如果是多文件编译, 可以使用make all命令, 编译单一cpp(含main)的文件, 使用make $(file)进行替换.

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# 描述: multifile 项目 makefile文件
# 版本: v2.0
# 修改记录: 1.先测试普通的cpp文件的编译运行
# 2.使用变量来改进我们的makefile文件
# 3.新加了一个源文件
# 4.使用伪目标,加上clean规则
# 5.使用wildcard函数,自动扫描当前目录下的源文件
# 6.加入了自动规则依赖
# 7.实现了opencv程序的编译
# 定义了可执行文件变量
BIN := bin
OUT := out
CFLAGS := -std=c++14


# 传递了文件参数
FILE := $(FILE)

# 定义了源文件列表变量
ifeq ($(strip $(FILE)), )
sources := $(wildcard *.cpp)
target:= all
else
sources := $(FILE)
target:=$(notdir $(basename $(sources)))
endif

executable := $(BIN)/$(target)
executable_main := $(BIN)/main

SRC := $(notdir $(sources))

# 使用变量的引用替换,定义了object文件列表
objects := $(addprefix $(OUT)/, $(SRC:.cpp=.o))

# 使用变量引用替换,定义依赖文件列表
deps := $(SRC:.cpp=.d)
# 定义编译命令变量
CC := g++-5
rm := rm -rf

#需要调用的链接库
LIBS := -lpthread

# 头文件路径
INCLUDE := -I.

# 链接库路径
LDFLAGS := -L/usr/local/lib
# 终极目标规则,生成可执行文件



$(executable) : $(objects)
-mkdir bin
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LIBS)
mv $(executable) $(executable_main)

$(objects): %.o: $(sources)
-mkdir $(OUT)
$(CC) $(CFLAGS) -o $@ -c $< $(INCLUDE)

all : $(executable)



#clean规则
.PHONY: clean
clean:
#清除编译生成的所有文件
#$(RM) $(executable) $(objects) $(deps)
#清除编译生成的所有文件,不包括可执行文件
$(RM) $(objects) $(deps) $(executable)

# 自动规则依赖
deps := $(addprefix $(OUT)/, $(SRC:.cpp=.d))
sinclude $(deps)
$(deps): %.d: $(sources)
$(CC) -MM $(CFLAGS) $< > $@
阅读全文 »

1. 编译相关

1.1. bp makefile通用规则

编译规则:

  • bp 可以引用bp定义的module
  • bp不能引用mk定义的module
  • mk可以引用mk和bp定义的module

传统的写法下, bp中不能引用外部的make定义的变量

可以借助原生文件的写法, 在soong_config.mk中引用mk文件
build/core/soong_config.mk
–include miui/build/soong/import_miui_soong_vars.mk

在mk文件中可以加bp规则的hook

1
2
3
4
ifeq (true,$(ENABLE_MIUI_DEBUGGING))
_adb_local_cflags := -UALLOW_ADBD_ROOT -DALLOW_ADBD_ROOT=1 -DALLOW_ADBD_DISABLE_VERITY -DALLOW_ADBD_NO_AUTH
$(call add_additional_soong_var, adbd_defaults, cflags, $(_adb_local_cflags))
endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cc_defaults {
name: "adbd_defaults",
defaults: ["adb_defaults"],

cflags: ["-UADB_HOST", "-DADB_HOST=0"],
...
}

cc_library {
name: "libadbd",
defaults: ["adbd_defaults", "host_adbd_supported"],
recovery_available: true,
...
}

参照上述写法, 可以在bp中引用外部的mk变量

阅读全文 »

Android AOSP gdb stl 支持

默认情况下不支持stl 输出, 需要gdb支持python脚本, 一般需要自己编译.

  1. 下载编译python3.x 源码:

    1
    2
    3
    4
    5
    6
    7
    curl -O https://www.python.org/ftp/python/3.8.1/Python-3.8.1.tar.xz
    cd Python-3.8.1
    mkdir build
    #prefix 是指定安装目录, 也可指到任一目录, 因为这里只用到编译python时生成的临时文件
    ../configure --prefix=~/Programs/python3 --enable-optimizations --enable-shared
    make
    make install
  2. 下载编译gdb源码:

    https://ftp.gnu.org/gnu/gdb/gdb-9.2.tar.xz

    这个链接有点慢, 可以直接下附件中的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    tar gdb-9.2.tar.xz
    mkdir build
    #prefix 是安装目录, with-python选项的路径填上一步编译python的build路径
    # arm64
    ../configure --target=aarch64-linux-android --prefix=/home/mi/Programs/gdb --enable-unicode=ucs4 --with-python=/home/mi/Programs/Python-3.8.1/build
    # mips
    ../configure --target=mips-mti-elf --prefix=/home/mi/program/mips-gdb --enable-unicode=ucs4 --with-python=/usr --with-auto-load-dir=$debugdir:$datadir/auto-load --with-auto-load-safe-path=$debugdir:$datadir/auto-load --with-expat --without-libunwind-ia64 --without-lzma --without-babeltrace --without-intel-pt --disable-libmcheck --without-mpfr --without-guile
    make
    make install
  3. 切换本地python版本为python3

    1
    sudo rm /usr/bin/python; sudo ln -s /usr/bin/python3 /usr/bin/python;

    这里注意的点是xiaomi的code环境是依赖python2的, repo可以切到python2上, 将repo的第一行改成#!/usr/bin/env python2 即可, 但代码编译时, 有些模块在python3下会报错, 目前发现的有依赖kernel 模块的, 使用ninja都会报错. 所以最好在编译时将python版本切换到python2.

  4. 定制gdbinit

    android上废弃了stlport和gnustl的支持, 只支持libc++的方式集成stl.

    所以python解析脚本是基于libc++开发的, 这里提供一下github上的一个脚本

    https://github.com/koutheir/libcxx-pretty-printers

    1
    git clone https://github.com/koutheir/libcxx-pretty-printers
    1
    2
    3
    4
    5
    6
    7
    python
    import sys
    #路径填刚才clone到本地的, 指定到第一级src目录
    sys.path.insert(0, '/home/mi/program/libcxx-pretty-printers/src')
    from libcxx.v1.printers import register_libcxx_printers
    register_libcxx_printers (None)
    end
  5. android编译module修改, Android.bp修改

    1
    2
    3
    4
    5
    6
    # 添加stl支持
    cflags: [
    "-O0",
    ],
    stl: "c++_static",
    stl: "c++_shared"
  6. vscode 中使用gdb

    vscode的launch.json也要配置打开 pretty-printers, 对于remote调试感兴趣的可以看另一篇文档中的介绍

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
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Remote Launch",
"type": "cppdbg",
"request": "launch",
"miDebuggerServerAddress": "127.0.0.1:8888",
"program": "/home/mi/work_space/miui-r-umi-dev/out/target/product/cmi/symbols/system/bin/test_code_aaaaaaa",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"sourceFileMap": {
"system/core/crypto_test": "/home/mi/work_space/miui-r-umi-dev/system/core/test_code"
},
"logging": {
"trace": true,
"traceResponse": true,
"engineLogging": true,
},
"MIMode": "gdb",
"miDebuggerPath": "/home/mi/Programs/gdb/bin/aarch64-linux-android-gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
],
}
]
}
阅读全文 »

vnote_backup_file_826537664 /home/mi/Documents/backup/VnoteBook/OTA相关/f2fs gc.md

1. f2fs gc

do_garbage_collect
-> gc_data_segment
-> move_data_page
-> f2fs_pin_file_control
-> stat_inc_seg_count

解密map

umi:/data/media/0/downloaded_rom # sha1sum /cache/recovery/block.map
a31f2e057e6a02fc64f55dedd3e69ed71c2c4821 /cache/recovery/block.map

初次解密后

umi:/data/media/0/downloaded_rom # sha1sum miui_UMI_9.11.18_6d674ad5a9_10.0.zip
631b3f61f9ea85911d354c277c98f9fcdb56b0bc miui_UMI_9.11.18_6d674ad5a9_10.0.zip

recovery会更改?
-rw-rw-r– 1 media_rw media_rw 2594048280 2019-11-18 10:14 miui_UMI_9.11.18_6d674ad5a9_10.0.zip
sha1sum miui_UMI_9.11.18_6d674ad5a9_10.0.zip
parse_ld_lib_path (null)
6fcdd51f751fe1a19af20c70302575b3fdb70086 miui_UMI_9.11.18_6d674ad5a9_10.0.zip

原始

[$] -> sha1sum ~/Downloads/miui_UMI_9.11.18_6d674ad5a9_10.0.zip
88abea31fe641216b7a2659a6e63f5c4d619efaa /home/mi/Downloads/miui_UMI_9.11.18_6d674ad5a9_10.0.zip

阅读全文 »

[TOC]

1. fbe与用户安全密码

之前介绍了fde与用户安全密码的关系,发现其是相对简单的。而对fbe和metadata加密的方式,在调研过程中发现密码的存储与文件ce区的密钥的关系则复杂的多。

1.1. 用户ce区文件解密

这个过程伴随着一个函数向下执行的,即unlockUserKey函数,首先看下伴随这个过程的密钥来自哪里

1
2
3
4
5
6
unlockUserKey(userId, null, auth.deriveDiskEncryptionKey());
/** Unlock disk encryption */
1712 private void unlockUserKey(int userId, byte[] token, byte[] secret) throws RemoteException {
1713 final UserInfo userInfo = mUserManager.getUserInfo(userId);
1714 mStorageManager.unlockUserKey(userId, userInfo.serialNumber, token, secret);
1715 }

以机主用户为例, 上述参数中userID为0, token 为空, serialNumber为0,未知的只有secret,来自deriveDiskEncryptionKey

1
2
3
4
5
6
7
8
9
10
11
12
13
      public byte[] deriveDiskEncryptionKey() {
179 return derivePassword(PERSONALIZATION_FBE_KEY);
180 }

160 private byte[] derivePassword(byte[] personalization) {
161 if (mVersion == SYNTHETIC_PASSWORD_VERSION_V3) {
162 return (new SP800Derive(syntheticPassword.getBytes()))
163 .withContext(personalization, PERSONALISATION_CONTEXT);
164 } else {
165 return SyntheticPasswordCrypto.personalisedHash(personalization,
166 syntheticPassword.getBytes());
167 }
168 }

关键参数只有一个syntheticPassword

1
2
3
4
5
        private void initialize(byte[] P0, byte[] P1) {
191 this.P1 = P1;
192 this.syntheticPassword = String.valueOf(HexEncoding.encode(
193 SyntheticPasswordCrypto.personalisedHash(
194 PERSONALIZATION_SP_SPLIT, P0, P1)));
阅读全文 »