mirror of
https://github.com/mandiant/capa.git
synced 2026-01-02 16:00:17 -08:00
Merge branch 'master' into vverbose-output-scope-enhancement
This commit is contained in:
@@ -1,6 +1,36 @@
|
||||
import logging
|
||||
|
||||
import idaapi
|
||||
import idc
|
||||
|
||||
logger = logging.getLogger('capa')
|
||||
|
||||
# file type names as returned by idaapi.get_file_type_name()
|
||||
SUPPORTED_FILE_TYPES = [
|
||||
'Portable executable for 80386 (PE)',
|
||||
'Portable executable for AMD64 (PE)',
|
||||
'Binary file' # x86/AMD64 shellcode support
|
||||
]
|
||||
|
||||
|
||||
def inform_user_ida_ui(message):
|
||||
idaapi.info('%s. Please refer to IDA Output window for more information.' % message)
|
||||
|
||||
|
||||
def is_supported_file_type():
|
||||
file_type = idaapi.get_file_type_name()
|
||||
if file_type not in SUPPORTED_FILE_TYPES:
|
||||
logger.error('-' * 80)
|
||||
logger.error(' Input file does not appear to be a PE file.')
|
||||
logger.error(' ')
|
||||
logger.error(
|
||||
' capa currently only supports analyzing PE files (or binary files containing x86/AMD64 shellcode) with IDA.')
|
||||
logger.error(' If you don\'t know the input file type, you can try using the `file` utility to guess it.')
|
||||
logger.error('-' * 80)
|
||||
inform_user_ida_ui('capa does not support the format of this file')
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_disasm_line(va):
|
||||
''' '''
|
||||
|
||||
@@ -26,16 +26,15 @@ import idaapi
|
||||
import capa.main
|
||||
import capa.rules
|
||||
import capa.features.extractors.ida
|
||||
import capa.ida.helpers
|
||||
|
||||
from capa.ida.explorer.view import CapaExplorerQtreeView
|
||||
from capa.ida.explorer.model import CapaExplorerDataModel
|
||||
from capa.ida.explorer.proxy import CapaExplorerSortFilterProxyModel
|
||||
|
||||
PLUGIN_NAME = 'capa explorer'
|
||||
|
||||
PLUGIN_NAME = 'capaex'
|
||||
|
||||
|
||||
logger = logging.getLogger(PLUGIN_NAME)
|
||||
logger = logging.getLogger('capa')
|
||||
|
||||
|
||||
class CapaExplorerIdaHooks(idaapi.UI_Hooks):
|
||||
@@ -326,12 +325,31 @@ class CapaExplorerForm(idaapi.PluginForm):
|
||||
rules_path = os.path.join(os.path.dirname(self._file_loc), '../..', 'rules')
|
||||
rules = capa.main.get_rules(rules_path)
|
||||
rules = capa.rules.RuleSet(rules)
|
||||
results = capa.main.find_capabilities(rules, capa.features.extractors.ida.IdaFeatureExtractor(), True)
|
||||
capabilities = capa.main.find_capabilities(rules, capa.features.extractors.ida.IdaFeatureExtractor(), True)
|
||||
|
||||
# support binary files specifically for x86/AMD64 shellcode
|
||||
# warn user binary file is loaded but still allow capa to process it
|
||||
# TODO: check specific architecture of binary files based on how user configured IDA processors
|
||||
if idaapi.get_file_type_name() == 'Binary file':
|
||||
logger.warning('-' * 80)
|
||||
logger.warning(' Input file appears to be a binary file.')
|
||||
logger.warning(' ')
|
||||
logger.warning(
|
||||
' capa currently only supports analyzing binary files containing x86/AMD64 shellcode with IDA.')
|
||||
logger.warning(
|
||||
' This means the results may be misleading or incomplete if the binary file loaded in IDA is not x86/AMD64.')
|
||||
logger.warning(' If you don\'t know the input file type, you can try using the `file` utility to guess it.')
|
||||
logger.warning('-' * 80)
|
||||
|
||||
capa.ida.helpers.inform_user_ida_ui('capa encountered warnings during analysis')
|
||||
|
||||
if capa.main.is_file_limitation(rules, capabilities, is_standalone=False):
|
||||
capa.ida.helpers.inform_user_ida_ui('capa encountered warnings during analysis')
|
||||
|
||||
logger.info('analysis completed.')
|
||||
|
||||
self._model_data.render_capa_results(rules, results)
|
||||
self._render_capa_summary(rules, results)
|
||||
self._model_data.render_capa_results(rules, capabilities)
|
||||
self._render_capa_summary(rules, capabilities)
|
||||
|
||||
logger.info('render views completed.')
|
||||
|
||||
@@ -441,6 +459,9 @@ def main():
|
||||
''' TODO: move to idaapi.plugin_t class '''
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
if not capa.ida.helpers.is_supported_file_type():
|
||||
return -1
|
||||
|
||||
global CAPA_EXPLORER_FORM
|
||||
|
||||
try:
|
||||
|
||||
124
capa/main.py
124
capa/main.py
@@ -409,6 +409,60 @@ def appears_rule_cat(rules, capabilities, rule_cat):
|
||||
return False
|
||||
|
||||
|
||||
def is_file_limitation(rules, capabilities, is_standalone=True):
|
||||
file_limitations = {
|
||||
# capa will likely detect installer specific functionality.
|
||||
# this is probably not what the user wants.
|
||||
'other-features/installer/': [
|
||||
' This sample appears to be an installer.',
|
||||
' ',
|
||||
' capa cannot handle installers well. This means the results may be misleading or incomplete.'
|
||||
' You should try to understand the install mechanism and analyze created files with capa.'
|
||||
],
|
||||
# capa won't detect much in .NET samples.
|
||||
# it might match some file-level things.
|
||||
# for consistency, bail on things that we don't support.
|
||||
'other-features/compiled-to-dot-net': [
|
||||
' This sample appears to be a .NET module.',
|
||||
' ',
|
||||
' .NET is a cross-platform framework for running managed applications.',
|
||||
' capa cannot handle non-native files. This means that the results may be misleading or incomplete.',
|
||||
' You may have to analyze the file manually, using a tool like the .NET decompiler dnSpy.'
|
||||
],
|
||||
# capa will detect dozens of capabilities for AutoIt samples,
|
||||
# but these are due to the AutoIt runtime, not the payload script.
|
||||
# so, don't confuse the user with FP matches - bail instead
|
||||
'other-features/compiled-with-autoit': [
|
||||
' This sample appears to be compiled with AutoIt.',
|
||||
' ',
|
||||
' AutoIt is a freeware BASIC-like scripting language designed for automating the Windows GUI.',
|
||||
' capa cannot handle AutoIt scripts. This means that the results will be misleading or incomplete.',
|
||||
' You may have to analyze the file manually, using a tool like the AutoIt decompiler MyAut2Exe.'
|
||||
],
|
||||
# capa won't detect much in packed samples
|
||||
'anti-analysis/packing/': [
|
||||
' This sample appears to be packed.',
|
||||
' ',
|
||||
' Packed samples have often been obfuscated to hide their logic.',
|
||||
' capa cannot handle obfuscation well. This means the results may be misleading or incomplete.',
|
||||
' If possible, you should try to unpack this input file before analyzing it with capa.'
|
||||
]
|
||||
}
|
||||
|
||||
for category, dialogue in file_limitations.items():
|
||||
if not appears_rule_cat(rules, capabilities, category):
|
||||
continue
|
||||
logger.warning('-' * 80)
|
||||
for line in dialogue:
|
||||
logger.warning(line)
|
||||
if is_standalone:
|
||||
logger.warning(' ')
|
||||
logger.warning(' Use -v or -vv if you really want to see the capabilities identified by capa.')
|
||||
logger.warning('-' * 80)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_supported_file_type(sample):
|
||||
'''
|
||||
Return if this is a supported file based on magic header values
|
||||
@@ -662,70 +716,12 @@ def main(argv=None):
|
||||
|
||||
capabilities = find_capabilities(rules, extractor)
|
||||
|
||||
if appears_rule_cat(rules, capabilities, 'other-features/installer/'):
|
||||
logger.warning('-' * 80)
|
||||
logger.warning(' This sample appears to be an installer.')
|
||||
logger.warning(' ')
|
||||
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(' ')
|
||||
logger.warning(' Use -v or -vv if you really want to see the capabilities identified by capa.')
|
||||
logger.warning('-' * 80)
|
||||
# capa will likely detect installer specific functionality.
|
||||
# this is probably not what the user wants.
|
||||
#
|
||||
if is_file_limitation(rules, capabilities):
|
||||
# bail if capa encountered file limitation e.g. a packed binary
|
||||
# do show the output in verbose mode, though.
|
||||
if not (args.verbose or args.vverbose):
|
||||
return -1
|
||||
|
||||
if appears_rule_cat(rules, capabilities, 'other-features/compiled-to-dot-net'):
|
||||
logger.warning('-' * 80)
|
||||
logger.warning(' This sample appears to be a .NET module.')
|
||||
logger.warning(' ')
|
||||
logger.warning(' .NET is a cross-platform framework for running managed applications.')
|
||||
logger.warning(
|
||||
' 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(' ')
|
||||
logger.warning(' Use -v or -vv if you really want to see the capabilities identified by capa.')
|
||||
logger.warning('-' * 80)
|
||||
|
||||
# capa won't detect much in .NET samples.
|
||||
# it might match some file-level things.
|
||||
# for consistency, bail on things that we don't support.
|
||||
#
|
||||
# do show the output in verbose mode, though.
|
||||
if not (args.verbose or args.vverbose):
|
||||
return -1
|
||||
|
||||
if appears_rule_cat(rules, capabilities, 'other-features/compiled-with-autoit'):
|
||||
logger.warning('-' * 80)
|
||||
logger.warning(' This sample appears to be compiled with AutoIt.')
|
||||
logger.warning(' ')
|
||||
logger.warning(' AutoIt is a freeware BASIC-like scripting language designed for automating the Windows GUI.')
|
||||
logger.warning(
|
||||
' 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(' ')
|
||||
logger.warning(' Use -v or -vv if you really want to see the capabilities identified by capa.')
|
||||
logger.warning('-' * 80)
|
||||
# capa will detect dozens of capabilities for AutoIt samples,
|
||||
# but these are due to the AutoIt runtime, not the payload script.
|
||||
# so, don't confuse the user with FP matches - bail instead
|
||||
#
|
||||
# do show the output in verbose mode, though.
|
||||
if not (args.verbose or args.vverbose):
|
||||
return -1
|
||||
|
||||
if appears_rule_cat(rules, capabilities, 'anti-analysis/packing/'):
|
||||
logger.warning('-' * 80)
|
||||
logger.warning(' This sample appears packed.')
|
||||
logger.warning(' ')
|
||||
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(' If possible, you should try to unpack this input file before analyzing it with capa.')
|
||||
logger.warning('-' * 80)
|
||||
|
||||
if args.vverbose:
|
||||
render_capabilities_vverbose(rules, capabilities)
|
||||
elif args.verbose:
|
||||
@@ -742,6 +738,10 @@ def ida_main():
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logging.getLogger().setLevel(logging.INFO)
|
||||
|
||||
import capa.ida.helpers
|
||||
if not capa.ida.helpers.is_supported_file_type():
|
||||
return -1
|
||||
|
||||
logger.info('-' * 80)
|
||||
logger.info(' Using default embedded rules.')
|
||||
logger.info(' ')
|
||||
@@ -764,6 +764,10 @@ def ida_main():
|
||||
|
||||
import capa.features.extractors.ida
|
||||
capabilities = find_capabilities(rules, capa.features.extractors.ida.IdaFeatureExtractor())
|
||||
|
||||
if is_file_limitation(rules, capabilities, is_standalone=False):
|
||||
capa.ida.helpers.inform_user_ida_ui('capa encountered warnings during analysis')
|
||||
|
||||
render_capabilities_default(rules, capabilities)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user