Skip to content

Commit d29e2f6

Browse files
Fixed major bugs that affect Logicytics (performance checker), plus QoL changes
Logicytics.py Fixed bug [ValueError String Formatting], where the memory was not a proper string if an application runs into an error Thanks to new changes, `Get.list_of_files` now ignores the `logicytics` folder and `, SysInternal_Suite` folder, which resulted in bugs when executed and crashes Added debug log to get length of execution list Hard limited memory changes (in performance checker) to be at minimum 0 (Logging will still show you the warning), this is to exclude the edge cases where freed memory is more than used memory Improved logging of `performance check` where messages are more in detail and memory is now in 3dp rather than 2dp Added try-except statements to prevent crashes if code fails (performance checker) Made function `zip_generated_files()` into a class `ZIP`, with the main and helper function in it Get.py Fixed bug in execution list where it included the `logicytics` library, which led to them being run, thus errors, adding new param: `exclude_dirs` Flag.py Fixed bug where CONFIG wasn't importing due to improper import statement (`from .Config import CONFIG` is now `from logicytics.Config import CONFIG`) network_psutil.py Fixed bug where __measure_network_bandwidth_usage wasn't run due to faulty async-await code, now fixed by making `get` and async function, and awaits `__measure_network_bandwidth_usage` Improved error logging to prevent crashes. Also, gitignore now ignore the exe files that are zipped when they are unzipped (`SysInternal suite`), Thus developers don't accidentally commit them Signed-off-by: Shahm Najeeb <Nirt_12023@outlook.com>
1 parent ea13d2e commit d29e2f6

5 files changed

Lines changed: 62 additions & 26 deletions

File tree

.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

CODE/Logicytics.py

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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/logicytics/Flag.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
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__':

CODE/logicytics/Get.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def list_of_files(
1111
append_file_list: list[str] = None,
1212
exclude_files: list[str] = None,
1313
exclude_extensions: list[str] = None,
14+
exclude_dirs: list[str] = None,
1415
) -> list[str]:
1516
"""
1617
Retrieves a list of files in the specified directory based on given extensions and exclusion criteria.
@@ -21,19 +22,25 @@ def list_of_files(
2122
append_file_list (list[str], optional): Existing list to append found filenames to. Defaults to None.
2223
exclude_files (list[str], optional): List of filenames to exclude from results. Defaults to None.
2324
exclude_extensions (list[str], optional): List of extensions to exclude from results. Defaults to None.
25+
exclude_dirs (list[str], optional): List of directory names to ignore. Defaults to None.
2426
2527
Returns:
2628
list[str]: A list of filenames matching the specified criteria.
2729
2830
Exclusion rules:
2931
- Ignores files starting with an underscore (_)
3032
- Skips files specified in `exclude_files`
33+
- Skips directories specified in `ignore_dirs`
3134
"""
3235
append_file_list = append_file_list or []
3336
exclude_files = set(exclude_files or [])
3437
exclude_extensions = set(exclude_extensions or [])
38+
exclude_dirs = set(exclude_dirs or []) # Set for faster lookup
39+
40+
for root, dirs, filenames in os.walk(directory):
41+
# Remove ignored directories from the dirs list to prevent os.walk from entering them
42+
dirs[:] = [d for d in dirs if d not in exclude_dirs]
3543

36-
for root, _, filenames in os.walk(directory):
3744
for filename in filenames:
3845
if filename.startswith("_") or filename in exclude_files:
3946
continue # Skip excluded files

CODE/network_psutil.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class NetworkInfo:
1313
"""
1414

1515
@log.function
16-
def get(self):
16+
async def get(self):
1717
"""
1818
Gathers and saves various network-related information by calling multiple internal methods.
1919
"""
@@ -24,7 +24,7 @@ def get(self):
2424
self.__fetch_network_interface_stats()
2525
self.__execute_external_network_command()
2626
self.__fetch_network_connections_with_process_info()
27-
self.__measure_network_bandwidth_usage()
27+
await self.__measure_network_bandwidth_usage()
2828
self.__fetch_hostname_and_ip()
2929
except Exception as e:
3030
log.error(f"Error getting network info: {e}, Type: {type(e).__name__}")
@@ -181,4 +181,9 @@ def __fetch_hostname_and_ip(self):
181181

182182

183183
if __name__ == "__main__":
184-
NetworkInfo().get()
184+
try:
185+
asyncio.run(NetworkInfo().get()) # Use asyncio.run to run the async get method
186+
except asyncio.CancelledError:
187+
log.warning("Operation cancelled by user.")
188+
except Exception as err: # Catch all exceptions
189+
log.error(f"An error occurred: {err}")

0 commit comments

Comments
 (0)