Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
mbevilacqua
committed
Apr 19, 2017
1 parent
544ce60
commit a06de9c
Showing
48 changed files
with
12,519 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# safelist | ||
branches: | ||
only: | ||
- master | ||
- develop | ||
|
||
os: | ||
- linux | ||
|
||
language: python | ||
python: | ||
- "2.7" | ||
|
||
before_install: | ||
- wget https://github.com/libyal/libregf/releases/download/20160424/libregf-alpha-20160424.tar.gz | ||
- tar xzvf libregf-alpha-20160424.tar.gz | ||
- pushd libregf-20160424 && ./configure --enable-python && make && sudo make install && python setup.py build && python setup.py install && popd | ||
|
||
# command to install dependencies | ||
install: | ||
- pip install faker | ||
- pip install -r requirements.txt | ||
|
||
# command to run tests | ||
script: pytest ./test/test_status.py ./test/test_dump.py ./test/test_filehitcount.py ./test/test_leven.py ./test/test_mpengine.py ./test/test_search.py ./test/test_stack.py ./test/test_tcorr.py ./test/test_tstack.py ./test/test_tstomp.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,249 @@ | ||
#!/usr/bin/python | ||
# Ripped by Matias Bevilacqua from Will Ballenthin's python-registry amcache sample | ||
# Refactored to work with ligref python bindings for speed purposes | ||
|
||
# The origianl code was part of the python-registry module. | ||
# | ||
# Copyright 2015 Will Ballenthin <william.ballenthin@mandiant.com> | ||
# while at Mandiant <http://www.mandiant.com> | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
import settings | ||
import logging | ||
from datetime import datetime | ||
from collections import namedtuple | ||
import os | ||
import sys | ||
try: | ||
import pyregf | ||
except ImportError: | ||
if settings.__PYREGF__: | ||
settings.__PYREGF__ = False | ||
print "Ooops seems you don't have pyregf!" | ||
print "AmCache loading support will be disabled" | ||
else: settings.__PYREGF__ = True | ||
|
||
try: | ||
from cStringIO import StringIO | ||
except: | ||
from StringIO import StringIO | ||
|
||
from appAux import update_progress, chunks, loadFile, checkLock | ||
|
||
logger = logging.getLogger(__name__) | ||
Field = namedtuple("Field", ["name", "getter"]) | ||
|
||
def make_value_getter(value_name): | ||
""" return a function that fetches the value from the registry key """ | ||
def _value_getter(key): | ||
try: | ||
return key[0].get_value_by_name(value_name).get_data_as_string() | ||
except: | ||
return None | ||
return _value_getter | ||
|
||
def make_integer_value_getter(value_name): | ||
""" return a function that fetches the value from the registry key """ | ||
def _value_getter(key): | ||
try: | ||
return key[0].get_value_by_name(value_name).get_data_as_integer() | ||
except: | ||
return None | ||
return _value_getter | ||
|
||
def make_windows_timestamp_value_getter(value_name): | ||
""" | ||
return a function that fetches the value from the registry key | ||
as a Windows timestamp. | ||
""" | ||
f = make_value_getter(value_name) | ||
def _value_getter(key): | ||
try: | ||
if key[0].get_value_by_name(value_name) != None: | ||
return parse_windows_timestamp(key[0].get_value_by_name(value_name).get_data_as_integer() or 0) | ||
else: return datetime.min | ||
except ValueError: | ||
return datetime.min | ||
return _value_getter | ||
|
||
|
||
def parse_unix_timestamp(qword): | ||
return datetime.fromtimestamp(qword) | ||
|
||
|
||
def parse_windows_timestamp(qword): | ||
try: | ||
return datetime.utcfromtimestamp(float(qword) * 1e-7 - 11644473600 ) | ||
except ValueError: | ||
return datetime.min | ||
|
||
|
||
def make_unix_timestamp_value_getter(value_name): | ||
""" | ||
return a function that fetches the value from the registry key | ||
as a UNIX timestamp. | ||
""" | ||
f = make_value_getter(value_name) | ||
def _value_getter(key): | ||
try: | ||
if key[0].get_value_by_name(value_name) != None: | ||
return parse_unix_timestamp(key[0].get_value_by_name(value_name).get_data_as_integer() or 0) | ||
else: return datetime.min | ||
except ValueError: | ||
return datetime.min | ||
return _value_getter | ||
|
||
|
||
UNIX_TIMESTAMP_ZERO = parse_unix_timestamp(0) | ||
WINDOWS_TIMESTAMP_ZERO = parse_windows_timestamp(0) | ||
|
||
|
||
# via: http://www.swiftforensics.com/2013/12/amcachehve-in-windows-8-goldmine-for.html | ||
#Product Name UNICODE string | ||
#============================================================================== | ||
#0 Product Name UNICODE string | ||
#1 Company Name UNICODE string | ||
#2 File version number only UNICODE string | ||
#3 Language code (1033 for en-US) DWORD | ||
#4 SwitchBackContext QWORD | ||
#5 File Version UNICODE string | ||
#6 File Size (in bytes) DWORD | ||
#7 PE Header field - SizeOfImage DWORD | ||
#8 Hash of PE Header (unknown algorithm) UNICODE string | ||
#9 PE Header field - Checksum DWORD | ||
#a Unknown QWORD | ||
#b Unknown QWORD | ||
#c File Description UNICODE string | ||
#d Unknown, maybe Major & Minor OS version DWORD | ||
#f Linker (Compile time) Timestamp DWORD - Unix time | ||
#10 Unknown DWORD | ||
#11 Last Modified Timestamp FILETIME | ||
#12 Created Timestamp FILETIME | ||
#15 Full path to file UNICODE string | ||
#16 Unknown DWORD | ||
#17 Last Modified Timestamp 2 FILETIME | ||
#100 Program ID UNICODE string | ||
#101 SHA1 hash of file | ||
|
||
|
||
# note: order here implicitly orders CSV column ordering cause I'm lazy | ||
FIELDS = [ | ||
Field("path", make_value_getter("15")), | ||
Field("sha1", make_value_getter("101")), | ||
Field("size", make_integer_value_getter("6")), | ||
Field("file_description", make_value_getter("c")), | ||
Field("first_run", lambda key: key[0].get_last_written_time()), | ||
Field("created_timestamp", make_windows_timestamp_value_getter("12")), | ||
Field("modified_timestamp", make_windows_timestamp_value_getter("11")), | ||
Field("modified_timestamp2", make_windows_timestamp_value_getter("17")), | ||
Field("linker_timestamp", make_unix_timestamp_value_getter("f")), | ||
Field("product", make_value_getter("0")), | ||
Field("company", make_value_getter("1")), | ||
Field("pe_sizeofimage", make_integer_value_getter("7")), | ||
Field("version_number", make_value_getter("2")), | ||
Field("version", make_value_getter("5")), | ||
Field("language", make_integer_value_getter("3")), | ||
Field("header_hash", make_value_getter("8")), | ||
Field("pe_checksum", make_integer_value_getter("9")), | ||
Field("id", make_integer_value_getter("100")), | ||
Field("switchbackcontext", make_integer_value_getter("4")), | ||
] | ||
|
||
|
||
ExecutionEntry = namedtuple("ExecutionEntry", map(lambda e: e.name, FIELDS)) | ||
|
||
|
||
def parse_execution_entry(key): | ||
# Note: Change required to make it work on python 2.6.6: | ||
# return(ExecutionEntry(**{e.name:e.getter(key) for e in FIELDS})) | ||
ret = {} | ||
for e in FIELDS: | ||
ret[e.name] = e.getter(key) | ||
|
||
return ExecutionEntry(**(ret)) | ||
|
||
class NotAnAmcacheHive(Exception): | ||
pass | ||
|
||
def get_sub_keys(key, path=''): | ||
# iterate all sub-keys of key returning (key,path) | ||
num_keys = key.get_number_of_sub_keys() | ||
|
||
for i in xrange(num_keys): | ||
cur_key = key.get_sub_key(i) | ||
new_path = os.path.join(path, cur_key.get_name()) | ||
yield (cur_key, new_path) | ||
|
||
for result in get_sub_keys(cur_key, new_path): | ||
yield result | ||
|
||
def parse_execution_entries(regf): | ||
|
||
tmp = regf.get_key_by_path(r'Root\File') | ||
if regf.get_key_by_path(r'Root\File') == None: | ||
raise NotAnAmcacheHive() | ||
else: | ||
ret = [] | ||
for volumekey, volumePath in get_sub_keys(regf.get_key_by_path(r'Root\File')): | ||
for filekey in get_sub_keys(volumekey): | ||
ret.append(parse_execution_entry(filekey)) | ||
return ret | ||
|
||
|
||
TimelineEntry = namedtuple("TimelineEntry", ["timestamp", "type", "entry"]) | ||
|
||
def _processAmCacheFile(fileFullPath): | ||
file_object = open(fileFullPath, "rb") | ||
regf_file = pyregf.file() | ||
regf_file.open_file_object(file_object, "r") | ||
|
||
try: | ||
ee = parse_execution_entries(regf_file) | ||
except NotAnAmcacheHive: | ||
logger.error("doesn't appear to be an Amcache.hve hive") | ||
return | ||
finally: | ||
regf_file.close() | ||
file_object.close() | ||
|
||
return ee | ||
|
||
|
||
def _processAmCacheFile_StringIO(data): | ||
regf_file = pyregf.file() | ||
regf_file.open_file_object(data, "r") | ||
|
||
try: | ||
ee = parse_execution_entries(regf_file) | ||
except NotAnAmcacheHive: | ||
logger.error("doesn't appear to be an Amcache.hve hive") | ||
return | ||
finally: | ||
regf_file.close() | ||
|
||
return ee | ||
|
||
if __name__ == "__main__": | ||
fileFullPath = str(sys.argv[1]) | ||
file_object = loadFile(fileFullPath) | ||
regf_file = pyregf.file() | ||
regf_file.open_file_object(file_object, "r") | ||
|
||
try: | ||
ee = parse_execution_entries(regf_file) | ||
except NotAnAmcacheHive: | ||
print("doesn't appear to be an Amcache.hve hive") | ||
finally: | ||
regf_file.close() | ||
file_object.close() |
Oops, something went wrong.