multivol 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,269 @@
1
+ # multi_volatility2.py
2
+ # Implements Volatility2 memory analysis orchestration, Docker command generation, and backend communication.
3
+ import time
4
+ import os
5
+ import json
6
+ from rich import print as rprint
7
+ import docker
8
+
9
+
10
+ class multi_volatility2:
11
+ def __init__(self):
12
+ # Constructor for multi_volatility2 class
13
+ pass
14
+
15
+ def resolve_path(self, path, host_path):
16
+ # If host_path is set, replacing the current working directory prefix with host_path
17
+ if host_path:
18
+ if path.startswith("/storage"):
19
+ # Handle special storage mapping for Docker
20
+ # Map /storage -> {host_path}/storage/data
21
+ rel_path = os.path.relpath(path, "/storage")
22
+ return os.path.join(host_path, "storage", "data", rel_path)
23
+
24
+ if path.startswith(os.getcwd()):
25
+ rel_path = os.path.relpath(path, os.getcwd())
26
+ return os.path.join(host_path, rel_path)
27
+ return path
28
+
29
+ def generate_command_volatility2(self, command, dump, dump_dir, profiles_path, docker_image, profile, format):
30
+ # Generates the Docker command to run a Volatility2 module
31
+ return [
32
+ "docker", "run", "--rm",
33
+ "-v", f"{dump_dir}:/dumps/{dump}",
34
+ "-v", f"{profiles_path}:/home/vol/profiles",
35
+ "-t", docker_image, "--plugins=/home/vol/profiles",
36
+ "-f", f"/dumps/{dump}",
37
+ f"--profile={profile}",
38
+ f"--output={format}",
39
+ f"{command}"
40
+ ]
41
+
42
+ def execute_command_volatility2(self, command, dump, dump_dir, profiles_path, docker_image, profile, output_dir, format, quiet=False, lock=None, host_path=None):
43
+ # Executes a Volatility2 command in Docker and handles output
44
+ if not quiet:
45
+ self.safe_print(f"[+] Starting {command}...", lock)
46
+
47
+ client = docker.from_env()
48
+
49
+ # Resolve paths for DooD
50
+ host_profiles_path = self.resolve_path(os.path.abspath(profiles_path), host_path)
51
+ host_dump_path_src = self.resolve_path(os.path.abspath(dump_dir), host_path) # dump_dir here is actually the full file path from main.py
52
+ host_output_dir = self.resolve_path(os.path.abspath(output_dir), host_path)
53
+
54
+ volumes = {
55
+ host_dump_path_src: {'bind': f'/dumps/{dump}', 'mode': 'rw'},
56
+ host_profiles_path: {'bind': '/home/vol/profiles', 'mode': 'rw'},
57
+ host_output_dir: {'bind': '/output', 'mode': 'rw'}
58
+ }
59
+
60
+ # Construct the command string to run inside the container
61
+ cmd_args = f"--plugins=/home/vol/profiles -f /dumps/{dump} --profile={profile} --output={format} {command}"
62
+
63
+ if format == "json":
64
+ self.output_file = os.path.join(output_dir, f"{command}_output.json")
65
+ else:
66
+ self.output_file = os.path.join(output_dir, f"{command}_output.txt")
67
+
68
+ try:
69
+ container = client.containers.run(
70
+ image=docker_image,
71
+ command=cmd_args,
72
+ volumes=volumes,
73
+ tty=True, # Corresponds to -t
74
+ remove=False,
75
+ detach=True
76
+ )
77
+
78
+ with open(self.output_file, "wb") as file:
79
+ for chunk in container.logs(stream=True):
80
+ file.write(chunk)
81
+
82
+ container.wait()
83
+ container.remove()
84
+
85
+ except Exception as e:
86
+ self.safe_print(f"[!] Error running {command}: {e}", lock)
87
+
88
+ time.sleep(0.5)
89
+ if format == "json":
90
+ try:
91
+ with open(self.output_file,"r") as f:
92
+ lines = f.readlines()
93
+ if lines: # Check if lines is not empty
94
+ with open(self.output_file,"w") as f:
95
+ f.writelines(lines[-1])
96
+ except:
97
+ pass
98
+
99
+
100
+
101
+ if not quiet:
102
+ self.safe_print(f"[+] {command} finished.", lock)
103
+ return command
104
+
105
+ def safe_print(self, message, lock):
106
+ if lock:
107
+ with lock:
108
+ rprint(message)
109
+ else:
110
+ rprint(message)
111
+
112
+ def getCommands(self, opsys):
113
+ # Returns a list of Volatility2 commands for the specified OS and mode
114
+ if opsys == "windows.light":
115
+ return ["cmdline",
116
+ "cmdscan",
117
+ "connscan",
118
+ "consoles",
119
+ "dlllist",
120
+ "filescan",
121
+ "hashdump",
122
+ "malfind",
123
+ "psscan",
124
+ "pslist",
125
+ "pstree",
126
+ "psxview",
127
+ ]
128
+ elif opsys == "windows.full":
129
+ return ["cmdline",
130
+ "cmdscan",
131
+ "connscan",
132
+ "consoles",
133
+ "dlllist",
134
+ "filescan",
135
+ "hashdump",
136
+ "malfind",
137
+ "mftparser",
138
+ "psscan",
139
+ "pslist",
140
+ "pstree",
141
+ "psxview",
142
+ "amcache",
143
+ "atoms",
144
+ "autoruns",
145
+ "bitlocker",
146
+ "cachedump",
147
+ "chromecookies",
148
+ "chromedownloads",
149
+ "chromehistory",
150
+ "chromevisits",
151
+ "clipboard",
152
+ "connections",
153
+ "devicetree",
154
+ "directoryenumerator",
155
+ "driverirp",
156
+ "drivermodule",
157
+ "driverscan",
158
+ "envars",
159
+ "evtlogs",
160
+ "firefoxcookies",
161
+ "firefoxdownloads",
162
+ "firefoxhistory",
163
+ "gahti",
164
+ "getservicesids",
165
+ "getsids",
166
+ "handles",
167
+ "hivelist",
168
+ "hivescan",
169
+ "hpakinfo",
170
+ "lsadump",
171
+ "mbrparser",
172
+ "messagehooks",
173
+ "modscan",
174
+ "modules",
175
+ "multiscan",
176
+ "mutantscan",
177
+ "networkpackets",
178
+ "prefetchparser",
179
+ "privs",
180
+ "psinfo",
181
+ "schtasks",
182
+ "screenshot",
183
+ "servicediff",
184
+ "sessions",
185
+ "shellbags",
186
+ "shimcache",
187
+ "sockets",
188
+ "sockscan",
189
+ "ssdt",
190
+ "svcscan",
191
+ "symlinkscan",
192
+ "thrdscan",
193
+ "threads",
194
+ "unloadedmodules",
195
+ "userassist",
196
+ "userhandles",
197
+ ]
198
+ elif opsys == "linux.light":
199
+ return ["linux_bash",
200
+ "linux_ifconfig",
201
+ "linux_malfind",
202
+ "linux_netscan",
203
+ "linux_enumerate_files",
204
+ "linux_netstat",
205
+ "linux_psaux",
206
+ "linux_pslist",
207
+ "linux_psscan",
208
+ "linux_pstree",
209
+ "linux_psxview"
210
+ ]
211
+ elif opsys == "linux.full":
212
+ return ["linux_banner",
213
+ "linux_bash",
214
+ "linux_ifconfig",
215
+ "linux_malfind",
216
+ "linux_netscan",
217
+ "linux_netstat",
218
+ "linux_psaux",
219
+ "linux_pslist",
220
+ "linux_psscan",
221
+ "linux_pstree",
222
+ "linux_psxview",
223
+ "linux_apihooks",
224
+ "linux_arp",
225
+ "linux_aslr_shift",
226
+ "linux_bash_env",
227
+ "linux_bash_hash",
228
+ "linux_check_afinfo",
229
+ "linux_check_creds",
230
+ "linux_check_fop",
231
+ "linux_check_idt",
232
+ "linux_check_inline_kernel",
233
+ "linux_check_modules",
234
+ "linux_check_syscall",
235
+ "linux_check_syscall_arm",
236
+ "linux_check_tty",
237
+ "linux_cpuinfo",
238
+ "linux_dentry_cache",
239
+ "linux_dmesg",
240
+ "linux_dynamic_env",
241
+ "linux_elfs",
242
+ "linux_getcwd",
243
+ "linux_hidden_modules",
244
+ "linux_info_regs",
245
+ "linux_iomem",
246
+ "linux_kernel_opened_files",
247
+ "linux_keyboard_notifiers",
248
+ "linux_ldrmodules",
249
+ "linux_library_list",
250
+ "linux_list_raw",
251
+ "linux_lsmod",
252
+ "linux_lsof",
253
+ "linux_memmap",
254
+ "linux_mount",
255
+ "linux_mount_cache",
256
+ "linux_netfilter",
257
+ "linux_pidhashtable",
258
+ "linux_pkt_queues",
259
+ "linux_plthook",
260
+ "linux_proc_maps",
261
+ "linux_proc_maps_rb",
262
+ "linux_process_hollow",
263
+ "linux_psenv",
264
+ "linux_pslist_cache",
265
+ "linux_route_cache",
266
+ "linux_sk_buff_cache",
267
+ "linux_threads",
268
+ "linux_truecrypt_passphrase"
269
+ ]
@@ -0,0 +1,266 @@
1
+ # multi_volatility3.py
2
+ # Implements Volatility3 memory analysis orchestration, Docker command generation, and backend communication.
3
+ import time
4
+ import os
5
+ import json
6
+ from rich import print as rprint
7
+ import docker
8
+
9
+
10
+ class multi_volatility3:
11
+ def __init__(self):
12
+ # Constructor for multi_volatility3 class
13
+ pass
14
+
15
+ def resolve_path(self, path, host_path):
16
+ # If host_path is set, replacing the current working directory prefix with host_path
17
+ if host_path:
18
+ if path.startswith("/storage"):
19
+ # Handle special storage mapping for Docker
20
+ # Map /storage -> {host_path}/storage/data
21
+ rel_path = os.path.relpath(path, "/storage")
22
+ return os.path.join(host_path, "storage", "data", rel_path)
23
+
24
+ if path.startswith(os.getcwd()):
25
+ rel_path = os.path.relpath(path, os.getcwd())
26
+ return os.path.join(host_path, rel_path)
27
+ return path
28
+
29
+
30
+ def generate_command_volatility3_json(self, command, dump, dump_dir, symbols_path, docker_image, cache_dir, plugin_dir):
31
+ # Generates the Docker command to run a Volatility3 module with JSON output
32
+ return [
33
+ "docker", "run", "--rm",
34
+ "-v", f"{dump_dir}:/dumps/{dump}",
35
+ "-v", f"{cache_dir}:/home/root/.cache",
36
+ "-v", f"{symbols_path}:/tmp",
37
+ "-v", f"{plugin_dir}:/root/plugins_dir",
38
+ "-ti", docker_image,
39
+ "vol",
40
+ "-q",
41
+ "-f", f"/dumps/{dump}",
42
+ "-s", "/tmp",
43
+ "-p", "/root/plugins_dir",
44
+ "-r", "json",
45
+ command
46
+ ]
47
+
48
+ def generate_command_volatility3_text(self, command, dump, dump_dir, symbols_path, docker_image, cache_dir, plugin_dir):
49
+ # Generates the Docker command to run a Volatility3 module with text output
50
+ return [
51
+ "docker", "run", "--rm",
52
+ "-v", f"{dump_dir}:/dumps/{dump}",
53
+ "-v", f"{cache_dir}:/home/root/.cache",
54
+ "-v", f"{symbols_path}:/tmp",
55
+ "-v", f"{plugin_dir}:/root/plugins_dir",
56
+ "-ti", docker_image,
57
+ "vol",
58
+ "-q",
59
+ "-f", f"/dumps/{dump}",
60
+ "-s", "/tmp",
61
+ "-p", "/root/plugins_dir",
62
+ command
63
+ ]
64
+
65
+ def execute_command_volatility3(self, command, dump, dump_dir, symbols_path, docker_image, cache_dir, plugin_dir, output_dir, format, quiet=False, lock=None, host_path=None):
66
+ # Executes a Volatility3 command in Docker and handles output
67
+ if not quiet:
68
+ self.safe_print(f"[+] Starting {command}...", lock)
69
+
70
+ client = docker.from_env()
71
+
72
+ # Resolve paths for DooD
73
+ host_symbols_path = self.resolve_path(os.path.abspath(symbols_path), host_path)
74
+ host_cache_path = self.resolve_path(os.path.abspath(cache_dir), host_path)
75
+ host_plugin_dir = self.resolve_path(os.path.abspath(plugin_dir), host_path)
76
+ host_output_dir = self.resolve_path(os.path.abspath(output_dir), host_path)
77
+
78
+ host_dump_path = self.resolve_path(os.path.abspath(dump_dir), host_path)
79
+ host_dump_dir = os.path.dirname(host_dump_path)
80
+
81
+ volumes = {
82
+ host_dump_dir: {'bind': '/dump_dir', 'mode': 'ro'},
83
+ host_symbols_path: {'bind': '/symbols', 'mode': 'rw'},
84
+ host_cache_path: {'bind': '/root/.cache/volatility3', 'mode': 'rw'},
85
+ host_plugin_dir: {'bind': '/plugins', 'mode': 'ro'},
86
+ host_output_dir: {'bind': '/output', 'mode': 'rw'}
87
+ }
88
+
89
+ # Base arguments
90
+ # Base arguments with new volume paths:
91
+ # dump_dir -> /dump_dir
92
+ # symbols -> /symbols
93
+ # cache -> /root/.cache/volatility3
94
+ # plugins -> /plugins
95
+
96
+ # NOTE: -f expects the file path. Volume maps dump_dir to /dump_dir.
97
+ # So dump file is at /dump_dir/basename(dump)
98
+ dump_filename = os.path.basename(dump)
99
+ base_args = f"vol -q -f /dump_dir/{dump_filename} -s /symbols -p /plugins"
100
+
101
+ if format == "json":
102
+ self.output_file = os.path.join(output_dir, f"{command}_output.json")
103
+ cmd_args = f"{base_args} -r json {command}"
104
+ else:
105
+ self.output_file = os.path.join(output_dir, f"{command}_output.txt")
106
+ cmd_args = f"{base_args} {command}"
107
+
108
+ try:
109
+ container = client.containers.run(
110
+ image=docker_image,
111
+ command=cmd_args,
112
+ volumes=volumes,
113
+ tty=True,
114
+ detach=True,
115
+ remove=False
116
+ )
117
+
118
+ with open(self.output_file, "wb") as file:
119
+ for chunk in container.logs(stream=True):
120
+ file.write(chunk)
121
+
122
+ container.wait()
123
+ container.remove()
124
+
125
+ except Exception as e:
126
+ self.safe_print(f"[!] Error running {command}: {e}", lock)
127
+
128
+ time.sleep(0.5)
129
+ if format == "json":
130
+ try:
131
+ with open(self.output_file,"r") as f:
132
+ lines = f.readlines()
133
+ if lines:
134
+ with open(self.output_file,"w") as f:
135
+ f.writelines(lines[2:])
136
+ except:
137
+ pass
138
+
139
+ # Filescan filtering logic (commented out in original)
140
+ """
141
+ if command == "windows.filescan.FileScan":
142
+ try:
143
+ with open(os.path.join(output_dir, "windows.filescan.FileScan_filtered_output.json"), "w") as file:
144
+ # ... implementation details omitted as logic matches original structure ...
145
+ pass
146
+ except:
147
+ pass
148
+ """
149
+
150
+
151
+
152
+ if not quiet:
153
+ self.safe_print(f"[+] {command} finished.", lock)
154
+
155
+ # Validation
156
+ success = False
157
+ try:
158
+ with open(self.output_file, "r") as f:
159
+ content = f.read()
160
+
161
+ # Check for known error string regardless of format
162
+ if "Volatility experienced" in content:
163
+ success = False
164
+ elif format == "json":
165
+ # Simple validation check matching API logic
166
+ start_index = content.find('[')
167
+ if start_index == -1:
168
+ start_index = content.find('{')
169
+
170
+ if start_index != -1:
171
+ json.loads(content[start_index:])
172
+ success = True
173
+ else:
174
+ # Fallback check
175
+ lines = content.splitlines()
176
+ if len(lines) > 1:
177
+ json.loads('\n'.join(lines[1:]))
178
+ success = True
179
+ else:
180
+ success = True # Assume text output is successful if no crash and no error string
181
+ except:
182
+ success = False
183
+
184
+ return (command, success)
185
+
186
+ def safe_print(self, message, lock):
187
+ if lock:
188
+ with lock:
189
+ rprint(message)
190
+ else:
191
+ rprint(message)
192
+
193
+ def getCommands(self, opsys):
194
+ # Returns a list of Volatility3 commands for the specified OS and mode
195
+ if opsys == "windows.full":
196
+ return ["windows.cmdline.CmdLine",
197
+ "windows.cachedump.Cachedump",
198
+ "windows.dlllist.DllList",
199
+ "windows.driverirp.DriverIrp",
200
+ "windows.drivermodule.DriverModule",
201
+ "windows.driverscan.DriverScan",
202
+ "windows.envars.Envars",
203
+ "windows.filescan.FileScan",
204
+ "windows.getservicesids.GetServiceSIDs",
205
+ "windows.getsids.GetSIDs",
206
+ "windows.handles.Handles",
207
+ "windows.hashdump.Hashdump",
208
+ "windows.lsadump.Lsadump",
209
+ "windows.info.Info",
210
+ "windows.malfind.Malfind",
211
+ "windows.mftscan.MFTScan",
212
+ "windows.modules.Modules",
213
+ "windows.netscan.NetScan",
214
+ "windows.netstat.NetStat",
215
+ "windows.privileges.Privs",
216
+ "windows.pslist.PsList",
217
+ "windows.psscan.PsScan",
218
+ "windows.pstree.PsTree",
219
+ "windows.registry.hivelist.HiveList",
220
+ "windows.registry.certificates.Certificates",
221
+ "windows.registry.hivescan.HiveScan",
222
+ "windows.registry.userassist.UserAssist",
223
+ "windows.sessions.Sessions"
224
+ ]
225
+ elif opsys == "windows.light":
226
+ return ["windows.cmdline.CmdLine",
227
+ "windows.filescan.FileScan",
228
+ "windows.netscan.NetScan",
229
+ "windows.netstat.NetStat",
230
+ "windows.pslist.PsList",
231
+ "windows.psscan.PsScan",
232
+ "windows.pstree.PsTree",
233
+ "windows.dlllist.DllList",
234
+ "windows.hashdump.Hashdump"
235
+ ]
236
+ elif opsys == "linux":
237
+ return ["linux.bash.Bash",
238
+ "linux.capabilities.Capabilities",
239
+ "linux.check_syscall.Check_syscall",
240
+ "linux.elfs.Elfs",
241
+ "linux.envars.Envars",
242
+ "linux.library_list.LibraryList",
243
+ "linux.lsmod.Lsmod",
244
+ "linux.lsof.Lsof",
245
+ "linux.malfind.Malfind",
246
+ "linux.mountinfo.MountInfo",
247
+ "linux.psaux.PsAux",
248
+ "linux.pslist.PsList",
249
+ "linux.psscan.PsScan",
250
+ "linux.pstree.PsTree",
251
+ "linux.sockstat.Sockstat",
252
+ "linux.boottime.Boottime",
253
+ "linux.check_creds.Check_creds",
254
+ "linux.hidden_modules.Hidden_modules",
255
+ "linux.ip.Addr",
256
+ "linux.ip.Link",
257
+ "linux.keyboard_notifiers.Keyboard_notifiers",
258
+ "linux.modxview.Modxview",
259
+ "linux.netfilter.Netfilter",
260
+ "linux.pagecache.Files",
261
+ "linux.pidhashtable.PIDHashTable",
262
+ "linux.tracing.ftrace.CheckFtrace",
263
+ "linux.tracing.perf_events.PerfEvents",
264
+ "linux.tracing.tracepoints.CheckTracepoints",
265
+ "linux.tty_check.tty_check"
266
+ ]