mirror of
				https://github.com/oSoWoSo/DistroHopper.git
				synced 2024-08-14 22:46:53 +00:00 
			
		
		
		
	Update macrecovery
Update from OpenCorePkg/Utilities/macrecovery/macrecovery.py master branch 6107d573eb535c7708f66cebb83c767863dfd107
This commit is contained in:
		
							parent
							
								
									d62d739e8a
								
							
						
					
					
						commit
						454f13f8a9
					
				
					 1 changed files with 88 additions and 3 deletions
				
			
		
							
								
								
									
										89
									
								
								macrecovery
									
										
									
									
									
								
							
							
						
						
									
										89
									
								
								macrecovery
									
										
									
									
									
								
							|  | @ -9,10 +9,14 @@ Copyright (c) 2019, vit9696 | ||||||
| from __future__ import print_function | from __future__ import print_function | ||||||
| 
 | 
 | ||||||
| import argparse | import argparse | ||||||
|  | import binascii | ||||||
| import datetime | import datetime | ||||||
|  | import hashlib | ||||||
| import json | import json | ||||||
|  | import linecache | ||||||
| import os | import os | ||||||
| import random | import random | ||||||
|  | import struct | ||||||
| import sys | import sys | ||||||
| import textwrap | import textwrap | ||||||
| import time | import time | ||||||
|  | @ -79,6 +83,54 @@ def mlb_from_eeee(eeee): | ||||||
| 
 | 
 | ||||||
|   return '00000000000' + eeee + '00' |   return '00000000000' + eeee + '00' | ||||||
| 
 | 
 | ||||||
|  | def int_from_unsigned_bytes(bytes, byteorder): | ||||||
|  |   if byteorder == 'little': bytes = bytes[::-1] | ||||||
|  |   encoded = binascii.hexlify(bytes) | ||||||
|  |   return int(encoded, 16) | ||||||
|  | 
 | ||||||
|  | # zhangyoufu https://gist.github.com/MCJack123/943eaca762730ca4b7ae460b731b68e7#gistcomment-3061078 2021-10-08 | ||||||
|  | Apple_EFI_ROM_public_key_1 = 0xC3E748CAD9CD384329E10E25A91E43E1A762FF529ADE578C935BDDF9B13F2179D4855E6FC89E9E29CA12517D17DFA1EDCE0BEBF0EA7B461FFE61D94E2BDF72C196F89ACD3536B644064014DAE25A15DB6BB0852ECBD120916318D1CCDEA3C84C92ED743FC176D0BACA920D3FCF3158AFF731F88CE0623182A8ED67E650515F75745909F07D415F55FC15A35654D118C55A462D37A3ACDA08612F3F3F6571761EFCCBCC299AEE99B3A4FD6212CCFFF5EF37A2C334E871191F7E1C31960E010A54E86FA3F62E6D6905E1CD57732410A3EB0C6B4DEFDABE9F59BF1618758C751CD56CEF851D1C0EAA1C558E37AC108DA9089863D20E2E7E4BF475EC66FE6B3EFDCF | ||||||
|  | 
 | ||||||
|  | ChunkListHeader = struct.Struct('<4sIBBBxQQQ') | ||||||
|  | assert ChunkListHeader.size == 0x24 | ||||||
|  | 
 | ||||||
|  | Chunk = struct.Struct('<I32s') | ||||||
|  | assert Chunk.size == 0x24 | ||||||
|  | 
 | ||||||
|  | def verify_chunklist(cnkpath): | ||||||
|  |     with open(cnkpath, 'rb') as f: | ||||||
|  |         hash_ctx = hashlib.sha256() | ||||||
|  |         data = f.read(ChunkListHeader.size) | ||||||
|  |         hash_ctx.update(data) | ||||||
|  |         magic, header_size, file_version, chunk_method, signature_method, chunk_count, chunk_offset, signature_offset = ChunkListHeader.unpack(data) | ||||||
|  |         assert magic == b'CNKL' | ||||||
|  |         assert header_size == ChunkListHeader.size | ||||||
|  |         assert file_version == 1 | ||||||
|  |         assert chunk_method == 1 | ||||||
|  |         assert signature_method in [1, 2] | ||||||
|  |         assert chunk_count > 0 | ||||||
|  |         assert chunk_offset == 0x24 | ||||||
|  |         assert signature_offset == chunk_offset + Chunk.size * chunk_count | ||||||
|  |         for i in range(chunk_count): | ||||||
|  |             data = f.read(Chunk.size) | ||||||
|  |             hash_ctx.update(data) | ||||||
|  |             chunk_size, chunk_sha256 = Chunk.unpack(data) | ||||||
|  |             yield chunk_size, chunk_sha256 | ||||||
|  |         digest = hash_ctx.digest() | ||||||
|  |         if signature_method == 1: | ||||||
|  |             data = f.read(256) | ||||||
|  |             assert len(data) == 256 | ||||||
|  |             signature = int_from_unsigned_bytes(data, 'little') | ||||||
|  |             plaintext = 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004200000000000000000000000000000000000000000000000000000000000000000 | int_from_unsigned_bytes(digest, 'big') | ||||||
|  |             assert pow(signature, 0x10001, Apple_EFI_ROM_public_key_1) == plaintext | ||||||
|  |         elif signature_method == 2: | ||||||
|  |             data = f.read(32) | ||||||
|  |             assert data == digest | ||||||
|  |             raise RuntimeError('Chunklist missing digital signature') | ||||||
|  |         else: | ||||||
|  |             raise NotImplementedError | ||||||
|  |         assert f.read(1) == b'' | ||||||
|  | 
 | ||||||
| def get_session(args): | def get_session(args): | ||||||
|   headers = { |   headers = { | ||||||
|     'Host'      : 'osrecovery.apple.com', |     'Host'      : 'osrecovery.apple.com', | ||||||
|  | @ -173,6 +225,26 @@ def save_image(url, sess, filename='', dir=''): | ||||||
|       sys.stdout.flush() |       sys.stdout.flush() | ||||||
|     print('\rDownload complete!') |     print('\rDownload complete!') | ||||||
| 
 | 
 | ||||||
|  |   return os.path.join(dir, os.path.basename(filename)) | ||||||
|  | 
 | ||||||
|  | def verify_image(dmgpath, cnkpath): | ||||||
|  |   print('Verifying image with chunklist...') | ||||||
|  | 
 | ||||||
|  |   with open (dmgpath, 'rb') as dmgf: | ||||||
|  |     cnkcount = 0 | ||||||
|  |     for cnksize, cnkhash in verify_chunklist(cnkpath): | ||||||
|  |       cnkcount += 1 | ||||||
|  |       print('\rChunk {} ({} bytes)'.format(cnkcount, cnksize), end='') | ||||||
|  |       sys.stdout.flush() | ||||||
|  |       cnk = dmgf.read(cnksize) | ||||||
|  |       if len(cnk) != cnksize: | ||||||
|  |         raise RuntimeError('Invalid chunk {} size: expected {}, read {}'.format(cnkcount, cnksize, len(cnk))) | ||||||
|  |       if hashlib.sha256(cnk).digest() != cnkhash: | ||||||
|  |         raise RuntimeError('Invalid chunk {}: hash mismatch'.format(cnkcount))  | ||||||
|  |     if dmgf.read(1) != b'': | ||||||
|  |       raise RuntimeError('Invalid image: larger than chunklist') | ||||||
|  |     print('\rImage verification complete!') | ||||||
|  | 
 | ||||||
| def action_download(args): | def action_download(args): | ||||||
|   """ |   """ | ||||||
|   Reference information for queries: |   Reference information for queries: | ||||||
|  | @ -208,10 +280,23 @@ def action_download(args): | ||||||
|     print(info) |     print(info) | ||||||
|   print('Downloading ' + info[INFO_PRODUCT] + '...') |   print('Downloading ' + info[INFO_PRODUCT] + '...') | ||||||
|   dmgname = '' if args.basename == '' else args.basename + '.dmg' |   dmgname = '' if args.basename == '' else args.basename + '.dmg' | ||||||
|   save_image(info[INFO_IMAGE_LINK], info[INFO_IMAGE_SESS], dmgname, args.outdir) |   dmgpath = save_image(info[INFO_IMAGE_LINK], info[INFO_IMAGE_SESS], dmgname, args.outdir) | ||||||
|   cnkname = '' if args.basename == '' else args.basename + '.chunklist' |   cnkname = '' if args.basename == '' else args.basename + '.chunklist' | ||||||
|   save_image(info[INFO_SIGN_LINK], info[INFO_SIGN_SESS], cnkname, args.outdir) |   cnkpath = save_image(info[INFO_SIGN_LINK], info[INFO_SIGN_SESS], cnkname, args.outdir) | ||||||
|  |   try: | ||||||
|  |     verify_image(dmgpath, cnkpath) | ||||||
|     return 0 |     return 0 | ||||||
|  |   except Exception as err: | ||||||
|  |     if isinstance(err, AssertionError) and str(err)=='': | ||||||
|  |       try: | ||||||
|  |         tb = sys.exc_info()[2] | ||||||
|  |         while tb.tb_next: | ||||||
|  |           tb = tb.tb_next | ||||||
|  |         err = linecache.getline(tb.tb_frame.f_code.co_filename, tb.tb_lineno, tb.tb_frame.f_globals).strip() | ||||||
|  |       except: | ||||||
|  |         err = "Invalid chunklist" | ||||||
|  |     print('\rImage verification failed. ({})'.format(err)) | ||||||
|  |     return 1 | ||||||
| 
 | 
 | ||||||
| def action_selfcheck(args): | def action_selfcheck(args): | ||||||
|   """ |   """ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue