source: repository/lib/Metabrik/Forensic/Volatility.pm

Last change on this file was 866:f6ad8c136b19, checked in by GomoR <gomor@…>, 8 months ago
  • update: copyright 2017
File size: 10.9 KB
Line 
1#
2# $Id$
3#
4# forensic::Volatility Brik
5#
6package Metabrik::Forensic::Volatility;
7use strict;
8use warnings;
9
10use base qw(Metabrik::Shell::Command Metabrik::System::Package);
11
12# Default attribute values put here will BE inherited by subclasses
13sub brik_properties {
14   return {
15      revision => '$Revision$',
16      tags => [ qw(unstable carving carve file filecarve filecarving) ],
17      author => 'GomoR <GomoR[at]metabrik.org>',
18      license => 'http://opensource.org/licenses/BSD-3-Clause',
19      attributes => {
20         datadir => [ qw(datadir) ],
21         profile => [ qw(profile) ],
22         input => [ qw(file) ],
23         capture_mode => [ qw(0|1) ],
24      },
25      attributes_default => {
26         profile => 'Win7SP1x64',
27         capture_mode => 1,
28      },
29      commands => {
30         install => [ ], # Inherited
31         imageinfo => [ qw(file|OPTIONAL) ],
32         command => [ qw(command file|OPTIONAL profile|OPTIONAL) ],
33         envars => [ qw(file|OPTIONAL profile|OPTIONAL) ],
34         pstree => [ qw(file|OPTIONAL profile|OPTIONAL) ],
35         pslist => [ qw(file|OPTIONAL profile|OPTIONAL) ],
36         netscan => [ qw(file|OPTIONAL profile|OPTIONAL) ],
37         hashdump => [ qw(file|OPTIONAL profile|OPTIONAL) ],
38         psxview => [ qw(file|OPTIONAL profile|OPTIONAL) ],
39         hivelist => [ qw(file|OPTIONAL profile|OPTIONAL) ],
40         hivedump => [ qw(offset file|OPTIONAL profile|OPTIONAL) ],
41         filescan => [ qw(file|OPTIONAL profile|OPTIONAL) ],
42         consoles => [ qw(file|OPTIONAL profile|OPTIONAL) ],
43         memdump => [ qw(pid file|OPTIONAL profile|OPTIONAL) ],
44      },
45      require_modules => {
46         'Metabrik::System::File' => [ ],
47      },
48      require_binaries => {
49         'volatility' => [ ],
50      },
51      need_packages => {
52         ubuntu => [ qw(volatility) ],
53         debian => [ qw(volatility) ],
54      },
55   };
56}
57
58sub imageinfo {
59   my $self = shift;
60   my ($file) = @_;
61
62   $file ||= $self->input;
63   my $datadir = $self->datadir;
64   $self->brik_help_run_undef_arg('imageinfo', $file) or return;
65   $self->brik_help_run_file_not_found('imageinfo', $file) or return;
66
67   my $cmd = "volatility imageinfo -f \"$file\"";
68
69   $self->log->info("imageinfo: running...");
70   my $data = $self->capture($cmd);
71   $self->log->info("imageinfo: running...done");
72
73   my @profiles = ();
74   for my $line (@$data) {
75      if ($line =~ m{suggested profile}i) {
76         my @toks = split(/\s+/, $line);
77         @profiles = @toks[4..$#toks];
78         for (@profiles) {
79            s/,$//g;
80         }
81      }
82   }
83
84   return \@profiles;
85}
86
87sub command {
88   my $self = shift;
89   my ($command, $file, $profile) = @_;
90
91   $file ||= $self->input;
92   $profile ||= $self->profile;
93   $self->brik_help_run_undef_arg('command', $command) or return;
94   $self->brik_help_run_undef_arg('command', $file) or return;
95   $self->brik_help_run_undef_arg('command', $profile) or return;
96
97   my $cmd = "volatility --profile $profile $command -f \"$file\"";
98
99   return $self->execute($cmd);
100}
101
102sub envars {
103   my $self = shift;
104   my ($file, $profile) = @_;
105
106   $file ||= $self->input;
107   $profile ||= $self->profile;
108   $self->brik_help_run_undef_arg('envars', $file) or return;
109   $self->brik_help_run_undef_arg('envars', $profile) or return;
110
111   my $cmd = "volatility --profile $profile envars -f $file";
112
113   return $self->execute($cmd);
114}
115
116sub pstree {
117   my $self = shift;
118   my ($file, $profile) = @_;
119
120   $file ||= $self->input;
121   $profile ||= $self->profile;
122   $self->brik_help_run_undef_arg('pstree', $file) or return;
123   $self->brik_help_run_undef_arg('pstree', $profile) or return;
124
125   my $cmd = "volatility --profile $profile pstree -v -f $file";
126
127   return $self->execute($cmd);
128}
129
130sub pslist {
131   my $self = shift;
132   my ($file, $profile) = @_;
133
134   $file ||= $self->input;
135   $profile ||= $self->profile;
136   $self->brik_help_run_undef_arg('pslist', $file) or return;
137   $self->brik_help_run_undef_arg('pslist', $profile) or return;
138
139   my $cmd = "volatility --profile $profile pslist -v -f $file";
140
141   $self->capture_stderr(0);
142   my $lines = $self->execute($cmd) or return;
143   $self->capture_stderr(1);
144
145   # Offset(V)|Name|PID|PPID|Thds|Hnds|Sess|Wow64|Start                          Exit
146   my $skip = 3;
147   my @info = ();
148   for my $line (@$lines) {
149      if ($skip != 0) {
150         $skip--;
151         next;
152      }
153      my @t = split(/\s+/, $line, 9);
154      my $offset = $t[0];
155      my $name = $t[1];
156      my $pid = $t[2];
157      my $ppid = $t[3];
158      my $thds = $t[4];
159      my $hhds = $t[5];
160      my $sess = $t[6];
161      my $wow64 = $t[7];
162      my $start_exit = $t[8];
163
164      # "2016-06-04 16:23:13 UTC+0000"
165      # "2016-06-04 16:26:04 UTC+0000   2016-06-04 16:26:06 UTC+0000"
166      $start_exit =~ s{\s*$}{};
167      my ($start, $exit) = $start_exit =~ m{^(\S+ \S+ \S+)(?:\s+(\S+ \S+ \S+))?$};
168
169      push @info, {
170         offset => $offset,
171         name => $name,
172         pid => $pid,
173         ppid => $ppid,
174         thds => $thds,
175         hhds => $hhds,
176         sess => $sess,
177         wow64 => $wow64,
178         start => $start,
179         exit => $exit,
180         #start_exit => $start_exit,
181      };
182   }
183
184   return \@info;
185}
186
187sub netscan {
188   my $self = shift;
189   my ($file, $profile) = @_;
190
191   $file ||= $self->input;
192   $profile ||= $self->profile;
193   $self->brik_help_run_undef_arg('netscan', $file) or return;
194   $self->brik_help_run_undef_arg('netscan', $profile) or return;
195
196   my $cmd = "volatility --profile $profile netscan -v -f $file";
197
198   $self->capture_stderr(0);
199   my $lines = $self->execute($cmd) or return;
200   $self->capture_stderr(1);
201
202   # "Offset(P)   Proto   Local Address   Foreign Address    State     Pid   Owner     Created",
203   my $skip = 1;
204   my @info = ();
205   my @raw = ();
206   for my $line (@$lines) {
207      if ($skip != 0) {
208         $skip--;
209         next;
210      }
211
212# "0x41b9520  TCPv6  -:0   7808:2401:80fa:ffff:7808:2401:80fa:ffff:0 CLOSED 1820  avgmfapx.exe"
213      if ($line =~ m{\s+TCPv(4|6)\s+}) {
214         my @t = split(/\s+/, $line, 7);
215         my $offset = $t[0];
216         my $proto = $t[1];
217         my $local_address = $t[2];
218         my $foreign_address = $t[3];
219         my $state = $t[4];
220         my $pid = $t[5];
221         my $owner = $t[6];
222
223         push @info, {
224            offset => $offset,
225            proto => $proto,
226            local_address => $local_address,
227            foreign_address => $foreign_address,
228            state => $state,
229            pid => $pid,
230            owner => $owner,
231            created => 'undef',
232         };
233      }
234# "0x171e1360 UDPv4  10.0.3.15:138  *:*    4  System  2016-10-15 14:58:46 UTC+0000",
235      elsif ($line =~ m{\s+UDPv(4|6)\s+}) {
236         my @t = split(/\s+/, $line, 7);
237         my $offset = $t[0];
238         my $proto = $t[1];
239         my $local_address = $t[2];
240         my $foreign_address = $t[3];
241         my $pid = $t[4];
242         my $owner = $t[5];
243         my $created = $t[6];
244
245         push @info, {
246            offset => $offset,
247            proto => $proto,
248            local_address => $local_address,
249            foreign_address => $foreign_address,
250            state => 'undef',
251            pid => $pid,
252            owner => $owner,
253            created => $created,
254         };
255      }
256      else {
257         $self->log->warning("netscan: don't know what to do with line [$line]");
258      }
259   }
260
261   return \@info;
262}
263
264sub memdump {
265   my $self = shift;
266   my ($pid, $file, $profile) = @_;
267
268   $file ||= $self->input;
269   $profile ||= $self->profile;
270   $self->brik_help_run_undef_arg('memdump', $pid) or return;
271   $self->brik_help_run_undef_arg('memdump', $file) or return;
272   $self->brik_help_run_undef_arg('memdump', $profile) or return;
273
274   my $sf = Metabrik::System::File->new_from_brik_init($self) or return;
275   $sf->mkdir($pid) or return;
276
277   my $cmd = "volatility --profile $profile memdump -p $pid --dump-dir $pid/ -f $file";
278   $self->execute($cmd) or return;
279
280   return "$pid/$pid.dmp";
281}
282
283sub hashdump {
284   my $self = shift;
285   my ($file, $profile) = @_;
286
287   $file ||= $self->input;
288   $profile ||= $self->profile;
289   $self->brik_help_run_undef_arg('hashdump', $file) or return;
290   $self->brik_help_run_undef_arg('hashdump', $profile) or return;
291
292   my $cmd = "volatility --profile $profile hashdump -f $file";
293
294   return $self->execute($cmd);
295}
296
297sub psxview {
298   my $self = shift;
299   my ($file, $profile) = @_;
300
301   $file ||= $self->input;
302   $profile ||= $self->profile;
303   $self->brik_help_run_undef_arg('psxview', $file) or return;
304   $self->brik_help_run_undef_arg('psxview', $profile) or return;
305
306   my $cmd = "volatility --profile $profile psxview -f $file";
307
308   return $self->execute($cmd);
309}
310
311sub hivelist {
312   my $self = shift;
313   my ($file, $profile) = @_;
314
315   $file ||= $self->input;
316   $profile ||= $self->profile;
317   $self->brik_help_run_undef_arg('hivelist', $file) or return;
318   $self->brik_help_run_undef_arg('hivelist', $profile) or return;
319
320   my $cmd = "volatility --profile $profile hivelist -f $file";
321
322   $self->capture_stderr(0);
323   my $lines = $self->execute($cmd) or return;
324   $self->capture_stderr(1);
325
326   # "Virtual            Physical           Name"
327   my $skip = 2;
328   my @info = ();
329   for my $line (@$lines) {
330      if ($skip != 0) {
331         $skip--;
332         next;
333      }
334      my @t = split(/\s+/, $line, 3);
335      my $virtual = $t[0];
336      my $physical = $t[1];
337      my $name = $t[2];
338
339      push @info, {
340         virtual => $virtual,
341         physical => $physical,
342         name => $name,
343      };
344   }
345
346   return \@info;
347}
348
349sub hivedump {
350   my $self = shift;
351   my ($offset, $file, $profile) = @_;
352
353   $file ||= $self->input;
354   $profile ||= $self->profile;
355   $self->brik_help_run_undef_arg('hivedump', $offset) or return;
356   $self->brik_help_run_undef_arg('hivedump', $file) or return;
357   $self->brik_help_run_undef_arg('hivedump', $profile) or return;
358
359   my $cmd = "volatility --profile $profile hivedump --hive-offset $offset -f $file";
360
361   return $self->execute($cmd);
362}
363
364sub filescan {
365   my $self = shift;
366   my ($offset, $file, $profile) = @_;
367
368   $file ||= $self->input;
369   $profile ||= $self->profile;
370   $self->brik_help_run_undef_arg('filescan', $offset) or return;
371   $self->brik_help_run_undef_arg('filescan', $file) or return;
372   $self->brik_help_run_undef_arg('filescan', $profile) or return;
373
374   my $cmd = "volatility --profile $profile filescan -f $file";
375
376   return $self->execute($cmd);
377}
378
379sub consoles {
380   my $self = shift;
381   my ($file, $profile) = @_;
382
383   $file ||= $self->input;
384   $profile ||= $self->profile;
385   $self->brik_help_run_undef_arg('consoles', $file) or return;
386   $self->brik_help_run_undef_arg('consoles', $profile) or return;
387
388   my $cmd = "volatility --profile $profile consoles -f $file";
389
390   return $self->execute($cmd);
391}
392
3931;
394
395__END__
396
397=head1 NAME
398
399Metabrik::Forensic::Volatility - forensic::volatility Brik
400
401=head1 COPYRIGHT AND LICENSE
402
403Copyright (c) 2014-2017, Patrice E<lt>GomoRE<gt> Auffret
404
405You may distribute this module under the terms of The BSD 3-Clause License.
406See LICENSE file in the source distribution archive.
407
408=head1 AUTHOR
409
410Patrice E<lt>GomoRE<gt> Auffret
411
412=cut
Note: See TracBrowser for help on using the repository browser.