From 9b7a7eba442bd15310820eef29676ff4341b81fc Mon Sep 17 00:00:00 2001 From: rastiqdev Date: Sat, 9 Dec 2023 20:44:58 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fixed=20and=20improved=20firmwar?= =?UTF-8?q?e=20keys=20grabber?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sunst0rm now grabs the keys directly from theapplewiki.com instead of m1stadev's wikiproxy, because wikiproxy currently seems down (note that the source code is taken from wikiproxy itself) --- requirements.txt | 2 + utils/api.py | 19 +++---- utils/wiki.py | 141 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 utils/wiki.py diff --git a/requirements.txt b/requirements.txt index 952fdc1..30abf6a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,5 @@ requests remotezip pyimg4 +datetime +wikitextparser diff --git a/utils/api.py b/utils/api.py index 7e07d9c..8bb33a3 100644 --- a/utils/api.py +++ b/utils/api.py @@ -1,9 +1,9 @@ -import requests +import wiki from remotezip import RemoteZip def get_keys(identifier, board, buildid): try: - f = requests.get(f"https://api.m1sta.xyz/wikiproxy/{identifier}/{board}/{buildid}").json() + f = wiki.get_firmware_keys(identifier, board, buildid) except Exception: if input(f"[?] Keys not found for this IPSW ({buildid}) for the board {board}. Do you want to enter keys manually? (y/n) ") == "y": iBSS_iv = input(" - Enter the iBSS IV: ") @@ -14,17 +14,16 @@ def get_keys(identifier, board, buildid): else: exit() print("Requesting keys...") - for dev in f['keys']: - if dev['image'] == "iBSS": - iBSS_iv = dev['iv'] - iBSS_key = dev['key'] - if dev['image'] == "iBEC": - iBEC_iv = dev['iv'] - iBEC_key = dev['key'] + + iBSS_iv = f['iBSSIV'] + iBSS_key = f['iBSSKey'] + iBEC_iv = f['iBECIV'] + iBEC_key = f['iBECKey'] + try: return iBSS_iv, iBSS_key, iBEC_iv, iBEC_key except UnboundLocalError: - print("[WARNING] Unable to get firmware keys, either the bootchain is not encrypted or the wikiproxy does not have it.") + print("[WARNING] Unable to get firmware keys, either the bootchain is not encrypted or theapplewiki.com does not have it.") input("Continue or not? (Press ENTER to continue, Ctrl-C to quit)") def partialzip_download(url, file, dest): diff --git a/utils/wiki.py b/utils/wiki.py new file mode 100644 index 0000000..7c51b81 --- /dev/null +++ b/utils/wiki.py @@ -0,0 +1,141 @@ +from datetime import datetime + +import requests +import re +import wikitextparser as wtp + +DEVICE_REGEX = re.compile(r'(iPhone|AppleTV|iPad|iPod)[0-9]+,[0-9]+') + +def get_key_page(identifier: str, buildid: str) -> str: + params = { + 'action': 'query', + 'list': 'search', + 'srsearch': f'Keys: {buildid} ({identifier})', + 'srwhat': 'title', + 'srlimit': '1', + 'format': 'json', + 'srnamespace': '2304', + } + resp = requests.get( + 'https://theapplewiki.com/api.php', params=params + ) + if resp.status_code != 200: + pass + else: + search = resp.json() + + if search['query']['searchinfo']['totalhits'] == 0: + raise ValueError( + f'No Firmware Keys page for device: {identifier}, buildid: {buildid}.' + ) + + params = { + 'action': 'parse', + 'prop': 'wikitext', + 'page': search['query']['search'][0]['title'], + 'format': 'json', + 'formatversion': 2, + } + resp = requests.get( + 'https://theapplewiki.com/api.php', params=params + ) + if resp.status_code != 200: + pass + + data = resp.json() + + return data['parse']['wikitext'] + + +def parse_page(data: str, identifer: str, boardconfig: str = None) -> dict: + data = ( + ' '.join([x for x in data.split(' ') if x != '']) + .replace('{{', '{| class="wikitable"') + .replace('}}', '|}') + ) + + page = wtp.parse(data) + page_data = {} + for entry in page.tables[0].data()[0]: + key, item = entry.split(' = ') + page_data[key] = item + + if boardconfig is not None: + if ('Model' not in page_data.keys()) and ('Model2' not in page_data.keys()): + return page_data + + if boardconfig.lower() not in [x.lower() for x in page_data.values()]: + raise ValueError( + f'Boardconfig: {boardconfig} for device: {identifer} is not valid!' + ) + + if page_data['Model2'].lower() == boardconfig.lower(): + for key in page_data: + if '2' in key: + page_data[key.replace('2', '')] = page_data[key] + + for key in list(page_data.keys()): + if '2' in key: + del page_data[key] + + response = { + 'identifier': page_data['Device'], + 'buildid': page_data['Build'], + 'codename': page_data['Codename'], + 'restoreramdiskexists': 'RestoreRamdisk' in page_data, + 'updateramdiskexists': 'UpdateRamdisk' in page_data, + 'keys': [], + } + + for component in page_data: + if component in ( + 'Version', + 'Build', + 'Device', + 'Model', + 'Codename', + 'Baseband', + 'DownloadURL', + ): + continue + + if any(component.endswith(x) for x in ('Key', 'IV', 'KBAG')): + continue + + image = { + 'image': component, + 'filename': page_data[component], + 'date': datetime.now().isoformat(), + } + + if any(component == x for x in ('RootFS', 'RestoreRamdisk', 'UpdateRamdisk')): + image['filename'] += '.dmg' + + for key in ('IV', 'Key') if component != 'RootFS' else ('Key',): + if component + key not in page_data.keys(): + continue + + if all( + x not in page_data[component + key] + for x in ('Unknown', 'Not Encrypted') + ): + image[key.lower()] = page_data[component + key] + + if ( + ('iv' not in image.keys()) + and ('key' not in image.keys()) + and not image['filename'].endswith('.dmg') + ): + continue + + if 'iv' in image and 'key' in image: + image['kbag'] = image['iv'] + image['key'] + + response['keys'].append(image) + + return response + +def get_firmware_keys(identifier: str, boardconfig: str, buildid: str) -> dict: + page = get_key_page(identifier, buildid) + + return parse_page(page, identifier, boardconfig) \ No newline at end of file