zoukankan      html  css  js  c++  java
  • mkbootimg hacking

      1 /**********************************************************************
      2  *                       mkbootimg hacking
      3  *  声明:
      4  *      1. 本文源代码来自myzr_android4_2_2_1_1_0.tar.bz2中的mkbootimg.c;
      5  *      2. 通过阅读该源码,可知Android的boot.img合成原理;
      6  *    
      7  *              深圳 南山平山村 曾剑鋒 Mon May  4 13:09:49 CST 2015
      8  **********************************************************************/
      9 
     10 /* tools/mkbootimg/mkbootimg.c
     11 **
     12 ** Copyright 2007, The Android Open Source Project
     13 **
     14 ** Licensed under the Apache License, Version 2.0 (the "License");
     15 ** you may not use this file except in compliance with the License.
     16 ** You may obtain a copy of the License at
     17 **
     18 **     http://www.apache.org/licenses/LICENSE-2.0
     19 **
     20 ** Unless required by applicable law or agreed to in writing, software
     21 ** distributed under the License is distributed on an "AS IS" BASIS,
     22 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     23 ** See the License for the specific language governing permissions and
     24 ** limitations under the License.
     25 */
     26 
     27 typedef struct boot_img_hdr boot_img_hdr;
     28 
     29 #define BOOT_MAGIC "ANDROID!"
     30 #define BOOT_MAGIC_SIZE 8
     31 #define BOOT_NAME_SIZE 16
     32 #define BOOT_ARGS_SIZE 512
     33 
     34 /**
     35  * 用于暂存需要的数据的结构体
     36  */
     37 struct boot_img_hdr
     38 {
     39     unsigned char magic[BOOT_MAGIC_SIZE];           //文件类型标识
     40 
     41     unsigned kernel_size;  /* size in bytes         内核文件大小 */
     42     unsigned kernel_addr;  /* physical load addr    内核文件的起始地址 */
     43 
     44     unsigned ramdisk_size; /* size in bytes         randisk文件的大小*/
     45     unsigned ramdisk_addr; /* physical load addr    randisk文件的起始地址 */
     46 
     47     unsigned second_size;  /* size in bytes         */
     48     unsigned second_addr;  /* physical load addr    */
     49 
     50     unsigned tags_addr;    /* physical addr for kernel tags */
     51     unsigned page_size;    /* flash page size we assume */
     52     unsigned unused[2];    /* future expansion: should be 0 */
     53 
     54     unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
     55     
     56     unsigned char cmdline[BOOT_ARGS_SIZE];   /* 如果U-Boot没有指定bootargs,就会使用这里的参数 */
     57 
     58     unsigned id[8]; /* timestamp / checksum / sha1 / etc  个人感觉主要用于保存校验数据 */
     59 };
     60 
     61 #include <stdio.h>
     62 #include <stdlib.h>
     63 #include <string.h>
     64 #include <unistd.h>
     65 #include <fcntl.h>
     66 #include <errno.h>
     67 
     68 #include "mincrypt/sha.h"
     69 #include "bootimg.h"
     70 
     71 /**
     72  * 主要用于加载各种需要的文件的函数
     73  */
     74 static void *load_file(const char *fn, unsigned *_sz)
     75 {
     76     char *data;
     77     int sz;
     78     int fd;
     79 
     80     data = 0;
     81     fd = open(fn, O_RDONLY);                    //带开文件
     82     if(fd < 0) return 0;
     83 
     84     sz = lseek(fd, 0, SEEK_END);                //跳到文件末尾,这样就知道文件的大小了
     85     if(sz < 0) goto oops;
     86 
     87     if(lseek(fd, 0, SEEK_SET) != 0) goto oops;  //返回到文件头
     88 
     89     data = (char*) malloc(sz);                  //分配和文件一样大小的内存空间
     90     if(data == 0) goto oops;
     91 
     92     if(read(fd, data, sz) != sz) goto oops;     //将文件内容读取到内存中
     93     close(fd);
     94 
     95     if(_sz) *_sz = sz;                          //相当于返回文件的大小
     96     return data;                                //返回文件数据的首地址
     97 
     98 oops:
     99     close(fd);
    100     if(data != 0) free(data);
    101     return 0;
    102 }
    103 
    104 /**
    105  * mkbootimg使用说明
    106  */
    107 int usage(void)
    108 {
    109     fprintf(stderr,"usage: mkbootimg
    "
    110             "       --kernel <filename>
    "
    111             "       --ramdisk <filename>
    "
    112             "       [ --second <2ndbootloader-filename> ]
    "
    113             "       [ --cmdline <kernel-commandline> ]
    "
    114             "       [ --board <boardname> ]
    "
    115             "       [ --base <address> ]
    "
    116             "       [ --pagesize <pagesize> ]
    "
    117             "       -o|--output <filename>
    "
    118             );
    119     return 1;
    120 }
    121 
    122 
    123 
    124 /**
    125  * boot.img中每部分数据都是以页为单位存储的,如果数据不足一页的倍数,
    126  * 那么就将该页剩下的空间以0填充
    127  */
    128 static unsigned char padding[4096] = { 0, };
    129 
    130 int write_padding(int fd, unsigned pagesize, unsigned itemsize)
    131 {
    132     /**
    133      * pagesize一般都是比较大的整数,例如:1k,2k,4k等等,那么
    134      * pagesize-1,就变成了由0开始,后面跟了一堆1,例如:
    135      * 1k   = 10000000000(二进制);
    136      * 1k-1 = 01111111111(二进制);
    137      */
    138     unsigned pagemask = pagesize - 1; 
    139     unsigned count;
    140 
    141     /**
    142      * 由上面的解析可知,这里是确保itemsize需要填充的0的个数
    143      * 小于pagesize并且大于0
    144      * itemsize&pagemask相当于itemsize对pagemask取余
    145      */
    146     if((itemsize & pagemask) == 0) {
    147         return 0;
    148     }
    149 
    150     /**
    151      * 计算出需要填充多少个0, itemsize&pagemask相当于itemsize对pagemask取余
    152      */
    153     count = pagesize - (itemsize & pagemask);
    154 
    155     if(write(fd, padding, count) != count) {
    156         return -1;
    157     } else {
    158         return 0;
    159     }
    160 }
    161 
    162 int main(int argc, char **argv)
    163 {
    164     boot_img_hdr hdr;
    165 
    166     char *kernel_fn = 0;
    167     void *kernel_data = 0;
    168     char *ramdisk_fn = 0;
    169     void *ramdisk_data = 0;
    170     char *second_fn = 0;
    171     void *second_data = 0;
    172     char *cmdline = "";
    173     char *bootimg = 0;
    174     char *board = "";
    175     unsigned pagesize = 2048;                   //默认一页占用2K
    176     int fd;
    177     SHA_CTX ctx;
    178     uint8_t* sha;
    179     unsigned base           = 0x10000000;       //基址
    180     unsigned kernel_offset  = 0x00008000;
    181     unsigned ramdisk_offset = 0x01000000;
    182     unsigned second_offset  = 0x00f00000;
    183     unsigned tags_offset    = 0x00000100;
    184 
    185     //可执行文件必须有参数,需知道内核文件在那里,ramdisk在那里等等信息
    186     argc--;      
    187     argv++;
    188 
    189     memset(&hdr, 0, sizeof(hdr));              //清空结构体数据
    190 
    191     /**
    192      * 获取命令行参数
    193      */
    194     while(argc > 0){
    195         char *arg = argv[0];
    196         char *val = argv[1];
    197         if(argc < 2) {
    198             return usage();
    199         }
    200         argc -= 2;
    201         argv += 2;
    202         if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
    203             bootimg = val;
    204         } else if(!strcmp(arg, "--kernel")) {
    205             kernel_fn = val;
    206         } else if(!strcmp(arg, "--ramdisk")) {
    207             ramdisk_fn = val;
    208         } else if(!strcmp(arg, "--second")) {
    209             second_fn = val;
    210         } else if(!strcmp(arg, "--cmdline")) {
    211             cmdline = val;
    212         } else if(!strcmp(arg, "--base")) {
    213             base = strtoul(val, 0, 16);
    214         } else if(!strcmp(arg, "--kernel_offset")) {
    215             kernel_offset = strtoul(val, 0, 16);
    216         } else if(!strcmp(arg, "--ramdisk_offset")) {
    217             ramdisk_offset = strtoul(val, 0, 16);
    218         } else if(!strcmp(arg, "--second_offset")) {
    219             second_offset = strtoul(val, 0, 16);
    220         } else if(!strcmp(arg, "--tags_offset")) {
    221             tags_offset = strtoul(val, 0, 16);
    222         } else if(!strcmp(arg, "--board")) {
    223             board = val;
    224         } else if(!strcmp(arg,"--pagesize")) {
    225             pagesize = strtoul(val, 0, 10);
    226             if ((pagesize != 2048) && (pagesize != 4096)) {     //页大小只能是两种情况,2k或者4k
    227                 fprintf(stderr,"error: unsupported page size %d
    ", pagesize);
    228                 return -1;
    229             }
    230         } else {
    231             return usage();
    232         }
    233     }
    234     hdr.page_size = pagesize;           //设置页大小
    235 
    236     /**
    237      * 计算各种偏移地址
    238      */
    239     hdr.kernel_addr =  base + kernel_offset;
    240     hdr.ramdisk_addr = base + ramdisk_offset;
    241     hdr.second_addr =  base + second_offset;
    242     hdr.tags_addr =    base + tags_offset;
    243 
    244     if(bootimg == 0) {
    245         fprintf(stderr,"error: no output filename specified
    ");
    246         return usage();
    247     }
    248 
    249     if(kernel_fn == 0) {
    250         fprintf(stderr,"error: no kernel image specified
    ");
    251         return usage();
    252     }
    253 
    254     if(ramdisk_fn == 0) {
    255         fprintf(stderr,"error: no ramdisk image specified
    ");
    256         return usage();
    257     }
    258 
    259     if(strlen(board) >= BOOT_NAME_SIZE) {
    260         fprintf(stderr,"error: board name too large
    ");
    261         return usage();
    262     }
    263 
    264     strcpy(hdr.name, board);    //板子类型
    265 
    266     memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);     //文件类型
    267 
    268     //kernel命令行参数,如果U-Boot没有给出,将是用这里的参数
    269     if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {        
    270         fprintf(stderr,"error: kernel commandline too large
    ");
    271         return 1;
    272     }
    273     strcpy((char*)hdr.cmdline, cmdline);
    274 
    275     //加载内核文件,同时获取内核文件的大小
    276     kernel_data = load_file(kernel_fn, &hdr.kernel_size);
    277     if(kernel_data == 0) {
    278         fprintf(stderr,"error: could not load kernel '%s'
    ", kernel_fn);
    279         return 1;
    280     }
    281 
    282     if(!strcmp(ramdisk_fn,"NONE")) {
    283         ramdisk_data = 0;
    284         hdr.ramdisk_size = 0;
    285     } else {
    286         ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size);
    287         if(ramdisk_data == 0) {
    288             fprintf(stderr,"error: could not load ramdisk '%s'
    ", ramdisk_fn);
    289             return 1;
    290         }
    291     }
    292 
    293     if(second_fn) {
    294         second_data = load_file(second_fn, &hdr.second_size);
    295         if(second_data == 0) {
    296             fprintf(stderr,"error: could not load secondstage '%s'
    ", second_fn);
    297             return 1;
    298         }
    299     }
    300 
    301     /* put a hash of the contents in the header so boot images can be
    302      * differentiated based on their first 2k.
    303      */
    304     /**
    305      * 个人理解这里是产生一些校验数据,可以不用关心,不影响阅读
    306      */
    307     SHA_init(&ctx);
    308     SHA_update(&ctx, kernel_data, hdr.kernel_size);
    309     SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size));
    310     SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size);
    311     SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size));
    312     SHA_update(&ctx, second_data, hdr.second_size);
    313     SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size));
    314     sha = SHA_final(&ctx);
    315     memcpy(hdr.id, sha,
    316            SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE);
    317 
    318     /**
    319      * 打开输出目标文件,如果文件不存在,那么就创建该文件,如果存在,那么就清空
    320      */
    321     fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);
    322     if(fd < 0) {
    323         fprintf(stderr,"error: could not create '%s'
    ", bootimg);
    324         return 1;
    325     }
    326 
    327     /**
    328      * 这里相当于写入文件头,和写bmp文件差不多的意思
    329      */
    330     if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
    331     if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
    332 
    333     /**
    334      * 接下来按一定顺序写内容
    335      */
    336     if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail;
    337     if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
    338 
    339     if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail;
    340     if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
    341 
    342     if(second_data) {
    343         if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail;
    344         if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
    345     }
    346 
    347     return 0;
    348 
    349 fail:
    350     unlink(bootimg);
    351     close(fd);
    352     fprintf(stderr,"error: failed writing '%s': %s
    ", bootimg,
    353             strerror(errno));
    354     return 1;
    355 }
  • 相关阅读:
    LINQ to Entities 查询中的标准查询运算符
    LINQ to Entities 基于方法的查询语法
    ajax 与 form 提交的区别
    i++ & ++i 区别
    sizeof 数据类型大小 32位&64位
    标准数据类型宏定义
    long & int 区别
    类函数修饰 const
    指针
    数组
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/4478163.html
Copyright © 2011-2022 走看看