From 5b6250e5df342d3035974da8485c981557f06583 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Tue, 14 Feb 2023 16:48:51 +0900 Subject: [PATCH 1/3] Added feature to check data signatures at Source.Python setup. --- .../packages/source-python/__init__.py | 56 +++++++++++++ .../packages/source-python/memory/helpers.py | 81 +++++++++++++++++++ 2 files changed, 137 insertions(+) mode change 100644 => 100755 addons/source-python/packages/source-python/__init__.py diff --git a/addons/source-python/packages/source-python/__init__.py b/addons/source-python/packages/source-python/__init__.py old mode 100644 new mode 100755 index 5ca9588e5..aa6cca369 --- a/addons/source-python/packages/source-python/__init__.py +++ b/addons/source-python/packages/source-python/__init__.py @@ -83,6 +83,7 @@ def load(): setup_logging() setup_exception_hooks() setup_data_update() + setup_check_signatures() setup_translations() setup_data() setup_global_pointers() @@ -136,6 +137,61 @@ def setup_data_update(): _sp_logger.log_exception( 'An error occured during the data update.', exc_info=True) +def setup_check_signatures(): + """Setup check signatures.""" + _sp_logger.log_debug('Checking data signatures...') + + # Python Imports + from warnings import warn + # Source.Python Imports + from memory.helpers import check_type_signature_from_file + from memory.helpers import check_pipe_signature_from_file + from paths import SP_DATA_PATH + + # iterate over SP_DATA_PATH / 'entities' and extract all files + files = set(SP_DATA_PATH / 'entities' / file.name for file in + (SP_DATA_PATH / 'entities').walkfiles('*.ini')) + + # add CBaseClient. + files.add(SP_DATA_PATH / 'client' / 'CBaseClient.ini') + + # add CBaseEntityOutput. + files.add(SP_DATA_PATH / 'entity_output' / 'CBaseEntityOutput.ini') + + class_warn = False + + # check the class type signatures. + for file in files: + for name, identifier in check_type_signature_from_file(file): + if not class_warn: + warn( + 'Invalid signature detected in class data, ' + 'specific function will not work.' + ) + class_warn = True + _sp_logger.log_warning( + 'Invalid signature detected.\n' + 'Name: {0}\nSignature: {1}\nFile: {2}'.format( + name, ' '.join("{:02X}".format(i) for i in identifier), file)) + + # check the global pointers signature + file = SP_DATA_PATH / 'memory' / 'global_pointers.ini' + + gp_warn = False + + for name, identifier in check_pipe_signature_from_file(file): + if not gp_warn: + warn( + 'Invalid signature detected in global pointers data, ' + 'may cause problems with Source.Python operation.' + ) + gp_warn = True + + _sp_logger.log_warning( + 'Invalid signature detected.\n' + 'Name: {0}\nSignature: {1}\nFile: {2}'.format( + name, ' '.join("{:02X}".format(i) for i in identifier), file)) + def setup_data(): """Setup data.""" _sp_logger.log_debug('Setting up data...') diff --git a/addons/source-python/packages/source-python/memory/helpers.py b/addons/source-python/packages/source-python/memory/helpers.py index 4c0ba2177..e14858e6f 100755 --- a/addons/source-python/packages/source-python/memory/helpers.py +++ b/addons/source-python/packages/source-python/memory/helpers.py @@ -11,6 +11,7 @@ # Source.Python # Core +from core import GameConfigObj from core import PLATFORM # Memory from memory import Convention @@ -18,6 +19,7 @@ from memory import Function from memory import Pointer from memory import TYPE_SIZES +from memory import find_binary from memory import make_object @@ -404,6 +406,85 @@ def parse_data(manager, raw_data, keys): yield (name, temp_data) +def check_type_signature_from_file(file): + """Checks if the data signatures are valid.""" + raw_data = GameConfigObj(file) + + # get the binary name from the data(defaults to server if not present) + _binary = Key.as_str(None, raw_data.get( + Key.BINARY + '_' + PLATFORM, raw_data.get(Key.BINARY, 'server'))) + _srv_check = Key.as_bool(None, raw_data.get( + Key.SRV_CHECK + '_' + PLATFORM, raw_data.get(Key.SRV_CHECK, 'True'))) + + key = Key.IDENTIFIER + binary = None + + for method, default in (('function', NO_DEFAULT), ): + for name, data in raw_data.get(method, {}).items(): + identifier = data.get(key + '_' + PLATFORM, data.get(key, default)) + + # ignore identifier + if identifier is None: + continue + + # if the identifier is NO_DEFAULT, the key is obviously missing + if identifier is NO_DEFAULT: + raise KeyError( + 'Missing identifier for "{0}".\nFile: {1}'.format( + name, file)) + + if binary is None: + try: + binary = find_binary(_binary, _srv_check) + except OSError as error: + print(error) + raise ValueError( + 'Could not find the binary.\nFile: {0}'.format(file)) + + try: + identifier = Key.as_identifier(None, identifier) + binary[identifier] + except ValueError: + yield (name, identifier) + +def check_pipe_signature_from_file(file): + """Checks if the data signatures are valid.""" + raw_data = GameConfigObj(file) + + key = Key.IDENTIFIER + + for name, data in raw_data.items(): + identifier = data.get(key + '_' + PLATFORM, data.get(key, NO_DEFAULT)) + + # if the identifier is NO_DEFAULT, the key is obviously missing + if identifier is NO_DEFAULT: + raise KeyError( + 'Missing identifier for "{0}".\nFile: {1}'.format( + name, file)) + + _binary = Key.as_str(None, data.get( + Key.BINARY + '_' + PLATFORM, data.get(Key.BINARY, NO_DEFAULT))) + if _binary is NO_DEFAULT: + raise KeyError( + 'Missing binary for "{0}".\nFile: {1}'.format( + name, file)) + + _srv_check = Key.as_bool(None, data.get( + Key.SRV_CHECK + '_' + PLATFORM, data.get(Key.SRV_CHECK, 'True'))) + + try: + binary = find_binary(_binary, _srv_check) + except OSError as error: + print(error) + raise ValueError( + 'Could not find the binary.\nFile: {0}'.format(file)) + + try: + identifier = Key.as_identifier(None, identifier) + binary[identifier] + except ValueError: + yield (name, identifier) + # Use this as a default value if the key is not allowed to have a default # value NO_DEFAULT = object() From c0de2238ab9668860c737f69c9470057addeaf61 Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Tue, 14 Feb 2023 18:51:22 +0900 Subject: [PATCH 2/3] Minor fixes. --- .../packages/source-python/__init__.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/addons/source-python/packages/source-python/__init__.py b/addons/source-python/packages/source-python/__init__.py index aa6cca369..29a1b4739 100755 --- a/addons/source-python/packages/source-python/__init__.py +++ b/addons/source-python/packages/source-python/__init__.py @@ -170,9 +170,13 @@ def setup_check_signatures(): ) class_warn = True _sp_logger.log_warning( - 'Invalid signature detected.\n' - 'Name: {0}\nSignature: {1}\nFile: {2}'.format( - name, ' '.join("{:02X}".format(i) for i in identifier), file)) + 'Invalid signature detected.\n' + 'Name: {0}\nSignature: {1}\nFile: {2}\n'.format( + name, + ' '.join("{:02X}".format(i) for i in identifier), + file + ) + ) # check the global pointers signature file = SP_DATA_PATH / 'memory' / 'global_pointers.ini' @@ -188,9 +192,13 @@ def setup_check_signatures(): gp_warn = True _sp_logger.log_warning( - 'Invalid signature detected.\n' - 'Name: {0}\nSignature: {1}\nFile: {2}'.format( - name, ' '.join("{:02X}".format(i) for i in identifier), file)) + 'Invalid signature detected.\n' + 'Name: {0}\nSignature: {1}\nFile: {2}\n'.format( + name, + ' '.join("{:02X}".format(i) for i in identifier), + file + ) + ) def setup_data(): """Setup data.""" From 2d024eb223f462a60a22de9478f73b8253ced99d Mon Sep 17 00:00:00 2001 From: Jonathan <30329245+CookStar@users.noreply.github.com> Date: Wed, 15 Feb 2023 12:59:32 +0900 Subject: [PATCH 3/3] Minor fixes. --- addons/source-python/packages/source-python/memory/helpers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/source-python/packages/source-python/memory/helpers.py b/addons/source-python/packages/source-python/memory/helpers.py index e14858e6f..c845fb455 100755 --- a/addons/source-python/packages/source-python/memory/helpers.py +++ b/addons/source-python/packages/source-python/memory/helpers.py @@ -32,6 +32,8 @@ 'MemberFunction', 'NO_DEFAULT', 'Type', + 'check_pipe_signature_from_file', + 'check_type_signature_from_file', 'parse_data', )