Skip to content

Commit

Permalink
Merge pull request #46 from Johann-PLW/main
Browse files Browse the repository at this point in the history
New Tkinter GUI
  • Loading branch information
Johann-PLW authored Mar 25, 2024
2 parents d9086a2 + 12444b1 commit 3ddfec9
Show file tree
Hide file tree
Showing 10 changed files with 651 additions and 380 deletions.
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ protobuf==3.10.0
PyCryptodome
PyMuPDF
PyPDF2
PySimpleGUI
pytz
simplekml
xmltodict
xlrd==1.2.0

Binary file added scripts/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 14 additions & 8 deletions scripts/ilapfuncs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import csv
import datetime
import os
import pathlib
import re
import shutil
import sqlite3
Expand Down Expand Up @@ -138,21 +137,28 @@ def does_table_exist(db, table_name):
class GuiWindow:
'''This only exists to hold window handle if script is run from GUI'''
window_handle = None # static variable
progress_bar_total = 0
progress_bar_handle = None

@staticmethod
def SetProgressBar(n):
if GuiWindow.progress_bar_handle:
GuiWindow.progress_bar_handle.UpdateBar(n)
def SetProgressBar(n, total):
if GuiWindow.window_handle:
progress_bar = GuiWindow.window_handle.nametowidget('!progressbar')
progress_bar.config(value=n)


def logfunc(message=""):
def redirect_logs(string):
log_text.insert('end', string)
log_text.see('end')
log_text.update()

if GuiWindow.window_handle:
log_text = GuiWindow.window_handle.nametowidget('logs_frame.log_text')
sys.stdout.write = redirect_logs

with open(OutputParameters.screen_output_file_path, 'a', encoding='utf8') as a:
print(message)
a.write(message + '<br>' + OutputParameters.nl)

if GuiWindow.window_handle:
GuiWindow.window_handle.refresh()

def logdevinfo(message=""):
with open(OutputParameters.screen_output_file_path_devinfo, 'a', encoding='utf8') as b:
Expand Down
6 changes: 3 additions & 3 deletions scripts/version_info.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
vleapp_version = '2.0.0'
vleapp_version = '2.1.0'

# Contributors List
# Format = [ Name, Blog-url, Twitter-handle, Github-url]
Expand All @@ -8,6 +8,6 @@
[ 'Yogesh Khatri', 'https://swiftforensics.com', '@SwiftForensics', 'https://github.com/ydkhatri'],
[ 'Geraldine Blay', 'https://gforce4n6.blogspot.com', '@i_am_the_gia', 'https://github.com/gforce4n6'],
[ 'Kevin Pagano', 'https://stark4n6.com', '@KevinPagano3', 'https://github.com/stark4n6'],
['James Habben', 'https://4n6ir.com/','@JamesHabben','https://github.com/JamesHabben']

['James Habben', 'https://4n6ir.com/','@JamesHabben','https://github.com/JamesHabben'],
['Johann Polewczyk', 'https://www.linkedin.com/in/johann-polewczyk-6a905425/', '@johannplw', 'https://github.com/Johann-PLW']
]
96 changes: 46 additions & 50 deletions vleapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,73 +43,70 @@ def validate_args(args):
# raise argparse.ArgumentError(None, 'Unknown timezone! Run the program again.')


def create_profile(available_plugins, path):
available_parsers = []
for parser_data in available_plugins:
available_parsers.append((parser_data.category, parser_data.name))

available_parsers.sort()
parsers_in_profile = {}

def create_profile(plugins, path):
available_modules = [(module_data.category, module_data.name) for module_data in plugins]
available_modules.sort()
modules_in_profile = {}

user_choice = ''
print('--- VLEAPP Profile file creation ---\n')
instructions = 'You can type:\n'
instructions += ' - \'a\' to add or remove parsers in the profile file\n'
instructions += ' - \'l\' to display the list of all available parsers with their number\n'
instructions += ' - \'p\' to display the parsers added into the profile file\n'
instructions += ' - \'a\' to add or remove modules in the profile file\n'
instructions += ' - \'l\' to display the list of all available modules with their number\n'
instructions += ' - \'p\' to display the modules added into the profile file\n'
instructions += ' - \'q\' to quit and save\n'
while not user_choice:
print(instructions)
user_choice = input('Please enter your choice: ').lower()
print()
if user_choice == "l":
print('Available parsers:')
for number, available_plugin in enumerate(available_parsers):
print(number + 1, available_plugin)
print('Available modules:')
for number, available_module in enumerate(available_modules):
print(number + 1, available_module)
print()
user_choice = ''
elif user_choice == "p":
if parsers_in_profile:
for number, parser in parsers_in_profile.items():
print(number, parser)
if modules_in_profile:
for number, module in modules_in_profile.items():
print(number, module)
print()
else:
print('No parser added to the profile file\n')
print('No module added to the profile file\n')
user_choice = ''
elif user_choice == 'a':
parser_numbers = input('Enter the numbers of parsers, seperated by a comma, to add or remove in the profile file: ')
parser_numbers = parser_numbers.split(',')
parser_numbers = [parser_number.strip() for parser_number in parser_numbers]
for parser_number in parser_numbers:
if parser_number.isdigit():
parser_number = int(parser_number)
if parser_number > 0 and parser_number <= len(available_parsers):
if parser_number not in parsers_in_profile:
parser_to_add = available_parsers[parser_number - 1]
parsers_in_profile[parser_number] = parser_to_add
print(f'parser number {parser_number} {parser_to_add} was added')
modules_numbers = input('Enter the numbers of modules, seperated by a comma, to add or remove in the profile file: ')
modules_numbers = modules_numbers.split(',')
modules_numbers = [module_number.strip() for module_number in modules_numbers]
for module_number in modules_numbers:
if module_number.isdigit():
module_number = int(module_number)
if module_number > 0 and module_number <= len(available_modules):
if module_number not in modules_in_profile:
module_to_add = available_modules[module_number - 1]
modules_in_profile[module_number] = module_to_add
print(f'module number {module_number} {module_to_add} was added')
else:
parser_to_remove = parsers_in_profile[parser_number]
print(f'parser number {parser_number} {parser_to_remove} was removed')
del parsers_in_profile[parser_number]
module_to_remove = modules_in_profile[module_number]
print(f'module number {module_number} {module_to_remove} was removed')
del modules_in_profile[module_number]
else:
print('Please enter the number of a parser!!!\n')
print('Please enter the number of a module!!!\n')
print()
user_choice = ''
elif user_choice == "q":
if parsers_in_profile:
parsers = [parser_info[1] for parser_info in parsers_in_profile.values()]
if modules_in_profile:
modules = [module_info[1] for module_info in modules_in_profile.values()]
profile_filename = ''
while not profile_filename:
profile_filename = input('Enter the name of the profile: ')
profile_filename += '.vlprofile'
filename = os.path.join(path, profile_filename)
with open(filename, "wt", encoding="utf-8") as profile_file:
json.dump({"leapp": "vleapp", "format_version": 1, "plugins": parsers}, profile_file)
json.dump({"leapp": "vleapp", "format_version": 1, "plugins": modules}, profile_file)
print('\nProfile saved:', filename)
print()
else:
print('No parser added. The profile file was not created.\n')
print('No module added. The profile file was not created.\n')
print()
return
else:
Expand Down Expand Up @@ -139,9 +136,9 @@ def main():
parser = argparse.ArgumentParser(description='VLEAPP: Vehicle Logs, Events, and Protobuf Parser.')
parser.add_argument('-t', choices=['fs', 'tar', 'zip', 'gz'], required=False, action="store",
help=("Specify the input type. "
"'fs' for a folder containing extracted files with normal paths and names, "
"'tar', 'zip', or 'gz' for compressed packages containing files with normal names. "
))
"'fs' for a folder containing extracted files with normal paths and names, "
"'tar', 'zip', or 'gz' for compressed packages containing files with normal names. "
))
parser.add_argument('-o', '--output_path', required=False, action="store",
help='Path to base output folder (this must exist)')
parser.add_argument('-i', '--input_path', required=False, action="store", help='Path to input file/folder')
Expand Down Expand Up @@ -201,7 +198,7 @@ def main():
create_choice = input('Please enter your choice: ').lower()
print()
if create_choice == '1':
create_profile(selected_plugins, args.create_profile_casedata)
create_profile(available_plugins, args.create_profile_casedata)
create_choice = ''
elif create_choice == '2':
create_casedata(args.create_profile_casedata)
Expand Down Expand Up @@ -258,7 +255,6 @@ def main():
print(profile_load_error)
return
else:
print(f'Profile loaded: {profile_filename}')
profile_plugins = set(profile.get("plugins", []))
selected_plugins = [selected_plugin for selected_plugin in available_plugins
if selected_plugin.name in profile_plugins]
Expand All @@ -280,13 +276,12 @@ def main():
if output_path[1] == ':': output_path = '\\\\?\\' + output_path.replace('/', '\\')

out_params = OutputParameters(output_path)
print(f"Info: {len(available_plugins)} plugins loaded.")

crunch_artifacts(selected_plugins, extracttype, input_path, out_params, 1, wrap_text, loader, casedata, time_offset, profile_filename)
crunch_artifacts(selected_plugins, extracttype, input_path, out_params, wrap_text, loader, casedata, time_offset, profile_filename)


def crunch_artifacts(
plugins: typing.Sequence[plugin_loader.PluginSpec], extracttype, input_path, out_params, ratio, wrap_text,
plugins: typing.Sequence[plugin_loader.PluginSpec], extracttype, input_path, out_params, wrap_text,
loader: plugin_loader.PluginLoader, casedata, time_offset, profile_filename):
start = process_time()
start_wall = perf_counter()
Expand Down Expand Up @@ -323,6 +318,7 @@ def crunch_artifacts(
return False

# Now ready to run
logfunc(f'Info: {len(loader)} modules loaded.')
if profile_filename:
logfunc(f'Loaded profile: {profile_filename}')
logfunc(f'Artifact categories to parse: {len(plugins)}')
Expand All @@ -333,16 +329,18 @@ def crunch_artifacts(
log.write(f'Extraction/Path selected: {input_path}<br><br>')
log.write(f'Timezone selected: {time_offset}<br><br>')

categories_searched = 0
parsed_modules = 0

# Search for the files per the arguments
for plugin in plugins:
if isinstance(plugin.search, list) or isinstance(plugin.search, tuple):
search_regexes = plugin.search
else:
search_regexes = [plugin.search]
parsed_modules += 1
GuiWindow.SetProgressBar(parsed_modules, len(plugins))
files_found = []
log.write(f'<b>For {plugin.name} parser</b>')
log.write(f'<b>For {plugin.name} module</b>')
for artifact_search_regex in search_regexes:
found = seeker.search(artifact_search_regex)
if not found:
Expand All @@ -356,6 +354,7 @@ def crunch_artifacts(
log.write(f'</li></ul>')
files_found.extend(found)
if files_found:
logfunc()
logfunc('{} [{}] artifact started'.format(plugin.name, plugin.module_name))
category_folder = os.path.join(out_params.report_folder_base, plugin.category)
if not os.path.exists(category_folder):
Expand All @@ -374,10 +373,7 @@ def crunch_artifacts(
continue # nope

logfunc('{} [{}] artifact completed'.format(plugin.name, plugin.module_name))
logfunc('')

categories_searched += 1
GuiWindow.SetProgressBar(categories_searched * ratio)
log.close()

logfunc('')
Expand Down
7 changes: 1 addition & 6 deletions vleapp.spec
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ block_cipher = None
a = Analysis(['vleapp.py'],
pathex=['.\\scripts\\artifacts'],
binaries=[],
datas=[('.\\scripts\\logo.jpg', '.\\scripts'),
('.\\scripts\\dashboard.css', '.\\scripts'),
('.\\scripts\\dark-mode.css', '.\\scripts'),
('.\\scripts\\dark-mode-switch.js', '.\\scripts'),
('.\\scripts\\MDB-Free_4.13.0', '.\\scripts\\MDB-Free_4.13.0'),
('.\\scripts\\artifacts', '\\scripts\\artifacts')],
datas=[('.\\scripts', '.\\scripts')],
hiddenimports=['simplekml'],
hookspath=['.\\'],
runtime_hooks=[],
Expand Down
Loading

0 comments on commit 3ddfec9

Please sign in to comment.