-
Notifications
You must be signed in to change notification settings - Fork 63
/
asar.py
140 lines (112 loc) · 4.86 KB
/
asar.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
# pylint: disable=E0611
"""
Fixes Hardcoded tray icons in Linux.
Author : Bilal Elmoussaoui (bil.elmoussaoui@gmail.com)
Contributors : Andreas Angerer, Joshua Fogg, Ivo Šmerek
Website : https://github.com/bil-elmoussaoui/Hardcode-Tray
Licence : The script is released under GPL, uses a modified script
form Chromium project released under BSD license
This file is part of Hardcode-Tray.
Hardcode-Tray is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Hardcode-Tray is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Hardcode-Tray. If not, see <http://www.gnu.org/licenses/>.
"""
from __future__ import absolute_import
from json import dumps, loads
from struct import error as StructError
from struct import pack, unpack
from HardcodeTray.modules.log import Logger
from HardcodeTray.utils import (change_dict_vals, get_from_dict,
set_in_dict)
class AsarFile:
"""Write into ASAR files easily."""
def __init__(self, asar_file):
self._asar_file = asar_file
self.success = True
self._keys = []
# hb for header bytes
self._hb = [None, None, None]
self._old_content = None
self._get_header()
@property
def keys(self):
"""Keys to access to the file."""
# See the write method
return self._keys
@property
def old_content(self):
"""return the old content of the file."""
return self._old_content
def _get_header(self):
asarfile = open(self._asar_file, 'rb')
try:
asarfile.seek(4)
# header size is stored in byte 12:16
self._hb[0] = unpack('I', asarfile.read(4))[0]
self._hb[1] = unpack('I', asarfile.read(4))[0]
self._hb[2] = unpack('I', asarfile.read(4))[0]
self._zeros = (self._hb[1] - 4 - self._hb[2])
header = asarfile.read(self._hb[2]).decode('utf-8')
self._header = loads(header)
self._offset = asarfile.tell() + self._zeros
asarfile.close()
except StructError:
Logger.error(
"Electron: Couldn't read asar file {}".format(self._asar_file))
self.success = False
def write(self, icon, pngbytes):
"""Write some bytes to a icon path."""
self._keys = icon.split("/")
fileinfo = get_from_dict(self._header, self._keys)
# Make sure the icon to replace is found on the asar file
# To avoid breaking the binary.
# This is due to apps renaming/moving the icons around
if (not isinstance(fileinfo, dict)
or "offset" not in fileinfo.keys()):
return
offset0 = int(fileinfo['offset'])
offset = offset0 + self._offset
size = int(fileinfo['size'])
with open(self._asar_file, 'rb') as asarfile:
asar = asarfile.read()
set_in_dict(self._header, self._keys + ['size'], len(pngbytes))
# Save the old binary content for backup
# See electron.py
self._old_content = asar[offset: offset + size]
new_asar = pngbytes.join([asar[:offset],
asar[offset + size:]])
sizediff = len(pngbytes) - size
# Replace the content on the header (as a dict)
new_files = change_dict_vals(self._header, sizediff, offset0)
new_header = dumps(new_files).encode('utf-8')
header_length = len(new_header)
first_byte = pack('I', header_length + (self._hb[0] - self._hb[2]))
sec_byte = pack('I', header_length + (self._hb[1] - self._hb[2]))
third_byte = pack('I', header_length)
asar_content = b''.join([asar[:4], first_byte,
sec_byte, third_byte, new_header,
b'\x00' * self._zeros,
new_asar[self._offset:]])
asarfile = open(self._asar_file, 'wb')
asarfile.write(asar_content)
asarfile.close()
def read_file(self, path):
"""Read a file in asar archive."""
self._keys = path.split("/")
fileinfo = get_from_dict(self._header, self._keys)
if (not isinstance(fileinfo, dict)
or "offset" not in fileinfo.keys()):
return
offset0 = int(fileinfo['offset'])
offset = offset0 + self._offset
size = int(fileinfo['size'])
with open(self._asar_file, 'rb') as asarfile:
asar = asarfile.read()
return asar[offset: offset + size]