mirror of
https://github.com/mandiant/capa.git
synced 2025-12-12 15:49:46 -08:00
explorer: improve rules error messaging and documentation (#1249)
This commit is contained in:
@@ -75,6 +75,7 @@
|
||||
- fix: accept only plaintext pasted content #1194 @williballenthin
|
||||
- fix: UnboundLocalError #1217 @williballenthin
|
||||
- extractor: add support for COFF files and extern functions #1223 @mike-hunhoff
|
||||
- doc: improve error messaging and documentation related to capa rule set #1249 @mike-hunhoff
|
||||
- fix: assume 32-bit displacement for offsets #1250 @mike-hunhoff
|
||||
|
||||
### Development
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||

|
||||
|
||||
capa explorer is an IDAPython plugin that integrates the FLARE team's open-source framework, capa, with IDA Pro. capa is a framework that uses a well-defined collection of rules to
|
||||
identify capabilities in a program. You can run capa against a PE file or shellcode and it tells you what it thinks the program can do. For example, it might suggest that
|
||||
the program is a backdoor, can install services, or relies on HTTP to communicate. capa explorer runs capa directly against your IDA Pro database (IDB) without requiring access
|
||||
identify capabilities in a program. You can run capa against a PE file, ELF file, or shellcode and it tells you what it thinks the program can do. For example, it might suggest that
|
||||
the program is a backdoor, can install services, or relies on HTTP to communicate. capa explorer runs capa analysis on your IDA Pro database (IDB) without needing access
|
||||
to the original binary file. Once a database has been analyzed, capa explorer helps you identify interesting areas of a program and build new capa rules using features extracted from your IDB.
|
||||
|
||||
We love using capa explorer during malware analysis because it teaches us what parts of a program suggest a behavior. As we click on rows, capa explorer jumps directly
|
||||
@@ -21,10 +21,10 @@ We can use capa explorer to navigate our Disassembly view directly to the suspec
|
||||
Using the `Rule Information` and `Details` columns capa explorer shows us that the suspect function matched `self delete via COMSPEC environment variable` because it contains capa rule matches for `create process`, `get COMSPEC environment variable`,
|
||||
and `query environment variable`, references to the strings `COMSPEC`, ` > nul`, and `/c del `, and calls to the Windows API functions `GetEnvironmentVariableA` and `ShellExecuteEx`.
|
||||
|
||||
capa explorer also helps you build new capa rules. To start select the `Rule Generator` tab, navigate to a function in your Disassembly view,
|
||||
capa explorer also helps you build and test new capa rules. To start, select the `Rule Generator` tab, navigate to a function in your Disassembly view,
|
||||
and click `Analyze`. capa explorer will extract features from the function and display them in the `Features` pane. You can add features listed in this pane to the `Editor` pane
|
||||
by either double-clicking a feature or using multi-select + right-click to add multiple features at once. The `Preview` and `Editor` panes help edit your rule. Use the `Preview` pane
|
||||
to modify the rule text directly and the `Editor` pane to construct and rearrange your hierarchy of statements and features. When you finish a rule you can save it directly to a file by clicking `Save`.
|
||||
to modify rule text directly and the `Editor` pane to construct and rearrange your hierarchy of statements and features. When you finish a rule you can save it directly to a file by clicking `Save`.
|
||||
|
||||

|
||||
|
||||
@@ -36,11 +36,15 @@ For more information on the FLARE team's open-source framework, capa, check out
|
||||
|
||||
You can install capa explorer using the following steps:
|
||||
|
||||
1. Install capa and its dependencies from PyPI for the Python interpreter used by your IDA installation:
|
||||
1. Install capa and its dependencies from PyPI using the Python interpreter configured for your IDA installation:
|
||||
```
|
||||
$ pip install flare-capa
|
||||
```
|
||||
2. Download the [standard collection of capa rules](https://github.com/mandiant/capa-rules) (capa explorer needs capa rules to analyze a database)
|
||||
2. Download and extract the [official capa rules](https://github.com/mandiant/capa-rules/releases) that match the version of capa you have installed
|
||||
1. Use the following command to view the version of capa you have installed:
|
||||
```commandline
|
||||
$ pip show flare-capa
|
||||
```
|
||||
3. Copy [capa_explorer.py](https://raw.githubusercontent.com/mandiant/capa/master/capa/ida/plugin/capa_explorer.py) to your IDA plugins directory
|
||||
|
||||
### Supported File Types
|
||||
@@ -59,15 +63,15 @@ capa explorer is limited to the file types supported by capa, which include:
|
||||
3. Select the `Program Analysis` tab
|
||||
4. Click the `Analyze` button
|
||||
|
||||
When running capa explorer for the first time you are prompted to select a file directory containing capa rules. The plugin conveniently
|
||||
remembers your selection for future runs; you can change this selection and other default settings by clicking `Settings`. We recommend
|
||||
downloading and using the [standard collection of capa rules](https://github.com/mandiant/capa-rules) when getting started with the plugin.
|
||||
The first time you run capa explorer you will be asked to specify a local directory containing capa rules to use for analysis. We recommend downloading and extracting the [official capa rules](https://github.com/mandiant/capa-rules/releases) that match
|
||||
the version of capa you have installed (see installation instructions above for more details). capa explorer remembers your selection for future analysis which you
|
||||
can update using the `Settings` button.
|
||||
|
||||
#### Tips for Program Analysis
|
||||
|
||||
* Start analysis by clicking the `Analyze` button
|
||||
* Reset the plugin user interface and remove highlighting from your Disassembly view by clicking the `Reset` button
|
||||
* Change your capa rules directory and other default settings by clicking `Settings`
|
||||
* Change your local capa rules directory and other default settings by clicking the `Settings` button
|
||||
* Hover your cursor over a rule match to view the source content of the rule
|
||||
* Double-click the `Address` column to navigate your Disassembly view to the address of the associated feature
|
||||
* Double-click a result in the `Rule Information` column to expand its children
|
||||
|
||||
@@ -49,6 +49,11 @@ CAPA_SETTINGS_RULE_PATH = "rule_path"
|
||||
CAPA_SETTINGS_RULEGEN_AUTHOR = "rulegen_author"
|
||||
CAPA_SETTINGS_RULEGEN_SCOPE = "rulegen_scope"
|
||||
|
||||
|
||||
CAPA_OFFICIAL_RULESET_URL = f"https://github.com/mandiant/capa-rules/releases/tag/v{capa.version.__version__}"
|
||||
CAPA_RULESET_DOC_URL = "https://github.com/mandiant/capa/blob/master/doc/rules.md"
|
||||
|
||||
|
||||
from enum import IntFlag
|
||||
|
||||
|
||||
@@ -214,6 +219,12 @@ class CapaSettingsInputDialog(QtWidgets.QDialog):
|
||||
self.edit_rule_path = QLineEditClicked(settings.user.get(CAPA_SETTINGS_RULE_PATH, ""))
|
||||
self.edit_rule_author = QtWidgets.QLineEdit(settings.user.get(CAPA_SETTINGS_RULEGEN_AUTHOR, ""))
|
||||
self.edit_rule_scope = QtWidgets.QComboBox()
|
||||
self.edit_rules_link = QtWidgets.QLabel()
|
||||
|
||||
self.edit_rules_link.setText(
|
||||
f'<a href="{CAPA_OFFICIAL_RULESET_URL}">Download and extract official capa rules</a>'
|
||||
)
|
||||
self.edit_rules_link.setOpenExternalLinks(True)
|
||||
|
||||
scopes = ("file", "function", "basic block")
|
||||
|
||||
@@ -223,7 +234,8 @@ class CapaSettingsInputDialog(QtWidgets.QDialog):
|
||||
buttons = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel, self)
|
||||
|
||||
layout = QtWidgets.QFormLayout(self)
|
||||
layout.addRow("capa rules path", self.edit_rule_path)
|
||||
layout.addRow("capa rules", self.edit_rule_path)
|
||||
layout.addRow("", self.edit_rules_link)
|
||||
layout.addRow("Default rule author", self.edit_rule_author)
|
||||
layout.addRow("Default rule scope", self.edit_rule_scope)
|
||||
|
||||
@@ -614,7 +626,7 @@ class CapaExplorerForm(idaapi.PluginForm):
|
||||
"""
|
||||
if post:
|
||||
if idaapi.get_imagebase() != meta.get("prev_base", -1):
|
||||
capa.ida.helpers.inform_user_ida_ui("Running capa analysis again after program rebase")
|
||||
capa.ida.helpers.inform_user_ida_ui("Running capa analysis using new program base")
|
||||
self.slot_analyze()
|
||||
else:
|
||||
meta["prev_base"] = idaapi.get_imagebase()
|
||||
@@ -629,15 +641,36 @@ class CapaExplorerForm(idaapi.PluginForm):
|
||||
try:
|
||||
# resolve rules directory - check self and settings first, then ask user
|
||||
if not os.path.exists(settings.user.get(CAPA_SETTINGS_RULE_PATH, "")):
|
||||
idaapi.info("Please select a file directory containing capa rules.")
|
||||
# configure rules selection messagebox
|
||||
rules_message = QtWidgets.QMessageBox()
|
||||
rules_message.setIcon(QtWidgets.QMessageBox.Information)
|
||||
rules_message.setWindowTitle("capa explorer")
|
||||
rules_message.setText("You must specify a directory containing capa rules before running analysis.")
|
||||
rules_message.setInformativeText(
|
||||
"Click 'Ok' to specify a local directory of rules or you can download and extract the official "
|
||||
f"rules from the URL listed in the details."
|
||||
)
|
||||
rules_message.setDetailedText(f"{CAPA_OFFICIAL_RULESET_URL}")
|
||||
rules_message.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
||||
|
||||
# display rules selection messagebox, check user button selection
|
||||
pressed = rules_message.exec_()
|
||||
if pressed == QtWidgets.QMessageBox.Cancel:
|
||||
raise UserCancelledError()
|
||||
|
||||
path = self.ask_user_directory()
|
||||
if not path:
|
||||
logger.warning(
|
||||
"You must select a file directory containing capa rules before analysis can be run. The standard collection of capa rules can be downloaded from https://github.com/mandiant/capa-rules."
|
||||
)
|
||||
return False
|
||||
raise UserCancelledError()
|
||||
|
||||
settings.user[CAPA_SETTINGS_RULE_PATH] = path
|
||||
except UserCancelledError as e:
|
||||
capa.ida.helpers.inform_user_ida_ui("Analysis requires capa rules")
|
||||
logger.warning(
|
||||
f"You must specify a directory containing capa rules before running analysis. Download and extract the official rules from {CAPA_OFFICIAL_RULESET_URL} (recommended)."
|
||||
)
|
||||
return False
|
||||
except Exception as e:
|
||||
capa.ida.helpers.inform_user_ida_ui("Failed to load capa rules")
|
||||
logger.error("Failed to load capa rules (error: %s).", e)
|
||||
return False
|
||||
|
||||
@@ -700,19 +733,16 @@ class CapaExplorerForm(idaapi.PluginForm):
|
||||
capa.ida.helpers.inform_user_ida_ui(
|
||||
"Failed to load capa rules from %s" % settings.user[CAPA_SETTINGS_RULE_PATH]
|
||||
)
|
||||
logger.error("Failed to load rules from %s (error: %s).", settings.user[CAPA_SETTINGS_RULE_PATH], e)
|
||||
|
||||
logger.error("Failed to load capa rules from %s (error: %s).", settings.user[CAPA_SETTINGS_RULE_PATH], e)
|
||||
logger.error(
|
||||
"Make sure your file directory contains properly formatted capa rules. You can download the standard "
|
||||
"collection of capa rules from https://github.com/mandiant/capa-rules/releases."
|
||||
)
|
||||
logger.error(
|
||||
"Please ensure you're using the rules that correspond to your major version of capa (%s)",
|
||||
capa.version.get_major_version(),
|
||||
)
|
||||
logger.error(
|
||||
"Or, for more details, see the rule set documentation here: %s",
|
||||
"https://github.com/mandiant/capa/blob/master/doc/rules.md",
|
||||
"Make sure your file directory contains properly "
|
||||
"formatted capa rules. You can download and extract the official rules from %s. "
|
||||
"Or, for more details, see the rules documentation here: %s",
|
||||
CAPA_OFFICIAL_RULESET_URL,
|
||||
CAPA_RULESET_DOC_URL,
|
||||
)
|
||||
|
||||
settings.user[CAPA_SETTINGS_RULE_PATH] = ""
|
||||
return False
|
||||
|
||||
@@ -831,7 +861,7 @@ class CapaExplorerForm(idaapi.PluginForm):
|
||||
|
||||
self.model_data.render_capa_doc(self.doc, self.view_show_results_by_function.isChecked())
|
||||
self.set_view_status_label(
|
||||
"capa rules directory: %s (%d rules)" % (settings.user[CAPA_SETTINGS_RULE_PATH], len(self.rules_cache))
|
||||
"capa rules: %s (%d rules)" % (settings.user[CAPA_SETTINGS_RULE_PATH], len(self.rules_cache))
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error("Failed to render results (error: %s)", e, exc_info=True)
|
||||
@@ -876,7 +906,7 @@ class CapaExplorerForm(idaapi.PluginForm):
|
||||
if not self.load_capa_rules():
|
||||
return False
|
||||
else:
|
||||
logger.info('Using cached ruleset, click "Reset" to reload rules from disk.')
|
||||
logger.info('Using cached capa rules, click "Reset" to load rules from disk.')
|
||||
|
||||
assert self.rules_cache is not None
|
||||
assert self.ruleset_cache is not None
|
||||
@@ -1034,7 +1064,7 @@ class CapaExplorerForm(idaapi.PluginForm):
|
||||
self.view_rulegen_status_label.clear()
|
||||
|
||||
if not is_analyze:
|
||||
# clear rules and ruleset cache only if user clicked "Reset"
|
||||
# clear rules and rule set cache only if user clicked "Reset"
|
||||
self.rules_cache = None
|
||||
self.ruleset_cache = None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user