double to single quotes

This commit is contained in:
Moritz Raabe
2020-06-24 15:00:35 +02:00
parent fa9bb946ed
commit beba3fb3c7
17 changed files with 173 additions and 158 deletions

View File

@@ -10,7 +10,7 @@ try:
except (ImportError, SyntaxError): except (ImportError, SyntaxError):
pass pass
__all__ = ["ida", "viv"] __all__ = ['ida', 'viv']
class FeatureExtractor(object): class FeatureExtractor(object):

View File

@@ -7,13 +7,13 @@ import re
from collections import namedtuple from collections import namedtuple
ASCII_BYTE = r" !\"#\$%&\'\(\)\*\+,-\./0123456789:;<=>\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\]\^_`abcdefghijklmnopqrstuvwxyz\{\|\}\\\~\t".encode('ascii') ASCII_BYTE = r' !\"#\$%&\'\(\)\*\+,-\./0123456789:;<=>\?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\]\^_`abcdefghijklmnopqrstuvwxyz\{\|\}\\\~\t'.encode('ascii')
ASCII_RE_4 = re.compile(b"([%s]{%d,})" % (ASCII_BYTE, 4)) ASCII_RE_4 = re.compile(b'([%s]{%d,})' % (ASCII_BYTE, 4))
UNICODE_RE_4 = re.compile(b"((?:[%s]\x00){%d,})" % (ASCII_BYTE, 4)) UNICODE_RE_4 = re.compile(b'((?:[%s]\x00){%d,})' % (ASCII_BYTE, 4))
REPEATS = [b"A", b"\x00", b"\xfe", b"\xff"] REPEATS = [b'A', b'\x00', b'\xfe', b'\xff']
SLICE_SIZE = 4096 SLICE_SIZE = 4096
String = namedtuple("String", ["s", "offset"]) String = namedtuple('String', ['s', 'offset'])
def buf_filled_with(buf, character): def buf_filled_with(buf, character):
@@ -46,10 +46,10 @@ def extract_ascii_strings(buf, n=4):
if n == 4: if n == 4:
r = ASCII_RE_4 r = ASCII_RE_4
else: else:
reg = b"([%s]{%d,})" % (ASCII_BYTE, n) reg = b'([%s]{%d,})' % (ASCII_BYTE, n)
r = re.compile(reg) r = re.compile(reg)
for match in r.finditer(buf): for match in r.finditer(buf):
yield String(match.group().decode("ascii"), match.start()) yield String(match.group().decode('ascii'), match.start())
def extract_unicode_strings(buf, n=4): def extract_unicode_strings(buf, n=4):
@@ -72,11 +72,11 @@ def extract_unicode_strings(buf, n=4):
if n == 4: if n == 4:
r = UNICODE_RE_4 r = UNICODE_RE_4
else: else:
reg = b"((?:[%s]\x00){%d,})" % (ASCII_BYTE, n) reg = b'((?:[%s]\x00){%d,})' % (ASCII_BYTE, n)
r = re.compile(reg) r = re.compile(reg)
for match in r.finditer(buf): for match in r.finditer(buf):
try: try:
yield String(match.group().decode("utf-16"), match.start()) yield String(match.group().decode('utf-16'), match.start())
except UnicodeDecodeError: except UnicodeDecodeError:
pass pass

View File

@@ -13,7 +13,7 @@ import file
import function import function
import basicblock import basicblock
import insn import insn
__all__ = ["file", "function", "basicblock", "insn"] __all__ = ['file', 'function', 'basicblock', 'insn']
def get_va(self): def get_va(self):

View File

@@ -237,17 +237,17 @@ def main(argv=None):
] ]
format_help = ', '.join(['%s: %s' % (f[0], f[1]) for f in formats]) format_help = ', '.join(['%s: %s' % (f[0], f[1]) for f in formats])
parser = argparse.ArgumentParser(description="save capa features to a file") parser = argparse.ArgumentParser(description='save capa features to a file')
parser.add_argument("sample", type=str, parser.add_argument('sample', type=str,
help="Path to sample to analyze") help='Path to sample to analyze')
parser.add_argument("output", type=str, parser.add_argument('output', type=str,
help="Path to output file") help='Path to output file')
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument('-v', '--verbose', action='store_true',
help="Enable verbose output") help='Enable verbose output')
parser.add_argument("-q", "--quiet", action="store_true", parser.add_argument('-q', '--quiet', action='store_true',
help="Disable all output but errors") help='Disable all output but errors')
parser.add_argument("-f", "--format", choices=[f[0] for f in formats], default="auto", parser.add_argument('-f', '--format', choices=[f[0] for f in formats], default='auto',
help="Select sample format, %s" % format_help) help='Select sample format, %s' % format_help)
args = parser.parse_args(args=argv) args = parser.parse_args(args=argv)
if args.quiet: if args.quiet:
@@ -271,6 +271,6 @@ def main(argv=None):
return 0 return 0
if __name__ == "__main__": if __name__ == '__main__':
import sys import sys
sys.exit(main()) sys.exit(main())

View File

@@ -362,7 +362,7 @@ class CapaExplorerForm(idaapi.PluginForm):
technique = parts[2].replace('-', ' ') technique = parts[2].replace('-', ' ')
techniques.add(technique) techniques.add(technique)
if len(parts) > 3: if len(parts) > 3:
raise capa.rules.InvalidRule(capa.main.RULE_CATEGORY + " tag must have at most three components") raise capa.rules.InvalidRule(capa.main.RULE_CATEGORY + ' tag must have at most three components')
# set row count to max set size # set row count to max set size
self._view_summary.setRowCount(max(map(len, (rules, objectives, behaviors, techniques)))) self._view_summary.setRowCount(max(map(len, (rules, objectives, behaviors, techniques))))

View File

@@ -221,7 +221,7 @@ def render_capabilities_default(ruleset, results):
technique = parts[2].replace('-', ' ') technique = parts[2].replace('-', ' ')
techniques.add(technique) techniques.add(technique)
if len(parts) > 3: if len(parts) > 3:
raise capa.rules.InvalidRule(RULE_CATEGORY + " tag must have at most three components") raise capa.rules.InvalidRule(RULE_CATEGORY + ' tag must have at most three components')
if technique: if technique:
o[objective][behavior][technique][rule.name] = rule o[objective][behavior][technique][rule.name] = rule
@@ -349,7 +349,7 @@ def render_result(res, indent=''):
if sum(map(lambda c: c.success, res.children)) > 0: if sum(map(lambda c: c.success, res.children)) > 0:
print('%soptional:' % indent) print('%soptional:' % indent)
else: else:
print("%s%d or more" % (indent, res.statement.count)) print('%s%d or more' % (indent, res.statement.count))
elif not isinstance(res.statement, (capa.features.Feature, capa.engine.Element, capa.engine.Range, capa.engine.Regex)): elif not isinstance(res.statement, (capa.features.Feature, capa.engine.Element, capa.engine.Range, capa.engine.Regex)):
# when rending a structural node (and/or/not), # when rending a structural node (and/or/not),
# then we only care about the node name. # then we only care about the node name.
@@ -517,7 +517,7 @@ def get_rules(rule_path):
with open(rule_path, 'rb') as f: with open(rule_path, 'rb') as f:
rule = capa.rules.Rule.from_yaml(f.read().decode('utf-8')) rule = capa.rules.Rule.from_yaml(f.read().decode('utf-8'))
if is_nursery_rule_path(root): if is_nursery_rule_path(rule_path):
rule.meta['nursery'] = True rule.meta['nursery'] = True
rules.append(rule) rules.append(rule)
@@ -637,35 +637,35 @@ def main(argv=None):
try: try:
extractor = get_extractor(args.sample, args.format) extractor = get_extractor(args.sample, args.format)
except UnsupportedFormatError: except UnsupportedFormatError:
logger.error("-" * 80) logger.error('-' * 80)
logger.error(" Input file does not appear to be a PE file.") logger.error(' Input file does not appear to be a PE file.')
logger.error(" ") logger.error(' ')
logger.error(" Today, capa currently only supports analyzing PE files (or shellcode, when using --format sc32|sc64).") logger.error(' Today, capa currently only supports analyzing PE files (or shellcode, when using --format sc32|sc64).')
logger.error(" If you don't know the input file type, you can try using the `file` utility to guess it.") logger.error(' If you don\'t know the input file type, you can try using the `file` utility to guess it.')
logger.error("-" * 80) logger.error('-' * 80)
return -1 return -1
except UnsupportedRuntimeError: except UnsupportedRuntimeError:
logger.error("-" * 80) logger.error('-' * 80)
logger.error(" Unsupported runtime or Python interpreter.") logger.error(' Unsupported runtime or Python interpreter.')
logger.error(" ") logger.error(' ')
logger.error(" Today, capa supports running under Python 2.7 using Vivisect for binary analysis.") logger.error(' Today, capa supports running under Python 2.7 using Vivisect for binary analysis.')
logger.error(" It can also run within IDA Pro, using either Python 2.7 or 3.5+.") logger.error(' It can also run within IDA Pro, using either Python 2.7 or 3.5+.')
logger.error(" ") logger.error(' ')
logger.error(" If you're seeing this message on the command line, please ensure you're running Python 2.7.") logger.error(' If you\'re seeing this message on the command line, please ensure you\'re running Python 2.7.')
logger.error("-" * 80) logger.error('-' * 80)
return -1 return -1
capabilities = find_capabilities(rules, extractor) capabilities = find_capabilities(rules, extractor)
if appears_rule_cat(rules, capabilities, 'other-features/installer/'): if appears_rule_cat(rules, capabilities, 'other-features/installer/'):
logger.warning("-" * 80) logger.warning('-' * 80)
logger.warning(" This sample appears to be an installer.") logger.warning(' This sample appears to be an installer.')
logger.warning(" ") logger.warning(' ')
logger.warning(" capa cannot handle installers well. This means the results may be misleading or incomplete.") logger.warning(' capa cannot handle installers well. This means the results may be misleading or incomplete.')
logger.warning(" You should try to understand the install mechanism and analyze created files with capa.") logger.warning(' You should try to understand the install mechanism and analyze created files with capa.')
logger.warning(" ") logger.warning(' ')
logger.warning(" Use -v or -vv if you really want to see the capabilities identified by capa.") logger.warning(' Use -v or -vv if you really want to see the capabilities identified by capa.')
logger.warning("-" * 80) logger.warning('-' * 80)
# capa will likely detect installer specific functionality. # capa will likely detect installer specific functionality.
# this is probably not what the user wants. # this is probably not what the user wants.
# #
@@ -674,16 +674,16 @@ def main(argv=None):
return -1 return -1
if appears_rule_cat(rules, capabilities, 'other-features/compiled-to-dot-net'): if appears_rule_cat(rules, capabilities, 'other-features/compiled-to-dot-net'):
logger.warning("-" * 80) logger.warning('-' * 80)
logger.warning(" This sample appears to be a .NET module.") logger.warning(' This sample appears to be a .NET module.')
logger.warning(" ") logger.warning(' ')
logger.warning(" .NET is a cross-platform framework for running managed applications.") logger.warning(' .NET is a cross-platform framework for running managed applications.')
logger.warning( logger.warning(
" Today, capa cannot handle non-native files. This means that the results may be misleading or incomplete.") ' Today, capa cannot handle non-native files. This means that the results may be misleading or incomplete.')
logger.warning(" You may have to analyze the file manually, using a tool like the .NET decompiler dnSpy.") logger.warning(' You may have to analyze the file manually, using a tool like the .NET decompiler dnSpy.')
logger.warning(" ") logger.warning(' ')
logger.warning(" Use -v or -vv if you really want to see the capabilities identified by capa.") logger.warning(' Use -v or -vv if you really want to see the capabilities identified by capa.')
logger.warning("-" * 80) logger.warning('-' * 80)
# capa won't detect much in .NET samples. # capa won't detect much in .NET samples.
# it might match some file-level things. # it might match some file-level things.
# for consistency, bail on things that we don't support. # for consistency, bail on things that we don't support.
@@ -693,16 +693,16 @@ def main(argv=None):
return -1 return -1
if appears_rule_cat(rules, capabilities, 'other-features/compiled-with-autoit'): if appears_rule_cat(rules, capabilities, 'other-features/compiled-with-autoit'):
logger.warning("-" * 80) logger.warning('-' * 80)
logger.warning(" This sample appears to be compiled with AutoIt.") logger.warning(' This sample appears to be compiled with AutoIt.')
logger.warning(" ") logger.warning(' ')
logger.warning(" AutoIt is a freeware BASIC-like scripting language designed for automating the Windows GUI.") logger.warning(' AutoIt is a freeware BASIC-like scripting language designed for automating the Windows GUI.')
logger.warning( logger.warning(
" Today, capa cannot handle AutoIt scripts. This means that the results will be misleading or incomplete.") ' Today, capa cannot handle AutoIt scripts. This means that the results will be misleading or incomplete.')
logger.warning(" You may have to analyze the file manually, using a tool like the AutoIt decompiler MyAut2Exe.") logger.warning(' You may have to analyze the file manually, using a tool like the AutoIt decompiler MyAut2Exe.')
logger.warning(" ") logger.warning(' ')
logger.warning(" Use -v or -vv if you really want to see the capabilities identified by capa.") logger.warning(' Use -v or -vv if you really want to see the capabilities identified by capa.')
logger.warning("-" * 80) logger.warning('-' * 80)
# capa will detect dozens of capabilities for AutoIt samples, # capa will detect dozens of capabilities for AutoIt samples,
# but these are due to the AutoIt runtime, not the payload script. # but these are due to the AutoIt runtime, not the payload script.
# so, don't confuse the user with FP matches - bail instead # so, don't confuse the user with FP matches - bail instead
@@ -712,13 +712,13 @@ def main(argv=None):
return -1 return -1
if appears_rule_cat(rules, capabilities, 'anti-analysis/packing/'): if appears_rule_cat(rules, capabilities, 'anti-analysis/packing/'):
logger.warning("-" * 80) logger.warning('-' * 80)
logger.warning(" This sample appears packed.") logger.warning(' This sample appears packed.')
logger.warning(" ") logger.warning(' ')
logger.warning(" Packed samples have often been obfuscated to hide their logic.") logger.warning(' Packed samples have often been obfuscated to hide their logic.')
logger.warning(" capa cannot handle obfuscation well. This means the results may be misleading or incomplete.") logger.warning(' capa cannot handle obfuscation well. This means the results may be misleading or incomplete.')
logger.warning(" If possible, you should try to unpack this input file before analyzing it with capa.") logger.warning(' If possible, you should try to unpack this input file before analyzing it with capa.')
logger.warning("-" * 80) logger.warning('-' * 80)
if args.vverbose: if args.vverbose:
render_capabilities_vverbose(capabilities) render_capabilities_vverbose(capabilities)
@@ -770,7 +770,7 @@ def is_runtime_ida():
return True return True
if __name__ == "__main__": if __name__ == '__main__':
if is_runtime_ida(): if is_runtime_ida():
ida_main() ida_main()
else: else:

View File

@@ -28,13 +28,13 @@ def main(argv=None):
] ]
format_help = ', '.join(['%s: %s' % (f[0], f[1]) for f in formats]) format_help = ', '.join(['%s: %s' % (f[0], f[1]) for f in formats])
parser = argparse.ArgumentParser(description="detect capabilities in programs.") parser = argparse.ArgumentParser(description='detect capabilities in programs.')
parser.add_argument("sample", type=str, parser.add_argument('sample', type=str,
help="Path to sample to analyze") help='Path to sample to analyze')
parser.add_argument("-f", "--format", choices=[f[0] for f in formats], default="auto", parser.add_argument('-f', '--format', choices=[f[0] for f in formats], default='auto',
help="Select sample format, %s" % format_help) help='Select sample format, %s' % format_help)
parser.add_argument("-F", "--function", type=lambda x: int(x, 0), parser.add_argument('-F', '--function', type=lambda x: int(x, 0),
help="Show features for specific function") help='Show features for specific function')
args = parser.parse_args(args=argv) args = parser.parse_args(args=argv)
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
@@ -77,5 +77,5 @@ def main(argv=None):
return 0 return 0
if __name__ == "__main__": if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@@ -26,7 +26,7 @@ def main():
fnames = {} fnames = {}
for f in idautils.Functions(): for f in idautils.Functions():
fname = idc.get_name(f) fname = idc.get_name(f)
if fname.startswith("sub_"): if fname.startswith('sub_'):
continue continue
name_demangled = idc.demangle_name(fname, INF_SHORT_DN_ATTR) name_demangled = idc.demangle_name(fname, INF_SHORT_DN_ATTR)
@@ -35,12 +35,12 @@ def main():
fnames[f] = fname fnames[f] = fname
with open(idc.ARGV[1], "w") as f: with open(idc.ARGV[1], 'w') as f:
json.dump(fnames, f) json.dump(fnames, f)
# exit IDA # exit IDA
idc.qexit(0) idc.qexit(0)
if __name__ == "__main__": if __name__ == '__main__':
main() main()

View File

@@ -40,5 +40,5 @@ def main():
idc.qexit(0) idc.qexit(0)
if __name__ == "__main__": if __name__ == '__main__':
main() main()

View File

@@ -66,15 +66,15 @@ def main(argv=None):
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]
parser = argparse.ArgumentParser(description="Freeze capa features of a file or of files in a directory") parser = argparse.ArgumentParser(description='Freeze capa features of a file or of files in a directory')
parser.add_argument("file_path", type=str, parser.add_argument('file_path', type=str,
help="Path to file or directory to analyze") help='Path to file or directory to analyze')
parser.add_argument("-r", "--reprocess", action="store_true", default=False, parser.add_argument('-r', '--reprocess', action='store_true', default=False,
help="Overwrite existing analysis") help='Overwrite existing analysis')
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument('-v', '--verbose', action='store_true',
help="Enable verbose output") help='Enable verbose output')
parser.add_argument("-q", "--quiet", action="store_true", parser.add_argument('-q', '--quiet', action='store_true',
help="Disable all output but errors") help='Disable all output but errors')
args = parser.parse_args(args=argv) args = parser.parse_args(args=argv)
if args.quiet: if args.quiet:
@@ -98,5 +98,5 @@ def main(argv=None):
return 0 return 0
if __name__ == "__main__": if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@@ -217,23 +217,23 @@ def main(argv=None):
if argv is None: if argv is None:
argv = sys.argv[1:] argv = sys.argv[1:]
parser = argparse.ArgumentParser(description="Run capa rule file against frozen features in a directory") parser = argparse.ArgumentParser(description='Run capa rule file against frozen features in a directory')
parser.add_argument("rules", type=str, parser.add_argument('rules', type=str,
help="Path to directory containing rules") help='Path to directory containing rules')
parser.add_argument("rule_name", type=str, parser.add_argument('rule_name', type=str,
help="Name of rule to test") help='Name of rule to test')
parser.add_argument("frozen_path", type=str, parser.add_argument('frozen_path', type=str,
help="Path to frozen feature file or directory") help='Path to frozen feature file or directory')
parser.add_argument("-f", "--fast", action="store_true", parser.add_argument('-f', '--fast', action='store_true',
help="Don't test slow files") help='Don't test slow files')
parser.add_argument("-o", "--only_matching", action="store_true", parser.add_argument('-o', '--only_matching', action='store_true',
help="Print only if rule matches") help='Print only if rule matches')
parser.add_argument("-s", "--save_image", action="store", parser.add_argument('-s', '--save_image', action='store',
help="Directory to save exported images of function graphs") help='Directory to save exported images of function graphs')
parser.add_argument("-v", "--verbose", action="count", default=0, parser.add_argument('-v', '--verbose', action='count', default=0,
help="Increase output verbosity") help='Increase output verbosity')
parser.add_argument("-q", "--quiet", action="store_true", parser.add_argument('-q', '--quiet', action='store_true',
help="Disable all output but errors") help='Disable all output but errors')
args = parser.parse_args(args=argv) args = parser.parse_args(args=argv)
if args.quiet: if args.quiet:
@@ -293,5 +293,5 @@ def main(argv=None):
print_summary(args.verbose, time0) print_summary(args.verbose, time0)
if __name__ == "__main__": if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@@ -85,13 +85,13 @@ def get_function_names(fnames_file):
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Launch IDA Pro in autonomous mode to dump function names of a file or of files in a directory") description='Launch IDA Pro in autonomous mode to dump function names of a file or of files in a directory')
parser.add_argument("file_path", type=str, parser.add_argument('file_path', type=str,
help="File or directory path to analyze") help='File or directory path to analyze')
parser.add_argument("-r", "--reprocess", action="store_true", default=False, parser.add_argument('-r', '--reprocess', action='store_true', default=False,
help="Overwrite existing analysis") help='Overwrite existing analysis')
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument('-v', '--verbose', action='store_true',
help="Enable verbose output") help='Enable verbose output')
args = parser.parse_args(args=sys.argv[1:]) args = parser.parse_args(args=sys.argv[1:])
if args.verbose: if args.verbose:
@@ -127,5 +127,5 @@ def main():
return 0 return 0
if __name__ == "__main__": if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@@ -101,17 +101,17 @@ def get_md5_hexdigest(sample_path):
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Launch IDA Pro in autonomous mode to export images of function graphs") description='Launch IDA Pro in autonomous mode to export images of function graphs')
parser.add_argument("file_path", type=str, parser.add_argument('file_path', type=str,
help="File to export from") help='File to export from')
parser.add_argument("out_dir", type=str, parser.add_argument('out_dir', type=str,
help="Export target directory") help='Export target directory')
parser.add_argument("-f", "--functions", action="store", parser.add_argument('-f', '--functions', action='store',
help="Comma separated list of functions to export") help='Comma separated list of functions to export')
parser.add_argument("-m", "--manual", action="store_true", parser.add_argument('-m', '--manual', action='store_true',
help="Manual mode: show IDA dialog boxes") help='Manual mode: show IDA dialog boxes')
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument('-v', '--verbose', action='store_true',
help="Enable verbose output") help='Enable verbose output')
args = parser.parse_args(args=sys.argv[1:]) args = parser.parse_args(args=sys.argv[1:])
if args.verbose: if args.verbose:
@@ -131,5 +131,5 @@ def main():
return 0 return 0
if __name__ == "__main__": if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@@ -5,26 +5,26 @@ import setuptools
requirements = [ requirements = [
"six", 'six',
"tqdm", 'tqdm',
"pyyaml", 'pyyaml',
"tabulate", 'tabulate',
] ]
if sys.version_info >= (3, 0): if sys.version_info >= (3, 0):
# py3 # py3
requirements.append("networkx") requirements.append('networkx')
else: else:
# py2 # py2
requirements.append("enum34") requirements.append('enum34')
requirements.append("vivisect") requirements.append('vivisect')
requirements.append("viv-utils") requirements.append('viv-utils')
requirements.append("networkx==2.2") # v2.2 is last version supported by Python 2.7 requirements.append('networkx==2.2') # v2.2 is last version supported by Python 2.7
# this sets __version__ # this sets __version__
# via: http://stackoverflow.com/a/7071358/87207 # via: http://stackoverflow.com/a/7071358/87207
# and: http://stackoverflow.com/a/2073599/87207 # and: http://stackoverflow.com/a/2073599/87207
with open(os.path.join("capa", "version.py"), "rb") as f: with open(os.path.join('capa', 'version.py'), 'rb') as f:
exec(f.read()) exec(f.read())
@@ -35,17 +35,17 @@ def get_rule_paths():
setuptools.setup( setuptools.setup(
name='capa', name='capa',
version=__version__, version=__version__,
description="", description='',
long_description="", long_description='',
author="Willi Ballenthin, Moritz Raabe", author='Willi Ballenthin, Moritz Raabe',
author_email='william.ballenthin@mandiant.com, moritz.raabe@mandiant.com', author_email='william.ballenthin@mandiant.com, moritz.raabe@mandiant.com',
url='https://www.github.com/fireeye/capa', url='https://www.github.com/fireeye/capa',
packages=setuptools.find_packages(exclude=['tests', 'testbed']), packages=setuptools.find_packages(exclude=['tests', 'testbed']),
package_dir={'capa': 'capa'}, package_dir={'capa': 'capa'},
package_data={'capa': get_rule_paths()}, package_data={'capa': get_rule_paths()},
entry_points={ entry_points={
"console_scripts": [ 'console_scripts': [
"capa=capa.main:main", 'capa=capa.main:main',
] ]
}, },
include_package_data=True, include_package_data=True,
@@ -56,7 +56,7 @@ setuptools.setup(
'Development Status :: 3 - Alpha', 'Development Status :: 3 - Alpha',
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'Natural Language :: English', 'Natural Language :: English',
"Programming Language :: Python :: 2", 'Programming Language :: Python :: 2',
"Programming Language :: Python :: 3", 'Programming Language :: Python :: 3',
], ],
) )

View File

@@ -159,12 +159,12 @@ def test_serialize_features():
def test_freeze_sample(tmpdir, sample_9324d1a8ae37a36ae560c37448c9705a): def test_freeze_sample(tmpdir, sample_9324d1a8ae37a36ae560c37448c9705a):
# tmpdir fixture handles cleanup # tmpdir fixture handles cleanup
o = tmpdir.mkdir("capa").join("test.frz").strpath o = tmpdir.mkdir('capa').join('test.frz').strpath
assert capa.features.freeze.main([sample_9324d1a8ae37a36ae560c37448c9705a.path, o, '-v']) == 0 assert capa.features.freeze.main([sample_9324d1a8ae37a36ae560c37448c9705a.path, o, '-v']) == 0
def test_freeze_load_sample(tmpdir, sample_9324d1a8ae37a36ae560c37448c9705a): def test_freeze_load_sample(tmpdir, sample_9324d1a8ae37a36ae560c37448c9705a):
o = tmpdir.mkdir("capa").join("test.frz") o = tmpdir.mkdir('capa').join('test.frz')
viv_extractor = capa.features.extractors.viv.VivisectFeatureExtractor(sample_9324d1a8ae37a36ae560c37448c9705a.vw, viv_extractor = capa.features.extractors.viv.VivisectFeatureExtractor(sample_9324d1a8ae37a36ae560c37448c9705a.vw,
sample_9324d1a8ae37a36ae560c37448c9705a.path) sample_9324d1a8ae37a36ae560c37448c9705a.path)
with open(o.strpath, 'wb') as f: with open(o.strpath, 'wb') as f:

View File

@@ -15,6 +15,21 @@ def test_main(sample_9324d1a8ae37a36ae560c37448c9705a):
assert capa.main.main([sample_9324d1a8ae37a36ae560c37448c9705a.path, '-v']) == 0 assert capa.main.main([sample_9324d1a8ae37a36ae560c37448c9705a.path, '-v']) == 0
def test_main_single_rule(sample_9324d1a8ae37a36ae560c37448c9705a, tmpdir):
# tests a single rule can be loaded successfully
RULE_CONTENT = textwrap.dedent('''
rule:
meta:
name: test rule
scope: file
features:
- string: test
''')
rule_file = tmpdir.mkdir('capa').join('rule.yml')
rule_file.write(RULE_CONTENT)
assert capa.main.main([sample_9324d1a8ae37a36ae560c37448c9705a.path, '-v', '-r', rule_file.strpath]) == 0
def test_main_shellcode(sample_499c2a85f6e8142c3f48d4251c9c7cd6_raw32): def test_main_shellcode(sample_499c2a85f6e8142c3f48d4251c9c7cd6_raw32):
assert capa.main.main([sample_499c2a85f6e8142c3f48d4251c9c7cd6_raw32.path, '-v', '-f', 'sc32']) == 0 assert capa.main.main([sample_499c2a85f6e8142c3f48d4251c9c7cd6_raw32.path, '-v', '-f', 'sc32']) == 0

View File

@@ -82,14 +82,14 @@ def test_string_features(mimikatz):
def test_byte_features(sample_9324d1a8ae37a36ae560c37448c9705a): def test_byte_features(sample_9324d1a8ae37a36ae560c37448c9705a):
features = extract_function_features(viv_utils.Function(sample_9324d1a8ae37a36ae560c37448c9705a.vw, 0x406F60)) features = extract_function_features(viv_utils.Function(sample_9324d1a8ae37a36ae560c37448c9705a.vw, 0x406F60))
wanted = capa.features.Bytes(b"\xED\x24\x9E\xF4\x52\xA9\x07\x47\x55\x8E\xE1\xAB\x30\x8E\x23\x61") wanted = capa.features.Bytes(b'\xED\x24\x9E\xF4\x52\xA9\x07\x47\x55\x8E\xE1\xAB\x30\x8E\x23\x61')
# use `==` rather than `is` because the result is not `True` but a truthy value. # use `==` rather than `is` because the result is not `True` but a truthy value.
assert wanted.evaluate(features) == True assert wanted.evaluate(features) == True
def test_byte_features64(sample_lab21_01): def test_byte_features64(sample_lab21_01):
features = extract_function_features(viv_utils.Function(sample_lab21_01.vw, 0x1400010C0)) features = extract_function_features(viv_utils.Function(sample_lab21_01.vw, 0x1400010C0))
wanted = capa.features.Bytes(b"\x32\xA2\xDF\x2D\x99\x2B\x00\x00") wanted = capa.features.Bytes(b'\x32\xA2\xDF\x2D\x99\x2B\x00\x00')
# use `==` rather than `is` because the result is not `True` but a truthy value. # use `==` rather than `is` because the result is not `True` but a truthy value.
assert wanted.evaluate(features) == True assert wanted.evaluate(features) == True