Compare commits

..

1 Commits

Author SHA1 Message Date
Lily 36450a9b8b
Merge 56b3f1aca2 into 182e2dd071 2024-08-07 14:14:05 +03:00
3 changed files with 43 additions and 53 deletions

View File

@ -143,8 +143,6 @@ processors work just fine (even for macOS Sonoma).
Note: Modern NVIDIA GPUs are supported on HighSierra but not on later Note: Modern NVIDIA GPUs are supported on HighSierra but not on later
versions of macOS. versions of macOS.
Note 2: Use https://github.com/corpnewt/gibMacOS to download macOS Sequoia.
* Convert the downloaded `BaseSystem.dmg` file into the `BaseSystem.img` file. * Convert the downloaded `BaseSystem.dmg` file into the `BaseSystem.img` file.
``` ```

View File

@ -16,29 +16,28 @@ pylint -> Your code has been rated at -0.08/10 ;(
""" """
import argparse import argparse
import binascii
import hashlib import hashlib
import json import json
import linecache import linecache
import os import os
import random import random
import struct import struct
import string
import sys import sys
try: try:
from urllib.request import Request, HTTPError, urlopen from urllib.request import Request, HTTPError, urlopen
from urllib.parse import urlparse from urllib.parse import urlparse
except ImportError: except ImportError:
print('ERROR: Python 2 is not supported, please use Python 3') from urllib2 import Request, HTTPError, urlopen
sys.exit(1) from urlparse import urlparse
SELF_DIR = os.path.dirname(os.path.realpath(__file__)) SELF_DIR = os.path.dirname(os.path.realpath(__file__))
# MacPro7,1 RECENT_MAC = 'Mac-7BA5B2D9E42DDD94'
RECENT_MAC = 'Mac-27AD2F918AE68F61'
MLB_ZERO = '00000000000000000' MLB_ZERO = '00000000000000000'
MLB_VALID = 'F5K105303J9K3F71M' MLB_VALID = 'C02749200YGJ803AX'
MLB_PRODUCT = 'F5K00000000K3F700' MLB_PRODUCT = '00000000000J80300'
TYPE_SID = 16 TYPE_SID = 16
TYPE_K = 64 TYPE_K = 64
@ -53,12 +52,12 @@ INFO_SIGN_HASH = 'CH'
INFO_SIGN_SESS = 'CT' INFO_SIGN_SESS = 'CT'
INFO_REQURED = [INFO_PRODUCT, INFO_IMAGE_LINK, INFO_IMAGE_HASH, INFO_IMAGE_SESS, INFO_SIGN_LINK, INFO_SIGN_HASH, INFO_SIGN_SESS] INFO_REQURED = [INFO_PRODUCT, INFO_IMAGE_LINK, INFO_IMAGE_HASH, INFO_IMAGE_SESS, INFO_SIGN_LINK, INFO_SIGN_HASH, INFO_SIGN_SESS]
# Use -2 for better resize stability on Windows
TERMINAL_MARGIN = 2
def run_query(url, headers, post=None, raw=False): def run_query(url, headers, post=None, raw=False):
if post is not None: if post is not None:
data = '\n'.join(entry + '=' + post[entry] for entry in post).encode() data = '\n'.join([entry + '=' + post[entry] for entry in post])
if sys.version_info[0] >= 3:
data = data.encode('utf-8')
else: else:
data = None data = None
req = Request(url=url, headers=headers, data=data) req = Request(url=url, headers=headers, data=data)
@ -73,11 +72,12 @@ def run_query(url, headers, post=None, raw=False):
def generate_id(id_type, id_value=None): def generate_id(id_type, id_value=None):
return id_value or ''.join(random.choices(string.hexdigits[:16].upper(), k=id_type)) valid_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
return ''.join(random.choice(valid_chars) for i in range(id_type)) if not id_value else id_value
def product_mlb(mlb): def product_mlb(mlb):
return '00000000000' + mlb[11:15] + '00' return '00000000000' + mlb[11] + mlb[12] + mlb[13] + mlb[14] + '00'
def mlb_from_eeee(eeee): def mlb_from_eeee(eeee):
@ -88,6 +88,13 @@ def mlb_from_eeee(eeee):
return f'00000000000{eeee}00' return f'00000000000{eeee}00'
def int_from_unsigned_bytes(byte_list, byteorder):
if byteorder == 'little':
byte_list = byte_list[::-1]
encoded = binascii.hexlify(byte_list)
return int(encoded, 16)
# zhangyoufu https://gist.github.com/MCJack123/943eaca762730ca4b7ae460b731b68e7#gistcomment-3061078 2021-10-08 # zhangyoufu https://gist.github.com/MCJack123/943eaca762730ca4b7ae460b731b68e7#gistcomment-3061078 2021-10-08
Apple_EFI_ROM_public_key_1 = 0xC3E748CAD9CD384329E10E25A91E43E1A762FF529ADE578C935BDDF9B13F2179D4855E6FC89E9E29CA12517D17DFA1EDCE0BEBF0EA7B461FFE61D94E2BDF72C196F89ACD3536B644064014DAE25A15DB6BB0852ECBD120916318D1CCDEA3C84C92ED743FC176D0BACA920D3FCF3158AFF731F88CE0623182A8ED67E650515F75745909F07D415F55FC15A35654D118C55A462D37A3ACDA08612F3F3F6571761EFCCBCC299AEE99B3A4FD6212CCFFF5EF37A2C334E871191F7E1C31960E010A54E86FA3F62E6D6905E1CD57732410A3EB0C6B4DEFDABE9F59BF1618758C751CD56CEF851D1C0EAA1C558E37AC108DA9089863D20E2E7E4BF475EC66FE6B3EFDCF Apple_EFI_ROM_public_key_1 = 0xC3E748CAD9CD384329E10E25A91E43E1A762FF529ADE578C935BDDF9B13F2179D4855E6FC89E9E29CA12517D17DFA1EDCE0BEBF0EA7B461FFE61D94E2BDF72C196F89ACD3536B644064014DAE25A15DB6BB0852ECBD120916318D1CCDEA3C84C92ED743FC176D0BACA920D3FCF3158AFF731F88CE0623182A8ED67E650515F75745909F07D415F55FC15A35654D118C55A462D37A3ACDA08612F3F3F6571761EFCCBCC299AEE99B3A4FD6212CCFFF5EF37A2C334E871191F7E1C31960E010A54E86FA3F62E6D6905E1CD57732410A3EB0C6B4DEFDABE9F59BF1618758C751CD56CEF851D1C0EAA1C558E37AC108DA9089863D20E2E7E4BF475EC66FE6B3EFDCF
@ -121,8 +128,8 @@ def verify_chunklist(cnkpath):
if signature_method == 1: if signature_method == 1:
data = f.read(256) data = f.read(256)
assert len(data) == 256 assert len(data) == 256
signature = int.from_bytes(data, 'little') signature = int_from_unsigned_bytes(data, 'little')
plaintext = int(f'0x1{"f"*404}003031300d060960864801650304020105000420{"0"*64}', 16) | int.from_bytes(digest, 'big') plaintext = 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004200000000000000000000000000000000000000000000000000000000000000000 | int_from_unsigned_bytes(digest, 'big')
assert pow(signature, 0x10001, Apple_EFI_ROM_public_key_1) == plaintext assert pow(signature, 0x10001, Apple_EFI_ROM_public_key_1) == plaintext
elif signature_method == 2: elif signature_method == 2:
data = f.read(32) data = f.read(32)
@ -187,9 +194,7 @@ def get_image_info(session, bid, mlb=MLB_ZERO, diag=False, os_type='default', ci
try: try:
key, value = line.split(': ') key, value = line.split(': ')
info[key] = value info[key] = value
except KeyError: except Exception:
continue
except ValueError:
continue continue
for k in INFO_REQURED: for k in INFO_REQURED:
@ -209,47 +214,34 @@ def save_image(url, sess, filename='', directory=''):
} }
if not os.path.exists(directory): if not os.path.exists(directory):
os.makedirs(directory) os.mkdir(directory)
if filename == '': if filename == '':
filename = os.path.basename(purl.path) filename = os.path.basename(purl.path)
if filename.find(os.sep) >= 0 or filename == '': if filename.find('/') >= 0 or filename == '':
raise RuntimeError('Invalid save path ' + filename) raise RuntimeError('Invalid save path ' + filename)
print(f'Saving {url} to {directory}{os.sep}{filename}...') print(f'Saving {url} to {directory}/{filename}...')
with open(os.path.join(directory, filename), 'wb') as fh: with open(os.path.join(directory, filename), 'wb') as fh:
response = run_query(url, headers, raw=True) response = run_query(url, headers, raw=True)
headers = dict(response.headers) total_size = int(response.headers['content-length']) / float(2 ** 20)
totalsize = -1 # print(total_size)
for header in headers: if total_size < 1:
if header.lower() == 'content-length': total_size = response.headers['content-length']
totalsize = int(headers[header]) print("Note: The total download size is %s bytes" % total_size)
break else:
print("Note: The total download size is %0.2f MB" % total_size)
size = 0 size = 0
oldterminalsize = 0
while True: while True:
chunk = response.read(2**20) chunk = response.read(2**20)
if not chunk: if not chunk:
break break
fh.write(chunk) fh.write(chunk)
size += len(chunk) size += len(chunk)
terminalsize = max(os.get_terminal_size().columns - TERMINAL_MARGIN, 0) print(f'\r{size / (2**20)} MBs downloaded...', end='')
if oldterminalsize != terminalsize:
print(f'\r{"":<{terminalsize}}', end='')
oldterminalsize = terminalsize
if totalsize > 0:
progress = size / totalsize
barwidth = terminalsize // 3
print(f'\r{size / (2**20):.1f}/{totalsize / (2**20):.1f} MB ', end='')
if terminalsize > 55:
print(f'|{"=" * int(barwidth * progress):<{barwidth}}|', end='')
print(f' {progress*100:.1f}% downloaded', end='')
else:
# Fallback if Content-Length isn't available
print(f'\r{size / (2**20)} MB downloaded...', end='')
sys.stdout.flush() sys.stdout.flush()
print('\nDownload complete!') print('\rDownload complete!\t\t\t\t\t')
return os.path.join(directory, os.path.basename(filename)) return os.path.join(directory, os.path.basename(filename))
@ -258,9 +250,10 @@ def verify_image(dmgpath, cnkpath):
print('Verifying image with chunklist...') print('Verifying image with chunklist...')
with open(dmgpath, 'rb') as dmgf: with open(dmgpath, 'rb') as dmgf:
for cnkcount, (cnksize, cnkhash) in enumerate(verify_chunklist(cnkpath), 1): cnkcount = 0
terminalsize = max(os.get_terminal_size().columns - TERMINAL_MARGIN, 0) for cnksize, cnkhash in verify_chunklist(cnkpath):
print(f'\r{f"Chunk {cnkcount} ({cnksize} bytes)":<{terminalsize}}', end='') cnkcount += 1
print(f'\rChunk {cnkcount} ({cnksize} bytes)', end='')
sys.stdout.flush() sys.stdout.flush()
cnk = dmgf.read(cnksize) cnk = dmgf.read(cnksize)
if len(cnk) != cnksize: if len(cnk) != cnksize:
@ -269,7 +262,7 @@ def verify_image(dmgpath, cnkpath):
raise RuntimeError(f'Invalid chunk {cnkcount}: hash mismatch') raise RuntimeError(f'Invalid chunk {cnkcount}: hash mismatch')
if dmgf.read(1) != b'': if dmgf.read(1) != b'':
raise RuntimeError('Invalid image: larger than chunklist') raise RuntimeError('Invalid image: larger than chunklist')
print('\nImage verification complete!') print('\rImage verification complete!\t\t\t\t\t')
def action_download(args): def action_download(args):
@ -305,10 +298,10 @@ def action_download(args):
if args.verbose: if args.verbose:
print(info) print(info)
print(f'Downloading {info[INFO_PRODUCT]}...') print(f'Downloading {info[INFO_PRODUCT]}...')
cnkname = '' if args.basename == '' else args.basename + '.chunklist'
cnkpath = save_image(info[INFO_SIGN_LINK], info[INFO_SIGN_SESS], cnkname, args.outdir)
dmgname = '' if args.basename == '' else args.basename + '.dmg' dmgname = '' if args.basename == '' else args.basename + '.dmg'
dmgpath = 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'
cnkpath = save_image(info[INFO_SIGN_LINK], info[INFO_SIGN_SESS], cnkname, args.outdir)
try: try:
verify_image(dmgpath, cnkpath) verify_image(dmgpath, cnkpath)
return 0 return 0
@ -381,7 +374,7 @@ def action_selfcheck(args):
if product_default[INFO_PRODUCT] != valid_default[INFO_PRODUCT]: if product_default[INFO_PRODUCT] != valid_default[INFO_PRODUCT]:
# Product-only MLB can give the same value with valid default MLB. # Product-only MLB can give the same value with valid default MLB.
# This is not an error for all models, but for our chosen code it is. # This is not an error for all models, but for our chosen code it is.
print(f'ERROR: Valid and product MLB give mismatch, got {product_default[INFO_PRODUCT]} and {valid_default[INFO_PRODUCT]}') print('ERROR: Valid and product MLB give mismatch, got {product_default[INFO_PRODUCT]} and {valid_default[INFO_PRODUCT]}')
return 1 return 1
print('SUCCESS: Found no discrepancies with MLB validation algorithm!') print('SUCCESS: Found no discrepancies with MLB validation algorithm!')
@ -530,7 +523,6 @@ def main():
# No action specified, so present a download menu instead # No action specified, so present a download menu instead
# https://github.com/acidanthera/OpenCorePkg/blob/master/Utilities/macrecovery/boards.json # https://github.com/acidanthera/OpenCorePkg/blob/master/Utilities/macrecovery/boards.json
# https://github.com/corpnewt/gibMacOS
products = [ products = [
{"name": "High Sierra (10.13)", "b": "Mac-7BA5B2D9E42DDD94", "m": "00000000000J80300", "short": "high-sierra"}, {"name": "High Sierra (10.13)", "b": "Mac-7BA5B2D9E42DDD94", "m": "00000000000J80300", "short": "high-sierra"},
{"name": "Mojave (10.14)", "b": "Mac-7BA5B2DFE22DDD8C", "m": "00000000000KXPG00", "short": "mojave"}, {"name": "Mojave (10.14)", "b": "Mac-7BA5B2DFE22DDD8C", "m": "00000000000KXPG00", "short": "mojave"},
@ -538,7 +530,7 @@ def main():
{"name": "Big Sur (11.7)", "b": "Mac-2BD1B31983FE1663", "m": "00000000000000000", "short": "big-sur"}, {"name": "Big Sur (11.7)", "b": "Mac-2BD1B31983FE1663", "m": "00000000000000000", "short": "big-sur"},
{"name": "Monterey (12.6)", "b": "Mac-B809C3757DA9BB8D", "m": "00000000000000000", "os_type": "latest", "short": "monterey"}, {"name": "Monterey (12.6)", "b": "Mac-B809C3757DA9BB8D", "m": "00000000000000000", "os_type": "latest", "short": "monterey"},
{"name": "Ventura (13) - RECOMMENDED", "b": "Mac-4B682C642B45593E", "m": "00000000000000000", "os_type": "latest", "short": "ventura"}, {"name": "Ventura (13) - RECOMMENDED", "b": "Mac-4B682C642B45593E", "m": "00000000000000000", "os_type": "latest", "short": "ventura"},
{"name": "Sonoma (14) ", "b": "Mac-827FAC58A8FDFA22", "m": "00000000000000000", "short": "sonoma"}, {"name": "Sonoma (14) ", "b": "Mac-A61BADE1FDAD7B05", "m": "00000000000000000", "short": "sonoma"}
] ]
for index, product in enumerate(products): for index, product in enumerate(products):
name = product["name"] name = product["name"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB