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'] dependencies=['memorpy', 'memstrings']
termevent = None
def init_argparse(self): def init_argparse(self):
self.arg_parser = PupyArgumentParser(prog='memstrings', description=self.__doc__) self.arg_parser = PupyArgumentParser(prog='memstrings', description=self.__doc__)
action = self.arg_parser.add_mutually_exclusive_group(required=True) action = self.arg_parser.add_mutually_exclusive_group(required=True)
@ -19,7 +21,7 @@ class MemStrings(PupyModule):
help='Include processes with specified pids') help='Include processes with specified pids')
action.add_argument('-n', '--name', nargs='*', default=[], action.add_argument('-n', '--name', nargs='*', default=[],
help='Include processes with specified names') 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: ' help='Avoid scanning: '
'i - ranges with file mapping; ' 'i - ranges with file mapping; '
's - ranges with shared region; ' 's - ranges with shared region; '
@ -29,9 +31,12 @@ class MemStrings(PupyModule):
help='Show only strings which are longer then specified length') help='Show only strings which are longer then specified length')
self.arg_parser.add_argument('-m', '--max-length', type=int, default=51, self.arg_parser.add_argument('-m', '--max-length', type=int, default=51,
help='Show only strings which are shorter then specified length') 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( self.arg_parser.add_argument(
'-log', '-o', '--output',
help='Save output to file. Omit output to stdout. You can use vars: ' help='Save output to file. Omit output to stdout. You can use vars: '
'%%h - host, %%m - mac, %%P - platform, %%u - user, %%a - ip address' '%%h - host, %%m - mac, %%P - platform, %%u - user, %%a - ip address'
'%%p - pid, %%n - name' '%%p - pid, %%n - name'
@ -39,62 +44,70 @@ class MemStrings(PupyModule):
def run(self, args): def run(self, args):
targets = args.pid + args.name 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(): for pid, name, strings in self.client.conn.modules.memstrings.iterate_strings(
name = items.get('name') targets,
strings = items.get('strings') 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: strings = obtain(strings)
log = args.log.replace( pid = str(pid) or '0'
'%m', self.client.desc['macaddr'] name = str(name) or ''
).replace(
'%P', self.client.desc['platform'] if not strings:
).replace( self.error('No dumps received')
'%a', self.client.desc['address'] return
).replace(
'%h', self.client.desc['hostname'].replace( if args.output:
'..', '__' if not pid in logs:
log = args.output.replace(
'%m', self.client.desc['macaddr']
).replace( ).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) dirname = os.path.dirname(log)
if not os.path.exists(dirname): if not os.path.exists(dirname):
os.makedirs(dirname) os.makedirs(dirname)
self.success('Dump {}:{} to {}'.format(name, pid, log)) self.success('Dumping {}:{} -> {}'.format(name, pid, log))
with open(log, 'w') as log: logs[pid] = open(log, 'a+')
for s in strings:
log.write(s+'\n') for s in strings:
logs[pid].write(s+'\n')
logs[pid].flush()
else: else:
self.success('Strings {}:{}'.format(name, pid)) self.success('Strings {}:{}'.format(name, pid))
@ -102,3 +115,10 @@ class MemStrings(PupyModule):
self.stdout.write(s+'\n') self.stdout.write(s+'\n')
self.stdout.write('\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: except:
return x 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: if not targets:
return {} return
if type(targets) == (str, int): if type(targets) == (str, int):
targets = [ targets ] 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)) printable = re.compile('^[\x20-\x7e]{{{},{}}}$'.format(min_length, max_length))
for process in memorpy.Process.list(): for process in memorpy.Process.list():
if terminate is not None and terminate.is_set():
break
if not ( if not (
os.path.basename(process.get('name')) in targets or process.get('pid') in targets os.path.basename(process.get('name')) in targets or process.get('pid') in targets
): ):
continue continue
strings = [] strings = []
results[process.get('pid')] = { pid = process.get('pid')
'name': process.get('name'), name = process.get('name')
'strings': strings
}
mw = memorpy.MemWorker(pid=process.get('pid')) mw = memorpy.MemWorker(pid=process.get('pid'))
duplicates = set() duplicates = set()
for _, (cstring,) in mw.mem_search('([^\x00]+)', ftype='groups', optimizations=omit): for _, (cstring,) in mw.mem_search('([^\x00]+)', ftype='groups', optimizations=omit):
if printable.match(cstring): if terminate is not None and terminate.is_set():
if not cstring in duplicates: break
duplicates.add(cstring)
strings.append(cstring)
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__": if __name__=="__main__":
import sys import sys