diff --git a/libray/core.py b/libray/core.py index c1c6e2b..6067943 100644 --- a/libray/core.py +++ b/libray/core.py @@ -20,6 +20,7 @@ import os import sys +import shutil import requests from bs4 import BeautifulSoup @@ -32,6 +33,8 @@ except ImportError: # Magic numbers / Constant variables SECTOR = 2048 +ALL_IRD_NET_LOC = 'http://jonnysp.bplaced.net/data.php' +GET_IRD_NET_LOC = 'http://jonnysp.bplaced.net/ird/' # Utility functions @@ -73,8 +76,42 @@ def error(msg): print('ERROR: %s' % msg) sys.exit(1) + +def warning(msg): + print('WARNING: %s. Continuing regardless' % msg) + + +def download_ird(ird_name): + ird_link = GET_IRD_NET_LOC + ird_name + r = requests.get(ird_link, stream=True) + + with open(ird_name, 'wb') as ird_file: + r.raw.decode_content = True + shutil.copyfileobj(r.raw, ird_file) + + +def ird_by_game_id(game_id): + gameid = game_id.replace('-','') + r = requests.get(ALL_IRD_NET_LOC, headers = {'User-Agent': 'Anonymous (You)' }, timeout=5) + soup = BeautifulSoup(r.text, "html.parser") + + ird_name = False + for elem in soup.find_all("a"): + url = elem.get('href').split('/')[-1].replace('\\"','') + if gameid in url: + ird_name = url + + if not ird_name: + error("Unable to download IRD, couldn't find link") + + download_ird(ird_name) + + return(ird_name) + + # Main functions + def decrypt(args): input_iso = iso.ISO(args) diff --git a/libray/ird.py b/libray/ird.py index f82da76..e357222 100644 --- a/libray/ird.py +++ b/libray/ird.py @@ -18,6 +18,7 @@ # You should have received a copy of the GNU General Public License # along with libray. If not, see . + import os import sys import zlib diff --git a/libray/iso.py b/libray/iso.py index 6024a73..29f3837 100644 --- a/libray/iso.py +++ b/libray/iso.py @@ -45,14 +45,24 @@ class ISO: self.regions = self.read_regions(input_iso, args.iso) + input_iso.seek(core.SECTOR) + playstation = input_iso.read(16) + self.game_id = input_iso.read(16).decode('utf8').strip() + if args.verbose: self.print_info() + if not args.ird: + core.warning('No IRD file specified, downloading required file') + args.ird = core.ird_by_game_id(self.game_id) # Download ird + self.ird = ird.IRD(args) if self.ird.region_count != len(self.regions)-1: - core.error('ISO corrupted. Expected %s regions, found %s regions' % (self.ird.region_count, len(self.regions)-1)) - sys.exit() + core.error('Corrupt ISO. Expected %s regions, found %s regions' % (self.ird.region_count, len(self.regions)-1)) + + if self.regions[-1]['start'] > self.size: + core.error('Corrupt ISO. Expected filesize larger than %.2f GiB, actual size is %.2f GiB' % (self.regions[-1]['start'] / 1024**3, self.size / 1024**3 ) ) cipher = AES.new(core.ISO_SECRET, AES.MODE_CBC, core.ISO_IV) self.disc_key = cipher.encrypt(self.ird.data1) @@ -65,7 +75,7 @@ class ISO: with open(args.iso, 'rb') as input_iso: with open(args.output, 'wb') as output_iso: - pbar = tqdm(total=self.size) + pbar = tqdm(total= (self.size // 2048) - 4 ) for i, region in enumerate(self.regions): input_iso.seek(region['start']) @@ -73,7 +83,10 @@ class ISO: if not region['enc']: while input_iso.tell() < region['end']: data = input_iso.read(core.SECTOR) - pbar.update(core.SECTOR) + if not data: + core.warning("Trying to read past the end of the file") + break + pbar.update(1) output_iso.write(data) continue else: @@ -85,7 +98,10 @@ class ISO: num >>= 8 data = input_iso.read(core.SECTOR) - pbar.update(core.SECTOR) + if not data: + core.warning("Trying to read past the end of the file") + break + pbar.update(1) cipher = AES.new(self.disc_key, AES.MODE_CBC, bytes(iv)) decrypted = cipher.decrypt(data) diff --git a/libray/libray.py b/libray/libray.py index f0b55b2..89cc4cb 100755 --- a/libray/libray.py +++ b/libray/libray.py @@ -34,9 +34,9 @@ if __name__ == '__main__': parser = argparse.ArgumentParser(description='A Libre (FLOSS) Python application for unencrypting, extracting, repackaging, and encrypting PS3 ISOs') parser.add_argument('-v', '--verbose', help="Increase verbosity", action='count') parser.add_argument('-o', '--output', dest='output', type=str, help="Output filename", default='output.iso') + parser.add_argument('-k', '--ird', dest='ird', type=str, help="Path to .ird file", default="") required = parser.add_argument_group('required arguments') required.add_argument('-i', '--iso', dest='iso', type=str, help="Path to .iso file", required=True) - required.add_argument('-k', '--ird', dest='ird', type=str, help="Path to .ird file", required=True) args = parser.parse_args() core.decrypt(args)