30
30
repo_name = 'binja_native_sigscan'
31
31
file_url = 'https://github.com/{}/{}/releases/latest/download' .format (repo_owner , repo_name )
32
32
33
- # Name of files in release section on github (leave blank if platform not supported)
34
- win_file = 'sigscan.dll'
35
- linux_file = ''
36
- darwin_file = ''
33
+ # File names in release section on github along with Binary Ninja versions for which they were compiled (leave whole variable blank if platform not supported)
34
+ # Both version variables are inclusive meaning any Binary Ninja version in between is supported, DO NOT include '-dev' suffix so instead of '3.4.4189-dev', use just '3.4.4189')
35
+ # Example:
36
+ # win_files = [
37
+ # ('3.1.3469', '3.3.3996', 'sigscan.dll'),
38
+ # ('3.4.4169', '3.4.4189', 'sigscan_dev.dll')
39
+ # ]
40
+ win_files = [
41
+ ('3.1.3469' , '3.1.3469' , 'sigscan_3469.dll' ),
42
+ ('3.2.3814' , '3.2.3814' , 'sigscan_3814.dll' ),
43
+ ('3.3.3996' , '3.3.3996' , 'sigscan.dll' ),
44
+ ('3.4.4169' , '3.4.4189' , 'sigscan_dev.dll' )
45
+ ]
46
+ linux_files = []
47
+ darwin_files = []
48
+
49
+ # Function that determines whether Binary Ninja version is supported (returns None if not, according file name if yes)
50
+ def is_version_supported (files ):
51
+ # Get current Binary Ninja version
52
+ version_numbers = binaryninja .core_version ().split ()[0 ].split ('-' )[0 ].split ('.' )
53
+ major , minor , build = map (int , version_numbers )
54
+
55
+ # Loop through files for current platform and see if our version is supported by any
56
+ for entry in files :
57
+ min_ver , max_ver , file = entry
58
+
59
+ min_parts = min_ver .split ('.' )
60
+ max_parts = max_ver .split ('.' )
61
+
62
+ major_match = (major >= int (min_parts [0 ]) and major <= int (max_parts [0 ]))
63
+ minor_match = (minor >= int (min_parts [1 ]) and minor <= int (max_parts [1 ]))
64
+ build_match = (build >= int (min_parts [2 ]) and build <= int (max_parts [2 ]))
65
+
66
+ if major_match and minor_match and build_match :
67
+ return file
68
+
69
+ return None
37
70
38
71
# Function that determines whether system is supported
39
72
def is_system_supported (file_name ):
@@ -57,13 +90,15 @@ def read_data_file():
57
90
return f .read ().splitlines ()
58
91
59
92
# Function that writes to current_native_plugin_data file
60
- def write_data_file (version , hash ):
93
+ def write_data_file (version , hash , file_name ):
61
94
with open (os .path .join (binaryninja .user_plugin_path (), 'native_plugins_data' , plugin_name + '.data' ), 'w' ) as f :
62
- f .write (version + '\n ' + hash )
95
+ f .write (version + '\n ' + hash + ' \n ' + file_name )
63
96
64
97
# Function that deletes file from current_native_plugin_data
65
98
def delete_data_file ():
66
- os .remove (os .path .join (binaryninja .user_plugin_path (), 'native_plugins_data' , plugin_name + '.data' ))
99
+ path = os .path .join (binaryninja .user_plugin_path (), 'native_plugins_data' , plugin_name + '.data' )
100
+ if os .path .isfile (path ):
101
+ os .remove (path )
67
102
68
103
# Function that calculates hash of file
69
104
def calculate_hash (file_path ):
@@ -96,63 +131,61 @@ def download_file_to_temp(file_url, file_name):
96
131
97
132
# Function that deletes file
98
133
def delete_file (file_path ):
99
- os .remove (file_path )
134
+ if os .path .isfile (file_path ):
135
+ os .remove (file_path )
100
136
101
137
# Function that deletes file from temp directory
102
138
def delete_file_from_temp (file_name ):
103
- os .remove (os .path .join (binaryninja .user_plugin_path (), 'temp' , file_name ))
139
+ path = os .path .join (binaryninja .user_plugin_path (), 'temp' , file_name )
140
+ if os .path .isfile (path ):
141
+ os .remove (path )
104
142
105
- # Function that determines whether plugin is installed
143
+ # Function that determines whether plugin is installed (for current Binary Ninja version)
106
144
def is_plugin_installed (file_name ):
107
145
return os .path .isfile (os .path .join (binaryninja .user_plugin_path (), file_name ))
108
146
109
- # Function that determines whether plugin is outdated
110
- def is_plugin_outdated (version , hash ):
111
- if data_folder_exists ():
112
- if data_file_exists (plugin_name ):
113
- data = read_data_file (plugin_name )
114
- if data [0 ] == version and data [1 ] == hash :
115
- return False
116
- else :
117
- return True
118
- else :
119
- return True
120
- else :
121
- return True
122
-
123
147
# Function that alerts user
124
148
def alert_user (description ):
125
149
binaryninja .interaction .show_message_box ('{} (Native plugin loader)' .format (plugin_name ), description , binaryninja .enums .MessageBoxButtonSet .OKButtonSet , binaryninja .enums .MessageBoxIcon .InformationIcon )
126
150
127
151
# Function that does the actual work
128
- def check_for_updates (repo_owner , repo_name , file_url , win_file , linux_file , darwin_file ):
129
- # Retrieve the HTML of the release page
130
- release_url = 'https://github.com/{}/{}/releases/latest' .format (repo_owner , repo_name )
131
- response = requests .get (release_url )
132
- html = response .content
133
-
134
- # Parse the HTML to extract the release version
135
- soup = bs4 .BeautifulSoup (html , 'html.parser' )
136
- latest_version_tag = getattr (soup .find ('span' , {'class' : 'css-truncate-target' }), 'text' , None )
137
- latest_version = latest_version_tag .strip () if latest_version_tag else None
138
-
152
+ def check_for_updates (repo_owner , repo_name , file_url , win_files , linux_files , darwin_files ):
139
153
# Determine OS we are running on
140
154
platform = sys .platform .lower ()
141
155
142
156
# Windows
143
157
if platform .startswith ('win' ):
144
- file_url = '{}/{}' .format (file_url , win_file )
145
- file = win_file
158
+ files = win_files
146
159
# Linux
147
160
elif platform .startswith ('linux' ):
148
- file_url = '{}/{}' .format (file_url , linux_file )
149
- file = linux_file
161
+ files = linux_files
150
162
# Mac
151
163
elif platform .startswith ('darwin' ):
152
- file_url = '{}/{}' .format (file_url , darwin_file )
153
- file = darwin_file
164
+ files = darwin_files
154
165
else :
155
166
alert_user (plugin_name , 'Unsupported platform' )
167
+ return
168
+
169
+ # Check Binary Ninja version and possible get file name for current version
170
+ file = is_version_supported (files )
171
+ if not file :
172
+ version_numbers = binaryninja .core_version ().split ()[0 ].split ('-' )[0 ].split ('.' )
173
+ major , minor , build = map (int , version_numbers )
174
+ alert_user ('Current version of Binary Ninja ({}) is not supported.' .format (str (major ) + '.' + str (minor ) + '.' + str (build )))
175
+ return
176
+
177
+ # Create url for file we need
178
+ file_url = '{}/{}' .format (file_url , file )
179
+
180
+ # Retrieve the HTML of the release page
181
+ release_url = 'https://github.com/{}/{}/releases/latest' .format (repo_owner , repo_name )
182
+ response = requests .get (release_url )
183
+ html = response .content
184
+
185
+ # Parse the HTML to extract the release version
186
+ soup = bs4 .BeautifulSoup (html , 'html.parser' )
187
+ latest_version_tag = getattr (soup .find ('span' , {'class' : 'css-truncate-target' }), 'text' , None )
188
+ latest_version = latest_version_tag .strip () if latest_version_tag else None
156
189
157
190
# Make sure we have data folder
158
191
if not data_folder_exists ():
@@ -166,21 +199,35 @@ def check_for_updates(repo_owner, repo_name, file_url, win_file, linux_file, dar
166
199
for file in os .listdir (os .path .join (binaryninja .user_plugin_path (), 'temp' )):
167
200
delete_file_from_temp (file )
168
201
169
- # Do the thing
202
+ # Verify we have correct file
170
203
if (is_system_supported (file ) and latest_version != None ):
171
204
plugin_data = (read_data_file () if data_file_exists () else None ) if data_folder_exists () else None
172
- # Check if we have both version and hash of the plugin
173
- if plugin_data == None or len (plugin_data ) != 2 or plugin_data [0 ] == None or plugin_data [1 ] == None :
205
+ # Check if we have all required data (version, hash, file name)
206
+ if plugin_data == None or len (plugin_data ) != 3 or plugin_data [0 ] == None or plugin_data [1 ] == None or plugin_data [ 2 ] == None :
174
207
delete_data_file () if data_file_exists () else None
175
208
plugin_data = None
176
209
177
210
data_version = plugin_data [0 ] if plugin_data != None else None
178
211
data_hash = plugin_data [1 ] if plugin_data != None else None
212
+ data_file_name = plugin_data [2 ] if plugin_data != None else None
213
+
214
+ # Check if we there is a binary for different Binary Ninja version
215
+ if (data_file_name != None and data_file_name != file ):
216
+ # Delete old file
217
+ delete_file (os .path .join (binaryninja .user_plugin_path (), data_file_name ))
218
+ # Delete data file
219
+ delete_data_file ()
220
+ # Reset data
221
+ plugin_data = None
222
+ data_version = None
223
+ data_hash = None
224
+ data_file_name = None
225
+
179
226
if not is_plugin_installed (file ):
180
227
# Plugin not installed, just download it
181
228
if download_file (file_url , file ):
182
229
# Register plugin in data directory
183
- write_data_file (latest_version , calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )))
230
+ write_data_file (latest_version , calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )), file )
184
231
alert_user ('Plugin downloaded successfully, please restart Binary Ninja to load it' )
185
232
else :
186
233
alert_user ('Failed to download plugin' )
@@ -191,7 +238,7 @@ def check_for_updates(repo_owner, repo_name, file_url, win_file, linux_file, dar
191
238
download_file_to_temp (file_url , file )
192
239
if (calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )) == calculate_hash (os .path .join (binaryninja .user_plugin_path (), 'temp' , file ))):
193
240
# We have the latest version, register it in data directory
194
- write_data_file (latest_version , calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )))
241
+ write_data_file (latest_version , calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )), file )
195
242
delete_file_from_temp (file )
196
243
else :
197
244
# We don't have the latest version, alert user
@@ -209,7 +256,7 @@ def check_for_updates(repo_owner, repo_name, file_url, win_file, linux_file, dar
209
256
download_file_to_temp (file_url , file )
210
257
if (calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )) == calculate_hash (os .path .join (binaryninja .user_plugin_path (), 'temp' , file ))):
211
258
# We have the latest version, register it in data directory so user is not prompted to update as he probably already did
212
- write_data_file (latest_version , calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )))
259
+ write_data_file (latest_version , calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )), file )
213
260
delete_file_from_temp (file )
214
261
else :
215
262
# We don't have the latest version, alert user
@@ -224,7 +271,7 @@ def check_for_updates(repo_owner, repo_name, file_url, win_file, linux_file, dar
224
271
download_file_to_temp (file_url , file )
225
272
if (calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )) == calculate_hash (os .path .join (binaryninja .user_plugin_path (), 'temp' , file ))):
226
273
# Yep, hash of the plugin in the github release corresponds to the hash of currently installed plugin so we have the latest one
227
- write_data_file (latest_version , calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )))
274
+ write_data_file (latest_version , calculate_hash (os .path .join (binaryninja .user_plugin_path (), file )), file )
228
275
delete_file_from_temp (file )
229
276
else :
230
277
# Not the latest one (according to the hash in the github release), but user might be intending to test different version of the plugin, add ignore option
@@ -237,7 +284,7 @@ def __init__(self):
237
284
binaryninja .BackgroundTaskThread .__init__ (self , 'Native plugin loader - checking for updates on: {}' .format (plugin_name ), True )
238
285
239
286
def run (self ):
240
- check_for_updates (repo_owner , repo_name , file_url , win_file , linux_file , darwin_file )
287
+ check_for_updates (repo_owner , repo_name , file_url , win_files , linux_files , darwin_files )
241
288
242
289
obj = Updater ()
243
290
obj .start ()
0 commit comments