forked from ydkhatri/mac_apt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmac_apt_artifact_only.py
161 lines (138 loc) · 7.02 KB
/
mac_apt_artifact_only.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
'''
Copyright (c) 2018 Yogesh Khatri
This file is part of mac_apt (macOS Artifact Parsing Tool).
Usage or distribution of this software/code is subject to the
terms of the MIT License.
mac_apt_artifact_only.py
------------------------
This is intended for situations where you don't have a full
disk/volume image, but just have artifact plist files or databases
to examine. This script allows a single plugin to run and process
multiple artifact files. Not all plugins support this option!
For usage information, run:
python mac_apt_artifact_only.py -h
NOTE: This currently works only on Python3.7 or higher.
'''
import sys
import os
import argparse
import traceback
import plugins.helpers.macinfo as macinfo
from plugins.helpers.writer import *
import logging
import time
import textwrap
from plugin import *
__VERSION = "0.7.dev"
__PROGRAMNAME = "macOS Artifact Parsing Tool - Artifact Only mode"
__EMAIL = "[email protected]"
def GetPlugin(name):
for plugin in plugins:
if plugin.__Plugin_Name == name: return plugin
return None
## Main program ##
plugins = []
plugin_count = ImportPlugins(plugins, 'ARTIFACTONLY')
if plugin_count == 0:
sys.exit ("No plugins could be added ! Exiting..")
plugin_name_list = []
plugins_info = f"The following {len(plugins)} plugins are available:"
for plugin in plugins:
plugins_info += "\n {:<20}{}".format(plugin.__Plugin_Name, textwrap.fill(plugin.__Plugin_Description, subsequent_indent=' '*24, initial_indent=' '*24, width=80)[24:])
plugin_name_list.append(plugin.__Plugin_Name)
arg_parser = argparse.ArgumentParser(description='mac_apt is a framework to process forensic artifacts on a Mac OSX system\n'\
f'You are running {__PROGRAMNAME} version {__VERSION}\n\n'\
'Note: The default output is now sqlite, no need to specify it now',
epilog=plugins_info, formatter_class=argparse.RawTextHelpFormatter)
arg_parser.add_argument('-i', '--input_path', nargs='+', help='Path to input file(s)') # Not optional !
arg_parser.add_argument('-o', '--output_path', help='Path where output files will be created') # Not optional !
arg_parser.add_argument('-x', '--xlsx', action="store_true", help='Save output in excel spreadsheet(s)')
arg_parser.add_argument('-c', '--csv', action="store_true", help='Save output as CSV files')
arg_parser.add_argument('-l', '--log_level', help='Log levels: INFO, DEBUG, WARNING, ERROR, CRITICAL (Default is INFO)')
arg_parser.add_argument('plugin', help="Plugin to run")
arg_parser.add_argument('--plugin_help', action="store_true", help="Plugin usage info")
args = arg_parser.parse_args()
plugin_to_run = args.plugin.upper() # convert plugin name entered by user to uppercase
if plugin_to_run in plugin_name_list:
plugin = GetPlugin(plugin_to_run)
if args.plugin_help:
# Display help for Module
print("\nHelp for Module {} ({})\n".format(plugin.__Plugin_Name, plugin.__Plugin_Friendly_Name))
print("-"*50 + "\n{}\n".format( textwrap.fill(plugin.__Plugin_ArtifactOnly_Usage, width=80, drop_whitespace=False)))
sys.exit()
else:
sys.exit("Exiting -> Plugin '" + args.plugin + "' is not a valid plugin name.")
if args.output_path:
if (os.name != 'nt'):
if args.output_path.startswith('~/') or args.output_path == '~': # for linux/mac, translate ~ to user profile folder
args.output_path = os.path.expanduser(args.output_path)
print ("Output path was : {}".format(args.output_path))
if not CheckOutputPath(args.output_path):
sys.exit("Exiting -> Output path not valid!")
else:
sys.exit("Exiting -> No output_path provided, the -o option is mandatory!")
if args.input_path:
try:
for in_file in args.input_path:
if not os.path.exists(in_file):
sys.exit("Exiting -> Input path '{}' does not exist!".format(in_file))
except Exception as ex:
sys.exit("Exiting -> Error while checking input_path\n" + str(ex))
else:
sys.exit("Exiting -> No input file provided, the -i option is mandatory. Please provide a file to process!")
if args.log_level:
args.log_level = args.log_level.upper()
if not args.log_level in ['INFO','DEBUG','WARNING','ERROR','CRITICAL']: # TODO: change to just [info, debug, error]
sys.exit("Exiting -> Invalid input type for log level. Valid values are INFO, DEBUG, WARNING, ERROR, CRITICAL")
else:
if args.log_level == "INFO": args.log_level = logging.INFO
elif args.log_level == "DEBUG": args.log_level = logging.DEBUG
elif args.log_level == "WARNING": args.log_level = logging.WARNING
elif args.log_level == "ERROR": args.log_level = logging.ERROR
elif args.log_level == "CRITICAL": args.log_level = logging.CRITICAL
else:
args.log_level = logging.INFO
log = CreateLogger(os.path.join(args.output_path, "Log." + str(time.strftime("%Y%m%d-%H%M%S")) + ".txt"), args.log_level, args.log_level) # Create logging infrastructure
log.setLevel(args.log_level)
log.info("Started {}, version {}".format(__PROGRAMNAME, __VERSION))
log.info("Dates and times are in UTC unless the specific artifact being parsed saves it as local time!")
log.debug(' '.join(sys.argv))
output_params = macinfo.OutputParams()
output_params.output_path = args.output_path
try:
log.debug("Trying to create db @ " + os.path.join(output_params.output_path, "mac_apt.db"))
output_params.output_db_path = SqliteWriter.CreateSqliteDb(os.path.join(output_params.output_path, "mac_apt.db"))
output_params.write_sql = True
except Exception as ex:
log.exception('Exception occurred when tried to create Sqlite db')
sys.exit('Exiting -> Cannot create sqlite db!')
if args.xlsx:
try:
xlsx_path = os.path.join(output_params.output_path, "mac_apt.xlsx")
output_params.xlsx_writer = ExcelWriter()
log.debug("Trying to create xlsx file @ " + xlsx_path)
output_params.xlsx_writer.CreateXlsxFile(xlsx_path)
output_params.write_xlsx = True
except Exception as ex:
log.info('XLSX file could not be created at : ' + xlsx_path)
log.exception('Exception occurred when trying to create XLSX file')
if args.csv:
output_params.write_csv = True
# At this point, all looks good, lets process the input file
# Start processing plugin now!
time_processing_started = time.time()
log.info("-"*50)
log.info("Running plugin " + plugin_to_run)
log.info("-"*50)
try:
plugin = GetPlugin(plugin_to_run)
plugin.Plugin_Start_Standalone(args.input_path, output_params)
except Exception as ex:
log.exception ("An exception occurred while running plugin - " + plugin_to_run)
log.info("-"*50)
if args.xlsx:
output_params.xlsx_writer.CommitAndCloseFile()
time_processing_ended = time.time()
run_time = time_processing_ended - time_processing_started
log.info("Finished in time = {}".format(time.strftime('%H:%M:%S', time.gmtime(run_time))))
log.info("Review the Log file and report any ERRORs or EXCEPTIONS to the developers")