Skip to content

Commit 6158c75

Browse files
committed
added basic dns redirection support
1 parent 63951d4 commit 6158c75

9 files changed

+215
-148
lines changed

README.md

+28-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,36 @@
1-
[![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/) [![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/)
1+
# PS5 Tools
22

3+
Usage: main.py [-h] [-v] {analyze,dns} ..
34

5+
positional arguments:
6+
{analyze,dns} Choose one of these options
7+
analyze Analyze PS5 file
8+
dns Redirect PS5 traffic via DNS
49

10+
optional arguments:
11+
-h, --help show this help message and exit
12+
-v Verbose mode
513

6-
# PS5 Tools
714

8-
Usage: main.py [-h] [-e] [-v] file
15+
# Analyze Mode
916

10-
positional arguments:<br>
17+
usage: main.py analyze [-h] [-e] file
18+
19+
positional arguments:
1120
file PS5 Input File
1221

13-
optional arguments:<br>
14-
-h, --help show this help message and exit<br>
15-
-e Extract given file if possible<br>
16-
-v Print verbose file info<br>
22+
optional arguments:
23+
-h, --help show this help message and exit
24+
-e Extract given file if possible
25+
26+
27+
# DNS Mode
28+
29+
usage: main.py dns [-h] domain a_record
30+
31+
positional arguments:
32+
domain Domain to redirect
33+
a_record A record to point to
34+
35+
optional arguments:
36+
-h, --help show this help message and exit

cnt.py

+43-32
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ def __init__(self, file, filename):
2020

2121
data_entry = Struct(
2222
Padding(2),
23-
'type' / Enum(Int8ub,
24-
UNKNOWN=0x00,
25-
TOC=0x01,
23+
'file_type' / Enum(Int8ub,
24+
UNKNOWN1 =0x00,
25+
TOC =0x01,
2626
FILENAMES=0x02,
27-
NOT_TO_BE_EXTRACTED=0x04,
28-
FILE2=0x10,
29-
FILE3=0x12,
30-
FILE4=0x14,
31-
FILE5=0x20,
32-
FILE6=0x21,
33-
FILE7=0x30,
27+
UNKNOWN2 =0x04,
28+
FILETYPE1=0x10,
29+
FILETYPE2=0x12,
30+
FILETYPE3=0x14,
31+
FILETYPE4=0x20,
32+
FILETYPE5=0x21,
33+
FILETYPE6=0x30,
3434
),
3535
Padding(1),
3636
'filename_offset' / Int32ub,
@@ -80,35 +80,31 @@ def __init__(self, file, filename):
8080

8181
self.cnt = cnt_header.parse(file)
8282

83-
def info_raw(self):
84-
85-
print('PS5 CNT iNFO')
86-
print('#############')
87-
88-
print('Filename: ' + os.path.basename(self.file))
89-
print(self.cnt)
90-
91-
def info(self):
83+
def info(self, verbose):
9284

9385
print('PS5 CNT iNFO')
9486
print('############')
95-
print('Filename: ' + os.path.basename(self.file))
96-
print('File Count: %i' % self.cnt.file_count)
97-
print('Data Size: 0x%X' % self.cnt.data_size)
98-
print('Title ID: ' + self.cnt.title_id)
99-
print('Contains:')
100-
self._get_filenames()
101-
print(self.file_names)
87+
88+
if verbose:
89+
print(self.cnt)
90+
else:
91+
print('Filename: ' + os.path.basename(self.file))
92+
print('File Count: %i' % self.cnt.file_count)
93+
print('Data Size: 0x%X' % self.cnt.data_size)
94+
print('Title ID: ' + self.cnt.title_id)
95+
print('Contains:')
96+
self._get_filenames()
97+
print(self.file_names)
10298

10399
def _get_filenames(self) -> bool:
104100

105101
for i in range(self.cnt.file_count - 1):
106-
if self.cnt.data_entries[i].type == 'FILENAMES':
102+
if self.cnt.data_entries[i].file_type == 'FILENAMES':
107103
file_names = ''.join(chr(x) for x in self.cnt.data[i].data)
108104
self.file_names = file_names.replace('\x00', ' ').split()
109105
return True
110106

111-
def extract(self):
107+
def extract(self, verbose):
112108

113109
print('')
114110
print('PS5 CNT EXTRACTiON')
@@ -121,23 +117,38 @@ def extract(self):
121117

122118
working_dir = _create_working_dir(str(os.path.basename(self.file)))
123119

120+
verbose_filetypes = {'UNKNOWN1', 'UNKNOWN2', 'TOC', 'FILENAMES'}
121+
if verbose:
122+
verbose_filetypes.clear()
123+
124124
for i in range(self.cnt.file_count - 1):
125125
if j >= self.cnt.file_count - filename_counter - 1 and filenames_available:
126126
filename = self.file_names[counter]
127127
counter += 1
128128
else:
129129
filename = ('%i.' % j) + _get_extension_by_signature(self.cnt.data[i].signature.hex())
130130

131-
os.makedirs(working_dir + os.path.dirname(filename), exist_ok=True)
131+
os.makedirs(working_dir + '/' + os.path.dirname(filename), exist_ok=True)
132+
133+
file_type = str(self.cnt.data_entries[i].file_type)
132134

133-
with open(working_dir + '/' + filename, 'wb') as f:
134-
f.write(self.cnt.data[i].data)
135-
print('EXTRACTED #%i: %s (0x%X Bytes)' % (
135+
if file_type not in verbose_filetypes:
136+
with open(working_dir + '/' + filename, 'wb') as f:
137+
f.write(self.cnt.data[i].data)
138+
print('EXTRACTED #%i: %s (0x%X Bytes)' % (
139+
i,
140+
filename,
141+
self.cnt.data_entries[i].data_size,
142+
)
143+
)
144+
else:
145+
print('SKIPPED #%i: %s (0x%X Bytes)' % (
136146
i,
137147
filename,
138148
self.cnt.data_entries[i].data_size,
139149
)
140150
)
151+
141152
j += 1
142153

143154
print('%i files extracted...' % (self.cnt.file_count - 1))

dns.py

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env python
2+
from dnslib.server import DNSServer
3+
from dnslib.dns import RR
4+
import time
5+
6+
7+
class DNS:
8+
9+
def __init__(self, domain, a_record, verbose):
10+
resolver = self.Resolver()
11+
resolver.set_redirect(domain, a_record, verbose)
12+
server = DNSServer(resolver)
13+
server.start_thread()
14+
print('DNS server running')
15+
print('Setup: '+domain+' <-> '+a_record)
16+
try:
17+
while server.isAlive():
18+
time.sleep(1)
19+
except KeyboardInterrupt:
20+
print('DNS server stopped')
21+
pass
22+
23+
class Resolver:
24+
domain = ''
25+
a_record = ''
26+
verbose = ''
27+
28+
def set_redirect(self, domain, a_record, verbose):
29+
self.domain = domain
30+
self.a_record = a_record
31+
self.verbose = verbose
32+
33+
def resolve(self, request, _handler):
34+
reply = request.reply()
35+
reply.add_answer(*RR.fromZone(self.domain+'. 60 A '+self.a_record))
36+
if self.verbose:
37+
print('Redirected request '+self.domain+' to '+self.a_record)
38+
return reply

fih.py

+27-31
Original file line numberDiff line numberDiff line change
@@ -43,40 +43,36 @@ def __init__(self, file, filename):
4343

4444
self.fih = fih_header.parse(file)
4545

46-
def info_raw(self):
47-
48-
print('PS5 FIH iNFO')
49-
print('#############')
50-
51-
print(self.fih)
52-
53-
def info(self):
46+
def info(self, verbose):
5447

5548
print('PS5 FIH iNFO')
5649
print('############')
57-
58-
print('Filename: ' + os.path.basename(self.file))
59-
print('Version: 0x%X' % self.fih.version)
60-
print('Encrypted Data Offset: 0x%X' % self.fih.fih_offset)
61-
print('Encrypted Data Size: 0x%X' % self.fih.fih_size)
62-
print('PFS Offset: 0x%X' % self.fih.pfs_offset)
63-
print('PFS Size: 0x%X' % self.fih.pfs_size)
64-
print('Hash 1: ' + self.fih.hash_1.hex().upper())
65-
print('Unknown a: 0x%X' % self.fih.a)
66-
print('SC Offset: 0x%X' % self.fih.sc_offset)
67-
print('Unknown b: 0x%X' % self.fih.b)
68-
print('Unknown c: 0x%X' % self.fih.c)
69-
print('Unknown d: 0x%X' % self.fih.d)
70-
print('Unknown e: 0x%X' % self.fih.e)
71-
print('Unknown f: 0x%X' % self.fih.f)
72-
print('Unknown g: 0x%X' % self.fih.g)
73-
print('Hash 2: ' + self.fih.hash_2.hex().upper())
74-
print('Unknown h: 0x%X' % self.fih.h)
75-
print('Unknown i: 0x%X' % self.fih.i)
76-
print('Hash 3: ' + self.fih.hash_3.hex().upper())
77-
print('Hash 4: ' + self.fih.hash_4.hex().upper())
78-
print('Unknown j: 0x%X' % self.fih.j)
79-
print('Unknown k: 0x%X' % self.fih.k)
50+
51+
if verbose:
52+
print(self.fih)
53+
else:
54+
print('Filename: ' + os.path.basename(self.file))
55+
print('Version: 0x%X' % self.fih.version)
56+
print('Encrypted Data Offset: 0x%X' % self.fih.fih_offset)
57+
print('Encrypted Data Size: 0x%X' % self.fih.fih_size)
58+
print('PFS Offset: 0x%X' % self.fih.pfs_offset)
59+
print('PFS Size: 0x%X' % self.fih.pfs_size)
60+
print('Hash 1: ' + self.fih.hash_1.hex().upper())
61+
print('Unknown a: 0x%X' % self.fih.a)
62+
print('SC Offset: 0x%X' % self.fih.sc_offset)
63+
print('Unknown b: 0x%X' % self.fih.b)
64+
print('Unknown c: 0x%X' % self.fih.c)
65+
print('Unknown d: 0x%X' % self.fih.d)
66+
print('Unknown e: 0x%X' % self.fih.e)
67+
print('Unknown f: 0x%X' % self.fih.f)
68+
print('Unknown g: 0x%X' % self.fih.g)
69+
print('Hash 2: ' + self.fih.hash_2.hex().upper())
70+
print('Unknown h: 0x%X' % self.fih.h)
71+
print('Unknown i: 0x%X' % self.fih.i)
72+
print('Hash 3: ' + self.fih.hash_3.hex().upper())
73+
print('Hash 4: ' + self.fih.hash_4.hex().upper())
74+
print('Unknown j: 0x%X' % self.fih.j)
75+
print('Unknown k: 0x%X' % self.fih.k)
8076

8177
def extract(self):
8278

main.py

+39-30
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
#!/usr/bin/env python
22
import argparse
3-
4-
__author__ = 'SKFU'
5-
__copyright__ = 'Copyright 2020, '+__author__
6-
__credits__ = 'tuxuser, SocraticBliss'
7-
__version__ = '11112020'
8-
3+
import sys
4+
from cnt import *
5+
from dns import *
6+
from fih import *
97
from pup import *
108
from slb2 import *
11-
from fih import *
12-
from cnt import *
139
from utils import known_signatures
1410

11+
__author__ = 'SKFU'
12+
__copyright__ = 'Copyright 2020, ' + __author__
13+
__credits__ = 'tuxuser, SocraticBliss'
14+
__version__ = '11122020'
15+
16+
1517
def load_file(filename):
16-
1718
with open(filename, 'rb') as f:
1819
magic = known_signatures.get(f.read(4).hex().upper())
1920
f.seek(0)
2021
file = f.read()
21-
22+
2223
if magic == 'pup':
23-
return PUP(file, filename)
24+
return PUP(file, filename)
2425
elif magic == 'slb2':
2526
return SLB2(file, filename)
2627
elif magic == 'fih':
@@ -31,28 +32,36 @@ def load_file(filename):
3132
raise SystemExit('ERROR: Filetype not currently supported!')
3233

3334

34-
def main(file: str, verbose: bool, extract: bool):
35-
35+
def analyze(file: str, extract: bool, verbose: bool):
3636
instance = load_file(file)
37-
38-
# Verbose
39-
if verbose:
40-
instance.info_raw()
41-
else:
42-
instance.info()
43-
44-
# Extract
37+
instance.info(verbose)
38+
4539
if extract:
46-
instance.extract()
40+
instance.extract(verbose)
41+
42+
43+
def dns_redirect(domain: str, a_record: str, verbose: bool):
44+
dns_server = DNS(domain, a_record, verbose)
4745

4846

4947
if __name__ == '__main__':
50-
51-
parser = argparse.ArgumentParser(description='PS5 Tools by '+__author__+' || Thanks to '+__credits__)
52-
53-
parser.add_argument('file', help='PS5 Input File')
54-
parser.add_argument('-e', help='Extract given file if possible', action='store_true')
55-
parser.add_argument('-v', help='Print verbose file info', action='store_true')
56-
48+
parser = argparse.ArgumentParser(description='PS5 Tools by ' + __author__, epilog='Thanks to ' + __credits__)
49+
parser.add_argument('-v', help='Verbose mode', action='store_true')
50+
subparsers = parser.add_subparsers(help='Choose one of these options', dest='command')
51+
52+
analyze_parser = subparsers.add_parser('analyze', help='Analyze PS5 file')
53+
analyze_parser.add_argument('file', help='PS5 Input File')
54+
analyze_parser.add_argument('-e', help='Extract given file if possible', action='store_true')
55+
56+
dns_parser = subparsers.add_parser('dns', help='Redirect PS5 traffic via DNS')
57+
dns_parser.add_argument('domain', help='Domain to redirect')
58+
dns_parser.add_argument('a_record', help='A record to point to')
59+
5760
args = parser.parse_args()
58-
main(args.file, args.v, args.e)
61+
if args.command == 'analyze':
62+
analyze(args.file, args.e, args.v)
63+
elif args.command == 'dns':
64+
dns_redirect(args.domain, args.a_record, args.v)
65+
else:
66+
parser.print_help()
67+
sys.exit(0)

pup.py

+7-12
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,16 @@ def __init__(self, file, filename):
1919

2020
self.pup = pup_header.parse(file)
2121

22-
def info_raw(self):
23-
24-
print('PS5 PUP iNFO')
25-
print('#############')
26-
27-
print('Filename: ' + os.path.basename(self.file))
28-
print(self.pup)
29-
30-
def info(self):
22+
def info(self, verbose):
3123

3224
print('PS5 PUP iNFO')
3325
print('############')
34-
35-
print('Filename: ' + os.path.basename(self.file))
36-
print('Header not analyzed, yet...')
26+
27+
if verbose:
28+
print(self.pup)
29+
else:
30+
print('Filename: ' + os.path.basename(self.file))
31+
print('Header not analyzed, yet...')
3732

3833
def extract(self):
3934

0 commit comments

Comments
 (0)