explorer: improve rules error messaging and documentation (#1249)

This commit is contained in:
Mike Hunhoff
2023-01-03 09:09:05 -07:00
committed by GitHub
parent c959506ae9
commit 90591811df
3 changed files with 66 additions and 31 deletions

View File

@@ -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

View File

@@ -1,8 +1,8 @@
![capa explorer](../../../.github/capa-explorer-logo.png)
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`.
![](../../../doc/img/rulegen_expanded.png)
@@ -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

View File

@@ -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