└── open_bump.py /open_bump.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # Copyright (C) 2014 Anthony King 5 | # Copyright (C) 2014 CyboLabs 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from __future__ import print_function 21 | 22 | import binascii 23 | import os 24 | import struct 25 | import sys 26 | 27 | # Proof of Concept 28 | POC = False 29 | 30 | 31 | usage = """\ 32 | Usage: open_bump.py [-ha] "" "" 33 | image_file - path to the image file to bump 34 | output_image - path to output the bumped file to (defaults to _bumped.img 35 | -a/--apend image_file - if in append mode, the is appended rather than being generated\ 36 | """ 37 | 38 | lg_magic = "41a9e467744d1d1ba429f2ecea655279" 39 | 40 | 41 | def get_kernel_size(image_name): 42 | page_size = get_page_size(image_name) 43 | f_image = open(image_name, 'a+b') 44 | paged_kernel_size = get_size_from_kernel(f_image, page_size, 8) 45 | paged_ramdisk_size = get_size_from_kernel(f_image, page_size, 16) 46 | paged_second_size = get_size_from_kernel(f_image, page_size, 24) 47 | if paged_second_size <= 0: 48 | paged_second_size = 0 49 | paged_dt_size = get_size_from_kernel(f_image, page_size, 40) 50 | if paged_dt_size <= 0: 51 | paged_dt_size = 0 52 | f_image.close() 53 | return page_size + paged_kernel_size + paged_ramdisk_size + paged_second_size + paged_dt_size 54 | 55 | 56 | def bumped(image_data): 57 | d = binascii.hexlify(image_data[-1024:]) 58 | return d.endswith(lg_magic) or d.startswith(lg_magic) 59 | 60 | 61 | def pair_reverse(s): 62 | n = len(s) / 2 63 | fmt = '%dh' % n 64 | return struct.pack(fmt, *reversed(struct.unpack(fmt, s))) 65 | 66 | 67 | def get_page_size(image_name): 68 | with open(image_name, 'rb') as f_img: 69 | f_img.seek(36, 0) 70 | return int(pair_reverse(binascii.hexlify(f_img.read(4))), 16) 71 | 72 | 73 | def get_size_from_kernel(f_image, page_size, seek_size): 74 | f_image.seek(seek_size, 0) 75 | return (int(pair_reverse(binascii.hexlify(f_image.read(4))), 16) / page_size) * page_size 76 | 77 | 78 | def pad_image(image_name): 79 | page_size = get_page_size(image_name) 80 | image_size = os.path.getsize(image_name) 81 | num_pages = image_size / page_size 82 | 83 | calculated_size = get_kernel_size(image_name) 84 | 85 | f_image = open(image_name, 'a+b') 86 | 87 | if calculated_size > image_size: 88 | print("Invalid image: %s: calculated size greater than actual size" % image_name) 89 | f_image.close() 90 | sys.exit(1) 91 | if image_size > calculated_size: 92 | difference = image_size - calculated_size 93 | if difference not in [page_size, page_size*2]: 94 | if difference not in [1024, page_size + 1024, 2 * page_size + 1024, 95 | 16, page_size + 16, 2 * page_size + 16]: 96 | print("Image already padded. Attempting to remove padding...") 97 | print("Beware: this may invalidate your image.") 98 | i = num_pages - 1 99 | f_image.seek(0, 0) 100 | while i >= 0: 101 | f_image.seek(page_size * i, 0) 102 | data = f_image.read(page_size) 103 | data = data.split('\x00')[0] 104 | if not data: 105 | f_image.truncate(page_size * i) 106 | i -= 1 107 | else: 108 | break 109 | else: 110 | print("%s: Image already patched. Bailing out" % image_name) 111 | sys.exit(1) 112 | f_image.close() 113 | 114 | 115 | def get_sha1(image_name): 116 | return hashlib.sha1(open(image_name, 'rb').read()).hexdigest() 117 | 118 | 119 | def finish(out_image): 120 | print("bumped image: %s" % out_image) 121 | sys.exit(0) 122 | 123 | 124 | def main(in_image, out_image): 125 | d_in_image = open(in_image, 'rb').read() 126 | open(out_image, 'wb').write(d_in_image) 127 | if bumped(d_in_image): 128 | print("Image already bumped") 129 | finish(out_image) 130 | pad_image(out_image) 131 | magic = binascii.unhexlify(lg_magic) 132 | with open(out_image, 'a+b') as f_out_image: 133 | f_out_image.write(magic) 134 | finish(out_image) 135 | 136 | 137 | def cli(): 138 | if len(sys.argv) < 2: 139 | print(usage) 140 | sys.exit(1) 141 | if sys.argv[1] in ["-h", "--help"]: 142 | print(usage) 143 | sys.exit(0) 144 | if sys.argv[1] in ["-a", "--append"]: 145 | if len(sys.argv) < 3: 146 | print(usage) 147 | sys.exit(1) 148 | image_name = out_image = sys.argv[2] 149 | else: 150 | image_name = sys.argv[1] 151 | if len(sys.argv) >= 3: 152 | out_image = sys.argv[2] 153 | else: 154 | out_split = os.path.splitext(image_name) 155 | out_image = out_split[0] + "_bumped" + out_split[1] 156 | if not os.path.isfile(image_name): 157 | print("file not found: %s" % image_name) 158 | sys.exit(1) 159 | main(image_name, out_image) 160 | 161 | 162 | if __name__ == '__main__': 163 | cli() 164 | --------------------------------------------------------------------------------