mirror of
https://github.com/henrypp/simplewall.git
synced 2026-10-21 18:43:09 -05:00
198 lines
5.9 KiB
Python
198 lines
5.9 KiB
Python
import os
|
|
import math
|
|
import re
|
|
import xml.dom.minidom
|
|
|
|
import ctypes
|
|
from ctypes import wintypes
|
|
|
|
FORMATS = {
|
|
"COMPRESSION_FORMAT_LZNT1" : ctypes.c_uint16 (2),
|
|
"COMPRESSION_FORMAT_XPRESS" : ctypes.c_uint16 (3),
|
|
"COMPRESSION_FORMAT_XPRESS_HUFF" : ctypes.c_uint16 (4)
|
|
}
|
|
|
|
ENGINES = {
|
|
"COMPRESSION_ENGINE_STANDARD" : ctypes.c_uint16 (0),
|
|
"COMPRESSION_ENGINE_MAXIMUM" : ctypes.c_uint16 (256)
|
|
}
|
|
|
|
|
|
def natural_sort (list, key=lambda s:s):
|
|
def get_alphanum_key_func (key):
|
|
convert = lambda text: int (text) if text.isdigit () else text
|
|
return lambda s: [convert (c) for c in re.split ('([0-9]+)', key (s))]
|
|
list.sort (key=get_alphanum_key_func (key))
|
|
|
|
def human_readable_size (size, decimal_places=2):
|
|
for unit in ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB']:
|
|
if size < 1024.0 or unit == 'PiB':
|
|
break
|
|
size /= 1024.0
|
|
|
|
return f"{size:.{decimal_places}f} {unit}"
|
|
|
|
def pack_file_lznt (buffer_data, buffer_length):
|
|
format_and_engine = wintypes.USHORT (FORMATS["COMPRESSION_FORMAT_LZNT1"].value | ENGINES["COMPRESSION_ENGINE_MAXIMUM"].value)
|
|
|
|
workspace_buffer_size = wintypes.ULONG()
|
|
workspace_fragment_size = wintypes.ULONG()
|
|
|
|
# RtlGetCompressionWorkSpaceSize
|
|
ctypes.windll.ntdll.RtlGetCompressionWorkSpaceSize.restype = wintypes.LONG
|
|
ctypes.windll.ntdll.RtlGetCompressionWorkSpaceSize.argtypes = (
|
|
wintypes.USHORT,
|
|
wintypes.PULONG,
|
|
wintypes.PULONG
|
|
)
|
|
|
|
status = ctypes.windll.ntdll.RtlGetCompressionWorkSpaceSize (
|
|
format_and_engine,
|
|
ctypes.byref(workspace_buffer_size),
|
|
ctypes.byref(workspace_fragment_size)
|
|
)
|
|
|
|
if status != 0:
|
|
print ('RtlGetCompressionWorkSpaceSize failed: 0x{0:X} {0:d} ({1:s})'.format(status, ctypes.FormatError(status)))
|
|
return None, 0
|
|
|
|
# Allocate memory
|
|
compressed_buffer = ctypes.create_string_buffer (buffer_length)
|
|
compressed_length = wintypes.ULONG()
|
|
|
|
workspace = ctypes.create_string_buffer (workspace_fragment_size.value)
|
|
|
|
# RtlCompressBuffer
|
|
ctypes.windll.ntdll.RtlCompressBuffer.restype = wintypes.LONG
|
|
ctypes.windll.ntdll.RtlCompressBuffer.argtypes = (
|
|
wintypes.USHORT,
|
|
wintypes.LPVOID,
|
|
wintypes.ULONG,
|
|
wintypes.LPVOID,
|
|
wintypes.ULONG,
|
|
wintypes.ULONG,
|
|
wintypes.PULONG,
|
|
wintypes.LPVOID
|
|
)
|
|
|
|
status = ctypes.windll.ntdll.RtlCompressBuffer (
|
|
format_and_engine,
|
|
ctypes.addressof (buffer_data),
|
|
ctypes.sizeof (buffer_data),
|
|
ctypes.addressof (compressed_buffer),
|
|
ctypes.sizeof (compressed_buffer),
|
|
wintypes.ULONG (4096),
|
|
ctypes.byref (compressed_length),
|
|
ctypes.addressof (workspace)
|
|
)
|
|
|
|
if status != 0:
|
|
print ('RtlCompressBuffer failed: 0x{0:X} {0:d} ({1:s})'.format (status, ctypes.FormatError(status)))
|
|
return None, 0
|
|
|
|
return compressed_buffer, compressed_length
|
|
|
|
CURRENT_DIRECTORY = os.path.dirname (os.path.abspath (__file__))
|
|
RULES_DIR = os.path.join (CURRENT_DIRECTORY, '..', '!repos', 'WindowsSpyBlocker', 'data', 'firewall')
|
|
RULES_FILE = os.path.join (CURRENT_DIRECTORY, 'bin', 'profile_internal.xml')
|
|
RULES_FILE_PACKED = os.path.join (CURRENT_DIRECTORY, 'bin', 'profile_internal_packed.bin')
|
|
|
|
if not os.path.isdir (RULES_DIR):
|
|
raise Exception ('Rules directory not found: ' + RULES_DIR)
|
|
|
|
if not os.path.isfile (RULES_FILE):
|
|
raise Exception ('Profile internal not found: ' + RULES_FILE)
|
|
|
|
# Open profile xml
|
|
with open (RULES_FILE, 'r', newline='') as f:
|
|
data = f.read ()
|
|
|
|
if not data:
|
|
raise Exception ('File reading failure: ' + RULES_FILE)
|
|
|
|
# toprettyxml() hack
|
|
data = data.replace ('\n', '')
|
|
data = data.replace ('\t', '')
|
|
|
|
xml_doc = xml.dom.minidom.parseString (data)
|
|
xml_root = xml_doc.getElementsByTagName ("root")
|
|
|
|
f.close ()
|
|
|
|
# Store timestamp
|
|
timestamp = int (xml_root[0].getAttribute ('timestamp'))
|
|
|
|
# Cleanup xml
|
|
for node in xml_doc.getElementsByTagName ('rules_blocklist'):
|
|
parent = node.parentNode
|
|
parent.removeChild (node)
|
|
|
|
xml_root[0].appendChild (xml_doc.createElement ('rules_blocklist'))
|
|
xml_section = xml_doc.getElementsByTagName ('rules_blocklist')
|
|
|
|
if not xml_section:
|
|
raise Exception ('Parse xml failure.')
|
|
|
|
# Enumerate Windows Spy Blocker spy/extra and update rules
|
|
for file_name in os.listdir (RULES_DIR):
|
|
module_name = os.path.splitext (file_name)[0]
|
|
module_path = os.path.join (RULES_DIR, file_name)
|
|
|
|
print ('Parsing ' + module_name + '...')
|
|
|
|
lastmod = int (os.path.getmtime (module_path));
|
|
|
|
if lastmod > timestamp:
|
|
timestamp = lastmod;
|
|
|
|
with open (module_path, 'r') as f:
|
|
rows = f.readlines ()
|
|
natural_sort (rows)
|
|
f.close ()
|
|
|
|
for string in rows:
|
|
line = string.strip ("\n\r\t ")
|
|
|
|
if line and not line.startswith ('#') and not line.startswith ('<') and not line.startswith ('>') and not line.startswith ('='):
|
|
new_item = xml_doc.createElement ('item')
|
|
new_item.setAttribute ('name', module_name + '_' + line)
|
|
new_item.setAttribute ('rule', line)
|
|
|
|
xml_section[0].appendChild (new_item)
|
|
|
|
# Set new rule timestamp
|
|
xml_root[0].setAttribute ('timestamp', str (timestamp))
|
|
|
|
# Save updated profile xml
|
|
data = xml_doc.toprettyxml (indent="\t", newl="\n")
|
|
|
|
if data:
|
|
data = data.replace ('/>', ' />')
|
|
|
|
with open (RULES_FILE, 'w', newline='') as fn:
|
|
fn.write (data)
|
|
fn.close ()
|
|
|
|
with open (RULES_FILE, 'rb') as fn:
|
|
data = fn.read ()
|
|
|
|
if data:
|
|
data_length = len (data)
|
|
data_buffer = (data_length * ctypes.c_ubyte).from_buffer_copy (data)
|
|
|
|
compressed_buffer, compressed_size = pack_file_lznt (data_buffer, data_length)
|
|
|
|
print ('\nPacking rules from %s to %s (%s saved)...' % (human_readable_size (data_length), human_readable_size (compressed_size.value), human_readable_size (data_length - compressed_size.value)))
|
|
|
|
if compressed_buffer != None and compressed_size.value != 0:
|
|
|
|
with open (RULES_FILE_PACKED, 'wb') as fn_pack:
|
|
write_array_buffer = (compressed_size.value * ctypes.c_ubyte).from_buffer_copy (compressed_buffer)
|
|
|
|
fn_pack.write (write_array_buffer)
|
|
fn_pack.close ()
|
|
|
|
fn.close ()
|
|
|
|
print ('\nBlocklist timetamp ' + str (timestamp))
|