-
Notifications
You must be signed in to change notification settings - Fork 2
/
template.py
153 lines (134 loc) · 5.1 KB
/
template.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
# Colin Cowie - @th3_protoCOL
# Template module for malware analysis
import os
import re
import string
import pefile
import exiftool
from viper.common.abstracts import Module
from viper.core.session import __sessions__
from viper.core.config import __config__
from viper.core.database import Database
from viper.core.storage import get_sample_path
from viper.common.objects import File
class Template(Module):
cmd = 'hunt'
description = 'Template module for tracking malware'
authors = ['th3_protoCOL']
emails = [] # todo: move to its own plugin
def __init__(self):
super(Template, self).__init__()
self.parser.add_argument('-a', '--all', action='store_true', help='Run the module on all samples')
self.parser.add_argument('-e', '--emails', action='store_true', help='Extract all email addresses')
self.parser.add_argument('-s', '--search', dest='search_string', help='Search for a specifc string')
def get_strings(self, f):
# String implementation see http://stackoverflow.com/a/17197027/6880819 - Extended with Unicode support. todo: explore other string detections
results = []
result = ""
counter = 1
wide_word = False
min = 3
for c in f.data.decode('utf-8', 'ignore'):
# Already have something, check if the second byte is a null
if counter == 2 and c == "\x00":
wide_word = True
counter += 1
continue
# Every 2 chars we allow a 00
if wide_word and c == "\x00" and not counter % 2:
counter += 1
continue
# Valid char, go to next - newlines are to be considered as the end of the string
if c in string.printable and c not in ['\n', '\r']:
result += c
counter += 1
continue
if len(result) >= min:
results.append(result)
# Reset the variables
result = ''
counter = 1
wide_word = False
if len(result) >= min: # Catch result at EOF
results.append(result)
return results
def parse_search(self, strings, search):
results = []
for entry in strings:
to_add = False
if re.search(search, entry):
results.append(entry)
return results
def parse_ips(self, strings):
IP_REGEX = re.compile(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
results = []
for entry in strings:
if IP_REGEX.search(entry):
results.append(entry)
return results;
def parse_pdb(self, strings):
PDB_REGEX = re.compile(r'\.pdb$', re.IGNORECASE)
result = None
for entry in strings:
if PDB_REGEX.search(entry):
result = entry;
return result;
def parse_emails(self, strings):
EMAIL_REGEX = re.compile(r'(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)', re.IGNORECASE)
emails = []
for entry in strings:
if EMAIL_REGEX.search(entry):
emails.append(entry);
return emails;
# Main analysis function
def scan(self, file):
sample = File(file)
strings = self.get_strings(sample)
# Sets up rows - modify these
rows = [
['Name', sample.name],
['MD5', sample.md5]
]
# Get exif data
metadata = []
timestamp = ""
with exiftool.ExifTool() as et:
metadata = et.get_metadata(file)
if 'EXE:TimeStamp' in metadata:
rows.append(['TimeStamp',metadata['EXE:TimeStamp'][:10]])
if 'EXE:CodeSize' in metadata:
rows.append(['CodeSize',metadata['EXE:CodeSize']])
header = ['Key', 'Value']
rows.append(['PDB Path', self.parse_pdb(strings)])
rows.append(['IPv4s', self.parse_ips(strings)])
rows.append(['Emails', self.parse_emails(strings)])
#Find Emails
if self.args.emails:
for email in self.parse_emails(strings):
self.emails.append(email)
# Search for specfic string
if self.args.search_string:
search_result = self.parse_search(strings, self.args.search_string)
if search_result:
rows.append(['Search Results: ', search_result])
self.log('table', dict(header=header, rows=rows))
print('')
else:
self.log('table', dict(header=header, rows=rows))
def run(self):
super(Template, self).run()
if self.args is None:
return
# Check arguments and scan accordingly
if self.args.all:
db = Database()
samples = db.find(key='all')
for sample in samples:
self.scan(get_sample_path(sample.sha256))
if self.args.emails:
self.log('success', "Found emails: ")
self.log('success', str(set(self.emails)))
elif __sessions__.is_set():
self.scan(__sessions__.current.file.path)
else:
self.usage()