├── .gitignore ├── README.md ├── avbtool ├── boot_image_tool ├── README.en.md ├── README.md ├── bin │ ├── BootSignature.jar │ └── mkbootfs ├── bootimgtool.sh └── mkbootfs │ ├── .gitignore │ ├── Makefile │ ├── NOTICE │ ├── mkbootfs.c │ └── private │ ├── android_filesystem_capability.h │ └── android_filesystem_config.h ├── emui_extractor ├── Makefile ├── emui_extractor.cc ├── image.cc └── image.h ├── mnt-droid ├── ota_converter ├── .gitignore ├── Makefile ├── README ├── include │ └── brotli │ │ ├── decode.h │ │ ├── encode.h │ │ ├── port.h │ │ └── types.h ├── lib │ ├── libbrotlicommon-static.a │ └── libbrotlidec-static.a ├── ota_converter.cc └── ota_converter.py ├── ozip_cracker ├── README.md └── ozip_cracker.py └── print_qcom_image_info ├── .gitignore ├── Makefile ├── README ├── include └── sys │ ├── elf32.h │ ├── elf64.h │ └── elf_common.h ├── qcert.cc └── scoped_fd.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Android Image Tools 2 | =================== 3 | 4 | 一些平时自己开发使用的,操作Android分区镜像的小工具。运行环境为Ubuntu 14.04及以后版本。 5 | 6 | 1. `boot_image_tool` 7 | 8 | 用于解压,重打包boot.img,也可以打印boot.img的header和签名信息。适用于AVB1.0。 9 | 10 | 更多内容请看[`boot_imge_tool`](./boot_image_tool/README.md)。 11 | 12 | 2. mnt-droid 13 | 14 | 转换并挂载ext4 稀疏文件系统镜像。一些手机厂商提供ROM的线刷包(工厂包)供用户下载,如Google的Pixel 15 | 等。其中包含system.img, vendor.img等分区的稀疏文件系统镜像。如果想要直接查看文件系统中的内容,则 16 | 需要挂载到本地。此工具用于挂载这些文件系统镜像。需要先安装simg2img工具: 17 | 18 | `sudo apt-get install simg2img` 19 | 20 | 用法: 21 | 22 | ``` 23 | # 挂载system.img到本地system目录 24 | mnt-droid system 25 | 26 | # 挂载vendor.img到本地vendor目录 27 | mnt-droid vendor 28 | ``` 29 | 30 | 3. `ota_converter` 31 | 32 | 将卡刷包中的system,vendor等分区数据,转换成文件系统镜像。一些手机厂商不提供ROM的线刷包(工厂包), 33 | 而只提供卡刷包。卡刷包中包含system等分区的完整数据,但是并非文件系统镜像格式,不能直接挂载,需要先 34 | 转换成文件系统镜像。此工具用于将卡刷包中的文件系统数据转换成文件系统镜像格式(**非稀疏文件系统镜像, 35 | 无需进一步转换即可直接挂载**)。 36 | 37 | 更多内容请看[`ota_converter`](./ota_converter/README)。 38 | 39 | 编译: 40 | 41 | `make` 42 | 43 | 用法: 44 | 45 | ``` 46 | # 转换system.ext4.img 47 | ./ota_converter system.transfer.list system.new.dat.br system.ext4.img 48 | ``` 49 | 50 | 4. avbtool 51 | 52 | 基于Android原生系统代码中的avbtool,加入一个打印vbmeta中公钥的功能。 53 | 54 | 用法: 55 | 56 | `avbtool dump_public_key --image vbmeta.img` 57 | 58 | 5. `print_qcom_image_info` 59 | 60 | 打印高通平台特定image的签名相关信息,如打印bootloader abl的签名信息。 61 | 62 | 编译: 63 | 64 | `make` 65 | 66 | 用法: 67 | 68 | ``` 69 | # 打印abl信息 70 | ./qcert abl.elf 71 | ``` 72 | 73 | 6. `emui_extractor` 74 | 75 | 查看、解压华为ROM包中的UPDATE.APP。 76 | 77 | 与Android原生img文件相比,有些分区解压出来的img文件,在文件头部会带有4096字节的额外信息,使用Android相关工具处理时如果无法识别,可以去除这部分信息然后再试。 78 | 79 | UPDATE.APP中带有crc校验信息,本工具忽略了相关校验。 80 | 81 | Windows系统有类似工具: [来源未知,慎用](https://pan.baidu.com/s/1O9M4VWfG6vGFEOkLVs-zuA) (提取码:8ghk)。 82 | 83 | 84 | ``` 85 | # build 86 | make 87 | 88 | # 查看所有image信息 89 | $ ./emui_extractor UPDATE.APP list 90 | ========================================================================= 91 | Sequence File.img Size Type Device 92 | ========================================================================= 93 | fe000000 SHA256RSA.img 256.00 B SHA256RSA HW7x27 94 | fe000000 CRC.img 301.01 KB CRC HW7x27 95 | fffffff0 CURVER.img 23.00 B CURVER HW7x27 96 | fffffff1 VERLIST.img 78.00 B VERLIST HW7x27 97 | 00000014 VBMETA.img 9.94 KB VBMETA HW7x27 98 | ... 99 | ========================================================================= 100 | 101 | # 解压并查看vbmeta.img 102 | $ ./emui_extractor UPDATE.APP dump VBMETA.img vbmeta_orig.img 103 | $ dd if=vbmeta_orig.img of=vbmeta.img bs=4096 skip=1 104 | $ avbtool info_image --image vbmeta.img 105 | 106 | # 解压所有文件 107 | $ ./emui_extractor UPDATE.APP dump all 108 | ``` 109 | 110 | 7. `ozip_cracker` 111 | 112 | Find Oppo's ozip decryption key. See [ozip cracker](./ozip_cracker/README.md) 113 | for details. 114 | -------------------------------------------------------------------------------- /boot_image_tool/README.en.md: -------------------------------------------------------------------------------- 1 | # bootimgtool.sh 2 | 3 | Pack, unpack or print information of boot.img. AVB1.0 is supported. 4 | 5 | Usage: 6 | 7 | ``` 8 | bootimgtool.sh boot.img cmd args 9 | printinfo : print header information 10 | printcert [-p] : print certificate in text format. Or in PEM format if -p option specific 11 | unpack dir : unpack into kernel, ramdisk fs, etc., into 12 | build dir [key_path]: build from . Sign using key_path.{pk8,x509.pem} 13 | if has parameter 14 | ``` 15 | -------------------------------------------------------------------------------- /boot_image_tool/README.md: -------------------------------------------------------------------------------- 1 | # bootimagetool.sh 2 | 3 | 解压/打包boot.img,或者打印boot.img header和签名信息。适用于AVB1.0系统(大部分小于等于android 8.0的系统) 4 | 5 | 用法: 6 | 7 | ``` 8 | bootimgtool.sh boot.img cmd args 9 | printinfo : 打印header信息(kernel加载地址,命令行参数等) 10 | printcert [-p] : 打印签名证书信息。默认打印text格式,如果指定`-p`参数,则打印pem格式。 11 | unpack dir : 解压boot.img 到指定目录 12 | build dir [your_key_path.pk8 you_key_path.x509.pem]: 重打包boot.img。如果制定了秘钥,则使用秘钥签名生成的boot.img。 13 | ``` 14 | -------------------------------------------------------------------------------- /boot_image_tool/bin/BootSignature.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntiger1024/android_image_tools/143bb84c52bb767269ca4887478746c9db98a6a3/boot_image_tool/bin/BootSignature.jar -------------------------------------------------------------------------------- /boot_image_tool/bin/mkbootfs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntiger1024/android_image_tools/143bb84c52bb767269ca4887478746c9db98a6a3/boot_image_tool/bin/mkbootfs -------------------------------------------------------------------------------- /boot_image_tool/bootimgtool.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 4 | # bootimgtool.sh - tools to manipulate boot.img 5 | ## 6 | 7 | #DEBUG="true" 8 | 9 | set -e 10 | 11 | usage() 12 | { 13 | echo "bootimgtool.sh boot.img cmd args" 14 | echo " printinfo : print header information" 15 | echo " printcert [-p] : print certificate in text format or PEM format" 16 | echo " unpack dir : unpack boot.img into kernel, ramdisk fs, etc. into dir" 17 | echo " build dir [key_path]: build boot.img from dir and sign using key_path.{pk8,x509.pem}" 18 | } 19 | 20 | # copy_from_file infile outfile offset size align 21 | copy_from_file() 22 | { 23 | infile=$1 24 | outfile=$2 25 | offset=$3 26 | size=$4 27 | align=$5 28 | 29 | count=$(( size / align )) 30 | remind=$(( size % align )) 31 | skip=$(( offset / align )) 32 | dd if=$infile of=$outfile bs=$align count=$count skip=$skip >/dev/null 2>&1 33 | skip=$(( offset + size - remind )) 34 | seek=$(( align * count )) 35 | dd if=$infile of=$outfile bs=1 count=$remind skip=$skip seek=$seek >/dev/null 2>&1 36 | } 37 | 38 | # append_file_and_update_header src dst padding update_off 39 | append_file_and_update_header() 40 | { 41 | local src=$1 42 | local dst=$2 43 | local padding=$3 44 | local update_off=$4 45 | 46 | if [ -f $src ]; then 47 | local size=`ls -l $src | cut -f 5 -d " "` 48 | # append file 49 | dd if=$src of=$dst conv=notrunc oflag=append 2>/dev/null 50 | dd if=/dev/zero of=$dst conv=notrunc oflag=append bs=1\ 51 | count=$(( (padding - size % padding) % padding )) 2>/dev/null 52 | 53 | # update header 54 | printf "%02x" $(( size & 255 )) | xxd -r -ps | dd of=$dst bs=1\ 55 | seek=$update_off conv=notrunc 2>/dev/null 56 | printf "%02x" $(( (size>>8) & 255 )) | xxd -r -ps | dd of=$dst bs=1\ 57 | count=1 seek=$(( update_off+1 )) conv=notrunc 2>/dev/null 58 | printf "%02x" $(( (size>>16) & 255 )) | xxd -r -ps | dd of=$dst bs=1\ 59 | count=1 seek=$(( update_off+2 )) conv=notrunc 2>/dev/null 60 | printf "%02x" $(( (size>>24) & 255 )) | xxd -r -ps | dd of=$dst bs=1\ 61 | count=1 seek=$(( update_off+3 )) conv=notrunc 2>/dev/null 62 | fi 63 | } 64 | 65 | # get_info boot.img/header 66 | get_info() 67 | { 68 | ks_off=8 # kernel_size offset 69 | rs_off=16 # ramdisk_size offset 70 | ss_off=24 # second size offset 71 | dt_off=40 # dt size offset 72 | id_off=$(( 48 + 16 + 512 )) 73 | 74 | local header=$1 75 | 76 | kernel_size=`hexdump -s $ks_off -n 4 -e '/4 "%u"' $header` 77 | kernel_addr=`hexdump -s 12 -n 4 -e '/4 "%u"' $header` 78 | 79 | ramdisk_size=`hexdump -s $rs_off -n 4 -e '/4 "%u"' $header` 80 | ramdisk_addr=`hexdump -s 20 -n 4 -e '/4 "%u"' $header` 81 | 82 | second_size=`hexdump -s $ss_off -n 4 -e '/4 "%u"' $header` 83 | second_addr=`hexdump -s 28 -n 4 -e '/4 "%u"' $header` 84 | 85 | tags_addr=`hexdump -s 32 -n 4 -e '/4 "%u"' $header` 86 | page_size=`hexdump -s 36 -n 4 -e '/4 "%u"' $header` 87 | 88 | dt_size=`hexdump -s $dt_off -n 4 -e '/4 "%u"' $header` 89 | 90 | padded_kernel_size=$(( (kernel_size+page_size-1)/page_size*page_size )) 91 | padded_ramdisk_size=$(( (ramdisk_size+page_size-1)/page_size*page_size )) 92 | padded_second_size=$(( (second_size+page_size-1)/page_size*page_size )) 93 | padded_dt_size=$(( (dt_size+page_size-1)/page_size*page_size )) 94 | 95 | os_version=`hexdump -s 44 -n 4 -e '/4 "%u"' $header` 96 | name=`hexdump -s 48 -n 16 -e '/16 "%s"' $header` 97 | cmdline=`hexdump -s $(( 48 + 16 )) -n 512 -e '/512 "%s"' $header` 98 | extra_cmdline=`hexdump -s $(( 48 + 16 + 512 + 32)) -n 1024 -e '/1024 "%s"' $header` 99 | 100 | total_size=$(( padded_kernel_size+padded_ramdisk_size+padded_second_size\ 101 | +padded_dt_size+page_size )) 102 | } 103 | 104 | print_info_internal() 105 | { 106 | printf "%-20s: 0x%x\n" "kernel_size" $kernel_size 107 | printf "%-20s: 0x%x\n" "padded_kernel_size" $padded_kernel_size 108 | printf "%-20s: 0x%x\n" "kernel_addr" $kernel_addr 109 | printf "%-20s: 0x%x\n" "ramdisk_size" $ramdisk_size 110 | printf "%-20s: 0x%x\n" "padded_ramdisk_size" $padded_ramdisk_size 111 | printf "%-20s: 0x%x\n" "ramdisk_addr" $ramdisk_addr 112 | printf "%-20s: 0x%x\n" "second_size" $second_size 113 | printf "%-20s: 0x%x\n" "second_addr" $second_addr 114 | printf "%-20s: 0x%x\n" "tags_addr" $tags_addr 115 | printf "%-20s: 0x%x\n" "page_size" $page_size 116 | printf "%-20s: 0x%x\n" "dt_size" $dt_size 117 | printf "%-20s: 0x%x\n" "padded_dt_size" $padded_dt_size 118 | printf "%-20s: 0x%x\n" "total_size" $total_size 119 | if [ $os_version -ne 0 ]; then 120 | local A=$(( (os_version >> 25) & 0x7f )) 121 | local B=$(( (os_version >> 18) & 0x7f )) 122 | local C=$(( (os_version >> 11) & 0x7f )) 123 | local Y=$(( ((os_version >> 4) & 0x7f) + 2000 )) 124 | local M=$(( os_version & 0xf )) 125 | printf "%-20s: %s\n" "version" "$A.$B.$C" 126 | printf "%-20s: %s\n" "patch_level" "$Y-$M" 127 | fi 128 | printf "%-20s: %s\n" "name" ${name:-"(null)"} 129 | echo "cmdline : "${cmdline:-"(null)"} 130 | echo "extra_cmdline : "${extra_cmdline:-"(null)"} 131 | } 132 | 133 | print_info() 134 | { 135 | if [ $# -ne 0 ];then 136 | usage && exit 1 137 | fi 138 | 139 | get_info $bootimg 140 | print_info_internal 141 | } 142 | 143 | 144 | print_cert() 145 | { 146 | while getopts "p" opt; do 147 | case $opt in 148 | p) 149 | pem="true";; 150 | *) 151 | usage 152 | exit 1 153 | esac 154 | done 155 | 156 | shift $(( OPTIND - 1 )) 157 | if [ -$# -lt 0 ]; then 158 | usage 159 | exit 1 160 | fi 161 | 162 | get_info $bootimg 163 | 164 | info_line=`openssl asn1parse -inform DER -in $bootimg -offset $total_size | grep "7:d=1"` 165 | cert_len=${info_line##*l=} 166 | cert_len=${cert_len%%cons:*} 167 | cert_len=`echo $cert_len | tr -d " "` 168 | if [ -n "$pem" ]; then 169 | dd if=$bootimg bs=1 skip=$(( total_size+7 )) count=$(( cert_len+4 )) 2>/dev/null |\ 170 | openssl x509 -inform DER 171 | else 172 | dd if=$bootimg bs=1 skip=$(( total_size+7 )) count=$(( cert_len+4 )) 2>/dev/null |\ 173 | openssl x509 -inform DER -noout -text 174 | fi 175 | } 176 | 177 | # unpack dir 178 | unpack() 179 | { 180 | # check argument 181 | if [ $# -ne 1 ]; then 182 | usage 183 | exit 1 184 | fi 185 | 186 | get_info $bootimg 187 | 188 | # mkdir 189 | dir=$1 190 | if [ ! -d $dir ]; then 191 | if ! mkdir $dir; then 192 | echo "Failed to make dir: $dir" && exit 1 193 | fi 194 | else 195 | echo "$dir alreday exists. Remove it first!" && exit 1 196 | fi 197 | 198 | # unpack 199 | dd if=$bootimg of=$dir/header bs=$page_size count=1 >/dev/null 2>&1 200 | test $kernel_size -ne 0 && copy_from_file $bootimg $dir/kernel $page_size $kernel_size\ 201 | $page_size 202 | test $ramdisk_size -ne 0 && copy_from_file $bootimg $dir/ramdisk\ 203 | $(( page_size + padded_kernel_size )) $ramdisk_size $page_size 204 | test $second_size -ne 0 && copy_from_file $bootimg $dir/second\ 205 | $(( page_size + padded_kernel_size + padded_ramdisk_size )) $second_size $page_size 206 | mkdir $dir/root 207 | cd $dir/root 208 | gunzip -c ../ramdisk | cpio -i >/dev/null 2>&1 209 | cd - >/dev/null 2>&1 210 | } 211 | 212 | # build dir 213 | build() 214 | { 215 | # check argument 216 | if [ $# -gt 2 ]; then 217 | usage 218 | exit 1 219 | fi 220 | 221 | local dir=$1 222 | local key_path=$2 223 | 224 | # check dir 225 | if [ ! -d $dir ]; then 226 | echo "$dir not exists." && exit 1 227 | fi 228 | if [ ! -f $dir/header ]; then 229 | echo "$dir/header not exists." && exit 1 230 | fi 231 | if [ -n "${key_path}" ]; then 232 | if [ ! -f ${key_path}.pk8 -o ! -f ${key_path}.x509.pem ]; then 233 | echo "${key_path}.{pk8,x509} not found." && exit 1 234 | fi 235 | fi 236 | 237 | # build 238 | # cd $dir/root || ( echo "No root dir" && exit 1 ) 239 | # find . | cpio -o -H newc 2>/dev/null | gzip > ../new_ramdisk 240 | # cd - >/dev/null 2>&1 241 | $tool_home/bin/mkbootfs $dir/root > $dir/new_ramdisk 242 | 243 | local kernel="" 244 | local ramdisk="" 245 | local second="" 246 | 247 | get_info $dir/header 248 | dd if=$dir/header of=${bootimg}_unsigned 2>/dev/null 249 | if [ -f $dir/kernel ];then 250 | kernel=$dir/kernel 251 | append_file_and_update_header $kernel ${bootimg}_unsigned $page_size $ks_off 252 | fi 253 | if [ -f $dir/new_ramdisk ];then 254 | ramdisk=$dir/new_ramdisk 255 | append_file_and_update_header $ramdisk ${bootimg}_unsigned $page_size $rs_off 256 | fi 257 | if [ -f $dir/second ];then 258 | second=$dir/second 259 | append_file_and_update_header $second ${bootimg}_unsigned $page_size $ss_off 260 | fi 261 | 262 | cat $kernel $ramdisk $second | openssl sha1 -binary | dd of=${bootimg}_unsigned bs=1\ 263 | count=20 seek=$id_off conv=notrunc 2>/dev/null 264 | if [ -z "$key_path" ]; then 265 | cp ${bootimg}_unsigned ${bootimg} 266 | else 267 | java -jar $tool_home/bin/BootSignature.jar /boot ${bootimg}_unsigned\ 268 | ${key_path}.pk8 ${key_path}.x509.pem $bootimg 269 | fi 270 | } 271 | 272 | ############ main ############# 273 | 274 | if [ $# -lt 2 ]; then 275 | usage 276 | exit 1 277 | fi 278 | 279 | tool_home=`dirname $0` 280 | bootimg=$1 281 | cmd=$2 282 | shift 2 283 | 284 | 285 | case $cmd in 286 | "printinfo") 287 | print_info $@;; 288 | "printcert") 289 | print_cert $@;; 290 | "unpack") 291 | unpack $@;; 292 | "build") 293 | build $@;; 294 | *) 295 | usage 296 | exit 1 297 | esac 298 | -------------------------------------------------------------------------------- /boot_image_tool/mkbootfs/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | mkbootfs.exe 3 | mkbootfs 4 | -------------------------------------------------------------------------------- /boot_image_tool/mkbootfs/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = gcc 3 | 4 | ifeq ($(windir),) 5 | EXE = 6 | RM = rm -f 7 | else 8 | EXE = .exe 9 | RM = del 10 | endif 11 | 12 | CFLAGS = -ffunction-sections -O3 13 | LDFLAGS = -Wl,--gc-sections 14 | OBJECTS = mkbootfs.o 15 | 16 | all:mkbootfs$(EXE) 17 | 18 | static:mkbootfs-static$(EXE) 19 | 20 | mkbootfs$(EXE):$(OBJECTS) 21 | $(CROSS_COMPILE)$(CC) -o $@ $^ -L. $(LDFLAGS) -s 22 | 23 | mkbootfs-static$(EXE):$(OBJECTS) 24 | $(CROSS_COMPILE)$(CC) -o $@ $^ -L. $(LDFLAGS) -static -s 25 | 26 | .c.o: 27 | $(CROSS_COMPILE)$(CC) -o $@ $(CFLAGS) -c $< -I. -Werror 28 | 29 | clean: 30 | $(RM) mkbootfs mkbootfs-static mkbootfs.exe mkbootfs-static.exe $(OBJECTS) Makefile.~ 31 | 32 | -------------------------------------------------------------------------------- /boot_image_tool/mkbootfs/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2008, The Android Open Source Project 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | * Redistributions of source code must retain the above copyright 6 | notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright 8 | notice, this list of conditions and the following disclaimer in the 9 | documentation and/or other materials provided with the distribution. 10 | * Neither the name of Google Inc. nor the names of its contributors may 11 | be used to endorse or promote products derived from this software 12 | without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 15 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 | EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /boot_image_tool/mkbootfs/mkbootfs.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | /* NOTES 18 | ** 19 | ** - see buffer-format.txt from the linux kernel docs for 20 | ** an explanation of this file format 21 | ** - directories named 'root' are ignored 22 | ** - device notes, pipes, etc are not supported (error) 23 | */ 24 | 25 | void die(const char *why, ...) 26 | { 27 | va_list ap; 28 | 29 | va_start(ap, why); 30 | fprintf(stderr,"error: "); 31 | vfprintf(stderr, why, ap); 32 | fprintf(stderr,"\n"); 33 | va_end(ap); 34 | exit(1); 35 | } 36 | 37 | struct fs_config_entry { 38 | char* name; 39 | int uid, gid, mode; 40 | }; 41 | 42 | static struct fs_config_entry* canned_config = NULL; 43 | static char *target_out_path = NULL; 44 | 45 | /* Each line in the canned file should be a path plus three ints (uid, 46 | * gid, mode). */ 47 | #ifdef PATH_MAX 48 | #define CANNED_LINE_LENGTH (PATH_MAX+100) 49 | #else 50 | #define CANNED_LINE_LENGTH (1024) 51 | #endif 52 | 53 | #define TRAILER "TRAILER!!!" 54 | 55 | static int verbose = 0; 56 | static int total_size = 0; 57 | 58 | static void fix_stat(const char *path, struct stat *s) 59 | { 60 | uint64_t capabilities; 61 | if (canned_config) { 62 | // Use the list of file uid/gid/modes loaded from the file 63 | // given with -f. 64 | 65 | struct fs_config_entry* empty_path_config = NULL; 66 | struct fs_config_entry* p; 67 | for (p = canned_config; p->name; ++p) { 68 | if (!p->name[0]) { 69 | empty_path_config = p; 70 | } 71 | if (strcmp(p->name, path) == 0) { 72 | s->st_uid = p->uid; 73 | s->st_gid = p->gid; 74 | s->st_mode = p->mode | (s->st_mode & ~07777); 75 | return; 76 | } 77 | } 78 | s->st_uid = empty_path_config->uid; 79 | s->st_gid = empty_path_config->gid; 80 | s->st_mode = empty_path_config->mode | (s->st_mode & ~07777); 81 | } else { 82 | // Use the compiled-in fs_config() function. 83 | unsigned st_mode = s->st_mode; 84 | int is_dir = S_ISDIR(s->st_mode) || strcmp(path, TRAILER) == 0; 85 | fs_config(path, is_dir, target_out_path, &s->st_uid, &s->st_gid, &st_mode, &capabilities); 86 | s->st_mode = (typeof(s->st_mode)) st_mode; 87 | } 88 | } 89 | 90 | static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize) 91 | { 92 | // Nothing is special about this value, just picked something in the 93 | // approximate range that was being used already, and avoiding small 94 | // values which may be special. 95 | static unsigned next_inode = 300000; 96 | 97 | while(total_size & 3) { 98 | total_size++; 99 | putchar(0); 100 | } 101 | 102 | fix_stat(out, s); 103 | if(verbose) { 104 | fprintf(stderr, "_eject %s: uid=%d gid=%d mode=0%o\n", out, s->st_uid, s->st_gid, s->st_mode); 105 | } 106 | 107 | printf("%06x%08x%08x%08x%08x%08x%08x" 108 | "%08x%08x%08x%08x%08x%08x%08x%s%c", 109 | 0x070701, 110 | next_inode++, // s.st_ino, 111 | s->st_mode, 112 | s->st_uid, 113 | s->st_gid, 114 | 1, // s.st_nlink, 115 | 0, // s.st_mtime, 116 | datasize, 117 | 0, // volmajor 118 | 0, // volminor 119 | 0, // devmajor 120 | 0, // devminor, 121 | olen + 1, 122 | 0, 123 | out, 124 | 0 125 | ); 126 | 127 | total_size += 6 + 8*13 + olen + 1; 128 | 129 | if(strlen(out) != (unsigned int)olen) die("ACK!"); 130 | 131 | while(total_size & 3) { 132 | total_size++; 133 | putchar(0); 134 | } 135 | 136 | if(datasize) { 137 | fwrite(data, datasize, 1, stdout); 138 | total_size += datasize; 139 | } 140 | } 141 | 142 | static void _eject_trailer() 143 | { 144 | struct stat s; 145 | memset(&s, 0, sizeof(s)); 146 | _eject(&s, TRAILER, 10, 0, 0); 147 | 148 | while(total_size & 0xff) { 149 | total_size++; 150 | putchar(0); 151 | } 152 | } 153 | 154 | static void _archive(char *in, char *out, int ilen, int olen); 155 | 156 | static int compare(const void* a, const void* b) { 157 | return strcmp(*(const char**)a, *(const char**)b); 158 | } 159 | 160 | static void _archive_dir(char *in, char *out, int ilen, int olen) 161 | { 162 | int i, t; 163 | DIR *d; 164 | struct dirent *de; 165 | 166 | if(verbose) { 167 | fprintf(stderr,"_archive_dir('%s','%s',%d,%d)\n", 168 | in, out, ilen, olen); 169 | } 170 | 171 | d = opendir(in); 172 | if(d == 0) die("cannot open directory '%s'", in); 173 | 174 | int size = 32; 175 | int entries = 0; 176 | char** names = malloc(size * sizeof(char*)); 177 | if (names == NULL) { 178 | fprintf(stderr, "failed to allocate dir names array (size %d)\n", size); 179 | exit(1); 180 | } 181 | 182 | while((de = readdir(d)) != 0){ 183 | /* xxx: hack. use a real exclude list */ 184 | if(!strcmp(de->d_name, ".")) continue; 185 | if(!strcmp(de->d_name, "..")) continue; 186 | if(!strcmp(de->d_name, "root")) continue; 187 | 188 | if (entries >= size) { 189 | size *= 2; 190 | names = realloc(names, size * sizeof(char*)); 191 | if (names == NULL) { 192 | fprintf(stderr, "failed to reallocate dir names array (size %d)\n", 193 | size); 194 | exit(1); 195 | } 196 | } 197 | names[entries] = strdup(de->d_name); 198 | if (names[entries] == NULL) { 199 | fprintf(stderr, "failed to strdup name \"%s\"\n", 200 | de->d_name); 201 | exit(1); 202 | } 203 | ++entries; 204 | } 205 | 206 | qsort(names, entries, sizeof(char*), compare); 207 | 208 | for (i = 0; i < entries; ++i) { 209 | t = strlen(names[i]); 210 | in[ilen] = '/'; 211 | memcpy(in + ilen + 1, names[i], t + 1); 212 | 213 | if(olen > 0) { 214 | out[olen] = '/'; 215 | memcpy(out + olen + 1, names[i], t + 1); 216 | _archive(in, out, ilen + t + 1, olen + t + 1); 217 | } else { 218 | memcpy(out, names[i], t + 1); 219 | _archive(in, out, ilen + t + 1, t); 220 | } 221 | 222 | in[ilen] = 0; 223 | out[olen] = 0; 224 | 225 | free(names[i]); 226 | } 227 | free(names); 228 | 229 | closedir(d); 230 | } 231 | 232 | static void _archive(char *in, char *out, int ilen, int olen) 233 | { 234 | struct stat s; 235 | 236 | if(verbose) { 237 | fprintf(stderr,"_archive('%s','%s',%d,%d)\n", 238 | in, out, ilen, olen); 239 | } 240 | 241 | if(lstat(in, &s)) die("could not stat '%s'\n", in); 242 | 243 | if(S_ISREG(s.st_mode)){ 244 | char *tmp; 245 | int fd; 246 | 247 | fd = open(in, O_RDONLY); 248 | if(fd < 0) die("cannot open '%s' for read", in); 249 | 250 | tmp = (char*) malloc(s.st_size); 251 | if(tmp == 0) die("cannot allocate %d bytes", s.st_size); 252 | 253 | if(read(fd, tmp, s.st_size) != s.st_size) { 254 | die("cannot read %d bytes", s.st_size); 255 | } 256 | 257 | _eject(&s, out, olen, tmp, s.st_size); 258 | 259 | free(tmp); 260 | close(fd); 261 | } else if(S_ISDIR(s.st_mode)) { 262 | _eject(&s, out, olen, 0, 0); 263 | _archive_dir(in, out, ilen, olen); 264 | } else if(S_ISLNK(s.st_mode)) { 265 | char buf[1024]; 266 | int size; 267 | size = readlink(in, buf, 1024); 268 | if(size < 0) die("cannot read symlink '%s'", in); 269 | _eject(&s, out, olen, buf, size); 270 | } else { 271 | die("Unknown '%s' (mode %d)?\n", in, s.st_mode); 272 | } 273 | } 274 | 275 | void archive(const char *start, const char *prefix) 276 | { 277 | char in[8192]; 278 | char out[8192]; 279 | 280 | strcpy(in, start); 281 | strcpy(out, prefix); 282 | 283 | _archive_dir(in, out, strlen(in), strlen(out)); 284 | } 285 | 286 | static void read_canned_config(char* filename) 287 | { 288 | int allocated = 8; 289 | int used = 0; 290 | 291 | canned_config = 292 | (struct fs_config_entry*)malloc(allocated * sizeof(struct fs_config_entry)); 293 | 294 | char line[CANNED_LINE_LENGTH]; 295 | FILE* f = fopen(filename, "r"); 296 | if (f == NULL) die("failed to open canned file"); 297 | 298 | while (fgets(line, CANNED_LINE_LENGTH, f) != NULL) { 299 | if (!line[0]) break; 300 | if (used >= allocated) { 301 | allocated *= 2; 302 | canned_config = (struct fs_config_entry*)realloc( 303 | canned_config, allocated * sizeof(struct fs_config_entry)); 304 | if (canned_config == NULL) die("failed to reallocate memory"); 305 | } 306 | 307 | struct fs_config_entry* cc = canned_config + used; 308 | 309 | if (isspace(line[0])) { 310 | cc->name = strdup(""); 311 | cc->uid = atoi(strtok(line, " \n")); 312 | } else { 313 | cc->name = strdup(strtok(line, " \n")); 314 | cc->uid = atoi(strtok(NULL, " \n")); 315 | } 316 | cc->gid = atoi(strtok(NULL, " \n")); 317 | cc->mode = strtol(strtok(NULL, " \n"), NULL, 8); 318 | ++used; 319 | } 320 | if (used >= allocated) { 321 | ++allocated; 322 | canned_config = (struct fs_config_entry*)realloc( 323 | canned_config, allocated * sizeof(struct fs_config_entry)); 324 | if (canned_config == NULL) die("failed to reallocate memory"); 325 | } 326 | canned_config[used].name = NULL; 327 | 328 | fclose(f); 329 | } 330 | 331 | 332 | int main(int argc, char *argv[]) 333 | { 334 | argc--; 335 | argv++; 336 | 337 | if (argc > 1 && strcmp(argv[0], "-d") == 0) { 338 | target_out_path = argv[1]; 339 | argc -= 2; 340 | argv += 2; 341 | } 342 | 343 | if (argc > 1 && strcmp(argv[0], "-f") == 0) { 344 | read_canned_config(argv[1]); 345 | argc -= 2; 346 | argv += 2; 347 | } 348 | 349 | if (argc > 1 && strcmp(argv[0], "-v") == 0) { 350 | verbose = 1; 351 | argc -= 1; 352 | argv += 1; 353 | } 354 | 355 | if(argc == 0) die("no directories to process?!"); 356 | 357 | while(argc-- > 0){ 358 | char *x = strchr(*argv, '='); 359 | if(x != 0) { 360 | *x++ = 0; 361 | } else { 362 | x = ""; 363 | } 364 | 365 | archive(*argv, x); 366 | 367 | argv++; 368 | } 369 | 370 | _eject_trailer(); 371 | 372 | return 0; 373 | } 374 | -------------------------------------------------------------------------------- /boot_image_tool/mkbootfs/private/android_filesystem_capability.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* 18 | * Taken from linux/capability.h, with minor modifications 19 | */ 20 | 21 | #ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H 22 | #define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H 23 | 24 | #include 25 | 26 | #define __user 27 | #define __u32 uint32_t 28 | #define __le32 uint32_t 29 | 30 | #define _LINUX_CAPABILITY_VERSION_1 0x19980330 31 | #define _LINUX_CAPABILITY_U32S_1 1 32 | #define _LINUX_CAPABILITY_VERSION_2 0x20071026 33 | #define _LINUX_CAPABILITY_U32S_2 2 34 | #define _LINUX_CAPABILITY_VERSION_3 0x20080522 35 | #define _LINUX_CAPABILITY_U32S_3 2 36 | 37 | typedef struct __user_cap_header_struct { 38 | __u32 version; 39 | int pid; 40 | } __user *cap_user_header_t; 41 | 42 | typedef struct __user_cap_data_struct { 43 | __u32 effective; 44 | __u32 permitted; 45 | __u32 inheritable; 46 | } __user *cap_user_data_t; 47 | 48 | #define VFS_CAP_REVISION_MASK 0xFF000000 49 | #define VFS_CAP_REVISION_SHIFT 24 50 | #define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK 51 | #define VFS_CAP_FLAGS_EFFECTIVE 0x000001 52 | #define VFS_CAP_REVISION_1 0x01000000 53 | #define VFS_CAP_U32_1 1 54 | #define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1)) 55 | #define VFS_CAP_REVISION_2 0x02000000 56 | #define VFS_CAP_U32_2 2 57 | #define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2)) 58 | #define XATTR_CAPS_SZ XATTR_CAPS_SZ_2 59 | #define VFS_CAP_U32 VFS_CAP_U32_2 60 | #define VFS_CAP_REVISION VFS_CAP_REVISION_2 61 | 62 | struct vfs_cap_data { 63 | __le32 magic_etc; 64 | struct { 65 | __le32 permitted; 66 | __le32 inheritable; 67 | } data[VFS_CAP_U32]; 68 | }; 69 | 70 | #define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1 71 | #define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1 72 | #define CAP_CHOWN 0 73 | #define CAP_DAC_OVERRIDE 1 74 | #define CAP_DAC_READ_SEARCH 2 75 | #define CAP_FOWNER 3 76 | #define CAP_FSETID 4 77 | #define CAP_KILL 5 78 | #define CAP_SETGID 6 79 | #define CAP_SETUID 7 80 | #define CAP_SETPCAP 8 81 | #define CAP_LINUX_IMMUTABLE 9 82 | #define CAP_NET_BIND_SERVICE 10 83 | #define CAP_NET_BROADCAST 11 84 | #define CAP_NET_ADMIN 12 85 | #define CAP_NET_RAW 13 86 | #define CAP_IPC_LOCK 14 87 | #define CAP_IPC_OWNER 15 88 | #define CAP_SYS_MODULE 16 89 | #define CAP_SYS_RAWIO 17 90 | #define CAP_SYS_CHROOT 18 91 | #define CAP_SYS_PTRACE 19 92 | #define CAP_SYS_PACCT 20 93 | #define CAP_SYS_ADMIN 21 94 | #define CAP_SYS_BOOT 22 95 | #define CAP_SYS_NICE 23 96 | #define CAP_SYS_RESOURCE 24 97 | #define CAP_SYS_TIME 25 98 | #define CAP_SYS_TTY_CONFIG 26 99 | #define CAP_MKNOD 27 100 | #define CAP_LEASE 28 101 | #define CAP_AUDIT_WRITE 29 102 | #define CAP_AUDIT_CONTROL 30 103 | #define CAP_SETFCAP 31 104 | #define CAP_MAC_OVERRIDE 32 105 | #define CAP_MAC_ADMIN 33 106 | #define CAP_SYSLOG 34 107 | #define CAP_WAKE_ALARM 35 108 | #define CAP_BLOCK_SUSPEND 36 109 | #define CAP_AUDIT_READ 37 110 | #define CAP_LAST_CAP CAP_AUDIT_READ 111 | #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) 112 | #define CAP_TO_INDEX(x) ((x) >> 5) 113 | #define CAP_TO_MASK(x) (1 << ((x) & 31)) 114 | 115 | #undef __user 116 | #undef __u32 117 | #undef __le32 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /boot_image_tool/mkbootfs/private/android_filesystem_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* This file is used to define the properties of the filesystem 18 | ** images generated by build tools (mkbootfs and mkyaffs2image) and 19 | ** by the device side of adb. 20 | */ 21 | 22 | /* 23 | * This file is consumed by build/tools/fs_config and is used 24 | * for generating various files. Anything #define AID_ 25 | * becomes the mapping for getpwnam/getpwuid, etc. The 26 | * field is lowercased. 27 | * For example: 28 | * #define AID_FOO_BAR 6666 becomes a friendly name of "foo_bar" 29 | * 30 | * The above holds true with the exception of: 31 | * mediacodec 32 | * mediaex 33 | * mediadrm 34 | * Whose friendly names do not match the #define statements. 35 | * 36 | * Additionally, AID_OEM_RESERVED_START and AID_OEM_RESERVED_END 37 | * can be used to define reserved OEM ranges used for sanity checks 38 | * during the build process. The rules are, they must end with START/END 39 | * The proper convention is incrementing a number like so: 40 | * AID_OEM_RESERVED_START 41 | * AID_OEM_RESERVED_1_START 42 | * AID_OEM_RESERVED_2_START 43 | * ... 44 | * The same applies to the END. 45 | * They are not required to be in order, but must not overlap each other and 46 | * must define a START and END'ing range. START must be smaller than END. 47 | */ 48 | 49 | #ifndef _ANDROID_FILESYSTEM_CONFIG_H_ 50 | #define _ANDROID_FILESYSTEM_CONFIG_H_ 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #if defined(__BIONIC__) 58 | #include 59 | #else 60 | #include "android_filesystem_capability.h" 61 | #endif 62 | 63 | #define CAP_MASK_LONG(cap_name) (1ULL << (cap_name)) 64 | 65 | /* This is the master Users and Groups config for the platform. 66 | * DO NOT EVER RENUMBER 67 | */ 68 | 69 | #define AID_ROOT 0 /* traditional unix root user */ 70 | 71 | #define AID_SYSTEM 1000 /* system server */ 72 | 73 | #define AID_RADIO 1001 /* telephony subsystem, RIL */ 74 | #define AID_BLUETOOTH 1002 /* bluetooth subsystem */ 75 | #define AID_GRAPHICS 1003 /* graphics devices */ 76 | #define AID_INPUT 1004 /* input devices */ 77 | #define AID_AUDIO 1005 /* audio devices */ 78 | #define AID_CAMERA 1006 /* camera devices */ 79 | #define AID_LOG 1007 /* log devices */ 80 | #define AID_COMPASS 1008 /* compass device */ 81 | #define AID_MOUNT 1009 /* mountd socket */ 82 | #define AID_WIFI 1010 /* wifi subsystem */ 83 | #define AID_ADB 1011 /* android debug bridge (adbd) */ 84 | #define AID_INSTALL 1012 /* group for installing packages */ 85 | #define AID_MEDIA 1013 /* mediaserver process */ 86 | #define AID_DHCP 1014 /* dhcp client */ 87 | #define AID_SDCARD_RW 1015 /* external storage write access */ 88 | #define AID_VPN 1016 /* vpn system */ 89 | #define AID_KEYSTORE 1017 /* keystore subsystem */ 90 | #define AID_USB 1018 /* USB devices */ 91 | #define AID_DRM 1019 /* DRM server */ 92 | #define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */ 93 | #define AID_GPS 1021 /* GPS daemon */ 94 | #define AID_UNUSED1 1022 /* deprecated, DO NOT USE */ 95 | #define AID_MEDIA_RW 1023 /* internal media storage write access */ 96 | #define AID_MTP 1024 /* MTP USB driver access */ 97 | #define AID_UNUSED2 1025 /* deprecated, DO NOT USE */ 98 | #define AID_DRMRPC 1026 /* group for drm rpc */ 99 | #define AID_NFC 1027 /* nfc subsystem */ 100 | #define AID_SDCARD_R 1028 /* external storage read access */ 101 | #define AID_CLAT 1029 /* clat part of nat464 */ 102 | #define AID_LOOP_RADIO 1030 /* loop radio devices */ 103 | #define AID_MEDIA_DRM 1031 /* MediaDrm plugins */ 104 | #define AID_PACKAGE_INFO 1032 /* access to installed package details */ 105 | #define AID_SDCARD_PICS 1033 /* external storage photos access */ 106 | #define AID_SDCARD_AV 1034 /* external storage audio/video access */ 107 | #define AID_SDCARD_ALL 1035 /* access all users external storage */ 108 | #define AID_LOGD 1036 /* log daemon */ 109 | #define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */ 110 | #define AID_DBUS 1038 /* dbus-daemon IPC broker process */ 111 | #define AID_TLSDATE 1039 /* tlsdate unprivileged user */ 112 | #define AID_MEDIA_EX 1040 /* mediaextractor process */ 113 | #define AID_AUDIOSERVER 1041 /* audioserver process */ 114 | #define AID_METRICS_COLL 1042 /* metrics_collector process */ 115 | #define AID_METRICSD 1043 /* metricsd process */ 116 | #define AID_WEBSERV 1044 /* webservd process */ 117 | #define AID_DEBUGGERD 1045 /* debuggerd unprivileged user */ 118 | #define AID_MEDIA_CODEC 1046 /* mediacodec process */ 119 | #define AID_CAMERASERVER 1047 /* cameraserver process */ 120 | #define AID_FIREWALL 1048 /* firewalld process */ 121 | #define AID_TRUNKS 1049 /* trunksd process (TPM daemon) */ 122 | #define AID_NVRAM 1050 /* Access-controlled NVRAM */ 123 | #define AID_DNS 1051 /* DNS resolution daemon (system: netd) */ 124 | #define AID_DNS_TETHER 1052 /* DNS resolution daemon (tether: dnsmasq) */ 125 | #define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */ 126 | #define AID_VEHICLE_NETWORK 1054 /* Vehicle network service */ 127 | #define AID_MEDIA_AUDIO 1055 /* GID for audio files on internal media storage */ 128 | #define AID_MEDIA_VIDEO 1056 /* GID for video files on internal media storage */ 129 | #define AID_MEDIA_IMAGE 1057 /* GID for image files on internal media storage */ 130 | #define AID_TOMBSTONED 1058 /* tombstoned user */ 131 | #define AID_MEDIA_OBB 1059 /* GID for OBB files on internal media storage */ 132 | #define AID_ESE 1060 /* embedded secure element (eSE) subsystem */ 133 | #define AID_OTA_UPDATE 1061 /* resource tracking UID for OTA updates */ 134 | #define AID_AUTOMOTIVE_EVS 1062 /* Automotive rear and surround view system */ 135 | /* Changes to this file must be made in AOSP, *not* in internal branches. */ 136 | 137 | #define AID_THEMEMAN 1300 /* theme manager */ 138 | #define AID_AUDIT 1301 /* audit daemon */ 139 | 140 | #define AID_SHELL 2000 /* adb and debug shell user */ 141 | #define AID_CACHE 2001 /* cache access */ 142 | #define AID_DIAG 2002 /* access to diagnostic resources */ 143 | 144 | /* The range 2900-2999 is reserved for OEM, and must never be 145 | * used here */ 146 | #define AID_OEM_RESERVED_START 2900 147 | 148 | #if !defined(QCOM_LEGACY_UIDS) 149 | #define AID_QCOM_DIAG 2950 /* access to QTI diagnostic resources */ 150 | #define AID_RFS 2951 /* Remote Filesystem for peripheral processors */ 151 | #define AID_RFS_SHARED 2952 /* Shared files for Remote Filesystem for peripheral processors */ 152 | #endif 153 | 154 | #define AID_OEM_RESERVED_END 2999 155 | 156 | /* The 3000 series are intended for use as supplemental group id's only. 157 | * They indicate special Android capabilities that the kernel is aware of. */ 158 | #define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */ 159 | #define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */ 160 | #define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */ 161 | #define AID_NET_RAW 3004 /* can create raw INET sockets */ 162 | #define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */ 163 | #define AID_NET_BW_STATS 3006 /* read bandwidth statistics */ 164 | #define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */ 165 | #define AID_NET_BT_STACK 3008 /* bluetooth: access config files */ 166 | #define AID_READPROC 3009 /* Allow /proc read access */ 167 | #define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */ 168 | #if defined(QCOM_LEGACY_UIDS) 169 | #define AID_QCOM_ONCRPC 3011 /* can read/write /dev/oncrpc files */ 170 | #define AID_QCOM_DIAG 3012 /* can read/write /dev/diag */ 171 | #elif defined(QCOM_UIDS) 172 | #define AID_SENSORS 3011 /* access to /dev/socket/sensor_ctl_socket & QCCI/QCSI */ 173 | #define AID_IMS 3012 /* can read/write /dev/socket/imsrtp */ 174 | 175 | #define AID_RFS_OLD 3013 /* DEPRECATED OLD ID FOR RFS, DO NOT USE */ 176 | #define AID_RFS_SHARED_OLD 3014 /* DEPRECATED OLD ID FOR RFS-SHARED */ 177 | #else 178 | #define AID_UHID 3011 /* Allow read/write to /dev/uhid node */ 179 | #endif 180 | 181 | /* The range 5000-5999 is also reserved for OEM, and must never be used here. */ 182 | #define AID_OEM_RESERVED_2_START 5000 183 | #define AID_OEM_RESERVED_2_END 5999 184 | 185 | #if defined(MOTOROLA_UIDS) 186 | #define AID_MOT_OSH 5000 /* OSH */ 187 | #define AID_MOT_ACCY 9000 /* access to accessory */ 188 | #define AID_MOT_PWRIC 9001 /* power IC */ 189 | #define AID_MOT_USB 9002 /* mot usb */ 190 | #define AID_MOT_DRM 9003 /* can access DRM resource. */ 191 | #define AID_MOT_TCMD 9004 /* mot_tcmd */ 192 | #define AID_MOT_SEC_RTC 9005 /* mot cpcap rtc */ 193 | #define AID_MOT_TOMBSTONE 9006 194 | #define AID_MOT_TPAPI 9007 /* mot_tpapi */ 195 | #define AID_MOT_SECCLKD 9008 /* mot_secclkd */ 196 | #define AID_MOT_WHISPER 9009 /* Whisper Protocol access */ 197 | #define AID_MOT_CAIF 9010 /* can create CAIF sockets */ 198 | #define AID_MOT_DLNA 9011 /* DLNA native */ 199 | #endif // MOTOROLA_UIDS 200 | 201 | #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */ 202 | #define AID_MISC 9998 /* access to misc storage */ 203 | #define AID_NOBODY 9999 204 | 205 | #define AID_APP 10000 /* TODO: switch users over to AID_APP_START */ 206 | #define AID_APP_START 10000 /* first app user */ 207 | #define AID_APP_END 19999 /* last app user */ 208 | 209 | #define AID_CACHE_GID_START 20000 /* start of gids for apps to mark cached data */ 210 | #define AID_CACHE_GID_END 29999 /* end of gids for apps to mark cached data */ 211 | 212 | #define AID_EXT_GID_START 30000 /* start of gids for apps to mark external data */ 213 | #define AID_EXT_GID_END 39999 /* end of gids for apps to mark external data */ 214 | 215 | #define AID_EXT_CACHE_GID_START 40000 /* start of gids for apps to mark external cached data */ 216 | #define AID_EXT_CACHE_GID_END 49999 /* end of gids for apps to mark external cached data */ 217 | 218 | #define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */ 219 | #define AID_SHARED_GID_END 59999 /* end of gids for apps in each user to share */ 220 | 221 | #define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */ 222 | #define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */ 223 | 224 | #define AID_USER 100000 /* TODO: switch users over to AID_USER_OFFSET */ 225 | #define AID_USER_OFFSET 100000 /* offset for uid ranges for each user */ 226 | 227 | /* 228 | * android_ids has moved to pwd/grp functionality. 229 | * If you need to add one, the structure is now 230 | * auto-generated based on the AID_ constraints 231 | * documented at the top of this header file. 232 | * Also see build/tools/fs_config for more details. 233 | */ 234 | 235 | #if !defined(EXCLUDE_FS_CONFIG_STRUCTURES) 236 | 237 | struct fs_path_config { 238 | unsigned mode; 239 | unsigned uid; 240 | unsigned gid; 241 | uint64_t capabilities; 242 | const char *prefix; 243 | }; 244 | 245 | /* Rules for directories. 246 | ** These rules are applied based on "first match", so they 247 | ** should start with the most specific path and work their 248 | ** way up to the root. 249 | */ 250 | 251 | static const struct fs_path_config android_dirs[] = { 252 | /* clang-format off */ 253 | 254 | /* Magisk ramdisk special directories */ 255 | { 00000, AID_ROOT, AID_ROOT, 0, ".backup" }, 256 | 257 | /* SuperSU ramdisk special directories */ 258 | { 00000, AID_ROOT, AID_ROOT, 0, ".subackup" }, 259 | { 00000, AID_ROOT, AID_ROOT, 0, ".sufrp" }, 260 | { 00000, AID_ROOT, AID_ROOT, 0, "boot/.sufrp" }, 261 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "boot/bt_firmware" }, 262 | { 00500, AID_ROOT, AID_ROOT, 0, "boot/config" }, 263 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "boot/data" }, 264 | { 00755, AID_ROOT, AID_SYSTEM, 0, "boot/mnt" }, 265 | { 00750, AID_ROOT, AID_SHELL, 0, "boot/sbin" }, 266 | { 00751, AID_ROOT, AID_SDCARD_R, 0, "boot/storage" }, 267 | { 00755, AID_ROOT, AID_SHELL, 0, "boot/vendor" }, 268 | { 00755, AID_ROOT, AID_ROOT, 0, "boot" }, 269 | 270 | { 00770, AID_SYSTEM, AID_CACHE, 0, "cache" }, 271 | { 00500, AID_ROOT, AID_ROOT, 0, "config" }, 272 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" }, 273 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" }, 274 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral" }, 275 | { 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" }, 276 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/data" }, 277 | { 00771, AID_SHELL, AID_SHELL, 0, "data/local/tmp" }, 278 | { 00771, AID_SHELL, AID_SHELL, 0, "data/local" }, 279 | { 00770, AID_DHCP, AID_DHCP, 0, "data/misc/dhcp" }, 280 | { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" }, 281 | { 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" }, 282 | { 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" }, 283 | { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" }, 284 | { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" }, 285 | { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest" }, 286 | { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64" }, 287 | { 00775, AID_ROOT, AID_ROOT, 0, "data/preloads" }, 288 | { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, 289 | { 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" }, 290 | { 00755, AID_ROOT, AID_ROOT, 0, "root" }, 291 | { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, 292 | { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, 293 | { 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" }, 294 | { 00755, AID_ROOT, AID_ROOT, 0, "system/addon.d" }, 295 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" }, 296 | { 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" }, 297 | { 00755, AID_ROOT, AID_SHELL, 0, "system/etc" }, 298 | { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, 299 | { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" }, 300 | { 00755, AID_ROOT, AID_SHELL, 0, "vendor" }, 301 | { 00755, AID_ROOT, AID_ROOT, 0, 0 }, 302 | /* clang-format on */ 303 | }; 304 | 305 | /* Rules for files. 306 | ** These rules are applied based on "first match", so they 307 | ** should start with the most specific path and work their 308 | ** way up to the root. Prefixes ending in * denotes wildcard 309 | ** and will allow partial matches. 310 | */ 311 | static const struct fs_path_config android_files[] = { 312 | /* clang-format off */ 313 | 314 | /* Motorola ramdisk special files */ 315 | { 00755, AID_ROOT, AID_ROOT, 0, "init.class_main.sh" }, 316 | { 00400, AID_ROOT, AID_ROOT, 0, "module_hashes" }, 317 | { 00750, AID_ROOT, AID_ROOT, 0, "xbin/qe" }, 318 | 319 | /* Magisk ramdisk special files */ 320 | { 00000, AID_ROOT, AID_ROOT, 0, ".backup/.rmlist" }, 321 | { 00750, AID_ROOT, AID_ROOT, 0, ".backup/init.rc" }, 322 | { 00755, AID_ROOT, AID_ROOT, 0, "sbin/magisk" }, 323 | { 00750, AID_ROOT, AID_ROOT, 0, "init.magisk.rc" }, 324 | 325 | /* SuperSU ramdisk special files */ 326 | { 00640, AID_ROOT, AID_ROOT, 0, ".subackup/0000_fstab.*" }, 327 | { 00640, AID_ROOT, AID_ROOT, 0, ".subackup/0001_fstab.*" }, 328 | { 00750, AID_ROOT, AID_ROOT, 0, ".subackup/0001_init*" }, 329 | { 00750, AID_ROOT, AID_ROOT, 0, ".subackup/0002_init*" }, 330 | { 00750, AID_ROOT, AID_ROOT, 0, ".subackup/0003_init*" }, 331 | { 00755, AID_ROOT, AID_ROOT, 0, ".sufrp/frp_install" }, 332 | { 00700, AID_ROOT, AID_ROOT, 0, "sbin/launch_daemonsu.sh" }, 333 | { 00750, AID_ROOT, AID_ROOT, 0, "init.environ.rc" }, 334 | { 00750, AID_ROOT, AID_ROOT, 0, "init.rc" }, 335 | { 00750, AID_ROOT, AID_ROOT, 0, "init.supersu.rc" }, 336 | { 00755, AID_ROOT, AID_ROOT, 0, "boot/.sufrp/frp_install" }, 337 | { 00700, AID_ROOT, AID_ROOT, 0, "boot/sbin/launch_daemonsu.sh" }, 338 | { 00750, AID_ROOT, AID_SHELL, 0, "boot/sbin/*" }, 339 | { 00640, AID_ROOT, AID_SHELL, 0, "boot/fstab.*" }, 340 | { 00750, AID_ROOT, AID_ROOT, 0, "boot/init.environ.rc" }, 341 | { 00750, AID_ROOT, AID_ROOT, 0, "boot/init.rc" }, 342 | { 00750, AID_ROOT, AID_ROOT, 0, "boot/init.supersu.rc" }, 343 | { 00750, AID_ROOT, AID_SHELL, 0, "boot/init*" }, 344 | 345 | { 00750, AID_ROOT, AID_SHELL, 0, "charger*" }, 346 | { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" }, 347 | { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-ephemeral/*" }, 348 | { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" }, 349 | { 00644, AID_APP, AID_APP, 0, "data/data/*" }, 350 | { 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" }, 351 | { 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest/tests.txt" }, 352 | { 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest64/tests.txt" }, 353 | { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest/*" }, 354 | { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" }, 355 | { 00600, AID_ROOT, AID_ROOT, 0, "default.prop" }, 356 | { 00600, AID_ROOT, AID_ROOT, 0, "odm/build.prop" }, 357 | { 00600, AID_ROOT, AID_ROOT, 0, "odm/default.prop" }, 358 | { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, 359 | { 00755, AID_ROOT, AID_ROOT, 0, "system/addon.d/*" }, 360 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" }, 361 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" }, 362 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" }, 363 | { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, 364 | { 00700, AID_ROOT, AID_ROOT, 0, "system/bin/secilc" }, 365 | { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, 366 | { 00600, AID_ROOT, AID_ROOT, 0, "system/build.prop" }, 367 | { 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" }, 368 | { 00755, AID_ROOT, AID_SHELL, 0, "system/etc/init.d/*" }, 369 | { 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" }, 370 | { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" }, 371 | { 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.ril" }, 372 | { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, 373 | { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, 374 | { 00440, AID_ROOT, AID_ROOT, 0, "system/etc/recovery.img" }, 375 | { 00600, AID_ROOT, AID_ROOT, 0, "system/odm/build.prop" }, 376 | { 00600, AID_ROOT, AID_ROOT, 0, "system/odm/default.prop" }, 377 | { 00444, AID_ROOT, AID_ROOT, 0, "system/odm/etc/fs_config_dirs" }, 378 | { 00444, AID_ROOT, AID_ROOT, 0, "system/odm/etc/fs_config_files" }, 379 | { 00444, AID_ROOT, AID_ROOT, 0, "system/oem/etc/fs_config_dirs" }, 380 | { 00444, AID_ROOT, AID_ROOT, 0, "system/oem/etc/fs_config_files" }, 381 | { 00600, AID_ROOT, AID_ROOT, 0, "system/vendor/build.prop" }, 382 | { 00600, AID_ROOT, AID_ROOT, 0, "system/vendor/default.prop" }, 383 | { 00444, AID_ROOT, AID_ROOT, 0, "system/vendor/etc/fs_config_dirs" }, 384 | { 00444, AID_ROOT, AID_ROOT, 0, "system/vendor/etc/fs_config_files" }, 385 | { 00600, AID_ROOT, AID_ROOT, 0, "vendor/build.prop" }, 386 | { 00600, AID_ROOT, AID_ROOT, 0, "vendor/default.prop" }, 387 | 388 | /* the following files are INTENTIONALLY set-uid, but they 389 | * are NOT included on user builds. */ 390 | { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, 391 | 392 | /* CM's daemonized su doesn't need the setuid bit */ 393 | { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, 394 | 395 | /* the following files have enhanced capabilities and ARE included 396 | * in user builds. */ 397 | { 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND), 398 | "system/bin/inputflinger" }, 399 | { 00550, AID_LOGD, AID_LOGD, CAP_MASK_LONG(CAP_SYSLOG) | 400 | CAP_MASK_LONG(CAP_AUDIT_CONTROL) | 401 | CAP_MASK_LONG(CAP_SETGID), 402 | "system/bin/logd" }, 403 | { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | 404 | CAP_MASK_LONG(CAP_SETGID), 405 | "system/bin/run-as" }, 406 | 407 | /* Support FIFO scheduling mode in SurfaceFlinger. */ 408 | { 00755, AID_SYSTEM, AID_GRAPHICS, CAP_MASK_LONG(CAP_SYS_NICE), 409 | "system/bin/surfaceflinger" }, 410 | 411 | /* Support hostapd administering a network interface. */ 412 | { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) | 413 | CAP_MASK_LONG(CAP_NET_RAW), 414 | "system/bin/hostapd" }, 415 | 416 | /* Support Bluetooth legacy hal accessing /sys/class/rfkill 417 | * Support RT scheduling in Bluetooth */ 418 | { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN) | 419 | CAP_MASK_LONG(CAP_SYS_NICE), 420 | "vendor/bin/hw/android.hardware.bluetooth@1.0-service" }, 421 | 422 | /* Support wifi_hal_legacy administering a network interface. */ 423 | { 00755, AID_WIFI, AID_WIFI, CAP_MASK_LONG(CAP_NET_ADMIN) | 424 | CAP_MASK_LONG(CAP_NET_RAW), 425 | "vendor/bin/hw/android.hardware.wifi@1.0-service" }, 426 | 427 | /* A non-privileged zygote that spawns 428 | * isolated processes for web rendering. */ 429 | { 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) | 430 | CAP_MASK_LONG(CAP_SETGID) | 431 | CAP_MASK_LONG(CAP_SETPCAP), 432 | "system/bin/webview_zygote32" }, 433 | { 0750, AID_ROOT, AID_ROOT, CAP_MASK_LONG(CAP_SETUID) | 434 | CAP_MASK_LONG(CAP_SETGID) | 435 | CAP_MASK_LONG(CAP_SETPCAP), 436 | "system/bin/webview_zygote64" }, 437 | 438 | /* generic defaults */ 439 | { 00755, AID_ROOT, AID_ROOT, 0, "bin/*" }, 440 | { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, 441 | { 00750, AID_ROOT, AID_SHELL, 0, "init*" }, 442 | { 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" }, 443 | { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, 444 | { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, 445 | { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, 446 | { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/bin/*" }, 447 | { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor/xbin/*" }, 448 | { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, 449 | { 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" }, 450 | { 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" }, 451 | { 00644, AID_ROOT, AID_ROOT, 0, 0 }, 452 | /* clang-format on */ 453 | }; 454 | 455 | static inline void fs_config(const char* path, int dir, const char* target_out_path, 456 | unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) { 457 | const struct fs_path_config* pc; 458 | size_t plen; 459 | 460 | if (path[0] == '/') { 461 | path++; 462 | } 463 | 464 | pc = dir ? android_dirs : android_files; 465 | plen = strlen(path); 466 | for(; pc->prefix; pc++){ 467 | int len = strlen(pc->prefix); 468 | if (dir) { 469 | if(plen < len) continue; 470 | if(!strncmp(pc->prefix, path, len)) break; 471 | continue; 472 | } 473 | /* If name ends in * then allow partial matches. */ 474 | if (pc->prefix[len -1] == '*') { 475 | if(!strncmp(pc->prefix, path, len - 1)) break; 476 | } else if (plen == len){ 477 | if(!strncmp(pc->prefix, path, len)) break; 478 | } 479 | } 480 | *uid = pc->uid; 481 | *gid = pc->gid; 482 | *mode = (*mode & (~07777)) | pc->mode; 483 | *capabilities = pc->capabilities; 484 | 485 | #if 0 486 | fprintf(stderr,"< '%s' '%s' %d %d %o >\n", 487 | path, pc->prefix ? pc->prefix : "", *uid, *gid, *mode); 488 | #endif 489 | } 490 | 491 | ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc); 492 | 493 | #endif 494 | #endif 495 | -------------------------------------------------------------------------------- /emui_extractor/Makefile: -------------------------------------------------------------------------------- 1 | emui_extractor: image.h image.cc emui_extractor.cc 2 | g++ -o emui_extractor image.cc emui_extractor.cc 3 | 4 | .PHONY: clean 5 | clean: 6 | rm emui_extractor 7 | -------------------------------------------------------------------------------- /emui_extractor/emui_extractor.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "image.h" 7 | 8 | using namespace std; 9 | 10 | static string convert_size_to_str(uint32_t size) { 11 | char buf[16]; 12 | const char *unit = "B"; 13 | double sd = size; 14 | if (size > 1024) { 15 | sd /= 1024; 16 | size /= 1024; 17 | unit = "KB"; 18 | } 19 | if (size > 1024) { 20 | sd /= 1024; 21 | size /= 1024; 22 | unit = "MB"; 23 | } 24 | if (size > 1024) { 25 | sd /= 1024; 26 | size /= 1024; 27 | unit = "GB"; 28 | } 29 | snprintf(buf, sizeof(buf), "%12.2lf %2s", sd, unit); 30 | return string(buf); 31 | } 32 | 33 | static int list_images(const char *in_file) { 34 | RoImageFile *image_file = RoImageFile::Create(in_file); 35 | if (!image_file->Load()) { 36 | fprintf(stderr, "Failed to load\n"); 37 | return -1; 38 | } 39 | 40 | auto images = image_file->GetAllImages(); 41 | unsigned size_len = 0; 42 | unsigned type_len = 0; 43 | for (const auto &img : images) { 44 | string size_str = convert_size_to_str(img->GetHdr()->data_len_); 45 | if (size_str.size() > size_len) { 46 | size_len = size_str.size(); 47 | } 48 | unsigned len = strlen(reinterpret_cast(img->GetHdr()->type_)); 49 | if (len > type_len) { 50 | type_len = len; 51 | } 52 | } 53 | string line(8 + 1 + type_len + 4 + 1 + size_len + 1 + type_len + 1 + 8, '='); 54 | fprintf(stdout, "%s\n", line.c_str()); 55 | fprintf(stdout, "%8s %*s.img %*s %*s %8s\n", "Sequence", type_len, "File", 56 | size_len, "Size", type_len, "Type", "Device"); 57 | fprintf(stdout, "%s\n", line.c_str()); 58 | for (const auto &img : images) { 59 | string size_str = convert_size_to_str(img->GetHdr()->data_len_); 60 | int i = sizeof(img->GetHdr()->hw_id_) - 1; 61 | while (i >= 0 && img->GetHdr()->hw_id_[i] == 0xff) { 62 | --i; 63 | } 64 | ++i; 65 | string device(reinterpret_cast(&img->GetHdr()->hw_id_[0]), i); 66 | fprintf(stdout, "%08x %*s.img %*s %*s %8s\n", img->GetHdr()->sequence_, 67 | type_len, img->GetHdr()->type_, size_len, size_str.c_str(), type_len, 68 | img->GetHdr()->type_, device.c_str()); 69 | } 70 | fprintf(stdout, "%s\n", line.c_str()); 71 | } 72 | 73 | static int dump_image(const char *in_file, const char *img_name, 74 | const char *out_file) { 75 | RoImageFile *image_file = RoImageFile::Create(in_file); 76 | if (!image_file->Load()) { 77 | fprintf(stderr, "Failed to load\n"); 78 | return -1; 79 | } 80 | 81 | auto images = image_file->GetAllImages(); 82 | for (const auto &img : images) { 83 | string type(reinterpret_cast(img->GetHdr()->type_)); 84 | type += ".img"; 85 | 86 | if (out_file == string("all")) { 87 | img->Dump(type); 88 | continue; 89 | } 90 | 91 | if (type != img_name) { 92 | continue; 93 | } 94 | img->Dump(out_file); 95 | return 0; 96 | } 97 | if (out_file != string("all")) { 98 | fprintf(stderr, "err find %s\n", img_name); 99 | return -1; 100 | } 101 | return 0; 102 | } 103 | 104 | static const char *usage = 105 | "Usage: emui_extractor UPDATE.APP cmd\n" 106 | " cmd:\n" 107 | " list - list all images in the UPDATE.APP\n" 108 | " dump image output - dump one of image in the UPDATE.APP\n"; 109 | 110 | int main(int argc, char **argv) { 111 | if (argc == 3 && strcmp(argv[2], "list") == 0) { 112 | return list_images(argv[1]); 113 | } else if (argc == 5 && strcmp(argv[2], "dump") == 0) { 114 | return dump_image(argv[1], argv[3], argv[4]); 115 | } else { 116 | fprintf(stderr, "%s", usage); 117 | return -1; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /emui_extractor/image.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "image.h" 8 | 9 | using namespace std; 10 | 11 | bool Image::Dump(const string &out_fn) const { 12 | int fd = open(out_fn.c_str(), O_WRONLY | O_CREAT, 13 | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); 14 | if (fd == -1) { 15 | fprintf(stderr, "error open %s: %s\n", out_fn.c_str(), strerror(errno)); 16 | return false; 17 | } 18 | 19 | DBG("dumping %s size: %d off: 0x%lx\n", hdr_->type_, hdr_->data_len_, 20 | data_off_); 21 | 22 | if (image_file_->SetPosition(data_off_)) { 23 | char buf[4096]; 24 | uint32_t total = hdr_->data_len_; 25 | while (total) { 26 | // DBG("0x%x\n", total); 27 | uint32_t to_read = total <= sizeof(buf) ? total : sizeof(buf); 28 | if (image_file_->Read(reinterpret_cast(buf), to_read)) { 29 | if (write(fd, buf, to_read) != to_read) { 30 | fprintf(stderr, "error write %s: %s\n", out_fn.c_str(), strerror(errno)); 31 | close(fd); 32 | return false; 33 | } 34 | total -= to_read; 35 | } else { 36 | close(fd); 37 | return false; 38 | } 39 | } 40 | close(fd); 41 | return true; 42 | } 43 | close(fd); 44 | return false; 45 | } 46 | 47 | RoImageFile::RoImageFile(const char *file_name) : file_name_(file_name) { 48 | fd_ = open(file_name, O_RDONLY); 49 | if (fd_ == -1) { 50 | fprintf(stderr, "error open %s: %s\n", file_name, strerror(errno)); 51 | return; 52 | } 53 | struct stat buf; 54 | if (fstat(fd_, &buf) == -1) { 55 | fprintf(stderr, "error stat %s: %s\n", file_name, strerror(errno)); 56 | return; 57 | } 58 | state_ = kGoodBit; 59 | size_ = buf.st_size; 60 | } 61 | 62 | bool RoImageFile::Load() { 63 | DBG("Begin load images...\n"); 64 | uint32_t magic, hdr_len; 65 | while (Read(reinterpret_cast(&magic), sizeof(magic))) { 66 | DBG("Now position: 0x%lx\n", GetPosition()); 67 | if (magic == Image::kMagic) { 68 | if (Read(reinterpret_cast(&hdr_len), sizeof(hdr_len))) { 69 | Skip(-(sizeof(magic) + sizeof(hdr_len))); 70 | off_t pos = GetPosition(); 71 | // shared_ptr hdr( 72 | // reinterpret_cast(new uint8_t[hdr_len]), 73 | // [](Image::ImageHdr *p) { delete[] reinterpret_cast(p); 74 | // }); 75 | shared_ptr hdr( 76 | reinterpret_cast(malloc(hdr_len)), free); 77 | if (Read(reinterpret_cast(hdr.get()), hdr_len)) { 78 | shared_ptr image = make_shared(hdr, this, pos); 79 | images_.push_back(image); 80 | 81 | Skip(hdr->data_len_); 82 | SkipAlign(); 83 | DBG("Got new header %s\n", hdr->type_); 84 | continue; 85 | } 86 | } 87 | } 88 | } 89 | DBG("End load images\n"); 90 | return Eof(); 91 | } 92 | 93 | RoImageFile &RoImageFile::Read(uint8_t *buf, size_t buf_sz) { 94 | if (Good()) { 95 | ssize_t count = read(fd_, buf, buf_sz); 96 | if (count == -1) { 97 | fprintf(stderr, "error read %s: %s\n", file_name_, strerror(errno)); 98 | state_ |= kBadBit; 99 | } else if (count < static_cast(buf_sz)) { 100 | // fprintf(stderr, "error read %s: EOF\n", file_name_); 101 | position_ += count; 102 | state_ |= kEofBit; 103 | } else { 104 | position_ += count; 105 | } 106 | } else { 107 | DBG("Bad state, not read\n"); 108 | } 109 | return *this; 110 | } 111 | 112 | RoImageFile &RoImageFile::Skip(off_t sz) { 113 | position_ += sz; 114 | if (position_ > size_) { 115 | position_ = size_; 116 | } else if (position_ < 0) { 117 | position_ = 0; 118 | } 119 | if (lseek(fd_, position_, SEEK_SET) == -1) { 120 | state_ |= kBadBit; 121 | } 122 | if ((state_ | kEofBit) != 0 && position_ < size_) { 123 | state_ &= ~kEofBit; 124 | } 125 | return *this; 126 | } 127 | -------------------------------------------------------------------------------- /emui_extractor/image.h: -------------------------------------------------------------------------------- 1 | #ifndef EMUI_EXTRACTOR_IMAGEHDR_H_ 2 | #define EMUI_EXTRACTOR_IMAGEHDR_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #ifdef DEBUG 16 | #define DBG(...) fprintf(stderr, __VA_ARGS__) 17 | #else 18 | #define DBG 19 | #endif 20 | 21 | class RoImageFile; 22 | 23 | class Image { 24 | friend RoImageFile; 25 | public: 26 | static const uint32_t kMagic = 0xA55AAA55; 27 | 28 | struct ImageHdr { 29 | uint8_t magic_[4]; 30 | uint32_t hdr_len_; 31 | uint32_t unused1_; 32 | uint8_t hw_id_[8]; 33 | uint32_t sequence_; 34 | uint32_t data_len_; 35 | uint8_t date_[16]; 36 | uint8_t time_[16]; 37 | uint8_t type_[32]; 38 | uint16_t hdr_checksum_; 39 | uint16_t unused3_; 40 | uint16_t unused4_; 41 | uint8_t data_checksum_[0]; 42 | }; 43 | 44 | // Image() : hdr_(nullptr), data_off_(0) {} 45 | Image(std::shared_ptr hdr, RoImageFile *ifp, off_t hdr_off) 46 | : hdr_(hdr), image_file_(ifp), data_off_(hdr->hdr_len_ + hdr_off) {} 47 | 48 | const std::shared_ptr GetImageHdr() const { 49 | return hdr_; 50 | } 51 | 52 | bool Dump(const std::string &out_fn) const; 53 | std::shared_ptr GetHdr() const { 54 | return hdr_; 55 | } 56 | 57 | private: 58 | Image(const Image &) = delete; 59 | Image &operator=(const Image &) = delete; 60 | 61 | std::shared_ptr hdr_; 62 | RoImageFile *image_file_; 63 | off_t data_off_; 64 | }; 65 | 66 | class RoImageFile { 67 | friend class Image; 68 | public: 69 | static RoImageFile *Create(const char *file_name) { 70 | DBG("Create RoImageFile\n"); 71 | static RoImageFile instance(file_name); 72 | return &instance; 73 | } 74 | 75 | const std::vector> &GetAllImages() const { 76 | return images_; 77 | } 78 | 79 | bool Load(); 80 | 81 | ~RoImageFile() { 82 | if (fd_ >= 0) { 83 | close(fd_); 84 | } 85 | } 86 | 87 | private: 88 | const unsigned kGoodBit = 0; 89 | const unsigned kBadBit = 1; 90 | const unsigned kEofBit = 2; 91 | 92 | RoImageFile(const char *file_name); 93 | 94 | // Do not allow copy 95 | RoImageFile(const RoImageFile &) = delete; 96 | RoImageFile &operator=(const RoImageFile &) = delete; 97 | 98 | explicit operator bool() const { 99 | return Good(); 100 | } 101 | 102 | RoImageFile &Read(uint8_t *buf, size_t buf_sz); 103 | RoImageFile &Skip(off_t sz); 104 | off_t GetPosition() const { return position_; } 105 | RoImageFile &SetPosition(off_t new_pos) { 106 | position_ = new_pos <= size_ ? new_pos : size_; 107 | if (lseek(fd_, position_, SEEK_SET) == -1) { 108 | state_ |= kBadBit; 109 | } 110 | if ((state_ & kEofBit) == kEofBit && position_ < size_) { 111 | state_ &= ~kEofBit; 112 | } 113 | return *this; 114 | } 115 | 116 | RoImageFile &SkipAlign() { 117 | off_t pos = GetPosition(); 118 | off_t pad = (pos + 3) / 4 * 4 - pos; 119 | return Skip(pad); 120 | } 121 | 122 | bool Good() const { return state_ == kGoodBit; } 123 | bool Bad() const { return (state_ & kBadBit) != 0; } 124 | bool Eof() const { return (state_ & kEofBit) != 0; } 125 | 126 | 127 | int fd_ = -1; 128 | off_t position_ = 0; 129 | off_t size_ = 0; 130 | unsigned state_ = kBadBit; 131 | const char *file_name_; // For debug 132 | std::vector> images_; 133 | }; 134 | #endif // EMUI_EXTRACTOR_IMAGEHDR_H_ 135 | -------------------------------------------------------------------------------- /mnt-droid: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "usage: [system/vendor]" 5 | exit 6 | fi 7 | 8 | part=$1 9 | simg2img ${part}.img ${part}.ext4 10 | mkdir $part 11 | sudo mount -oloop -text4 -r ${part}.ext4 $part 12 | -------------------------------------------------------------------------------- /ota_converter/.gitignore: -------------------------------------------------------------------------------- 1 | ota_converter 2 | .vscode 3 | env 4 | -------------------------------------------------------------------------------- /ota_converter/Makefile: -------------------------------------------------------------------------------- 1 | all: ota_converter 2 | 3 | ota_converter: ota_converter.cc lib/libbrotlidec-static.a lib/libbrotlicommon-static.a 4 | g++ -g -DLOG_LEVEL=4 -Iinclude ota_converter.cc -o ota_converter -static lib/libbrotlidec-static.a lib/libbrotlicommon-static.a 5 | 6 | .PHONY: clean 7 | clean: 8 | -rm ota_converter 9 | -------------------------------------------------------------------------------- /ota_converter/README: -------------------------------------------------------------------------------- 1 | This program convert full ota data (xx.transfer.list, xx.new.dat.br) in 2 | android ota package update.zip to image data (xx.ext4.img). 3 | 4 | ### CC Build 5 | 6 | make 7 | 8 | ### CC Run 9 | 10 | ./ota_converter system.transfer.list system.new.dat.br system.img 11 | 12 | ### Python setup and run 13 | 14 | # optional python3 -m venv env 15 | # optional . env/bin/activate 16 | python3 -m pip install brotli 17 | ./ota_converter.py system.transfer.list system.new.dat.br system.img 18 | 19 | ### Worlflow 20 | 21 | 1. Download update.zip of the device you want to hack from forum. 22 | 2. Unzip the update.zip. You get: 23 | update 24 | |-----xxx.elf 25 | |-----xxx.mbn 26 | |-----boot.img 27 | |-----system.transfer.list 28 | |-----system.new.dat.br 29 | |... 30 | 31 | 3. Convert system.transfer.list and system.new.dat.br to system.img which is an 32 | ext4 filesystem image 33 | 4. Mount the system.img and hack it! 34 | -------------------------------------------------------------------------------- /ota_converter/include/brotli/decode.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Google Inc. All Rights Reserved. 2 | 3 | Distributed under MIT license. 4 | See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 | */ 6 | 7 | /** 8 | * @file 9 | * API for Brotli decompression. 10 | */ 11 | 12 | #ifndef BROTLI_DEC_DECODE_H_ 13 | #define BROTLI_DEC_DECODE_H_ 14 | 15 | #include 16 | #include 17 | 18 | #if defined(__cplusplus) || defined(c_plusplus) 19 | extern "C" { 20 | #endif 21 | 22 | /** 23 | * Opaque structure that holds decoder state. 24 | * 25 | * Allocated and initialized with ::BrotliDecoderCreateInstance. 26 | * Cleaned up and deallocated with ::BrotliDecoderDestroyInstance. 27 | */ 28 | typedef struct BrotliDecoderStateStruct BrotliDecoderState; 29 | 30 | /** 31 | * Result type for ::BrotliDecoderDecompress and 32 | * ::BrotliDecoderDecompressStream functions. 33 | */ 34 | typedef enum { 35 | /** Decoding error, e.g. corrupted input or memory allocation problem. */ 36 | BROTLI_DECODER_RESULT_ERROR = 0, 37 | /** Decoding successfully completed. */ 38 | BROTLI_DECODER_RESULT_SUCCESS = 1, 39 | /** Partially done; should be called again with more input. */ 40 | BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2, 41 | /** Partially done; should be called again with more output. */ 42 | BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3 43 | } BrotliDecoderResult; 44 | 45 | /** 46 | * Template that evaluates items of ::BrotliDecoderErrorCode. 47 | * 48 | * Example: @code {.cpp} 49 | * // Log Brotli error code. 50 | * switch (brotliDecoderErrorCode) { 51 | * #define CASE_(PREFIX, NAME, CODE) \ 52 | * case BROTLI_DECODER ## PREFIX ## NAME: \ 53 | * LOG(INFO) << "error code:" << #NAME; \ 54 | * break; 55 | * #define NEWLINE_ 56 | * BROTLI_DECODER_ERROR_CODES_LIST(CASE_, NEWLINE_) 57 | * #undef CASE_ 58 | * #undef NEWLINE_ 59 | * default: LOG(FATAL) << "unknown brotli error code"; 60 | * } 61 | * @endcode 62 | */ 63 | #define BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE, SEPARATOR) \ 64 | BROTLI_ERROR_CODE(_, NO_ERROR, 0) SEPARATOR \ 65 | /* Same as BrotliDecoderResult values */ \ 66 | BROTLI_ERROR_CODE(_, SUCCESS, 1) SEPARATOR \ 67 | BROTLI_ERROR_CODE(_, NEEDS_MORE_INPUT, 2) SEPARATOR \ 68 | BROTLI_ERROR_CODE(_, NEEDS_MORE_OUTPUT, 3) SEPARATOR \ 69 | \ 70 | /* Errors caused by invalid input */ \ 71 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_NIBBLE, -1) SEPARATOR \ 72 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, RESERVED, -2) SEPARATOR \ 73 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_META_NIBBLE, -3) SEPARATOR \ 74 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_ALPHABET, -4) SEPARATOR \ 75 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_SAME, -5) SEPARATOR \ 76 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, CL_SPACE, -6) SEPARATOR \ 77 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, HUFFMAN_SPACE, -7) SEPARATOR \ 78 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, CONTEXT_MAP_REPEAT, -8) SEPARATOR \ 79 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_1, -9) SEPARATOR \ 80 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_2, -10) SEPARATOR \ 81 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, TRANSFORM, -11) SEPARATOR \ 82 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, DICTIONARY, -12) SEPARATOR \ 83 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, WINDOW_BITS, -13) SEPARATOR \ 84 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR \ 85 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR \ 86 | BROTLI_ERROR_CODE(_ERROR_FORMAT_, DISTANCE, -16) SEPARATOR \ 87 | \ 88 | /* -17..-18 codes are reserved */ \ 89 | \ 90 | BROTLI_ERROR_CODE(_ERROR_, DICTIONARY_NOT_SET, -19) SEPARATOR \ 91 | BROTLI_ERROR_CODE(_ERROR_, INVALID_ARGUMENTS, -20) SEPARATOR \ 92 | \ 93 | /* Memory allocation problems */ \ 94 | BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MODES, -21) SEPARATOR \ 95 | /* Literal, insert and distance trees together */ \ 96 | BROTLI_ERROR_CODE(_ERROR_ALLOC_, TREE_GROUPS, -22) SEPARATOR \ 97 | /* -23..-24 codes are reserved for distinct tree groups */ \ 98 | BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MAP, -25) SEPARATOR \ 99 | BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_1, -26) SEPARATOR \ 100 | BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_2, -27) SEPARATOR \ 101 | /* -28..-29 codes are reserved for dynamic ring-buffer allocation */ \ 102 | BROTLI_ERROR_CODE(_ERROR_ALLOC_, BLOCK_TYPE_TREES, -30) SEPARATOR \ 103 | \ 104 | /* "Impossible" states */ \ 105 | BROTLI_ERROR_CODE(_ERROR_, UNREACHABLE, -31) 106 | 107 | /** 108 | * Error code for detailed logging / production debugging. 109 | * 110 | * See ::BrotliDecoderGetErrorCode and ::BROTLI_LAST_ERROR_CODE. 111 | */ 112 | typedef enum { 113 | #define BROTLI_COMMA_ , 114 | #define BROTLI_ERROR_CODE_ENUM_ITEM_(PREFIX, NAME, CODE) \ 115 | BROTLI_DECODER ## PREFIX ## NAME = CODE 116 | BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE_ENUM_ITEM_, BROTLI_COMMA_) 117 | } BrotliDecoderErrorCode; 118 | #undef BROTLI_ERROR_CODE_ENUM_ITEM_ 119 | #undef BROTLI_COMMA_ 120 | 121 | /** 122 | * The value of the last error code, negative integer. 123 | * 124 | * All other error code values are in the range from ::BROTLI_LAST_ERROR_CODE 125 | * to @c -1. There are also 4 other possible non-error codes @c 0 .. @c 3 in 126 | * ::BrotliDecoderErrorCode enumeration. 127 | */ 128 | #define BROTLI_LAST_ERROR_CODE BROTLI_DECODER_ERROR_UNREACHABLE 129 | 130 | /** Options to be used with ::BrotliDecoderSetParameter. */ 131 | typedef enum BrotliDecoderParameter { 132 | /** 133 | * Disable "canny" ring buffer allocation strategy. 134 | * 135 | * Ring buffer is allocated according to window size, despite the real size of 136 | * the content. 137 | */ 138 | BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION = 0, 139 | /** 140 | * Flag that determines if "Large Window Brotli" is used. 141 | */ 142 | BROTLI_DECODER_PARAM_LARGE_WINDOW = 1 143 | } BrotliDecoderParameter; 144 | 145 | /** 146 | * Sets the specified parameter to the given decoder instance. 147 | * 148 | * @param state decoder instance 149 | * @param param parameter to set 150 | * @param value new parameter value 151 | * @returns ::BROTLI_FALSE if parameter is unrecognized, or value is invalid 152 | * @returns ::BROTLI_TRUE if value is accepted 153 | */ 154 | BROTLI_DEC_API BROTLI_BOOL BrotliDecoderSetParameter( 155 | BrotliDecoderState* state, BrotliDecoderParameter param, uint32_t value); 156 | 157 | /** 158 | * Creates an instance of ::BrotliDecoderState and initializes it. 159 | * 160 | * The instance can be used once for decoding and should then be destroyed with 161 | * ::BrotliDecoderDestroyInstance, it cannot be reused for a new decoding 162 | * session. 163 | * 164 | * @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the 165 | * case they are both zero, default memory allocators are used. @p opaque is 166 | * passed to @p alloc_func and @p free_func when they are called. @p free_func 167 | * has to return without doing anything when asked to free a NULL pointer. 168 | * 169 | * @param alloc_func custom memory allocation function 170 | * @param free_func custom memory free function 171 | * @param opaque custom memory manager handle 172 | * @returns @c 0 if instance can not be allocated or initialized 173 | * @returns pointer to initialized ::BrotliDecoderState otherwise 174 | */ 175 | BROTLI_DEC_API BrotliDecoderState* BrotliDecoderCreateInstance( 176 | brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); 177 | 178 | /** 179 | * Deinitializes and frees ::BrotliDecoderState instance. 180 | * 181 | * @param state decoder instance to be cleaned up and deallocated 182 | */ 183 | BROTLI_DEC_API void BrotliDecoderDestroyInstance(BrotliDecoderState* state); 184 | 185 | /** 186 | * Performs one-shot memory-to-memory decompression. 187 | * 188 | * Decompresses the data in @p encoded_buffer into @p decoded_buffer, and sets 189 | * @p *decoded_size to the decompressed length. 190 | * 191 | * @param encoded_size size of @p encoded_buffer 192 | * @param encoded_buffer compressed data buffer with at least @p encoded_size 193 | * addressable bytes 194 | * @param[in, out] decoded_size @b in: size of @p decoded_buffer; \n 195 | * @b out: length of decompressed data written to 196 | * @p decoded_buffer 197 | * @param decoded_buffer decompressed data destination buffer 198 | * @returns ::BROTLI_DECODER_RESULT_ERROR if input is corrupted, memory 199 | * allocation failed, or @p decoded_buffer is not large enough; 200 | * @returns ::BROTLI_DECODER_RESULT_SUCCESS otherwise 201 | */ 202 | BROTLI_DEC_API BrotliDecoderResult BrotliDecoderDecompress( 203 | size_t encoded_size, 204 | const uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(encoded_size)], 205 | size_t* decoded_size, 206 | uint8_t decoded_buffer[BROTLI_ARRAY_PARAM(*decoded_size)]); 207 | 208 | /** 209 | * Decompresses the input stream to the output stream. 210 | * 211 | * The values @p *available_in and @p *available_out must specify the number of 212 | * bytes addressable at @p *next_in and @p *next_out respectively. 213 | * When @p *available_out is @c 0, @p next_out is allowed to be @c NULL. 214 | * 215 | * After each call, @p *available_in will be decremented by the amount of input 216 | * bytes consumed, and the @p *next_in pointer will be incremented by that 217 | * amount. Similarly, @p *available_out will be decremented by the amount of 218 | * output bytes written, and the @p *next_out pointer will be incremented by 219 | * that amount. 220 | * 221 | * @p total_out, if it is not a null-pointer, will be set to the number 222 | * of bytes decompressed since the last @p state initialization. 223 | * 224 | * @note Input is never overconsumed, so @p next_in and @p available_in could be 225 | * passed to the next consumer after decoding is complete. 226 | * 227 | * @param state decoder instance 228 | * @param[in, out] available_in @b in: amount of available input; \n 229 | * @b out: amount of unused input 230 | * @param[in, out] next_in pointer to the next compressed byte 231 | * @param[in, out] available_out @b in: length of output buffer; \n 232 | * @b out: remaining size of output buffer 233 | * @param[in, out] next_out output buffer cursor; 234 | * can be @c NULL if @p available_out is @c 0 235 | * @param[out] total_out number of bytes decompressed so far; can be @c NULL 236 | * @returns ::BROTLI_DECODER_RESULT_ERROR if input is corrupted, memory 237 | * allocation failed, arguments were invalid, etc.; 238 | * use ::BrotliDecoderGetErrorCode to get detailed error code 239 | * @returns ::BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT decoding is blocked until 240 | * more input data is provided 241 | * @returns ::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT decoding is blocked until 242 | * more output space is provided 243 | * @returns ::BROTLI_DECODER_RESULT_SUCCESS decoding is finished, no more 244 | * input might be consumed and no more output will be produced 245 | */ 246 | BROTLI_DEC_API BrotliDecoderResult BrotliDecoderDecompressStream( 247 | BrotliDecoderState* state, size_t* available_in, const uint8_t** next_in, 248 | size_t* available_out, uint8_t** next_out, size_t* total_out); 249 | 250 | /** 251 | * Checks if decoder has more output. 252 | * 253 | * @param state decoder instance 254 | * @returns ::BROTLI_TRUE, if decoder has some unconsumed output 255 | * @returns ::BROTLI_FALSE otherwise 256 | */ 257 | BROTLI_DEC_API BROTLI_BOOL BrotliDecoderHasMoreOutput( 258 | const BrotliDecoderState* state); 259 | 260 | /** 261 | * Acquires pointer to internal output buffer. 262 | * 263 | * This method is used to make language bindings easier and more efficient: 264 | * -# push data to ::BrotliDecoderDecompressStream, 265 | * until ::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT is reported 266 | * -# use ::BrotliDecoderTakeOutput to peek bytes and copy to language-specific 267 | * entity 268 | * 269 | * Also this could be useful if there is an output stream that is able to 270 | * consume all the provided data (e.g. when data is saved to file system). 271 | * 272 | * @attention After every call to ::BrotliDecoderTakeOutput @p *size bytes of 273 | * output are considered consumed for all consecutive calls to the 274 | * instance methods; returned pointer becomes invalidated as well. 275 | * 276 | * @note Decoder output is not guaranteed to be contiguous. This means that 277 | * after the size-unrestricted call to ::BrotliDecoderTakeOutput, 278 | * immediate next call to ::BrotliDecoderTakeOutput may return more data. 279 | * 280 | * @param state decoder instance 281 | * @param[in, out] size @b in: number of bytes caller is ready to take, @c 0 if 282 | * any amount could be handled; \n 283 | * @b out: amount of data pointed by returned pointer and 284 | * considered consumed; \n 285 | * out value is never greater than in value, unless it is @c 0 286 | * @returns pointer to output data 287 | */ 288 | BROTLI_DEC_API const uint8_t* BrotliDecoderTakeOutput( 289 | BrotliDecoderState* state, size_t* size); 290 | 291 | /** 292 | * Checks if instance has already consumed input. 293 | * 294 | * Instance that returns ::BROTLI_FALSE is considered "fresh" and could be 295 | * reused. 296 | * 297 | * @param state decoder instance 298 | * @returns ::BROTLI_TRUE if decoder has already used some input bytes 299 | * @returns ::BROTLI_FALSE otherwise 300 | */ 301 | BROTLI_DEC_API BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* state); 302 | 303 | /** 304 | * Checks if decoder instance reached the final state. 305 | * 306 | * @param state decoder instance 307 | * @returns ::BROTLI_TRUE if decoder is in a state where it reached the end of 308 | * the input and produced all of the output 309 | * @returns ::BROTLI_FALSE otherwise 310 | */ 311 | BROTLI_DEC_API BROTLI_BOOL BrotliDecoderIsFinished( 312 | const BrotliDecoderState* state); 313 | 314 | /** 315 | * Acquires a detailed error code. 316 | * 317 | * Should be used only after ::BrotliDecoderDecompressStream returns 318 | * ::BROTLI_DECODER_RESULT_ERROR. 319 | * 320 | * See also ::BrotliDecoderErrorString 321 | * 322 | * @param state decoder instance 323 | * @returns last saved error code 324 | */ 325 | BROTLI_DEC_API BrotliDecoderErrorCode BrotliDecoderGetErrorCode( 326 | const BrotliDecoderState* state); 327 | 328 | /** 329 | * Converts error code to a c-string. 330 | */ 331 | BROTLI_DEC_API const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c); 332 | 333 | /** 334 | * Gets a decoder library version. 335 | * 336 | * Look at BROTLI_VERSION for more information. 337 | */ 338 | BROTLI_DEC_API uint32_t BrotliDecoderVersion(void); 339 | 340 | #if defined(__cplusplus) || defined(c_plusplus) 341 | } /* extern "C" */ 342 | #endif 343 | 344 | #endif /* BROTLI_DEC_DECODE_H_ */ 345 | -------------------------------------------------------------------------------- /ota_converter/include/brotli/encode.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Google Inc. All Rights Reserved. 2 | 3 | Distributed under MIT license. 4 | See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 | */ 6 | 7 | /** 8 | * @file 9 | * API for Brotli compression. 10 | */ 11 | 12 | #ifndef BROTLI_ENC_ENCODE_H_ 13 | #define BROTLI_ENC_ENCODE_H_ 14 | 15 | #include 16 | #include 17 | 18 | #if defined(__cplusplus) || defined(c_plusplus) 19 | extern "C" { 20 | #endif 21 | 22 | /** Minimal value for ::BROTLI_PARAM_LGWIN parameter. */ 23 | #define BROTLI_MIN_WINDOW_BITS 10 24 | /** 25 | * Maximal value for ::BROTLI_PARAM_LGWIN parameter. 26 | * 27 | * @note equal to @c BROTLI_MAX_DISTANCE_BITS constant. 28 | */ 29 | #define BROTLI_MAX_WINDOW_BITS 24 30 | /** 31 | * Maximal value for ::BROTLI_PARAM_LGWIN parameter 32 | * in "Large Window Brotli" (32-bit). 33 | */ 34 | #define BROTLI_LARGE_MAX_WINDOW_BITS 30 35 | /** Minimal value for ::BROTLI_PARAM_LGBLOCK parameter. */ 36 | #define BROTLI_MIN_INPUT_BLOCK_BITS 16 37 | /** Maximal value for ::BROTLI_PARAM_LGBLOCK parameter. */ 38 | #define BROTLI_MAX_INPUT_BLOCK_BITS 24 39 | /** Minimal value for ::BROTLI_PARAM_QUALITY parameter. */ 40 | #define BROTLI_MIN_QUALITY 0 41 | /** Maximal value for ::BROTLI_PARAM_QUALITY parameter. */ 42 | #define BROTLI_MAX_QUALITY 11 43 | 44 | /** Options for ::BROTLI_PARAM_MODE parameter. */ 45 | typedef enum BrotliEncoderMode { 46 | /** 47 | * Default compression mode. 48 | * 49 | * In this mode compressor does not know anything in advance about the 50 | * properties of the input. 51 | */ 52 | BROTLI_MODE_GENERIC = 0, 53 | /** Compression mode for UTF-8 formatted text input. */ 54 | BROTLI_MODE_TEXT = 1, 55 | /** Compression mode used in WOFF 2.0. */ 56 | BROTLI_MODE_FONT = 2 57 | } BrotliEncoderMode; 58 | 59 | /** Default value for ::BROTLI_PARAM_QUALITY parameter. */ 60 | #define BROTLI_DEFAULT_QUALITY 11 61 | /** Default value for ::BROTLI_PARAM_LGWIN parameter. */ 62 | #define BROTLI_DEFAULT_WINDOW 22 63 | /** Default value for ::BROTLI_PARAM_MODE parameter. */ 64 | #define BROTLI_DEFAULT_MODE BROTLI_MODE_GENERIC 65 | 66 | /** Operations that can be performed by streaming encoder. */ 67 | typedef enum BrotliEncoderOperation { 68 | /** 69 | * Process input. 70 | * 71 | * Encoder may postpone producing output, until it has processed enough input. 72 | */ 73 | BROTLI_OPERATION_PROCESS = 0, 74 | /** 75 | * Produce output for all processed input. 76 | * 77 | * Actual flush is performed when input stream is depleted and there is enough 78 | * space in output stream. This means that client should repeat 79 | * ::BROTLI_OPERATION_FLUSH operation until @p available_in becomes @c 0, and 80 | * ::BrotliEncoderHasMoreOutput returns ::BROTLI_FALSE. If output is acquired 81 | * via ::BrotliEncoderTakeOutput, then operation should be repeated after 82 | * output buffer is drained. 83 | * 84 | * @warning Until flush is complete, client @b SHOULD @b NOT swap, 85 | * reduce or extend input stream. 86 | * 87 | * When flush is complete, output data will be sufficient for decoder to 88 | * reproduce all the given input. 89 | */ 90 | BROTLI_OPERATION_FLUSH = 1, 91 | /** 92 | * Finalize the stream. 93 | * 94 | * Actual finalization is performed when input stream is depleted and there is 95 | * enough space in output stream. This means that client should repeat 96 | * ::BROTLI_OPERATION_FINISH operation until @p available_in becomes @c 0, and 97 | * ::BrotliEncoderHasMoreOutput returns ::BROTLI_FALSE. If output is acquired 98 | * via ::BrotliEncoderTakeOutput, then operation should be repeated after 99 | * output buffer is drained. 100 | * 101 | * @warning Until finalization is complete, client @b SHOULD @b NOT swap, 102 | * reduce or extend input stream. 103 | * 104 | * Helper function ::BrotliEncoderIsFinished checks if stream is finalized and 105 | * output fully dumped. 106 | * 107 | * Adding more input data to finalized stream is impossible. 108 | */ 109 | BROTLI_OPERATION_FINISH = 2, 110 | /** 111 | * Emit metadata block to stream. 112 | * 113 | * Metadata is opaque to Brotli: neither encoder, nor decoder processes this 114 | * data or relies on it. It may be used to pass some extra information from 115 | * encoder client to decoder client without interfering with main data stream. 116 | * 117 | * @note Encoder may emit empty metadata blocks internally, to pad encoded 118 | * stream to byte boundary. 119 | * 120 | * @warning Until emitting metadata is complete client @b SHOULD @b NOT swap, 121 | * reduce or extend input stream. 122 | * 123 | * @warning The whole content of input buffer is considered to be the content 124 | * of metadata block. Do @b NOT @e append metadata to input stream, 125 | * before it is depleted with other operations. 126 | * 127 | * Stream is soft-flushed before metadata block is emitted. Metadata block 128 | * @b MUST be no longer than than 16MiB. 129 | */ 130 | BROTLI_OPERATION_EMIT_METADATA = 3 131 | } BrotliEncoderOperation; 132 | 133 | /** Options to be used with ::BrotliEncoderSetParameter. */ 134 | typedef enum BrotliEncoderParameter { 135 | /** 136 | * Tune encoder for specific input. 137 | * 138 | * ::BrotliEncoderMode enumerates all available values. 139 | */ 140 | BROTLI_PARAM_MODE = 0, 141 | /** 142 | * The main compression speed-density lever. 143 | * 144 | * The higher the quality, the slower the compression. Range is 145 | * from ::BROTLI_MIN_QUALITY to ::BROTLI_MAX_QUALITY. 146 | */ 147 | BROTLI_PARAM_QUALITY = 1, 148 | /** 149 | * Recommended sliding LZ77 window size. 150 | * 151 | * Encoder may reduce this value, e.g. if input is much smaller than 152 | * window size. 153 | * 154 | * Window size is `(1 << value) - 16`. 155 | * 156 | * Range is from ::BROTLI_MIN_WINDOW_BITS to ::BROTLI_MAX_WINDOW_BITS. 157 | */ 158 | BROTLI_PARAM_LGWIN = 2, 159 | /** 160 | * Recommended input block size. 161 | * 162 | * Encoder may reduce this value, e.g. if input is much smaller than input 163 | * block size. 164 | * 165 | * Range is from ::BROTLI_MIN_INPUT_BLOCK_BITS to 166 | * ::BROTLI_MAX_INPUT_BLOCK_BITS. 167 | * 168 | * @note Bigger input block size allows better compression, but consumes more 169 | * memory. \n The rough formula of memory used for temporary input 170 | * storage is `3 << lgBlock`. 171 | */ 172 | BROTLI_PARAM_LGBLOCK = 3, 173 | /** 174 | * Flag that affects usage of "literal context modeling" format feature. 175 | * 176 | * This flag is a "decoding-speed vs compression ratio" trade-off. 177 | */ 178 | BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING = 4, 179 | /** 180 | * Estimated total input size for all ::BrotliEncoderCompressStream calls. 181 | * 182 | * The default value is 0, which means that the total input size is unknown. 183 | */ 184 | BROTLI_PARAM_SIZE_HINT = 5, 185 | /** 186 | * Flag that determines if "Large Window Brotli" is used. 187 | */ 188 | BROTLI_PARAM_LARGE_WINDOW = 6, 189 | /** 190 | * Recommended number of postfix bits (NPOSTFIX). 191 | * 192 | * Encoder may change this value. 193 | * 194 | * Range is from 0 to ::BROTLI_MAX_NPOSTFIX. 195 | */ 196 | BROTLI_PARAM_NPOSTFIX = 7, 197 | /** 198 | * Recommended number of direct distance codes (NDIRECT). 199 | * 200 | * Encoder may change this value. 201 | * 202 | * Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX). 203 | */ 204 | BROTLI_PARAM_NDIRECT = 8 205 | } BrotliEncoderParameter; 206 | 207 | /** 208 | * Opaque structure that holds encoder state. 209 | * 210 | * Allocated and initialized with ::BrotliEncoderCreateInstance. 211 | * Cleaned up and deallocated with ::BrotliEncoderDestroyInstance. 212 | */ 213 | typedef struct BrotliEncoderStateStruct BrotliEncoderState; 214 | 215 | /** 216 | * Sets the specified parameter to the given encoder instance. 217 | * 218 | * @param state encoder instance 219 | * @param param parameter to set 220 | * @param value new parameter value 221 | * @returns ::BROTLI_FALSE if parameter is unrecognized, or value is invalid 222 | * @returns ::BROTLI_FALSE if value of parameter can not be changed at current 223 | * encoder state (e.g. when encoding is started, window size might be 224 | * already encoded and therefore it is impossible to change it) 225 | * @returns ::BROTLI_TRUE if value is accepted 226 | * @warning invalid values might be accepted in case they would not break 227 | * encoding process. 228 | */ 229 | BROTLI_ENC_API BROTLI_BOOL BrotliEncoderSetParameter( 230 | BrotliEncoderState* state, BrotliEncoderParameter param, uint32_t value); 231 | 232 | /** 233 | * Creates an instance of ::BrotliEncoderState and initializes it. 234 | * 235 | * @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the 236 | * case they are both zero, default memory allocators are used. @p opaque is 237 | * passed to @p alloc_func and @p free_func when they are called. @p free_func 238 | * has to return without doing anything when asked to free a NULL pointer. 239 | * 240 | * @param alloc_func custom memory allocation function 241 | * @param free_func custom memory free function 242 | * @param opaque custom memory manager handle 243 | * @returns @c 0 if instance can not be allocated or initialized 244 | * @returns pointer to initialized ::BrotliEncoderState otherwise 245 | */ 246 | BROTLI_ENC_API BrotliEncoderState* BrotliEncoderCreateInstance( 247 | brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); 248 | 249 | /** 250 | * Deinitializes and frees ::BrotliEncoderState instance. 251 | * 252 | * @param state decoder instance to be cleaned up and deallocated 253 | */ 254 | BROTLI_ENC_API void BrotliEncoderDestroyInstance(BrotliEncoderState* state); 255 | 256 | /** 257 | * Calculates the output size bound for the given @p input_size. 258 | * 259 | * @warning Result is only valid if quality is at least @c 2 and, in 260 | * case ::BrotliEncoderCompressStream was used, no flushes 261 | * (::BROTLI_OPERATION_FLUSH) were performed. 262 | * 263 | * @param input_size size of projected input 264 | * @returns @c 0 if result does not fit @c size_t 265 | */ 266 | BROTLI_ENC_API size_t BrotliEncoderMaxCompressedSize(size_t input_size); 267 | 268 | /** 269 | * Performs one-shot memory-to-memory compression. 270 | * 271 | * Compresses the data in @p input_buffer into @p encoded_buffer, and sets 272 | * @p *encoded_size to the compressed length. 273 | * 274 | * @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero 275 | * value, then output is guaranteed to be no longer than that. 276 | * 277 | * @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY 278 | * @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW 279 | * @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE 280 | * @param input_size size of @p input_buffer 281 | * @param input_buffer input data buffer with at least @p input_size 282 | * addressable bytes 283 | * @param[in, out] encoded_size @b in: size of @p encoded_buffer; \n 284 | * @b out: length of compressed data written to 285 | * @p encoded_buffer, or @c 0 if compression fails 286 | * @param encoded_buffer compressed data destination buffer 287 | * @returns ::BROTLI_FALSE in case of compression error 288 | * @returns ::BROTLI_FALSE if output buffer is too small 289 | * @returns ::BROTLI_TRUE otherwise 290 | */ 291 | BROTLI_ENC_API BROTLI_BOOL BrotliEncoderCompress( 292 | int quality, int lgwin, BrotliEncoderMode mode, size_t input_size, 293 | const uint8_t input_buffer[BROTLI_ARRAY_PARAM(input_size)], 294 | size_t* encoded_size, 295 | uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(*encoded_size)]); 296 | 297 | /** 298 | * Compresses input stream to output stream. 299 | * 300 | * The values @p *available_in and @p *available_out must specify the number of 301 | * bytes addressable at @p *next_in and @p *next_out respectively. 302 | * When @p *available_out is @c 0, @p next_out is allowed to be @c NULL. 303 | * 304 | * After each call, @p *available_in will be decremented by the amount of input 305 | * bytes consumed, and the @p *next_in pointer will be incremented by that 306 | * amount. Similarly, @p *available_out will be decremented by the amount of 307 | * output bytes written, and the @p *next_out pointer will be incremented by 308 | * that amount. 309 | * 310 | * @p total_out, if it is not a null-pointer, will be set to the number 311 | * of bytes compressed since the last @p state initialization. 312 | * 313 | * 314 | * 315 | * Internally workflow consists of 3 tasks: 316 | * -# (optionally) copy input data to internal buffer 317 | * -# actually compress data and (optionally) store it to internal buffer 318 | * -# (optionally) copy compressed bytes from internal buffer to output stream 319 | * 320 | * Whenever all 3 tasks can't move forward anymore, or error occurs, this 321 | * method returns the control flow to caller. 322 | * 323 | * @p op is used to perform flush, finish the stream, or inject metadata block. 324 | * See ::BrotliEncoderOperation for more information. 325 | * 326 | * Flushing the stream means forcing encoding of all input passed to encoder and 327 | * completing the current output block, so it could be fully decoded by stream 328 | * decoder. To perform flush set @p op to ::BROTLI_OPERATION_FLUSH. 329 | * Under some circumstances (e.g. lack of output stream capacity) this operation 330 | * would require several calls to ::BrotliEncoderCompressStream. The method must 331 | * be called again until both input stream is depleted and encoder has no more 332 | * output (see ::BrotliEncoderHasMoreOutput) after the method is called. 333 | * 334 | * Finishing the stream means encoding of all input passed to encoder and 335 | * adding specific "final" marks, so stream decoder could determine that stream 336 | * is complete. To perform finish set @p op to ::BROTLI_OPERATION_FINISH. 337 | * Under some circumstances (e.g. lack of output stream capacity) this operation 338 | * would require several calls to ::BrotliEncoderCompressStream. The method must 339 | * be called again until both input stream is depleted and encoder has no more 340 | * output (see ::BrotliEncoderHasMoreOutput) after the method is called. 341 | * 342 | * @warning When flushing and finishing, @p op should not change until operation 343 | * is complete; input stream should not be swapped, reduced or 344 | * extended as well. 345 | * 346 | * @param state encoder instance 347 | * @param op requested operation 348 | * @param[in, out] available_in @b in: amount of available input; \n 349 | * @b out: amount of unused input 350 | * @param[in, out] next_in pointer to the next input byte 351 | * @param[in, out] available_out @b in: length of output buffer; \n 352 | * @b out: remaining size of output buffer 353 | * @param[in, out] next_out compressed output buffer cursor; 354 | * can be @c NULL if @p available_out is @c 0 355 | * @param[out] total_out number of bytes produced so far; can be @c NULL 356 | * @returns ::BROTLI_FALSE if there was an error 357 | * @returns ::BROTLI_TRUE otherwise 358 | */ 359 | BROTLI_ENC_API BROTLI_BOOL BrotliEncoderCompressStream( 360 | BrotliEncoderState* state, BrotliEncoderOperation op, size_t* available_in, 361 | const uint8_t** next_in, size_t* available_out, uint8_t** next_out, 362 | size_t* total_out); 363 | 364 | /** 365 | * Checks if encoder instance reached the final state. 366 | * 367 | * @param state encoder instance 368 | * @returns ::BROTLI_TRUE if encoder is in a state where it reached the end of 369 | * the input and produced all of the output 370 | * @returns ::BROTLI_FALSE otherwise 371 | */ 372 | BROTLI_ENC_API BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* state); 373 | 374 | /** 375 | * Checks if encoder has more output. 376 | * 377 | * @param state encoder instance 378 | * @returns ::BROTLI_TRUE, if encoder has some unconsumed output 379 | * @returns ::BROTLI_FALSE otherwise 380 | */ 381 | BROTLI_ENC_API BROTLI_BOOL BrotliEncoderHasMoreOutput( 382 | BrotliEncoderState* state); 383 | 384 | /** 385 | * Acquires pointer to internal output buffer. 386 | * 387 | * This method is used to make language bindings easier and more efficient: 388 | * -# push data to ::BrotliEncoderCompressStream, 389 | * until ::BrotliEncoderHasMoreOutput returns BROTL_TRUE 390 | * -# use ::BrotliEncoderTakeOutput to peek bytes and copy to language-specific 391 | * entity 392 | * 393 | * Also this could be useful if there is an output stream that is able to 394 | * consume all the provided data (e.g. when data is saved to file system). 395 | * 396 | * @attention After every call to ::BrotliEncoderTakeOutput @p *size bytes of 397 | * output are considered consumed for all consecutive calls to the 398 | * instance methods; returned pointer becomes invalidated as well. 399 | * 400 | * @note Encoder output is not guaranteed to be contiguous. This means that 401 | * after the size-unrestricted call to ::BrotliEncoderTakeOutput, 402 | * immediate next call to ::BrotliEncoderTakeOutput may return more data. 403 | * 404 | * @param state encoder instance 405 | * @param[in, out] size @b in: number of bytes caller is ready to take, @c 0 if 406 | * any amount could be handled; \n 407 | * @b out: amount of data pointed by returned pointer and 408 | * considered consumed; \n 409 | * out value is never greater than in value, unless it is @c 0 410 | * @returns pointer to output data 411 | */ 412 | BROTLI_ENC_API const uint8_t* BrotliEncoderTakeOutput( 413 | BrotliEncoderState* state, size_t* size); 414 | 415 | 416 | /** 417 | * Gets an encoder library version. 418 | * 419 | * Look at BROTLI_VERSION for more information. 420 | */ 421 | BROTLI_ENC_API uint32_t BrotliEncoderVersion(void); 422 | 423 | #if defined(__cplusplus) || defined(c_plusplus) 424 | } /* extern "C" */ 425 | #endif 426 | 427 | #endif /* BROTLI_ENC_ENCODE_H_ */ 428 | -------------------------------------------------------------------------------- /ota_converter/include/brotli/port.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2016 Google Inc. All Rights Reserved. 2 | 3 | Distributed under MIT license. 4 | See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 | */ 6 | 7 | /* Macros for compiler / platform specific API declarations. */ 8 | 9 | #ifndef BROTLI_COMMON_PORT_H_ 10 | #define BROTLI_COMMON_PORT_H_ 11 | 12 | /* The following macros were borrowed from https://github.com/nemequ/hedley 13 | * with permission of original author - Evan Nemerson */ 14 | 15 | /* >>> >>> >>> hedley macros */ 16 | 17 | #define BROTLI_MAKE_VERSION(major, minor, revision) \ 18 | (((major) * 1000000) + ((minor) * 1000) + (revision)) 19 | 20 | #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) 21 | #define BROTLI_GNUC_VERSION \ 22 | BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) 23 | #elif defined(__GNUC__) 24 | #define BROTLI_GNUC_VERSION BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, 0) 25 | #endif 26 | 27 | #if defined(BROTLI_GNUC_VERSION) 28 | #define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) \ 29 | (BROTLI_GNUC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 30 | #else 31 | #define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) (0) 32 | #endif 33 | 34 | #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) 35 | #define BROTLI_MSVC_VERSION \ 36 | BROTLI_MAKE_VERSION((_MSC_FULL_VER / 10000000), \ 37 | (_MSC_FULL_VER % 10000000) / 100000, \ 38 | (_MSC_FULL_VER % 100000) / 100) 39 | #elif defined(_MSC_FULL_VER) 40 | #define BROTLI_MSVC_VERSION \ 41 | BROTLI_MAKE_VERSION((_MSC_FULL_VER / 1000000), \ 42 | (_MSC_FULL_VER % 1000000) / 10000, \ 43 | (_MSC_FULL_VER % 10000) / 10) 44 | #elif defined(_MSC_VER) 45 | #define BROTLI_MSVC_VERSION \ 46 | BROTLI_MAKE_VERSION(_MSC_VER / 100, _MSC_VER % 100, 0) 47 | #endif 48 | 49 | #if !defined(_MSC_VER) 50 | #define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) (0) 51 | #elif defined(_MSC_VER) && (_MSC_VER >= 1400) 52 | #define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \ 53 | (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) 54 | #elif defined(_MSC_VER) && (_MSC_VER >= 1200) 55 | #define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \ 56 | (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) 57 | #else 58 | #define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \ 59 | (_MSC_VER >= ((major * 100) + (minor))) 60 | #endif 61 | 62 | #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) 63 | #define BROTLI_INTEL_VERSION \ 64 | BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, \ 65 | __INTEL_COMPILER % 100, \ 66 | __INTEL_COMPILER_UPDATE) 67 | #elif defined(__INTEL_COMPILER) 68 | #define BROTLI_INTEL_VERSION \ 69 | BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) 70 | #endif 71 | 72 | #if defined(BROTLI_INTEL_VERSION) 73 | #define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) \ 74 | (BROTLI_INTEL_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 75 | #else 76 | #define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) (0) 77 | #endif 78 | 79 | #if defined(__PGI) && \ 80 | defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) 81 | #define BROTLI_PGI_VERSION \ 82 | BROTLI_MAKE_VERSION(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) 83 | #endif 84 | 85 | #if defined(BROTLI_PGI_VERSION) 86 | #define BROTLI_PGI_VERSION_CHECK(major, minor, patch) \ 87 | (BROTLI_PGI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 88 | #else 89 | #define BROTLI_PGI_VERSION_CHECK(major, minor, patch) (0) 90 | #endif 91 | 92 | #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) 93 | #define BROTLI_SUNPRO_VERSION \ 94 | BROTLI_MAKE_VERSION( \ 95 | (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \ 96 | (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \ 97 | (__SUNPRO_C & 0xf) * 10) 98 | #elif defined(__SUNPRO_C) 99 | #define BROTLI_SUNPRO_VERSION \ 100 | BROTLI_MAKE_VERSION((__SUNPRO_C >> 8) & 0xf, \ 101 | (__SUNPRO_C >> 4) & 0xf, \ 102 | (__SUNPRO_C) & 0xf) 103 | #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) 104 | #define BROTLI_SUNPRO_VERSION \ 105 | BROTLI_MAKE_VERSION( \ 106 | (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \ 107 | (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \ 108 | (__SUNPRO_CC & 0xf) * 10) 109 | #elif defined(__SUNPRO_CC) 110 | #define BROTLI_SUNPRO_VERSION \ 111 | BROTLI_MAKE_VERSION((__SUNPRO_CC >> 8) & 0xf, \ 112 | (__SUNPRO_CC >> 4) & 0xf, \ 113 | (__SUNPRO_CC) & 0xf) 114 | #endif 115 | 116 | #if defined(BROTLI_SUNPRO_VERSION) 117 | #define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) \ 118 | (BROTLI_SUNPRO_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 119 | #else 120 | #define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) (0) 121 | #endif 122 | 123 | #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) 124 | #define BROTLI_ARM_VERSION \ 125 | BROTLI_MAKE_VERSION((__ARMCOMPILER_VERSION / 1000000), \ 126 | (__ARMCOMPILER_VERSION % 1000000) / 10000, \ 127 | (__ARMCOMPILER_VERSION % 10000) / 100) 128 | #elif defined(__CC_ARM) && defined(__ARMCC_VERSION) 129 | #define BROTLI_ARM_VERSION \ 130 | BROTLI_MAKE_VERSION((__ARMCC_VERSION / 1000000), \ 131 | (__ARMCC_VERSION % 1000000) / 10000, \ 132 | (__ARMCC_VERSION % 10000) / 100) 133 | #endif 134 | 135 | #if defined(BROTLI_ARM_VERSION) 136 | #define BROTLI_ARM_VERSION_CHECK(major, minor, patch) \ 137 | (BROTLI_ARM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 138 | #else 139 | #define BROTLI_ARM_VERSION_CHECK(major, minor, patch) (0) 140 | #endif 141 | 142 | #if defined(__ibmxl__) 143 | #define BROTLI_IBM_VERSION \ 144 | BROTLI_MAKE_VERSION(__ibmxl_version__, \ 145 | __ibmxl_release__, \ 146 | __ibmxl_modification__) 147 | #elif defined(__xlC__) && defined(__xlC_ver__) 148 | #define BROTLI_IBM_VERSION \ 149 | BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) 150 | #elif defined(__xlC__) 151 | #define BROTLI_IBM_VERSION BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, 0) 152 | #endif 153 | 154 | #if defined(BROTLI_IBM_VERSION) 155 | #define BROTLI_IBM_VERSION_CHECK(major, minor, patch) \ 156 | (BROTLI_IBM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 157 | #else 158 | #define BROTLI_IBM_VERSION_CHECK(major, minor, patch) (0) 159 | #endif 160 | 161 | #if defined(__TI_COMPILER_VERSION__) 162 | #define BROTLI_TI_VERSION \ 163 | BROTLI_MAKE_VERSION((__TI_COMPILER_VERSION__ / 1000000), \ 164 | (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ 165 | (__TI_COMPILER_VERSION__ % 1000)) 166 | #endif 167 | 168 | #if defined(BROTLI_TI_VERSION) 169 | #define BROTLI_TI_VERSION_CHECK(major, minor, patch) \ 170 | (BROTLI_TI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 171 | #else 172 | #define BROTLI_TI_VERSION_CHECK(major, minor, patch) (0) 173 | #endif 174 | 175 | #if defined(__IAR_SYSTEMS_ICC__) 176 | #if __VER__ > 1000 177 | #define BROTLI_IAR_VERSION \ 178 | BROTLI_MAKE_VERSION((__VER__ / 1000000), \ 179 | (__VER__ / 1000) % 1000, \ 180 | (__VER__ % 1000)) 181 | #else 182 | #define BROTLI_IAR_VERSION BROTLI_MAKE_VERSION(VER / 100, __VER__ % 100, 0) 183 | #endif 184 | #endif 185 | 186 | #if defined(BROTLI_IAR_VERSION) 187 | #define BROTLI_IAR_VERSION_CHECK(major, minor, patch) \ 188 | (BROTLI_IAR_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 189 | #else 190 | #define BROTLI_IAR_VERSION_CHECK(major, minor, patch) (0) 191 | #endif 192 | 193 | #if defined(__TINYC__) 194 | #define BROTLI_TINYC_VERSION \ 195 | BROTLI_MAKE_VERSION(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) 196 | #endif 197 | 198 | #if defined(BROTLI_TINYC_VERSION) 199 | #define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) \ 200 | (BROTLI_TINYC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) 201 | #else 202 | #define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) (0) 203 | #endif 204 | 205 | #if defined(__has_attribute) 206 | #define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ 207 | __has_attribute(attribute) 208 | #else 209 | #define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ 210 | BROTLI_GNUC_VERSION_CHECK(major, minor, patch) 211 | #endif 212 | 213 | #if defined(__has_builtin) 214 | #define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \ 215 | __has_builtin(builtin) 216 | #else 217 | #define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \ 218 | BROTLI_GNUC_VERSION_CHECK(major, minor, patch) 219 | #endif 220 | 221 | #if defined(_WIN32) || defined(__CYGWIN__) 222 | #define BROTLI_PUBLIC 223 | #elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \ 224 | BROTLI_TI_VERSION_CHECK(8, 0, 0) || \ 225 | BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \ 226 | BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \ 227 | BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \ 228 | BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \ 229 | (BROTLI_TI_VERSION_CHECK(7, 3, 0) && \ 230 | defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__)) 231 | #define BROTLI_PUBLIC __attribute__ ((visibility ("default"))) 232 | #else 233 | #define BROTLI_PUBLIC 234 | #endif 235 | 236 | #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ 237 | !defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \ 238 | !defined(__PGI) && !defined(__PGIC__) && !defined(__TINYC__) 239 | #define BROTLI_ARRAY_PARAM(name) (name) 240 | #else 241 | #define BROTLI_ARRAY_PARAM(name) 242 | #endif 243 | 244 | /* <<< <<< <<< end of hedley macros. */ 245 | 246 | #if defined(BROTLI_SHARED_COMPILATION) 247 | #if defined(_WIN32) 248 | #if defined(BROTLICOMMON_SHARED_COMPILATION) 249 | #define BROTLI_COMMON_API __declspec(dllexport) 250 | #else 251 | #define BROTLI_COMMON_API __declspec(dllimport) 252 | #endif /* BROTLICOMMON_SHARED_COMPILATION */ 253 | #if defined(BROTLIDEC_SHARED_COMPILATION) 254 | #define BROTLI_DEC_API __declspec(dllexport) 255 | #else 256 | #define BROTLI_DEC_API __declspec(dllimport) 257 | #endif /* BROTLIDEC_SHARED_COMPILATION */ 258 | #if defined(BROTLIENC_SHARED_COMPILATION) 259 | #define BROTLI_ENC_API __declspec(dllexport) 260 | #else 261 | #define BROTLI_ENC_API __declspec(dllimport) 262 | #endif /* BROTLIENC_SHARED_COMPILATION */ 263 | #else /* _WIN32 */ 264 | #define BROTLI_COMMON_API BROTLI_PUBLIC 265 | #define BROTLI_DEC_API BROTLI_PUBLIC 266 | #define BROTLI_ENC_API BROTLI_PUBLIC 267 | #endif /* _WIN32 */ 268 | #else /* BROTLI_SHARED_COMPILATION */ 269 | #define BROTLI_COMMON_API 270 | #define BROTLI_DEC_API 271 | #define BROTLI_ENC_API 272 | #endif 273 | 274 | #endif /* BROTLI_COMMON_PORT_H_ */ 275 | -------------------------------------------------------------------------------- /ota_converter/include/brotli/types.h: -------------------------------------------------------------------------------- 1 | /* Copyright 2013 Google Inc. All Rights Reserved. 2 | 3 | Distributed under MIT license. 4 | See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 | */ 6 | 7 | /** 8 | * @file 9 | * Common types used in decoder and encoder API. 10 | */ 11 | 12 | #ifndef BROTLI_COMMON_TYPES_H_ 13 | #define BROTLI_COMMON_TYPES_H_ 14 | 15 | #include /* for size_t */ 16 | 17 | #if defined(_MSC_VER) && (_MSC_VER < 1600) 18 | typedef __int8 int8_t; 19 | typedef unsigned __int8 uint8_t; 20 | typedef __int16 int16_t; 21 | typedef unsigned __int16 uint16_t; 22 | typedef __int32 int32_t; 23 | typedef unsigned __int32 uint32_t; 24 | typedef unsigned __int64 uint64_t; 25 | typedef __int64 int64_t; 26 | #else 27 | #include 28 | #endif /* defined(_MSC_VER) && (_MSC_VER < 1600) */ 29 | 30 | /** 31 | * A portable @c bool replacement. 32 | * 33 | * ::BROTLI_BOOL is a "documentation" type: actually it is @c int, but in API it 34 | * denotes a type, whose only values are ::BROTLI_TRUE and ::BROTLI_FALSE. 35 | * 36 | * ::BROTLI_BOOL values passed to Brotli should either be ::BROTLI_TRUE or 37 | * ::BROTLI_FALSE, or be a result of ::TO_BROTLI_BOOL macros. 38 | * 39 | * ::BROTLI_BOOL values returned by Brotli should not be tested for equality 40 | * with @c true, @c false, ::BROTLI_TRUE, ::BROTLI_FALSE, but rather should be 41 | * evaluated, for example: @code{.cpp} 42 | * if (SomeBrotliFunction(encoder, BROTLI_TRUE) && 43 | * !OtherBrotliFunction(decoder, BROTLI_FALSE)) { 44 | * bool x = !!YetAnotherBrotliFunction(encoder, TO_BROLTI_BOOL(2 * 2 == 4)); 45 | * DoSomething(x); 46 | * } 47 | * @endcode 48 | */ 49 | #define BROTLI_BOOL int 50 | /** Portable @c true replacement. */ 51 | #define BROTLI_TRUE 1 52 | /** Portable @c false replacement. */ 53 | #define BROTLI_FALSE 0 54 | /** @c bool to ::BROTLI_BOOL conversion macros. */ 55 | #define TO_BROTLI_BOOL(X) (!!(X) ? BROTLI_TRUE : BROTLI_FALSE) 56 | 57 | #define BROTLI_MAKE_UINT64_T(high, low) ((((uint64_t)(high)) << 32) | low) 58 | 59 | #define BROTLI_UINT32_MAX (~((uint32_t)0)) 60 | #define BROTLI_SIZE_MAX (~((size_t)0)) 61 | 62 | /** 63 | * Allocating function pointer type. 64 | * 65 | * @param opaque custom memory manager handle provided by client 66 | * @param size requested memory region size; can not be @c 0 67 | * @returns @c 0 in the case of failure 68 | * @returns a valid pointer to a memory region of at least @p size bytes 69 | * long otherwise 70 | */ 71 | typedef void* (*brotli_alloc_func)(void* opaque, size_t size); 72 | 73 | /** 74 | * Deallocating function pointer type. 75 | * 76 | * This function @b SHOULD do nothing if @p address is @c 0. 77 | * 78 | * @param opaque custom memory manager handle provided by client 79 | * @param address memory region pointer returned by ::brotli_alloc_func, or @c 0 80 | */ 81 | typedef void (*brotli_free_func)(void* opaque, void* address); 82 | 83 | #endif /* BROTLI_COMMON_TYPES_H_ */ 84 | -------------------------------------------------------------------------------- /ota_converter/lib/libbrotlicommon-static.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntiger1024/android_image_tools/143bb84c52bb767269ca4887478746c9db98a6a3/ota_converter/lib/libbrotlicommon-static.a -------------------------------------------------------------------------------- /ota_converter/lib/libbrotlidec-static.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ntiger1024/android_image_tools/143bb84c52bb767269ca4887478746c9db98a6a3/ota_converter/lib/libbrotlidec-static.a -------------------------------------------------------------------------------- /ota_converter/ota_converter.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | using namespace std; 19 | 20 | const int kBlockSize = 4096; 21 | const char kZeroBlock[kBlockSize] = {0}; 22 | 23 | ////////////////// LOG ////////////////// 24 | enum { 25 | LOG_FATAL, 26 | LOG_ERROR, 27 | LOG_WARN, 28 | LOG_INFO, 29 | LOG_DEBUG, 30 | LOG_VERBOSE, 31 | LOG_DEFAULT = LOG_ERROR, 32 | }; 33 | 34 | #define pr_msg(...) fprintf(stderr, __VA_ARGS__) 35 | #define pr_err(...) \ 36 | do { \ 37 | if (LOG_ERROR <= gLogLevel) { \ 38 | pr_msg(__VA_ARGS__); \ 39 | } \ 40 | } while (0) 41 | 42 | #define pr_dbg(...) \ 43 | do { \ 44 | if (LOG_DEBUG <= gLogLevel) { \ 45 | pr_msg(__VA_ARGS__); \ 46 | } \ 47 | } while (0) 48 | 49 | #ifdef LOG_LEVEL 50 | static int gLogLevel = LOG_LEVEL; 51 | #else 52 | static int gLogLevel = LOG_DEFAULT; 53 | #endif 54 | //////////////// END LOG ////////////////// 55 | 56 | static int erase(int fd, vector *ranges) { 57 | for (size_t i = 0; i < ranges->size(); i += 2) { 58 | size_t begin = (*ranges)[i]; 59 | size_t end = (*ranges)[i + 1]; 60 | size_t blocks[2]; 61 | blocks[0] = begin * kBlockSize; 62 | blocks[1] = (end - begin) * kBlockSize; 63 | if (ioctl(fd, BLKDISCARD, &blocks) == -1) { 64 | pr_err("BLKDISCARD ioctl failed: %s\n", strerror(errno)); 65 | return -1; 66 | } 67 | } 68 | return 0; 69 | } 70 | 71 | static int zeroize(int fd, vector *ranges) { 72 | for (size_t i = 0; i < ranges->size(); i += 2) { 73 | size_t begin = (*ranges)[i]; 74 | size_t end = (*ranges)[i + 1]; 75 | size_t offset = begin * kBlockSize; 76 | if (lseek64(fd, offset, SEEK_SET) == -1) { 77 | pr_err("Failed to seek to 0x%lx\n", offset); 78 | return -1; 79 | } 80 | for (size_t j = begin; j < end; ++j) { 81 | if (write(fd, kZeroBlock, sizeof(kZeroBlock)) != sizeof(kZeroBlock)) { 82 | pr_err("Failed to write block %ld\n", j); 83 | return -1; 84 | } 85 | } 86 | } 87 | return 0; 88 | } 89 | 90 | shared_ptr> parse_args(string &args) { 91 | string::size_type pos = 0; 92 | string::size_type next; 93 | shared_ptr> ret; 94 | 95 | if ((next = args.find(',', pos)) == string::npos) { 96 | pr_err("Too few args: %s\n", args.c_str()); 97 | return ret; 98 | } 99 | int num = stoi(args.substr(pos, next)); 100 | if (num == 0 || num % 2 == 1) { 101 | pr_err("Invalid num: %d\n", num); 102 | return ret; 103 | } 104 | // pr_dbg("num: %d\n", num); 105 | 106 | ret.reset(new vector); 107 | pos = next + 1; 108 | for (auto i = 0; i < num; ++i) { 109 | next = args.find(',', pos); 110 | if (next == string::npos) { 111 | if (i == num - 1) { 112 | ret->push_back(stoi(args.substr(pos))); 113 | } else { 114 | pr_err("Not enough args: %ld\n", ret->size()); 115 | return shared_ptr>(); 116 | } 117 | } else { 118 | ret->push_back(stoi(args.substr(pos, next))); 119 | pos = next + 1; 120 | } 121 | } 122 | return ret; 123 | } 124 | 125 | int get_max_block(ifstream &ifs) { 126 | int max_block = -1; 127 | // auto saved_pos = ifs.tellg(); 128 | string line; 129 | while (getline(ifs, line)) { 130 | stringstream ss(line); 131 | string cmd, args; 132 | ss >> cmd >> args; 133 | if (!ss) { 134 | pr_err("Failed to parse line: %s\n", line.c_str()); 135 | goto out; 136 | } 137 | // pr_dbg("%s %s\n", cmd.c_str(), args.c_str()); 138 | 139 | shared_ptr> ranges = parse_args(args); 140 | for (auto it = ranges->begin(); it != ranges->end(); ++it) { 141 | if (*it > max_block) { 142 | max_block = *it; 143 | } 144 | } 145 | } 146 | 147 | out: 148 | // if (! ifs.seekg(saved_pos)) { 149 | // pr_err("Can't restore position\n"); 150 | // max_block = -1; 151 | // } 152 | return max_block; 153 | } 154 | 155 | shared_ptr create_image_loop(const char *image_fn, int blocks) { 156 | // Create image file 157 | int fd = 158 | open(image_fn, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 159 | if (fd == -1) { 160 | pr_err("Failed to open image file: %s\n", image_fn); 161 | return shared_ptr(); 162 | } 163 | unsigned long size_in_bytes = (unsigned long)blocks * kBlockSize; 164 | if (ftruncate(fd, size_in_bytes) == -1) { 165 | pr_err("Failed to truncate file %ld\n", size_in_bytes); 166 | close(fd); 167 | return shared_ptr(); 168 | } 169 | 170 | #ifndef SET_LOOP_DEV 171 | close(fd); 172 | return make_shared(image_fn); 173 | 174 | #else // SET_LOOP_DEV 175 | // Attach to a loop device 176 | int lcfd = open("/dev/loop-control", O_RDONLY); 177 | if (lcfd == -1) { 178 | pr_err("Failed to open loop control: %s\n", strerror(errno)); 179 | close(fd); 180 | return shared_ptr(); 181 | } 182 | long devnr = ioctl(lcfd, LOOP_CTL_GET_FREE); 183 | if (devnr == -1) { 184 | pr_err("Can't find free loop device: %s\n", strerror(errno)); 185 | close(fd); 186 | close(lcfd); 187 | return shared_ptr(); 188 | } 189 | char loop_name[256]; 190 | snprintf(loop_name, sizeof(loop_name), "/dev/loop%ld", devnr); 191 | int lfd = open(loop_name, O_RDWR); 192 | if (lfd == -1) { 193 | pr_err("Failed to open loop device: %s %s\n", loop_name, strerror(errno)); 194 | close(fd); 195 | close(lcfd); 196 | return shared_ptr(); 197 | } 198 | if (ioctl(lfd, LOOP_SET_FD, fd) == -1) { 199 | pr_err("Can't set loop device: %s %s\n", loop_name, strerror(errno)); 200 | close(fd); 201 | close(lcfd); 202 | close(lfd); 203 | return shared_ptr(); 204 | } 205 | 206 | close(fd); 207 | close(lcfd); 208 | close(lfd); 209 | return make_shared(loop_name); 210 | #endif 211 | } 212 | 213 | int detech_image_loop(const char *loop_dev) { 214 | #ifdef SET_LOOP_DEV 215 | int lfd = open(loop_dev, O_RDWR); 216 | if (lfd == -1) { 217 | pr_err("Can't open loop device %s: %s\n", loop_dev, strerror(errno)); 218 | return -1; 219 | } 220 | 221 | if (ioctl(lfd, LOOP_CLR_FD) == -1) { 222 | pr_err("Failed to detech loop device %s %s\n", loop_dev, strerror(errno)); 223 | return -1; 224 | } 225 | #endif 226 | 227 | return 0; 228 | } 229 | 230 | struct cookie { 231 | int dfd; 232 | uint8_t in_buf[kBlockSize]; 233 | size_t in_available; 234 | const uint8_t *next_in; 235 | 236 | uint8_t out_buf[kBlockSize]; 237 | size_t out_available; 238 | uint8_t *next_out; 239 | }; 240 | 241 | int copy_data(struct cookie *cookie, int tfd, vector *ranges, 242 | BrotliDecoderState *state) { 243 | for (size_t i = 0; i < ranges->size(); i += 2) { 244 | size_t begin = (*ranges)[i]; 245 | size_t end = (*ranges)[i + 1]; 246 | size_t size = (end - begin) * kBlockSize; 247 | // pr_dbg("copy_data %ld %ld\n", begin, end); 248 | 249 | if (lseek64(tfd, begin * kBlockSize, SEEK_SET) == -1) { 250 | pr_err("Can't seek to %ld\n", begin * kBlockSize); 251 | return -1; 252 | } 253 | 254 | while (1) { 255 | // For brotli compressed data. 256 | if (state) { 257 | if (cookie->out_available == 0) { 258 | int count; 259 | if ((count = write(tfd, cookie->out_buf, sizeof(cookie->out_buf))) != 260 | sizeof(cookie->out_buf)) { 261 | pr_err("Can't write data %ld %ld %d/%d: %s\n", begin, 262 | begin * kBlockSize, count, kBlockSize, strerror(errno)); 263 | return -1; 264 | } 265 | cookie->next_out = cookie->out_buf; 266 | cookie->out_available = sizeof(cookie->out_buf); 267 | 268 | size -= sizeof(cookie->out_buf); 269 | if (size == 0) { 270 | break; 271 | } 272 | } 273 | if (cookie->in_available == 0) { 274 | cookie->in_available = 275 | read(cookie->dfd, cookie->in_buf, sizeof(cookie->in_buf)); 276 | if (cookie->in_available < 0) { 277 | if (!BrotliDecoderHasMoreOutput(state)) { 278 | pr_err("Can't read data\n"); 279 | return -1; 280 | } else { 281 | cookie->in_available = 0; 282 | } 283 | } 284 | cookie->next_in = cookie->in_buf; 285 | } 286 | BrotliDecoderResult result = BrotliDecoderDecompressStream( 287 | state, &cookie->in_available, &cookie->next_in, 288 | &cookie->out_available, &cookie->next_out, nullptr); 289 | if (result == BROTLI_DECODER_RESULT_ERROR) { 290 | pr_err("Decompression failed with %s\n", 291 | BrotliDecoderErrorString(BrotliDecoderGetErrorCode(state))); 292 | return -1; 293 | } 294 | } else { 295 | // For uncompressed data. 296 | int count; 297 | if ((count = read(cookie->dfd, cookie->in_buf, 298 | sizeof(cookie->in_buf))) < 0) { 299 | pr_err("Can't read data\n"); 300 | return -1; 301 | } 302 | if (write(tfd, cookie->in_buf, count) != count) { 303 | pr_err("Can't write data %ld %ld %d/%d: %s\n", begin, 304 | begin * kBlockSize, count, kBlockSize, strerror(errno)); 305 | return -1; 306 | } 307 | size -= count; 308 | if (size == 0) { 309 | break; 310 | } 311 | } 312 | } 313 | } 314 | return 0; 315 | } 316 | 317 | int transfer(ifstream &ifs, const char *data_file, const char *target_dev) { 318 | int ret = -1; 319 | int fd = open(target_dev, O_WRONLY); 320 | if (fd == -1) { 321 | pr_err("Can't open %s for write\n", target_dev); 322 | return -1; 323 | } 324 | 325 | string filename(data_file); 326 | bool br_compressed = true; 327 | if (filename.find(".br", filename.size() - 3) == string::npos) { 328 | br_compressed = false; 329 | } 330 | int dfd = open(data_file, O_RDONLY); 331 | if (dfd == -1) { 332 | pr_err("Can't open %s for read\n", data_file); 333 | close(fd); 334 | return -1; 335 | } 336 | 337 | BrotliDecoderState *state = nullptr; 338 | struct cookie cookie; 339 | if (br_compressed) { 340 | state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr); 341 | if (!state) { 342 | pr_err("Can't create brotli decoder\n"); 343 | close(fd); 344 | close(dfd); 345 | return -1; 346 | } 347 | } 348 | cookie.dfd = dfd; 349 | cookie.in_available = 0; 350 | cookie.next_in = cookie.in_buf; 351 | cookie.out_available = sizeof(cookie.out_buf); 352 | cookie.next_out = cookie.out_buf; 353 | 354 | string line; 355 | string cmd, args; 356 | while (getline(ifs, line)) { 357 | stringstream ss(line); 358 | ss >> cmd >> args; 359 | if (!ss) { 360 | pr_err("Invalid line: %s\n", line.c_str()); 361 | goto out; 362 | } 363 | auto ranges = parse_args(args); 364 | if (!ranges) { 365 | pr_err("Failed to parse args: %s\n", args.c_str()); 366 | goto out; 367 | } 368 | 369 | if (strcmp(cmd.c_str(), "erase") == 0) { 370 | pr_dbg("erase %s\n", args.c_str()); 371 | } else if (strcmp(cmd.c_str(), "zero") == 0) { 372 | pr_dbg("zero %s\n", args.c_str()); 373 | if (zeroize(fd, ranges.get())) { 374 | pr_err("failed to zeroize\n"); 375 | goto out; 376 | } 377 | } else if (strcmp(cmd.c_str(), "new") == 0) { 378 | pr_dbg("new %s\n", args.c_str()); 379 | if (copy_data(&cookie, fd, ranges.get(), state)) { 380 | pr_err("failed to copy data\n"); 381 | goto out; 382 | } 383 | } else { 384 | pr_err("Unsupported command: %s\n", cmd.c_str()); 385 | goto out; 386 | } 387 | } 388 | 389 | ret = 0; 390 | 391 | out: 392 | BrotliDecoderDestroyInstance(state); 393 | close(dfd); 394 | close(fd); 395 | return ret; 396 | } 397 | 398 | int main(int argc, char **argv) { 399 | int ret = 0; 400 | 401 | if (argc != 4) { 402 | pr_err("usage: %s transfer.list new.dat[.br] image_file\n", argv[0]); 403 | return 1; 404 | } 405 | 406 | ifstream ifs(argv[1]); 407 | if (!ifs) { 408 | pr_err("Failed to open %s\n", argv[1]); 409 | return 1; 410 | } 411 | 412 | // first line 413 | string version_str; 414 | if (!getline(ifs, version_str)) { 415 | pr_err("Failed to read version line\n"); 416 | return 1; 417 | } 418 | int version = stoi(version_str); 419 | if (version != 3 && version != 4) { 420 | pr_err("Unsupported version: %d\n", version); 421 | return 1; 422 | } 423 | printf("Version: %d\n", version); 424 | 425 | // second line 426 | string blocks_str; 427 | if (!getline(ifs, blocks_str)) { 428 | pr_err("Failed to read block line\n"); 429 | return 1; 430 | } 431 | int blocks = stoi(blocks_str); 432 | if (blocks <= 0) { 433 | pr_err("Invalid blocks: %d\n", blocks); 434 | return 1; 435 | } 436 | 437 | // ignore 3rd and 4th lines 438 | string unused; 439 | if (!getline(ifs, unused) || !getline(ifs, unused)) { 440 | pr_err("Failed to read 3rd and 4th lines\n"); 441 | return 1; 442 | } 443 | 444 | int max_block = get_max_block(ifs); 445 | if (max_block < blocks) { 446 | pr_err("Invalid max block: %d\n", max_block); 447 | return 1; 448 | } 449 | printf("Max block: %d\n", max_block); 450 | // Restore state 451 | ifs.close(); 452 | ifs.open(argv[1]); 453 | for (int i = 0; i < 4; ++i) { 454 | getline(ifs, unused); 455 | } 456 | if (!ifs) { 457 | pr_err("Can't restore file state\n"); 458 | return 1; 459 | } 460 | 461 | // Create file with max block. 462 | shared_ptr image_loop_dev = create_image_loop(argv[3], max_block); 463 | if (!image_loop_dev) { 464 | pr_err("Failed to create image loop device\n"); 465 | return 1; 466 | } 467 | printf("Create image loop device %s\n", image_loop_dev->c_str()); 468 | 469 | // Transfer data. 470 | if (transfer(ifs, argv[2], image_loop_dev->c_str()) == -1) { 471 | pr_err("Failed to transfer data\n"); 472 | ret = 1; 473 | goto out; 474 | } 475 | 476 | out: 477 | // Detech loop device 478 | if (detech_image_loop(image_loop_dev->c_str()) == -1) { 479 | pr_err("Failed to detech loop device: %s\n", image_loop_dev->c_str()); 480 | ret = 1; 481 | } else { 482 | printf("Deteched image loop device %s\n", image_loop_dev->c_str()); 483 | } 484 | 485 | return ret; 486 | } 487 | -------------------------------------------------------------------------------- /ota_converter/ota_converter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Convert system/vendor data in ota package update.zip to image data 4 | # in system/vendor.img 5 | # 6 | # Usage: python3 ota_converter.py xx.transfer.list xx.new.dat.br xx.img 7 | # 8 | # TODO: handle exceptions 9 | 10 | import brotli 11 | import logging 12 | import sys 13 | 14 | BLOCK_SIZE = 4096 15 | BUF_SIZE = BLOCK_SIZE * 1024 16 | ZERO_BLOCK = b'\x00' * BLOCK_SIZE 17 | 18 | 19 | def cmd_erase(file, ranges): 20 | '''Erase command. 21 | 22 | This command is for ssd so we don't use it. 23 | ''' 24 | 25 | pass 26 | 27 | 28 | def cmd_zero(file, ranges): 29 | '''Zeroize those blocks in #ranges.''' 30 | 31 | for begin, end in ranges: 32 | file.seek(begin * BLOCK_SIZE, 0) 33 | while begin != end: 34 | file.write(ZERO_BLOCK) 35 | begin = begin + 1 36 | 37 | 38 | def cmd_new(file, ranges, data_file, dec, cookie): 39 | '''Decompress and write data.''' 40 | 41 | for begin, end in ranges: 42 | #logging.debug('new: {}'.format(begin)) 43 | begin_byte = begin * BLOCK_SIZE 44 | end_byte = end * BLOCK_SIZE 45 | file.seek(begin_byte, 0) 46 | while begin_byte != end_byte: 47 | # logging.debug('begin_byte: {}, end_byte: {}'.format( 48 | # begin_byte, end_byte)) 49 | space = end_byte - begin_byte 50 | if dec: 51 | if cookie[0]: 52 | output = cookie[0] 53 | else: 54 | data = data_file.read(BUF_SIZE) 55 | output = dec.process(data) 56 | 57 | if space > BUF_SIZE: 58 | space = BUF_SIZE 59 | if len(output) > space: 60 | cookie[0] = output[space:] 61 | output = output[:space] 62 | else: 63 | cookie[0] = None 64 | else: 65 | if space > BUF_SIZE: 66 | space = BUF_SIZE 67 | output = data_file.read(space) 68 | 69 | if output: 70 | file.write(output) 71 | begin_byte = begin_byte + len(output) 72 | 73 | 74 | def parse_ranges(args): 75 | '''Parse args to a set of (begin, end) ranges.''' 76 | 77 | tokens = args.split(',') 78 | if len(tokens) % 2 != 1: 79 | logging.error('Invalid args: ' + args) 80 | return None 81 | 82 | try: 83 | num = int(tokens[0]) 84 | except ValueError: 85 | logging.error('Invalid number {}'.format(tokens[0])) 86 | return None 87 | if num != len(tokens) - 1: 88 | logging.error('Invalid number {}'.format(tokens[0])) 89 | return None 90 | ret = [] 91 | for i in range(1, len(tokens), 2): 92 | try: 93 | begin = int(tokens[i]) 94 | end = int(tokens[i+1]) 95 | ret.append((begin, end)) 96 | except ValueError: 97 | logging.error('Invalid range number: {}, {}'.format( 98 | tokens[i], tokens[i+1])) 99 | return None 100 | return ret 101 | 102 | 103 | def get_max_block(file): 104 | max_block = 0 105 | saved_pos = file.tell() 106 | for line in file.readlines(): 107 | tokens = line.split() 108 | if len(tokens) != 2: 109 | logging.error('Invalid line: ' + line) 110 | return max_block 111 | args = tokens[1] 112 | ranges = parse_ranges(args) 113 | for range in ranges: 114 | if range[1] > max_block: 115 | max_block = range[1] 116 | file.seek(saved_pos) 117 | return max_block 118 | 119 | 120 | def create_image(file_name, blocks): 121 | '''Create target image file.''' 122 | 123 | file = open(file_name, 'wb') 124 | file.truncate(blocks * BLOCK_SIZE) 125 | file.close() 126 | 127 | 128 | def transfer(file, dat_fn, img_fn): 129 | '''Transfer data.''' 130 | 131 | br_compressed = True if dat_fn.endswith('.br') else False 132 | 133 | dec = brotli.Decompressor() if br_compressed else None 134 | dat_f = open(dat_fn, 'rb') 135 | img_f = open(img_fn, 'wb') 136 | cookie = [None] 137 | 138 | for line in file.readlines(): 139 | logging.info(line) 140 | tokens = line.split() 141 | if len(tokens) != 2: 142 | logging.error('Invalid line: ' + line) 143 | return False 144 | cmd = tokens[0] 145 | ranges = parse_ranges(tokens[1]) 146 | if cmd == 'erase': 147 | cmd_erase(img_f, ranges) 148 | elif cmd == 'zero': 149 | cmd_zero(img_f, ranges) 150 | elif cmd == 'new': 151 | cmd_new(img_f, ranges, dat_f, dec, cookie) 152 | else: 153 | logging.error('Invalid cmd: ' + cmd) 154 | return False 155 | return True 156 | 157 | 158 | def main(): 159 | if len(sys.argv) != 4: 160 | logging.error( 161 | 'usage: {} xxx.transfer.list xxx.new.dat[.br] xxx.img'.format(sys.argv[0])) 162 | sys.exit(1) 163 | 164 | logging.basicConfig(level=logging.INFO) 165 | file = open(sys.argv[1], 'r') 166 | version = int(file.readline()) 167 | print('[*] version: {}'.format(version)) 168 | 169 | block = int(file.readline()) 170 | file.readline() 171 | file.readline() 172 | max_block = get_max_block(file) 173 | if max_block < block: 174 | logging.error('Invalid max block: {}'.format(max_block)) 175 | sys.exit(1) 176 | 177 | print('[*] blocks: {}'.format(max_block)) 178 | create_image(sys.argv[3], max_block) 179 | 180 | print('[*] transfering...') 181 | if not transfer(file, sys.argv[2], sys.argv[3]): 182 | sys.exit(1) 183 | 184 | print('[*] done') 185 | sys.exit(0) 186 | 187 | 188 | if __name__ == '__main__': 189 | main() 190 | -------------------------------------------------------------------------------- /ozip_cracker/README.md: -------------------------------------------------------------------------------- 1 | # Ozip Cracker 2 | 3 | Ozip cracker is a brute force tool to find ozip aes keys of oppo devices. 4 | 5 | ## What is it? 6 | 7 | Oppo devices' ROM packages is not normal zip file format but a customed file 8 | format called 'ozip'. The ozip file is created like this: 9 | 10 | ``` 11 | xx.ozip 12 | +--------------+ 13 | xx.zip | 0x1050 header| 14 | +-------------+ encrypt +--------------+ 15 | | 0x10 B | ===> | 0x10 B | 16 | +-------------+ +--------------+ 17 | | | copy | | 18 | | 0x4000 B | ===> | 0x4000 B | 19 | | | | | 20 | +-------------+ encrypt +--------------| 21 | | 0x10 B | ===> | 0x10 B | 22 | +-------------+ +--------------+ 23 | | | copy | | 24 | | 0x4000 B | ===> | 0x4000 B | 25 | | | | | 26 | +-------------+ +--------------+ 27 | ... ===> ... 28 | ``` 29 | 30 | Sometimes I want to unpack ozip file to check something. So I must find the way 31 | to decrypt the ozip file. There are already some tools to decrypt them. But they 32 | don't support newer devices like R17, Reno, etc. After google I get this 33 | [artical](https://bkerler.github.io/reversing/2019/04/24/the-game-begins/). 34 | From it I know that: 35 | 36 | 1. The encrytion algorithm is AES-128-ECB 37 | 2. The key is stored in `/vendor/lib64/libapplypatch_jni.so` as plaintext. 38 | 39 | So, brute force may be a better way to get the key than reverse engineering... 40 | 41 | 42 | ## Usage 43 | 44 | To find the key of an ozip file, you have to get the `libapplypatch_jni.so` from 45 | its corresponding device. For example, if you have an Oppo FindX device and its 46 | ozip file `PAFM00_11_OTA_0300_all_rqjUlPT7h9J9.ozip`. Now you want to find its 47 | ozip key. You can do this: 48 | 49 | ``` 50 | $ adb pull /vendor/lib64/libapplypatch_jni.so ./ 51 | $ ./ozip_cracker PAFM00_11_OTA_0300_all_rqjUlPT7h9J9.ozip libapplypatch_jni.so 52 | d4d2cd61d4afdce13b5e01221bd14d20 53 | ``` 54 | 55 | When you get the key, you can decrypt ozip files using which tools you like. 56 | Here I use this tool: [`oppo_ozip_decrypt`](https://github.com/ntiger1024/oppo_ozip_decrypt). 57 | 58 | ``` 59 | $ python ozipdecrypt.py PBDM00_11_A.17_OTA_0170_all_201901072337.ozip d4d2cd61d4afdce13b5e01221bd14d20 60 | ozipdecrypt 0.5 (c) B.Kerler 2017-2019 61 | using your key: d4d2cd61d4afdce13b5e01221bd14d20 62 | Decrypting... 63 | DONE!! 64 | ``` 65 | -------------------------------------------------------------------------------- /ozip_cracker/ozip_cracker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | '''Brute force ozip aes key. 3 | ''' 4 | 5 | import binascii 6 | import os 7 | import sys 8 | from Crypto.Cipher import AES 9 | 10 | 11 | def main(): 12 | '''Main function. 13 | ''' 14 | if len(sys.argv) != 3: 15 | print('Usage: {} update.ozip libapplypatch_jni.so'.format(sys.argv[0])) 16 | sys.exit(1) 17 | 18 | ozip_file = open(sys.argv[1], 'rb') 19 | key_file = open(sys.argv[2], 'rb') 20 | 21 | ozip_file.seek(0x1050, 0) 22 | test_data = ozip_file.read(16) 23 | 24 | key_file_size = os.path.getsize(sys.argv[2]) 25 | pos = 0 26 | while pos < key_file_size - 16: 27 | key_file.seek(pos, 0) 28 | key = key_file.read(16) 29 | pos = pos + 4 30 | 31 | aes = AES.new(key, AES.MODE_ECB) 32 | plain = aes.decrypt(test_data) 33 | if plain[0:4] == b'\x50\x4B\x03\x04': 34 | print(binascii.hexlify(key).decode()) 35 | 36 | 37 | if __name__ == '__main__': 38 | main() 39 | -------------------------------------------------------------------------------- /print_qcom_image_info/.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.img 3 | qcert 4 | -------------------------------------------------------------------------------- /print_qcom_image_info/Makefile: -------------------------------------------------------------------------------- 1 | UNAME := $(shell uname) 2 | src := qcert.cc 3 | flags := -Iinclude -lcrypto -DDEBUG 4 | ifeq ($(UNAME), Darwin) 5 | flags += -L/usr/local/opt/openssl/lib -I/usr/local/opt/openssl/include 6 | endif 7 | 8 | qcert : $(src) 9 | g++ -o qcert $(src) -std=c++11 $(flags) 10 | 11 | run: qcert 12 | ./qcert xbl.img 13 | 14 | .PHONY: clean 15 | clean: 16 | rm qcert 17 | -------------------------------------------------------------------------------- /print_qcom_image_info/README: -------------------------------------------------------------------------------- 1 | Print information of Qcom secureboot relative images. 2 | -------------------------------------------------------------------------------- /print_qcom_image_info/include/sys/elf32.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 | * 4 | * Copyright (c) 1996-1998 John D. Polstra. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | * 28 | * $FreeBSD$ 29 | */ 30 | 31 | #ifndef _SYS_ELF32_H_ 32 | #define _SYS_ELF32_H_ 1 33 | 34 | #include "elf_common.h" 35 | 36 | /* 37 | * ELF definitions common to all 32-bit architectures. 38 | */ 39 | 40 | typedef uint32_t Elf32_Addr; 41 | typedef uint16_t Elf32_Half; 42 | typedef uint32_t Elf32_Off; 43 | typedef int32_t Elf32_Sword; 44 | typedef uint32_t Elf32_Word; 45 | typedef uint64_t Elf32_Lword; 46 | 47 | typedef Elf32_Word Elf32_Hashelt; 48 | 49 | /* Non-standard class-dependent datatype used for abstraction. */ 50 | typedef Elf32_Word Elf32_Size; 51 | typedef Elf32_Sword Elf32_Ssize; 52 | 53 | /* 54 | * ELF header. 55 | */ 56 | 57 | typedef struct { 58 | unsigned char e_ident[EI_NIDENT]; /* File identification. */ 59 | Elf32_Half e_type; /* File type. */ 60 | Elf32_Half e_machine; /* Machine architecture. */ 61 | Elf32_Word e_version; /* ELF format version. */ 62 | Elf32_Addr e_entry; /* Entry point. */ 63 | Elf32_Off e_phoff; /* Program header file offset. */ 64 | Elf32_Off e_shoff; /* Section header file offset. */ 65 | Elf32_Word e_flags; /* Architecture-specific flags. */ 66 | Elf32_Half e_ehsize; /* Size of ELF header in bytes. */ 67 | Elf32_Half e_phentsize; /* Size of program header entry. */ 68 | Elf32_Half e_phnum; /* Number of program header entries. */ 69 | Elf32_Half e_shentsize; /* Size of section header entry. */ 70 | Elf32_Half e_shnum; /* Number of section header entries. */ 71 | Elf32_Half e_shstrndx; /* Section name strings section. */ 72 | } Elf32_Ehdr; 73 | 74 | /* 75 | * Shared object information, found in SHT_MIPS_LIBLIST. 76 | */ 77 | 78 | typedef struct { 79 | Elf32_Word l_name; /* The name of a shared object. */ 80 | Elf32_Word l_time_stamp; /* 32-bit timestamp. */ 81 | Elf32_Word l_checksum; /* Checksum of visible symbols, sizes. */ 82 | Elf32_Word l_version; /* Interface version string index. */ 83 | Elf32_Word l_flags; /* Flags (LL_*). */ 84 | } Elf32_Lib; 85 | 86 | /* 87 | * Section header. 88 | */ 89 | 90 | typedef struct { 91 | Elf32_Word sh_name; /* Section name (index into the 92 | section header string table). */ 93 | Elf32_Word sh_type; /* Section type. */ 94 | Elf32_Word sh_flags; /* Section flags. */ 95 | Elf32_Addr sh_addr; /* Address in memory image. */ 96 | Elf32_Off sh_offset; /* Offset in file. */ 97 | Elf32_Word sh_size; /* Size in bytes. */ 98 | Elf32_Word sh_link; /* Index of a related section. */ 99 | Elf32_Word sh_info; /* Depends on section type. */ 100 | Elf32_Word sh_addralign; /* Alignment in bytes. */ 101 | Elf32_Word sh_entsize; /* Size of each entry in section. */ 102 | } Elf32_Shdr; 103 | 104 | /* 105 | * Program header. 106 | */ 107 | 108 | typedef struct { 109 | Elf32_Word p_type; /* Entry type. */ 110 | Elf32_Off p_offset; /* File offset of contents. */ 111 | Elf32_Addr p_vaddr; /* Virtual address in memory image. */ 112 | Elf32_Addr p_paddr; /* Physical address (not used). */ 113 | Elf32_Word p_filesz; /* Size of contents in file. */ 114 | Elf32_Word p_memsz; /* Size of contents in memory. */ 115 | Elf32_Word p_flags; /* Access permission flags. */ 116 | Elf32_Word p_align; /* Alignment in memory and file. */ 117 | } Elf32_Phdr; 118 | 119 | /* 120 | * Dynamic structure. The ".dynamic" section contains an array of them. 121 | */ 122 | 123 | typedef struct { 124 | Elf32_Sword d_tag; /* Entry type. */ 125 | union { 126 | Elf32_Word d_val; /* Integer value. */ 127 | Elf32_Addr d_ptr; /* Address value. */ 128 | } d_un; 129 | } Elf32_Dyn; 130 | 131 | /* 132 | * Relocation entries. 133 | */ 134 | 135 | /* Relocations that don't need an addend field. */ 136 | typedef struct { 137 | Elf32_Addr r_offset; /* Location to be relocated. */ 138 | Elf32_Word r_info; /* Relocation type and symbol index. */ 139 | } Elf32_Rel; 140 | 141 | /* Relocations that need an addend field. */ 142 | typedef struct { 143 | Elf32_Addr r_offset; /* Location to be relocated. */ 144 | Elf32_Word r_info; /* Relocation type and symbol index. */ 145 | Elf32_Sword r_addend; /* Addend. */ 146 | } Elf32_Rela; 147 | 148 | /* Macros for accessing the fields of r_info. */ 149 | #define ELF32_R_SYM(info) ((info) >> 8) 150 | #define ELF32_R_TYPE(info) ((unsigned char)(info)) 151 | 152 | /* Macro for constructing r_info from field values. */ 153 | #define ELF32_R_INFO(sym, type) (((sym) << 8) + (unsigned char)(type)) 154 | 155 | /* 156 | * Note entry header 157 | */ 158 | typedef Elf_Note Elf32_Nhdr; 159 | 160 | /* 161 | * Move entry 162 | */ 163 | typedef struct { 164 | Elf32_Lword m_value; /* symbol value */ 165 | Elf32_Word m_info; /* size + index */ 166 | Elf32_Word m_poffset; /* symbol offset */ 167 | Elf32_Half m_repeat; /* repeat count */ 168 | Elf32_Half m_stride; /* stride info */ 169 | } Elf32_Move; 170 | 171 | /* 172 | * The macros compose and decompose values for Move.r_info 173 | * 174 | * sym = ELF32_M_SYM(M.m_info) 175 | * size = ELF32_M_SIZE(M.m_info) 176 | * M.m_info = ELF32_M_INFO(sym, size) 177 | */ 178 | #define ELF32_M_SYM(info) ((info) >> 8) 179 | #define ELF32_M_SIZE(info) ((unsigned char)(info)) 180 | #define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size)) 181 | 182 | /* 183 | * Hardware/Software capabilities entry 184 | */ 185 | typedef struct { 186 | Elf32_Word c_tag; /* how to interpret value */ 187 | union { 188 | Elf32_Word c_val; 189 | Elf32_Addr c_ptr; 190 | } c_un; 191 | } Elf32_Cap; 192 | 193 | /* 194 | * Symbol table entries. 195 | */ 196 | 197 | typedef struct { 198 | Elf32_Word st_name; /* String table index of name. */ 199 | Elf32_Addr st_value; /* Symbol value. */ 200 | Elf32_Word st_size; /* Size of associated object. */ 201 | unsigned char st_info; /* Type and binding information. */ 202 | unsigned char st_other; /* Reserved (not used). */ 203 | Elf32_Half st_shndx; /* Section index of symbol. */ 204 | } Elf32_Sym; 205 | 206 | /* Macros for accessing the fields of st_info. */ 207 | #define ELF32_ST_BIND(info) ((info) >> 4) 208 | #define ELF32_ST_TYPE(info) ((info)&0xf) 209 | 210 | /* Macro for constructing st_info from field values. */ 211 | #define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) 212 | 213 | /* Macro for accessing the fields of st_other. */ 214 | #define ELF32_ST_VISIBILITY(oth) ((oth)&0x3) 215 | 216 | /* Structures used by Sun & GNU symbol versioning. */ 217 | typedef struct { 218 | Elf32_Half vd_version; 219 | Elf32_Half vd_flags; 220 | Elf32_Half vd_ndx; 221 | Elf32_Half vd_cnt; 222 | Elf32_Word vd_hash; 223 | Elf32_Word vd_aux; 224 | Elf32_Word vd_next; 225 | } Elf32_Verdef; 226 | 227 | typedef struct { 228 | Elf32_Word vda_name; 229 | Elf32_Word vda_next; 230 | } Elf32_Verdaux; 231 | 232 | typedef struct { 233 | Elf32_Half vn_version; 234 | Elf32_Half vn_cnt; 235 | Elf32_Word vn_file; 236 | Elf32_Word vn_aux; 237 | Elf32_Word vn_next; 238 | } Elf32_Verneed; 239 | 240 | typedef struct { 241 | Elf32_Word vna_hash; 242 | Elf32_Half vna_flags; 243 | Elf32_Half vna_other; 244 | Elf32_Word vna_name; 245 | Elf32_Word vna_next; 246 | } Elf32_Vernaux; 247 | 248 | typedef Elf32_Half Elf32_Versym; 249 | 250 | typedef struct { 251 | Elf32_Half si_boundto; /* direct bindings - symbol bound to */ 252 | Elf32_Half si_flags; /* per symbol flags */ 253 | } Elf32_Syminfo; 254 | 255 | typedef struct { 256 | Elf32_Word ch_type; 257 | Elf32_Word ch_size; 258 | Elf32_Word ch_addralign; 259 | } Elf32_Chdr; 260 | 261 | #endif /* !_SYS_ELF32_H_ */ 262 | -------------------------------------------------------------------------------- /print_qcom_image_info/include/sys/elf64.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 | * 4 | * Copyright (c) 1996-1998 John D. Polstra. 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | * 28 | * $FreeBSD$ 29 | */ 30 | 31 | #ifndef _SYS_ELF64_H_ 32 | #define _SYS_ELF64_H_ 1 33 | 34 | #include 35 | #include "elf_common.h" 36 | 37 | /* 38 | * ELF definitions common to all 64-bit architectures. 39 | */ 40 | 41 | typedef uint64_t Elf64_Addr; 42 | typedef uint16_t Elf64_Half; 43 | typedef uint64_t Elf64_Off; 44 | typedef int32_t Elf64_Sword; 45 | typedef int64_t Elf64_Sxword; 46 | typedef uint32_t Elf64_Word; 47 | typedef uint64_t Elf64_Lword; 48 | typedef uint64_t Elf64_Xword; 49 | 50 | /* 51 | * Types of dynamic symbol hash table bucket and chain elements. 52 | * 53 | * This is inconsistent among 64 bit architectures, so a machine dependent 54 | * typedef is required. 55 | */ 56 | 57 | typedef Elf64_Word Elf64_Hashelt; 58 | 59 | /* Non-standard class-dependent datatype used for abstraction. */ 60 | typedef Elf64_Xword Elf64_Size; 61 | typedef Elf64_Sxword Elf64_Ssize; 62 | 63 | /* 64 | * ELF header. 65 | */ 66 | 67 | typedef struct { 68 | unsigned char e_ident[EI_NIDENT]; /* File identification. */ 69 | Elf64_Half e_type; /* File type. */ 70 | Elf64_Half e_machine; /* Machine architecture. */ 71 | Elf64_Word e_version; /* ELF format version. */ 72 | Elf64_Addr e_entry; /* Entry point. */ 73 | Elf64_Off e_phoff; /* Program header file offset. */ 74 | Elf64_Off e_shoff; /* Section header file offset. */ 75 | Elf64_Word e_flags; /* Architecture-specific flags. */ 76 | Elf64_Half e_ehsize; /* Size of ELF header in bytes. */ 77 | Elf64_Half e_phentsize; /* Size of program header entry. */ 78 | Elf64_Half e_phnum; /* Number of program header entries. */ 79 | Elf64_Half e_shentsize; /* Size of section header entry. */ 80 | Elf64_Half e_shnum; /* Number of section header entries. */ 81 | Elf64_Half e_shstrndx; /* Section name strings section. */ 82 | } Elf64_Ehdr; 83 | 84 | /* 85 | * Shared object information, found in SHT_MIPS_LIBLIST. 86 | */ 87 | 88 | typedef struct { 89 | Elf64_Word l_name; /* The name of a shared object. */ 90 | Elf64_Word l_time_stamp; /* 64-bit timestamp. */ 91 | Elf64_Word l_checksum; /* Checksum of visible symbols, sizes. */ 92 | Elf64_Word l_version; /* Interface version string index. */ 93 | Elf64_Word l_flags; /* Flags (LL_*). */ 94 | } Elf64_Lib; 95 | 96 | /* 97 | * Section header. 98 | */ 99 | 100 | typedef struct { 101 | Elf64_Word sh_name; /* Section name (index into the 102 | section header string table). */ 103 | Elf64_Word sh_type; /* Section type. */ 104 | Elf64_Xword sh_flags; /* Section flags. */ 105 | Elf64_Addr sh_addr; /* Address in memory image. */ 106 | Elf64_Off sh_offset; /* Offset in file. */ 107 | Elf64_Xword sh_size; /* Size in bytes. */ 108 | Elf64_Word sh_link; /* Index of a related section. */ 109 | Elf64_Word sh_info; /* Depends on section type. */ 110 | Elf64_Xword sh_addralign; /* Alignment in bytes. */ 111 | Elf64_Xword sh_entsize; /* Size of each entry in section. */ 112 | } Elf64_Shdr; 113 | 114 | /* 115 | * Program header. 116 | */ 117 | 118 | typedef struct { 119 | Elf64_Word p_type; /* Entry type. */ 120 | Elf64_Word p_flags; /* Access permission flags. */ 121 | Elf64_Off p_offset; /* File offset of contents. */ 122 | Elf64_Addr p_vaddr; /* Virtual address in memory image. */ 123 | Elf64_Addr p_paddr; /* Physical address (not used). */ 124 | Elf64_Xword p_filesz; /* Size of contents in file. */ 125 | Elf64_Xword p_memsz; /* Size of contents in memory. */ 126 | Elf64_Xword p_align; /* Alignment in memory and file. */ 127 | } Elf64_Phdr; 128 | 129 | /* 130 | * Dynamic structure. The ".dynamic" section contains an array of them. 131 | */ 132 | 133 | typedef struct { 134 | Elf64_Sxword d_tag; /* Entry type. */ 135 | union { 136 | Elf64_Xword d_val; /* Integer value. */ 137 | Elf64_Addr d_ptr; /* Address value. */ 138 | } d_un; 139 | } Elf64_Dyn; 140 | 141 | /* 142 | * Relocation entries. 143 | */ 144 | 145 | /* Relocations that don't need an addend field. */ 146 | typedef struct { 147 | Elf64_Addr r_offset; /* Location to be relocated. */ 148 | Elf64_Xword r_info; /* Relocation type and symbol index. */ 149 | } Elf64_Rel; 150 | 151 | /* Relocations that need an addend field. */ 152 | typedef struct { 153 | Elf64_Addr r_offset; /* Location to be relocated. */ 154 | Elf64_Xword r_info; /* Relocation type and symbol index. */ 155 | Elf64_Sxword r_addend; /* Addend. */ 156 | } Elf64_Rela; 157 | 158 | /* Macros for accessing the fields of r_info. */ 159 | #define ELF64_R_SYM(info) ((info) >> 32) 160 | #define ELF64_R_TYPE(info) ((info)&0xffffffffL) 161 | 162 | /* Macro for constructing r_info from field values. */ 163 | #define ELF64_R_INFO(sym, type) (((sym) << 32) + ((type)&0xffffffffL)) 164 | 165 | #define ELF64_R_TYPE_DATA(info) (((Elf64_Xword)(info) << 32) >> 40) 166 | #define ELF64_R_TYPE_ID(info) (((Elf64_Xword)(info) << 56) >> 56) 167 | #define ELF64_R_TYPE_INFO(data, type) \ 168 | (((Elf64_Xword)(data) << 8) + (Elf64_Xword)(type)) 169 | 170 | /* 171 | * Note entry header 172 | */ 173 | typedef Elf_Note Elf64_Nhdr; 174 | 175 | /* 176 | * Move entry 177 | */ 178 | typedef struct { 179 | Elf64_Lword m_value; /* symbol value */ 180 | Elf64_Xword m_info; /* size + index */ 181 | Elf64_Xword m_poffset; /* symbol offset */ 182 | Elf64_Half m_repeat; /* repeat count */ 183 | Elf64_Half m_stride; /* stride info */ 184 | } Elf64_Move; 185 | 186 | #define ELF64_M_SYM(info) ((info) >> 8) 187 | #define ELF64_M_SIZE(info) ((unsigned char)(info)) 188 | #define ELF64_M_INFO(sym, size) (((sym) << 8) + (unsigned char)(size)) 189 | 190 | /* 191 | * Hardware/Software capabilities entry 192 | */ 193 | typedef struct { 194 | Elf64_Xword c_tag; /* how to interpret value */ 195 | union { 196 | Elf64_Xword c_val; 197 | Elf64_Addr c_ptr; 198 | } c_un; 199 | } Elf64_Cap; 200 | 201 | /* 202 | * Symbol table entries. 203 | */ 204 | 205 | typedef struct { 206 | Elf64_Word st_name; /* String table index of name. */ 207 | unsigned char st_info; /* Type and binding information. */ 208 | unsigned char st_other; /* Reserved (not used). */ 209 | Elf64_Half st_shndx; /* Section index of symbol. */ 210 | Elf64_Addr st_value; /* Symbol value. */ 211 | Elf64_Xword st_size; /* Size of associated object. */ 212 | } Elf64_Sym; 213 | 214 | /* Macros for accessing the fields of st_info. */ 215 | #define ELF64_ST_BIND(info) ((info) >> 4) 216 | #define ELF64_ST_TYPE(info) ((info)&0xf) 217 | 218 | /* Macro for constructing st_info from field values. */ 219 | #define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf)) 220 | 221 | /* Macro for accessing the fields of st_other. */ 222 | #define ELF64_ST_VISIBILITY(oth) ((oth)&0x3) 223 | 224 | /* Structures used by Sun & GNU-style symbol versioning. */ 225 | typedef struct { 226 | Elf64_Half vd_version; 227 | Elf64_Half vd_flags; 228 | Elf64_Half vd_ndx; 229 | Elf64_Half vd_cnt; 230 | Elf64_Word vd_hash; 231 | Elf64_Word vd_aux; 232 | Elf64_Word vd_next; 233 | } Elf64_Verdef; 234 | 235 | typedef struct { 236 | Elf64_Word vda_name; 237 | Elf64_Word vda_next; 238 | } Elf64_Verdaux; 239 | 240 | typedef struct { 241 | Elf64_Half vn_version; 242 | Elf64_Half vn_cnt; 243 | Elf64_Word vn_file; 244 | Elf64_Word vn_aux; 245 | Elf64_Word vn_next; 246 | } Elf64_Verneed; 247 | 248 | typedef struct { 249 | Elf64_Word vna_hash; 250 | Elf64_Half vna_flags; 251 | Elf64_Half vna_other; 252 | Elf64_Word vna_name; 253 | Elf64_Word vna_next; 254 | } Elf64_Vernaux; 255 | 256 | typedef Elf64_Half Elf64_Versym; 257 | 258 | typedef struct { 259 | Elf64_Half si_boundto; /* direct bindings - symbol bound to */ 260 | Elf64_Half si_flags; /* per symbol flags */ 261 | } Elf64_Syminfo; 262 | 263 | typedef struct { 264 | Elf64_Word ch_type; 265 | Elf64_Word ch_reserved; 266 | Elf64_Xword ch_size; 267 | Elf64_Xword ch_addralign; 268 | } Elf64_Chdr; 269 | 270 | #endif /* !_SYS_ELF64_H_ */ 271 | -------------------------------------------------------------------------------- /print_qcom_image_info/qcert.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "scoped_fd.h" 16 | #include "sys/elf32.h" 17 | #include "sys/elf64.h" 18 | 19 | #ifdef DEBUG 20 | #define DBG(...) fprintf(stderr, __VA_ARGS__) 21 | #else 22 | #define DBG 23 | #endif 24 | 25 | #define Elf 26 | 27 | using namespace std; 28 | 29 | const Elf64_Xword kElfPhdrTypeMask = 7 << 24; 30 | const Elf64_Xword kElfPhdrTypeHash = 2 << 24; 31 | const int kHashSegHeaderSz = 40; 32 | const int kHashSegHeaderSzV6 = 48; 33 | const int kMaxCerts = 3; 34 | const int kKeyChainSize = 0x1800; 35 | const int kMbnV6 = 6; 36 | const int kSha1Sz = 20; 37 | 38 | struct mi_boot_image_header_type { 39 | uint32_t res1; /* Reserved for compatibility: was image_id */ 40 | uint32_t version; /* Reserved for compatibility: was header_vsn_num */ 41 | uint32_t res3; /* Reserved for compatibility: was image_src */ 42 | uint32_t res4; /* Reserved for compatibility: was image_dest_ptr */ 43 | uint32_t image_size; /* Size of complete hash segment in bytes */ 44 | uint32_t code_size; /* Size of hash table in bytes */ 45 | uint32_t res5; /* Reserved for compatibility: was signature_ptr */ 46 | uint32_t signature_size; /* Size of the attestation signature in bytes */ 47 | uint32_t res6; /* Reserved for compatibility: was cert_chain_ptr */ 48 | uint32_t cert_chain_size; /* Size of the attestation chain in bytes */ 49 | }; 50 | 51 | struct mi_boot_image_header_type_v6 { 52 | struct mi_boot_image_header_type base; 53 | uint32_t qti_md_size; 54 | uint32_t md_size; 55 | }; 56 | 57 | struct metadata_base { 58 | uint32_t major; 59 | uint32_t minor; 60 | }; 61 | 62 | struct metadata_0_0 { 63 | metadata_base base; 64 | uint32_t sw_id; 65 | uint32_t hw_id; 66 | uint32_t oem_id; 67 | uint32_t model_id; 68 | uint32_t app_id; 69 | uint32_t rot_en : 1; 70 | uint32_t in_use_soc_hw_version : 1; 71 | uint32_t use_serial_number_in_signing : 1; 72 | uint32_t oem_id_independent : 1; 73 | uint32_t root_revoke_activate_enable : 2; 74 | uint32_t uie_key_switch_enable : 2; 75 | uint32_t debug : 2; 76 | uint32_t soc_vers[12]; 77 | uint32_t multi_serial_numbers[8]; 78 | uint32_t mrc_index; 79 | uint32_t anti_rollback_version; 80 | }; 81 | 82 | static char byte2char(int b) { 83 | if (0 <= b && b <= 9) { 84 | return b + '0'; 85 | } else { 86 | return b - 10 + 'A'; 87 | } 88 | } 89 | static string hex_encode(const char *bin, int len) { 90 | string hex; 91 | int i; 92 | for (i=0; i> 4) & 0xf; 94 | int lo = bin[i] & 0xf; 95 | hex.push_back(byte2char(hi)); 96 | hex.push_back(byte2char(lo)); 97 | } 98 | return hex; 99 | } 100 | 101 | static string parse_cert_sn(X509 *cert) { 102 | string sn; 103 | 104 | ASN1_INTEGER *serial = X509_get_serialNumber(cert); 105 | BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL); 106 | if (!bn) { 107 | fprintf(stderr, "unable to convert ASN1INTEGER to BN\n"); 108 | return sn; 109 | } 110 | 111 | char *tmp = BN_bn2dec(bn); 112 | if (!tmp) { 113 | fprintf(stderr, "unable to convert BN to decimal string.\n"); 114 | BN_free(bn); 115 | return sn; 116 | } 117 | 118 | sn = tmp; 119 | BN_free(bn); 120 | OPENSSL_free(tmp); 121 | return sn; 122 | } 123 | 124 | static int print_certs(shared_ptr data, uint32_t sz, const char *fn=NULL) { 125 | const unsigned char *p = reinterpret_cast(data.get()); 126 | const unsigned char *end = p + sz; 127 | int i = 0; 128 | int nr_certs; 129 | 130 | if (sz == kKeyChainSize) { 131 | nr_certs = kMaxCerts; 132 | } else if (sz == kKeyChainSize * 2) { 133 | nr_certs = kMaxCerts * 2; 134 | } else { 135 | fprintf(stderr, "Invalid cert size %d\n", sz); 136 | return -1; 137 | } 138 | while (p < end && i < nr_certs) { 139 | ++i; 140 | if (i == kMaxCerts + 1) { 141 | p = end - kKeyChainSize; 142 | sz = kKeyChainSize; 143 | // TODO: Skip signature. How to know size of signature. 144 | p += 256; 145 | } 146 | const unsigned char *s = p; 147 | unique_ptr cert(d2i_X509(NULL, &p, sz), X509_free); 148 | if (!cert) { 149 | fprintf(stderr, "Unable to parse cert\n"); 150 | return -1; 151 | } 152 | sz = end - p; 153 | 154 | if (fn) { 155 | string fni = fn + to_string(i) + ".cert"; 156 | DBG("write cert to %s\n", fni.c_str()); 157 | int fd = open(fni.c_str(), O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); 158 | if (fd == -1) { 159 | perror("open"); 160 | return -1; 161 | } 162 | if (write(fd, s, p - s) != p - s) { 163 | perror("write"); 164 | close(fd); 165 | return -1; 166 | } 167 | close(fd); 168 | continue; 169 | } 170 | 171 | char *subj = X509_NAME_oneline(X509_get_subject_name(cert.get()), NULL, 0); 172 | if (!subj) { 173 | fprintf(stderr, "Unable to get subject\n"); 174 | return -1; 175 | } 176 | char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert.get()), NULL, 0); 177 | if (!issuer) { 178 | fprintf(stderr, "Unable to get subject\n"); 179 | OPENSSL_free(subj); 180 | return -1; 181 | } 182 | const EVP_MD *digest = EVP_sha1(); 183 | unsigned len; 184 | char buf[kSha1Sz]; 185 | int rc = X509_digest(cert.get(), digest, (unsigned char*) buf, &len); 186 | if (rc == 0 || len != kSha1Sz) { 187 | fprintf(stderr, "Unable to get sha1 of cert\n"); 188 | return -1; 189 | } 190 | string sha1 = hex_encode(buf, len); 191 | string sn = parse_cert_sn(cert.get()); 192 | 193 | printf("[*] Cert %d:\n", i); 194 | printf(" Subject: %s\n", subj); 195 | printf(" Issuer : %s\n", issuer); 196 | printf(" Sha1 : %s\n", sha1.c_str()); 197 | // printf(" SN : %s\n", sn.c_str()); 198 | 199 | vector ous; 200 | char *token; 201 | while ((token = strsep(&subj, "/")) != NULL) { 202 | if (token[0] == '\0') { 203 | continue; 204 | } 205 | if (strncmp(token, "OU", 2) == 0) { 206 | ous.push_back(token); 207 | } 208 | } 209 | sort(ous.begin(), ous.end(), 210 | [](char *a, char *b) { return strcmp(a, b) < 0; }); 211 | for (auto it = ous.cbegin(); it != ous.cend(); ++it) { 212 | printf(" %s\n", *it); 213 | } 214 | OPENSSL_free(subj); 215 | OPENSSL_free(issuer); 216 | } 217 | 218 | return 0; 219 | } 220 | 221 | static int read_file(int fd, uint32_t off, uint32_t len, void *buf) { 222 | if (lseek(fd, off, SEEK_SET) == -1) { 223 | perror("lseek"); 224 | return -1; 225 | } 226 | if (read(fd, buf, len) != len) { 227 | perror("read"); 228 | return -1; 229 | } 230 | return 0; 231 | } 232 | 233 | static int elf32_find_hashseg(int fd, uint32_t &offset, uint32_t &size) { 234 | Elf32_Ehdr ehdr; 235 | if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) { 236 | perror("read"); 237 | return -1; 238 | } 239 | 240 | Elf32_Phdr phdr; 241 | for (int i = 0; i < ehdr.e_phnum; ++i) { 242 | uint32_t poff = ehdr.e_phoff + i * ehdr.e_phentsize; 243 | if (read_file(fd, poff, sizeof(phdr), &phdr) == -1) { 244 | return -1; 245 | } 246 | 247 | if ((phdr.p_flags & kElfPhdrTypeMask) == kElfPhdrTypeHash) { 248 | offset = phdr.p_offset; 249 | size = phdr.p_filesz; 250 | return 0; 251 | } 252 | } 253 | 254 | return -1; 255 | } 256 | 257 | static int elf64_find_hashseg(int fd, uint32_t &offset, uint32_t &size) { 258 | Elf64_Ehdr ehdr; 259 | if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) { 260 | perror("read"); 261 | return -1; 262 | } 263 | 264 | Elf64_Phdr phdr; 265 | for (int i = 0; i < ehdr.e_phnum; ++i) { 266 | uint32_t poff = ehdr.e_phoff + i * ehdr.e_phentsize; 267 | if (read_file(fd, poff, sizeof(phdr), &phdr) == -1) { 268 | return -1; 269 | } 270 | 271 | if ((phdr.p_flags & kElfPhdrTypeMask) == kElfPhdrTypeHash) { 272 | offset = phdr.p_offset; 273 | size = phdr.p_filesz; 274 | return 0; 275 | } 276 | } 277 | 278 | return -1; 279 | } 280 | 281 | static void usage(const char *cmd) { 282 | fprintf(stderr, "%s [-d] img\n", cmd); 283 | exit(-1); 284 | } 285 | 286 | static int find_hash_segment(int fd, uint32_t &hash_off, uint32_t &hash_sz) { 287 | unsigned char ident[EI_NIDENT]; 288 | if (read(fd, ident, sizeof(ident)) != sizeof(ident)) { 289 | perror("read"); 290 | return -1; 291 | } 292 | if (ident[0] != ELFMAG0 || ident[1] != ELFMAG1 || ident[2] != ELFMAG2 || 293 | ident[3] != ELFMAG3) { 294 | fprintf(stderr, "Not elf format\n"); 295 | return -1; 296 | } 297 | 298 | if (lseek(fd, 0, SEEK_SET) == -1) { 299 | perror("lseek"); 300 | return -1; 301 | } 302 | 303 | int ret; 304 | if (ident[EI_CLASS] == ELFCLASS32) { 305 | ret = elf32_find_hashseg(fd, hash_off, hash_sz); 306 | } else if (ident[EI_CLASS] == ELFCLASS64) { 307 | ret = elf64_find_hashseg(fd, hash_off, hash_sz); 308 | } else { 309 | fprintf(stderr, "Invalid elf format\n"); 310 | return -1; 311 | } 312 | 313 | return ret; 314 | } 315 | 316 | static int print_metadata(int fd, uint32_t off, uint32_t sz, const char *type) { 317 | if (sz == 0) { 318 | return 0; 319 | } else if (sz <= sizeof(metadata_base)) { 320 | fprintf(stderr, "invalid metadata\n"); 321 | return -1; 322 | } 323 | 324 | shared_ptr meta_base(new metadata_base); 325 | if (!meta_base) { 326 | fprintf(stderr, "OOM\n"); 327 | return -1; 328 | } 329 | 330 | if (read_file(fd, off, sizeof(metadata_base), meta_base.get()) == -1) { 331 | return -1; 332 | } 333 | 334 | if (meta_base->major != 0 || meta_base->minor != 0) { 335 | fprintf(stderr, "unsupported version: %d.%d\n", meta_base->major, 336 | meta_base->minor); 337 | return -1; 338 | } 339 | 340 | // Only support 0.0 now. 341 | if (sz != sizeof(metadata_0_0)) { 342 | fprintf(stderr, "invalid metadata version 0.0\n"); 343 | return -1; 344 | } 345 | 346 | shared_ptr meta(new metadata_0_0); 347 | if (!meta) { 348 | fprintf(stderr, "OOM\n"); 349 | return -1; 350 | } 351 | 352 | if (read_file(fd, off, sizeof(metadata_0_0), meta.get()) == -1) { 353 | return -1; 354 | } 355 | 356 | printf("[*] %s METADATA:\n", type); 357 | printf(" SW_ID: %x\n", meta->sw_id); 358 | printf(" HW_ID(JTAG): %x\n", meta->hw_id); 359 | printf(" OEM_ID: %x\n", meta->oem_id); 360 | printf(" MODEL_ID: %x\n", meta->model_id); 361 | printf(" APP_ID: %x\n", meta->app_id); 362 | printf(" SOC_VERS: "); 363 | int i; 364 | for (i=0; i<12; ++i) { 365 | printf("%x, ", meta->soc_vers[i]); 366 | } 367 | printf("\n"); 368 | printf(" MULTI_SNS: "); 369 | for (i=0; i<8; ++i) { 370 | printf("%x, ", meta->multi_serial_numbers[i]); 371 | } 372 | printf("\n"); 373 | printf(" ROLLBACK: %x\n", meta->anti_rollback_version); 374 | printf(" ROT_EN: %x\n", meta->rot_en); 375 | printf(" IN_USE_SOC_HW_VER: %x\n", meta->in_use_soc_hw_version); 376 | printf(" USE_SERIAL_NUMBER_IN_SIGNING: %x\n", meta->use_serial_number_in_signing); 377 | printf(" OEM_ID_INDEPENDENT: %x\n", meta->oem_id_independent); 378 | printf(" ROOT_REVOKE_ACTIVATE_ENABLE: %x\n", meta->root_revoke_activate_enable); 379 | printf(" UIE_KEY_SWITCH_ENABLE: %x\n", meta->uie_key_switch_enable); 380 | printf(" DEBUG: %x\n", meta->debug); 381 | return 0; 382 | } 383 | 384 | static int print_ous_in_header( 385 | int fd, uint32_t hash_off, uint32_t hash_sz, 386 | shared_ptr header) { 387 | uint32_t qti_md_sz = header->qti_md_size; 388 | uint32_t qti_md_off = hash_off + sizeof(mi_boot_image_header_type_v6); 389 | int ret = print_metadata(fd, qti_md_off, qti_md_sz, "QTI"); 390 | 391 | uint32_t md_sz = header->md_size; 392 | uint32_t md_off = qti_md_off + qti_md_sz; 393 | ret = ret || print_metadata(fd, md_off, md_sz, "OEM"); 394 | return ret; 395 | } 396 | 397 | static int find_certs(int fd, uint32_t hash_off, uint32_t hash_sz, 398 | uint32_t cert_off, uint32_t cert_sz, const char *dump_file) { 399 | uint32_t off = hash_off + cert_off; 400 | shared_ptr buf(new char[cert_sz]); 401 | if (!buf) { 402 | fprintf(stderr, "OOM\n"); 403 | return -1; 404 | } 405 | 406 | if (read_file(fd, off, cert_sz, buf.get()) == -1) { 407 | return -1; 408 | } 409 | 410 | if (dump_file) { 411 | return print_certs(buf, cert_sz, dump_file); 412 | } else { 413 | return print_certs(buf, cert_sz); 414 | } 415 | } 416 | 417 | int main(int argc, char **argv) { 418 | int dump = 0; 419 | char *dump_file = NULL; 420 | int c; 421 | const char *cmd = argv[0]; 422 | struct option options[] = { 423 | {"dump", no_argument, NULL, 'd'}, 424 | {NULL, 0, NULL, 0}, 425 | }; 426 | 427 | while ((c = getopt_long(argc, argv, "d", options, NULL)) != -1) { 428 | switch (c) { 429 | case 'd': 430 | dump = 1; 431 | break; 432 | default: 433 | usage(cmd); 434 | break; 435 | } 436 | } 437 | argc -= optind; 438 | argv += optind; 439 | 440 | if (argc != 1) { 441 | usage(cmd); 442 | } 443 | if (dump) { 444 | dump_file = argv[0]; 445 | } 446 | 447 | ScopedFd fd(open(argv[0], O_RDONLY)); 448 | if (!fd) { 449 | perror("open"); 450 | return -1; 451 | } 452 | 453 | uint32_t hash_off, hash_sz; 454 | if (find_hash_segment(fd.get(), hash_off, hash_sz) == -1) { 455 | //fprintf(stderr, "Can't find hash segment\n"); 456 | return -1; 457 | } 458 | DBG("hash segment: %x %x\n", hash_off, hash_sz); 459 | 460 | shared_ptr header(new mi_boot_image_header_type); 461 | if (!header) { 462 | fprintf(stderr, "OOM\n"); 463 | return -1; 464 | } 465 | 466 | if (read_file(fd.get(), hash_off, kHashSegHeaderSz, header.get()) == -1) { 467 | return -1; 468 | } 469 | 470 | // TODO: support -d(--dump) 471 | 472 | if (header->version > kMbnV6) { 473 | fprintf(stderr, "Unsupported mbn version %d\n", header->version); 474 | return -1; 475 | } else if (header->version == kMbnV6) { 476 | DBG("V6 header\n"); 477 | shared_ptr header_v6( 478 | new mi_boot_image_header_type_v6); 479 | if (read_file(fd.get(), hash_off, kHashSegHeaderSzV6, header_v6.get()) == 480 | -1) { 481 | return -1; 482 | } 483 | uint32_t cert_off = sizeof(mi_boot_image_header_type_v6) + 484 | header_v6->qti_md_size + 485 | header_v6->md_size + 486 | header_v6->base.code_size + 487 | header_v6->base.signature_size; 488 | DBG("cert: %x %x\n", cert_off, header_v6->base.cert_chain_size); 489 | if (dump_file) { 490 | return find_certs(fd.get(), hash_off, hash_sz, cert_off, 491 | header_v6->base.cert_chain_size, dump_file); 492 | } else { 493 | if (print_ous_in_header(fd.get(), hash_off, hash_sz, header_v6) || 494 | find_certs(fd.get(), hash_off, hash_sz, cert_off, 495 | header_v6->base.cert_chain_size, dump_file)) { 496 | return -1; 497 | } 498 | } 499 | } else { 500 | uint32_t cert_off = sizeof(mi_boot_image_header_type) + header->code_size + 501 | header->signature_size; 502 | return find_certs(fd.get(), hash_off, hash_sz, cert_off, 503 | header->cert_chain_size, dump_file); 504 | } 505 | } 506 | -------------------------------------------------------------------------------- /print_qcom_image_info/scoped_fd.h: -------------------------------------------------------------------------------- 1 | #ifndef SCOPED_FD_ 2 | #define SCOPED_FD_ 3 | 4 | #include 5 | 6 | class ScopedFd { 7 | public: 8 | ScopedFd() : fd_(-1) {} 9 | ScopedFd(int fd) : fd_(fd) {} 10 | ~ScopedFd() { reset(); } 11 | 12 | int get() const { return fd_; } 13 | void reset(int fd = -1) { 14 | if (fd_ >= 0) { 15 | close(fd_); 16 | } 17 | fd_ = fd; 18 | } 19 | 20 | int release() { 21 | int local_fd = fd_; 22 | fd_ = -1; 23 | return local_fd; 24 | } 25 | 26 | operator bool() const { 27 | if (fd_ < 0) { 28 | return false; 29 | } else { 30 | return true; 31 | } 32 | } 33 | 34 | private: 35 | ScopedFd(const ScopedFd&) = delete; 36 | ScopedFd& operator=(const ScopedFd&) = delete; 37 | 38 | private: 39 | int fd_; 40 | }; 41 | #endif // SCOPED_FD_ 42 | --------------------------------------------------------------------------------