Skip to content

Commit 7895e7b

Browse files
Fixed major bugs that affect Logicytics (performance checker) (#224)
2 parents 9a32917 + efbc0a2 commit 7895e7b

File tree

15 files changed

+186
-111
lines changed

15 files changed

+186
-111
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,3 +322,9 @@ $RECYCLE.BIN/
322322
/CODE/VulnScan/tools/NN features/
323323
/CODE/logicytics/User_History.json.gz
324324
/CODE/logicytics/User_History.json
325+
/CODE/SysInternal_Suite/psfile.exe
326+
/CODE/SysInternal_Suite/PsGetsid.exe
327+
/CODE/SysInternal_Suite/PsInfo.exe
328+
/CODE/SysInternal_Suite/pslist.exe
329+
/CODE/SysInternal_Suite/PsLoggedon.exe
330+
/CODE/SysInternal_Suite/psloglist.exe

.idea/csv-editor.xml

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CODE/Logicytics.py

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
import psutil
1313
from prettytable import PrettyTable
1414

15-
from logicytics import Log, Execute, Check, Get, FileManagement, Flag, DEBUG, DELETE_LOGS, CONFIG
15+
from logicytics import Log, Execute, Check, Get, FileManagement, Flag, DEBUG, DELETE_LOGS, config
1616

1717
# Initialization
1818
log = Log({"log_level": DEBUG, "delete_log": DELETE_LOGS})
1919
ACTION, SUB_ACTION = None, None
20-
MAX_WORKERS = CONFIG.getint("Settings", "max_workers", fallback=min(32, (os.cpu_count() or 1) + 4))
20+
MAX_WORKERS = config.getint("Settings", "max_workers", fallback=min(32, (os.cpu_count() or 1) + 4))
2121
log.debug(f"MAX_WORKERS: {MAX_WORKERS}")
2222

2323

@@ -67,7 +67,8 @@ def __generate_execution_list(self) -> list[str]:
6767
- Warns users about potential long execution times for certain actions
6868
"""
6969
execution_list = Get.list_of_files(".", only_extensions=(".py", ".exe", ".ps1", ".bat"),
70-
exclude_files=["Logicytics.py"])
70+
exclude_files=["Logicytics.py"],
71+
exclude_dirs=["logicytics", "SysInternal_Suite"])
7172
files_to_remove = {
7273
"sensitive_data_miner.py",
7374
"dir_list.py",
@@ -101,7 +102,8 @@ def __generate_execution_list(self) -> list[str]:
101102
elif ACTION == "modded":
102103
# Add all files in MODS to execution list
103104
execution_list = Get.list_of_files("../MODS", only_extensions=(".py", ".exe", ".ps1", ".bat"),
104-
append_file_list=execution_list, exclude_files=["Logicytics.py"])
105+
append_file_list=execution_list, exclude_files=["Logicytics.py"],
106+
exclude_dirs=["logicytics", "SysInternal_Suite"])
105107

106108
elif ACTION == "depth":
107109
log.warning(
@@ -128,6 +130,7 @@ def __generate_execution_list(self) -> list[str]:
128130
log.critical("Nothing is in the execution list.. This is due to faulty code or corrupted Logicytics files!")
129131
exit(1)
130132

133+
log.debug(f"Execution list length: {len(execution_list)}")
131134
log.debug(f"The following will be executed: {execution_list}")
132135
return execution_list
133136

@@ -208,18 +211,32 @@ def __performance(self):
208211
end_time = datetime.now()
209212
end_memory = process.memory_full_info().uss / 1024 / 1024 # MB
210213
elapsed_time = end_time - start_time
211-
memory_delta = end_memory - start_memory
212-
memory_usage.append((self.execution_list[file], str(memory_delta)))
214+
memory_delta = max(0, end_memory - start_memory) # Clamps negative delta to 0
215+
memory_usage.append((self.execution_list[file], f"{memory_delta}"))
213216
execution_times.append((self.execution_list[file], elapsed_time))
214217
log.info(f"{self.execution_list[file]} executed in {elapsed_time}")
215-
log.info(f"{self.execution_list[file]} used {memory_delta:.2f}MB of memory")
216-
log.debug(f"Started with {start_memory}MB of memory and ended with {end_memory}MB of memory")
218+
try:
219+
if (end_memory - start_memory) < 0:
220+
log.info(
221+
f"{self.execution_list[file]} used {memory_delta:.3f}MB of memory - \033[33mPossible Affected by outside processes\033[0m")
222+
else:
223+
log.info(f"{self.execution_list[file]} used {memory_delta:.3f}MB of memory")
224+
except Exception as e:
225+
log.warning("Failed to log memory usage delta, reason: " + str(e))
226+
log.debug(f"Started with {start_memory:.3f}MB of memory and ended with {end_memory:.3f}MB of memory")
217227

218228
table = PrettyTable()
219229
table.field_names = ["Script", "Execution Time", "Memory Usage (MB)"]
220230
for script, elapsed_time in execution_times:
221-
memory = next(m[1] for m in memory_usage if m[0] == script)
222-
table.add_row([script, elapsed_time, f"{memory:.2f}"])
231+
try:
232+
memory = f"{float(next(m[1] for m in memory_usage if m[0] == script)):.3f}"
233+
except StopIteration:
234+
log.warning(f"No memory data found for {script}")
235+
memory = "N/A"
236+
except Exception as e:
237+
log.warning(f"Failed to log memory usage for {script}, reason: " + str(e))
238+
memory = "N/A"
239+
table.add_row([script, elapsed_time, f"{memory}"])
223240

224241
try:
225242
with open(
@@ -228,9 +245,9 @@ def __performance(self):
228245
) as f:
229246
f.write(table.get_string())
230247
f.write(
231-
"\nSome values may be negative, Reason may be due to external resources playing with memory usage, "
232-
"close background tasks to get more accurate readings")
233-
f.write("Note: This is not a low-level memory logger, data here isn't 100% accurate!")
248+
"\nSome values may be negative, Reason may be due to external resources playing with memory usage,\n"
249+
"Close background tasks to get more accurate readings\n\n")
250+
f.write("Note: This is not a low-level memory logger, data here isn't 100% accurate!\n")
234251
log.info("Performance check complete! Performance log found in ACCESS/LOGS/PERFORMANCE")
235252
except Exception as e:
236253
log.error(f"Error writing performance log: {e}")
@@ -434,10 +451,16 @@ def check_privileges():
434451
log.warning("UAC is enabled, this may cause issues - Please disable UAC if possible")
435452

436453

437-
def zip_generated_files():
438-
"""Zips generated files based on the action."""
454+
class ZIP:
455+
@classmethod
456+
def files(cls):
457+
"""Zips generated files based on the action."""
458+
if ACTION == "modded":
459+
cls.__and_log("..\\MODS", "MODS")
460+
cls.__and_log(".", "CODE")
439461

440-
def zip_and_log(directory: str, name: str):
462+
@staticmethod
463+
def __and_log(directory: str, name: str):
441464
log.debug(f"Zipping directory '{directory}' with name '{name}' under action '{ACTION}'")
442465
zip_values = FileManagement.Zip.and_hash(
443466
directory,
@@ -451,10 +474,6 @@ def zip_and_log(directory: str, name: str):
451474
log.info(zip_loc)
452475
log.debug(hash_loc)
453476

454-
if ACTION == "modded":
455-
zip_and_log("..\\MODS", "MODS")
456-
zip_and_log(".", "CODE")
457-
458477

459478
def handle_sub_action():
460479
"""
@@ -472,8 +491,7 @@ def handle_sub_action():
472491
elif SUB_ACTION == "reboot":
473492
subprocess.call("shutdown /r /t 3", shell=False)
474493
# elif sub_action == "webhook":
475-
# Implement this in future
476-
# log.warning("This feature is not implemented yet! Sorry")
494+
# TODO: Implement this in future v3.5
477495

478496

479497
@log.function
@@ -501,7 +519,7 @@ def Logicytics():
501519
# Execute scripts
502520
ExecuteScript().handler()
503521
# Zip generated files
504-
zip_generated_files()
522+
ZIP.files()
505523
# Finish with sub actions
506524
handle_sub_action()
507525
# Finish

CODE/_dev.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def _handle_file_operations() -> None:
116116
Handles file operations and logging for added, removed, and normal files.
117117
"""
118118
EXCLUDE_FILES = ["logicytics\\User_History.json.gz", "logicytics\\User_History.json"]
119-
files = Get.list_of_files(".", exclude_files=EXCLUDE_FILES)
119+
files = Get.list_of_files(".", exclude_files=EXCLUDE_FILES, exclude_dirs=["SysInternal_Suite"])
120120
added_files, removed_files, normal_files = [], [], []
121121
clean_files_list = [file.replace('"', '') for file in CURRENT_FILES]
122122

CODE/config.ini

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ save_preferences = true
2626
[System Settings]
2727
# Do not play with these settings unless you know what you are doing
2828
# Dev Mode allows a safe way to modify these settings!!
29-
version = 3.4.0
30-
files = "bluetooth_details.py, bluetooth_logger.py, browser_miner.ps1, cmd_commands.py, config.ini, dir_list.py, dump_memory.py, event_log.py, Logicytics.py, log_miner.py, media_backup.py, netadapter.ps1, network_psutil.py, packet_sniffer.py, property_scraper.ps1, registry.py, sensitive_data_miner.py, ssh_miner.py, sys_internal.py, tasklist.py, tree.ps1, vulnscan.py, wifi_stealer.py, window_feature_miner.ps1, wmic.py, logicytics\Checks.py, logicytics\Config.py, logicytics\Execute.py, logicytics\FileManagement.py, logicytics\Flag.py, logicytics\Get.py, logicytics\Logger.py, logicytics\User_History.json.gz, SysInternal_Suite\.sys.ignore, SysInternal_Suite\SysInternal_Suite.zip, VulnScan\Model SenseMini .3n3.pth, VulnScan\README.md, VulnScan\Vectorizer .3n3.pkl"
29+
version = 3.4.1
30+
files = "bluetooth_details.py, bluetooth_logger.py, browser_miner.ps1, cmd_commands.py, config.ini, dir_list.py, dump_memory.py, event_log.py, Logicytics.py, log_miner.py, media_backup.py, netadapter.ps1, network_psutil.py, packet_sniffer.py, property_scraper.ps1, registry.py, sensitive_data_miner.py, ssh_miner.py, sys_internal.py, tasklist.py, tree.ps1, vulnscan.py, wifi_stealer.py, window_feature_miner.ps1, wmic.py, logicytics\Checks.py, logicytics\Config.py, logicytics\Execute.py, logicytics\FileManagement.py, logicytics\Flag.py, logicytics\Get.py, logicytics\Logger.py, logicytics\User_History.json.gz, VulnScan\Model SenseMini .3n3.pth, VulnScan\README.md, VulnScan\Vectorizer .3n3.pkl"
3131

3232
########################################################
3333
# The following settings are for specific modules #
@@ -56,14 +56,45 @@ model_debug = false
5656

5757
###################################################
5858

59+
[DumpMemory Settings]
60+
# If the file size generated exceeds this limit,
61+
# the file will be truncated with a message
62+
# Put 0 to disable the limit - Limit is in MiB - int
63+
file_size_limit = 0
64+
# Safety margin to check, it multiplies with the size limit
65+
# This makes sure that after the file is created, there is still
66+
# disk space left for other tasks,
67+
# Make sure its above 1 or else it will fail
68+
# Put 1 to disable the limit - Limit is in MiB - float
69+
file_size_safety = 1.5
70+
71+
###################################################
72+
73+
[NetWorkPsutil Settings]
74+
# Total time this will take will be `sample_count * interval`
75+
76+
# Number of samples to take for feature `measure network bandwidth usage`
77+
# This is an integer, and should be 1 and above
78+
sample_count = 5
79+
# Time between samples in seconds for feature `measure network bandwidth usage`
80+
# This is a float, and should be above 0
81+
interval = 1.5
82+
83+
###################################################
84+
5985
[PacketSniffer Settings]
6086
# The interface to sniff packets on, keep it as WiFi for most cases
6187
# Autocorrects between WiFi and Wi-Fi
6288
interface = WiFi
6389
# The number of packets to sniff,
64-
packet_count = 10000
65-
# The time to timeout the sniffing process
90+
# Must be greater than or equal to 1 - int
91+
packet_count = 5000
92+
# The time to timeout the sniffing process only,
93+
# Must be greater than or equal to 5 - int
6694
timeout = 10
95+
# The maximum retry time for the whole process,
96+
# Must be greater than or equal to 10 and timeout - int
97+
max_retry_time = 30
6798

6899
###################################################
69100

CODE/dump_memory.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@
55

66
import psutil
77

8-
from logicytics import log
8+
from logicytics import log, config
99

1010
# TODO v3.4.1
1111
# psutil.virtual_memory(): used, free, percent, total
1212
# psutil.swap_memory(): used, free, percent, total
1313

14-
# If the file size exceeds this limit, the file will be truncated with a message
15-
# Put 0 to disable the limit
16-
# TODO v3.4.1: Make this take from config.ini
17-
LIMIT_FILE_SIZE = 20 # Always in MiB
14+
LIMIT_FILE_SIZE = config.getint("DumpMemory Settings", "file_size_limit") # Always in MiB
15+
SAFETY_MARGIN = config.getfloat("DumpMemory Settings", "file_size_safety") # Always in MiB
16+
if SAFETY_MARGIN < 1:
17+
log.critical("Invalid Safety Margin Inputted - Cannot proceed with dump memory")
18+
exit(1)
1819

1920

2021
# Capture RAM Snapshot
@@ -41,7 +42,7 @@ def capture_ram_snapshot():
4142
log.info("Capturing RAM Snapshot...")
4243
memory = psutil.virtual_memory()
4344
swap = psutil.swap_memory()
44-
with open("Ram_Snapshot.txt", "w") as file:
45+
with open("memory_dumps/Ram_Snapshot.txt", "w") as file:
4546
try:
4647
file.write(f"Total RAM: {memory.total / (1024 ** 3):.2f} GB\n")
4748
file.write(f"Used RAM: {memory.used / (1024 ** 3):.2f} GB\n")
@@ -91,13 +92,13 @@ def gather_system_info():
9192
except Exception as e:
9293
log.error(f"Error gathering system information: {e}")
9394
sys_info = {'Error': 'Failed to gather system information'}
94-
with open("SystemRam_Info.txt", "w") as file:
95+
with open("memory_dumps/SystemRam_Info.txt", "w") as file:
9596
for key, value in sys_info.items():
9697
file.write(f"{key}: {value}\n")
9798
log.info("System Information saved to SystemRam_Info.txt")
9899

99100

100-
# Memory Dump (Windows-specific, using psutil)
101+
# Memory Dump
101102
def memory_dump():
102103
"""
103104
Perform a memory dump of the current process, capturing detailed metadata for each readable memory region.
@@ -127,12 +128,12 @@ def memory_dump():
127128

128129
try:
129130
process = psutil.Process(pid)
130-
with open("Ram_Dump.txt", "wb") as dump_file:
131+
with open("memory_dumps/Ram_Dump.txt", "wb") as dump_file:
131132
total_size = 0
132133
for mem_region in process.memory_maps(grouped=False):
133134
# Check available disk space
134135
if os.path.exists("Ram_Dump.txt"):
135-
required_space = LIMIT_FILE_SIZE * 1024 * 1024 * 1.5 # 2x safety margin
136+
required_space = LIMIT_FILE_SIZE * 1024 * 1024 * SAFETY_MARGIN # 2x safety margin
136137
free_space = psutil.disk_usage(".").free
137138
if free_space < required_space:
138139
log.error(f"Not enough disk space. Need {required_space / 1024 / 1024:.2f}MB")
@@ -206,6 +207,7 @@ def main():
206207
No parameters.
207208
No return value.
208209
"""
210+
os.makedirs("memory_dumps", exist_ok=True)
209211
log.info("Starting system memory collection tasks...")
210212
capture_ram_snapshot()
211213
gather_system_info()

CODE/logicytics/Config.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def __config_data() -> tuple[str, str, list[str], bool, str]:
1515
- Version (str): System version from configuration
1616
- Files (list[str]): List of files specified in configuration
1717
- Delete old logs (bool): Flag indicating whether to delete old log files
18-
- CONFIG itself
18+
- config itself
1919
2020
Raises:
2121
SystemExit: If the 'config.ini' file cannot be found in any of the attempted locations
@@ -30,21 +30,21 @@ def _config_path() -> str:
3030
print("The config.ini file is not found in the expected location.")
3131
exit(1)
3232

33-
config = configparser.ConfigParser()
33+
config_local = configparser.ConfigParser()
3434
path = _config_path()
35-
config.read(path)
35+
config_local.read(path)
3636

37-
log_using_debug = config.getboolean("Settings", "log_using_debug")
38-
delete_old_logs = config.getboolean("Settings", "delete_old_logs")
39-
version = config.get("System Settings", "version")
40-
files = config.get("System Settings", "files").split(", ")
37+
log_using_debug = config_local.getboolean("Settings", "log_using_debug")
38+
delete_old_logs = config_local.getboolean("Settings", "delete_old_logs")
39+
version = config_local.get("System Settings", "version")
40+
files = config_local.get("System Settings", "files").split(", ")
4141

4242
log_using_debug = "DEBUG" if log_using_debug else "INFO"
4343

44-
return log_using_debug, version, files, delete_old_logs, config
44+
return log_using_debug, version, files, delete_old_logs, config_local
4545

4646

4747
# Check if the script is being run directly, if not, set up the library
4848
if __name__ == '__main__':
4949
exit("This is a library, Please import rather than directly run.")
50-
DEBUG, VERSION, CURRENT_FILES, DELETE_LOGS, CONFIG = __config_data()
50+
DEBUG, VERSION, CURRENT_FILES, DELETE_LOGS, config = __config_data()

CODE/logicytics/Flag.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,23 @@
88
from collections import Counter
99
from datetime import datetime
1010

11-
from .Config import CONFIG
11+
from logicytics.Config import config
1212

1313
# Check if the script is being run directly, if not, set up the library
1414
if __name__ == '__main__':
1515
exit("This is a library, Please import rather than directly run.")
1616
else:
1717
# Save user preferences?
18-
SAVE_PREFERENCES = CONFIG.getboolean("Settings", "save_preferences")
18+
SAVE_PREFERENCES = config.getboolean("Settings", "save_preferences")
1919
# Debug mode for Sentence Transformer
20-
DEBUG_MODE = CONFIG.getboolean("Flag Settings", "model_debug") # Debug mode for Sentence Transformer
20+
DEBUG_MODE = config.getboolean("Flag Settings", "model_debug") # Debug mode for Sentence Transformer
2121
# File for storing user history data
2222
HISTORY_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'User_History.json.gz') # User history file
2323
# Minimum accuracy threshold for flag suggestions
2424
MIN_ACCURACY_THRESHOLD = float(
25-
CONFIG.get("Flag Settings", "accuracy_min")) # Minimum accuracy threshold for flag suggestions
26-
if not 0 <= MIN_ACCURACY_THRESHOLD <= 100:
27-
raise ValueError("accuracy_min must be between 0 and 100")
25+
config.get("Flag Settings", "accuracy_min")) # Minimum accuracy threshold for flag suggestions
26+
if not 1 <= MIN_ACCURACY_THRESHOLD <= 99:
27+
raise ValueError("accuracy_min must be between 1 and 99")
2828

2929

3030
class _Match:
@@ -61,11 +61,11 @@ def __get_sim(user_input: str, all_descriptions: list[str]) -> list[float]:
6161
logging.getLogger("sentence_transformers").setLevel(logging.ERROR)
6262

6363
try:
64-
MODEL = SentenceTransformer(CONFIG.get("Flag Settings", "model_to_use"))
64+
MODEL = SentenceTransformer(config.get("Flag Settings", "model_to_use"))
6565
except Exception as e:
6666
print(f"Error: {e}")
6767
print("Please check the model name in the config file.")
68-
print(f"Model name {CONFIG.get('Flag Settings', 'model_to_use')} may not be valid.")
68+
print(f"Model name {config.get('Flag Settings', 'model_to_use')} may not be valid.")
6969
exit(1)
7070

7171
user_embedding = MODEL.encode(user_input, convert_to_tensor=True, show_progress_bar=DEBUG_MODE)

0 commit comments

Comments
 (0)