-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhpeutil.py
executable file
·92 lines (73 loc) · 2.99 KB
/
hpeutil.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env python3
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 1, March 2023
# Everyone is permitted to copy and distribute verbatim or modified
# copies of this license document, and changing it is allowed as long
# as the name is changed.
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
# 0. You just DO WHAT THE FUCK YOU WANT TO.
import argparse
import gzip
import os
import shutil
# This is what passes for clever in many
# parts of the world. Maybe Uniden would
# sell more scanners if they stopped being
# clever and stuck to CSV or JSON files that
# everybody can work with. They probably
# have some good ol' boy non-compete agreement
# with the ProScan guy.
UNIDEN_OBFUSCATION_KEY = 0x0C
UNIDEN_BYTE_ORDER = "little"
def xor_byte(byte: bytes) -> bytes:
byte_as_int = int.from_bytes(byte, UNIDEN_BYTE_ORDER)
xored = byte_as_int ^ UNIDEN_OBFUSCATION_KEY
return xored.to_bytes(1, UNIDEN_BYTE_ORDER)
def hpe_to_txt(file_path: str, cleanup: bool):
path, _ = os.path.splitext(file_path)
temp_gzip_file = f"{path}_tmp_decoding.gz"
dest_file = f"{path}_decoded.txt"
print(f"Decoding to {dest_file}...")
try:
# De-XOR to .gz
with open(file_path, "rb") as source:
with open(temp_gzip_file, "wb") as dest:
while (byte := source.read(1)):
dest.write(xor_byte(byte))
# Gunzip to .txt
with gzip.open(temp_gzip_file, "rb") as zipped:
with open(dest_file, "wb") as unzipped:
shutil.copyfileobj(zipped, unzipped)
finally:
if cleanup:
os.remove(temp_gzip_file)
def txt_to_hpe(file_path: str, cleanup: bool):
path, _ = os.path.splitext(file_path)
temp_gzip_file = f"{path}_tmp_encoding.gz"
dest_file = f"{path}_encoded.hpe"
print(f"Encoding to {dest_file}...")
try:
# Gzip with very minimal compression so Uniden's
# god-awful .NET code from the 90s can handle it.
with open(file_path, "rb") as source:
with gzip.open(temp_gzip_file, "wb", compresslevel=1) as zipped:
zipped.writelines(source)
# XOR to .hpe
with open(dest_file, "wb") as dest:
with open(temp_gzip_file, "rb") as zipped:
while (byte := zipped.read(1)):
dest.write(xor_byte(byte))
finally:
if cleanup:
os.remove(temp_gzip_file)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Tool for dealing with Uniden's offshore cubicle software")
parser.add_argument('operation', choices=['encode', 'decode'], help="Either 'encode' or 'decode'.")
parser.add_argument('filename', help="Path to the file that you want to operate on.")
parser.add_argument('--no-cleanup', action='store_true', help="Leaves intermediate .gz files in place for debugging purposes.")
args = parser.parse_args()
if args.operation == 'decode':
hpe_to_txt(args.filename, args.no_cleanup == False)
elif args.operation == 'encode':
txt_to_hpe(args.filename, args.no_cleanup == False)