Support termination and preserve memory during strings dump

This commit is contained in:
Oleksii Shevchuk 2017-04-11 21:34:00 +03:00
parent c2d817e264
commit 4db302b048
2 changed files with 95 additions and 62 deletions

View File

@ -12,6 +12,8 @@ class MemStrings(PupyModule):
"""
dependencies=['memorpy', 'memstrings']
termevent = None
def init_argparse(self):
self.arg_parser = PupyArgumentParser(prog='memstrings', description=self.__doc__)
action = self.arg_parser.add_mutually_exclusive_group(required=True)
@ -19,7 +21,7 @@ class MemStrings(PupyModule):
help='Include processes with specified pids')
action.add_argument('-n', '--name', nargs='*', default=[],
help='Include processes with specified names')
self.arg_parser.add_argument('-o', '--omit', type=str, default='isrx',
self.arg_parser.add_argument('-x', '--omit', type=str, default='isrx',
help='Avoid scanning: '
'i - ranges with file mapping; '
's - ranges with shared region; '
@ -29,9 +31,12 @@ class MemStrings(PupyModule):
help='Show only strings which are longer then specified length')
self.arg_parser.add_argument('-m', '--max-length', type=int, default=51,
help='Show only strings which are shorter then specified length')
self.arg_parser.add_argument('-P', '--portions', type=int, default=8192,
help='Strings portion block')
self.arg_parser.add_argument('-d', '--no-duplication', default=False, action='store_true',
help='Enable strings deduplication (will increase memory usage)')
self.arg_parser.add_argument(
'-log',
'-o', '--output',
help='Save output to file. Omit output to stdout. You can use vars: '
'%%h - host, %%m - mac, %%P - platform, %%u - user, %%a - ip address'
'%%p - pid, %%n - name'
@ -39,62 +44,70 @@ class MemStrings(PupyModule):
def run(self, args):
targets = args.pid + args.name
dump = self.client.conn.modules.memstrings.find_strings(
targets,
min_length=args.min_length,
max_length=args.max_length,
omit=args.omit
)
dump = obtain(dump)
if not dump:
self.error('No dumps received')
return
self.success('Get {} dumps'.format(len(dump)))
self.termevent = self.client.conn.modules.threading.Event()
log = None
logs = {}
for pid, items in dump.iteritems():
name = items.get('name')
strings = items.get('strings')
for pid, name, strings in self.client.conn.modules.memstrings.iterate_strings(
targets,
min_length=args.min_length,
max_length=args.max_length,
omit=args.omit,
portions=args.portions,
terminate=self.termevent,
nodup=args.no_duplication,
):
if args.log:
log = args.log.replace(
'%m', self.client.desc['macaddr']
).replace(
'%P', self.client.desc['platform']
).replace(
'%a', self.client.desc['address']
).replace(
'%h', self.client.desc['hostname'].replace(
'..', '__'
strings = obtain(strings)
pid = str(pid) or '0'
name = str(name) or ''
if not strings:
self.error('No dumps received')
return
if args.output:
if not pid in logs:
log = args.output.replace(
'%m', self.client.desc['macaddr']
).replace(
'/', '_'
'%P', self.client.desc['platform']
).replace(
'%a', self.client.desc['address']
).replace(
'%h', self.client.desc['hostname'].replace(
'..', '__'
).replace(
'/', '_'
)
).replace(
'%u', self.client.desc['user'].replace(
'..', '__'
).replace(
'/', '_'
)
).replace(
'%p', str(pid),
).replace(
'%n', name.replace(
'..', '__'
).replace(
'/', '_'
),
)
).replace(
'%u', self.client.desc['user'].replace(
'..', '__'
).replace(
'/', '_'
)
).replace(
'%p', pid,
).replace(
'%n', name.replace(
'..', '__'
).replace(
'/', '_'
),
)
dirname = os.path.dirname(log)
if not os.path.exists(dirname):
os.makedirs(dirname)
dirname = os.path.dirname(log)
if not os.path.exists(dirname):
os.makedirs(dirname)
self.success('Dump {}:{} to {}'.format(name, pid, log))
with open(log, 'w') as log:
for s in strings:
log.write(s+'\n')
self.success('Dumping {}:{} -> {}'.format(name, pid, log))
logs[pid] = open(log, 'a+')
for s in strings:
logs[pid].write(s+'\n')
logs[pid].flush()
else:
self.success('Strings {}:{}'.format(name, pid))
@ -102,3 +115,10 @@ class MemStrings(PupyModule):
self.stdout.write(s+'\n')
self.stdout.write('\n')
for log in logs.itervalues():
log.close()
def interrupt(self):
if self.termevent:
self.termevent.set()

View File

@ -11,9 +11,9 @@ def try_int(x):
except:
return x
def find_strings(targets, min_length=4, max_length=51, omit='isxr'):
def iterate_strings(targets, min_length=4, max_length=51, omit='isxr', portions=4096, nodup=True, terminate=None):
if not targets:
return {}
return
if type(targets) == (str, int):
targets = [ targets ]
@ -24,26 +24,39 @@ def find_strings(targets, min_length=4, max_length=51, omit='isxr'):
printable = re.compile('^[\x20-\x7e]{{{},{}}}$'.format(min_length, max_length))
for process in memorpy.Process.list():
if terminate is not None and terminate.is_set():
break
if not (
os.path.basename(process.get('name')) in targets or process.get('pid') in targets
):
continue
strings = []
results[process.get('pid')] = {
'name': process.get('name'),
'strings': strings
}
pid = process.get('pid')
name = process.get('name')
mw = memorpy.MemWorker(pid=process.get('pid'))
duplicates = set()
for _, (cstring,) in mw.mem_search('([^\x00]+)', ftype='groups', optimizations=omit):
if printable.match(cstring):
if not cstring in duplicates:
duplicates.add(cstring)
strings.append(cstring)
if terminate is not None and terminate.is_set():
break
return results
if printable.match(cstring):
if nodup:
if cstring in duplicates:
continue
duplicates.add(cstring)
strings.append(cstring)
if len(strings) >= portions:
yield pid, name, strings
strings = []
if strings:
yield pid, name, strings
strings = []
if __name__=="__main__":
import sys