-
Notifications
You must be signed in to change notification settings - Fork 348
/
lznt1.py
160 lines (137 loc) · 4.51 KB
/
lznt1.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import struct
import copy
def _decompress_chunk(chunk):
out = bytearray()
while chunk:
flags = chunk[0]
chunk = chunk[1:]
for i in range(8):
if not (flags >> i & 1):
out += chunk[0].to_bytes(length=1, byteorder='little')
chunk = chunk[1:]
else:
flag = struct.unpack('<H', chunk[:2])[0]
pos = len(out) - 1
l_mask = 0xFFF
o_shift = 12
while pos >= 0x10:
l_mask >>= 1
o_shift -= 1
pos >>= 1
length = (flag & l_mask) + 3
offset = (flag >> o_shift) + 1
if length >= offset:
tmp = out[-offset:] * int(0xFFF / len(out[-offset:]) + 1)
out += tmp[:length]
else:
out += out[-offset:-offset+length]
chunk = chunk[2:]
if len(chunk) == 0:
break
return out
def decompress(buf, length_check=True):
out = bytearray()
while buf:
header = struct.unpack('<H', bytes(buf[:2]))[0]
length = (header & 0xFFF) + 1
if length_check and length > len(buf[2:]):
raise ValueError('invalid chunk length')
else:
chunk = buf[2:2+length]
if header & 0x8000:
out += _decompress_chunk(chunk)
else:
out += chunk
buf = buf[2+length:]
return out
def _find(src, target, max_len):
result_offset = 0
result_length = 0
for i in range(1, max_len):
offset = src.rfind(target[:i])
if offset == -1:
break
tmp_offset = len(src) - offset
tmp_length = i
if tmp_offset == tmp_length:
tmp = src[offset:] * int(0xFFF / len(src[offset:]) + 1)
for j in range(i, max_len+1):
offset = tmp.rfind(target[:j])
if offset == -1:
break
tmp_length = j
if tmp_length > result_length:
result_offset = tmp_offset
result_length = tmp_length
if result_length < 3:
return 0, 0
return result_offset, result_length
def _compress_chunk(chunk):
blob = copy.copy(chunk)
out = b""
pow2 = 0x10
l_mask3 = 0x1002
o_shift = 12
while len(blob) > 0:
bits = 0
tmp = b""
for i in range(8):
bits >>= 1
while pow2 < (len(chunk) - len(blob)):
pow2 <<= 1
l_mask3 = (l_mask3 >> 1) + 1
o_shift -= 1
if len(blob) < l_mask3:
max_len = len(blob)
else:
max_len = l_mask3
offset, length = _find(chunk[:len(chunk) -
len(blob)], blob, max_len)
# try to find more compressed pattern
offset2, length2 = _find(chunk[:len(chunk) -
len(blob)+1], blob[1:], max_len)
if length < length2:
length = 0
if length > 0:
symbol = ((offset-1) << o_shift) | (length - 3)
tmp += struct.pack('<H', symbol)
# set the highest bit
bits |= 0x80
blob = blob[length:]
else:
tmp += bytes([blob[0]])
blob = blob[1:]
if len(blob) == 0:
break
out += struct.pack('B', bits >> (7 - i))
out += tmp
return out
def compress(buf, chunk_size=0x1000):
out = b""
while buf:
chunk = buf[:chunk_size]
compressed = _compress_chunk(chunk)
# chunk is compressed
if len(compressed) < len(chunk):
flags = 0xB000
header = struct.pack('<H', flags | (len(compressed)-1))
out += header + compressed
else:
flags = 0x3000
header = struct.pack('<H', flags | (len(chunk)-1))
out += header + chunk
buf = buf[chunk_size:]
return out
def compress_evil(buf, chunk_size=0x1000):
out = b""
while buf:
chunk = buf[:chunk_size]
compressed = _compress_chunk(chunk)
# always use the compressed chunk, even if it's larger >:)
flags = 0xB000
header = struct.pack('<H', flags | (len(compressed)-1))
out += header + compressed
buf = buf[chunk_size:]
# corrupt the "next" chunk
out += struct.pack('<H', 0x1337)
return out