diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index b3c57cc2..bed2512d 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -21,6 +21,7 @@ jobs: git config user.name 'Capa Bot' name=${{ github.event.release.tag_name }} git tag $name -m "https://github.com/mandiant/capa/releases/$name" + # TODO update branch name-major=${name%%.*} - name: Push tag to capa-rules uses: ad-m/github-push-action@master with: diff --git a/CHANGELOG.md b/CHANGELOG.md index ee64ea84..8c0c90d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - add mixed mode characteristic feature extraction for dotnet files #1024 @mike-hunhoff - emit class and namespace features for dotnet files #1030 @mike-hunhoff - render: support Addresses that aren't simple integers, like .NET token+offset #981 @williballenthin + - document rule tags and branches #1006 @williballenthin, @mr-tz ### Breaking Changes diff --git a/capa/ida/plugin/form.py b/capa/ida/plugin/form.py index 956a623e..75b1a5c1 100644 --- a/capa/ida/plugin/form.py +++ b/capa/ida/plugin/form.py @@ -704,6 +704,18 @@ class CapaExplorerForm(idaapi.PluginForm): 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." ) + 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( + "You can check out these rules with the following command:\n %s", + capa.version.get_rules_checkout_command(), + ) + logger.error( + "Or, for more details, see the rule set documentation here: %s", + "https://github.com/mandiant/capa/blob/master/doc/rules.md", + ) settings.user[CAPA_SETTINGS_RULE_PATH] = "" return False diff --git a/capa/main.py b/capa/main.py index 3ce5b3db..2fded828 100644 --- a/capa/main.py +++ b/capa/main.py @@ -1029,6 +1029,18 @@ def main(argv=None): logger.debug(" %d. %s", i, r) except (IOError, capa.rules.InvalidRule, capa.rules.InvalidRuleSet) as e: logger.error("%s", str(e)) + 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( + "You can check out these rules with the following command:\n %s", + capa.version.get_rules_checkout_command(), + ) + logger.error( + "Or, for more details, see the rule set documentation here: %s", + "https://github.com/mandiant/capa/blob/master/doc/rules.md", + ) return E_INVALID_RULE # file feature extractors are pretty lightweight: they don't do any code analysis. diff --git a/capa/version.py b/capa/version.py index 11731085..0231e179 100644 --- a/capa/version.py +++ b/capa/version.py @@ -1 +1,13 @@ __version__ = "3.2.0" + + +def get_major_version(): + return int(__version__.partition(".")[0]) + + +def get_rules_branch(): + return f"v{get_major_version()}" + + +def get_rules_checkout_command(): + return f"$ git clone https://github.com/mandiant/capa-rules.git -b {get_rules_branch()} /local/path/to/rules" diff --git a/doc/installation.md b/doc/installation.md index 87b08b1d..0e455c10 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -26,7 +26,13 @@ To install capa as a Python library use `pip` to fetch the `flare-capa` module. #### *Note*: This method is appropriate for integrating capa in an existing project. -This technique doesn't pull the default rule set, so you should check it out separately from [capa-rules](https://github.com/mandiant/capa-rules/) and pass the directory to the entrypoint using `-r` or set the rules path in the IDA Pro plugin. +This technique doesn't pull the default rule set, so you should check it out separately from [capa-rules](https://github.com/mandiant/capa-rules/) and pass the directory to the entrypoint using `-r` or set the rules path in the IDA Pro plugin: + +```console +$ git clone https://github.com/mandiant/capa-rules.git -b v3 /local/path/to/rules +$ capa -r /local/path/to/rules suspicious.exe +``` + This technique also doesn't set up the default library identification [signatures](https://github.com/mandiant/capa/tree/master/sigs). You can pass the signature directory using the `-s` argument. For example, to run capa with both a rule path and a signature path: diff --git a/doc/release.md b/doc/release.md index e527a3b5..cd26fd84 100644 --- a/doc/release.md +++ b/doc/release.md @@ -38,6 +38,12 @@ - [ ] Create a PR with the updated [CHANGELOG.md](https://github.com/mandiant/capa/blob/master/CHANGELOG.md) and [capa/version.py](https://github.com/mandiant/capa/blob/master/capa/version.py). Copy this checklist in the PR description. - [ ] After PR review, merge the PR and [create the release in GH](https://github.com/mandiant/capa/releases/new) using text from the [CHANGELOG.md](https://github.com/mandiant/capa/blob/master/CHANGELOG.md). - [ ] Verify GH actions [upload artifacts](https://github.com/mandiant/capa/releases), [publish to PyPI](https://pypi.org/project/flare-capa) and [create a tag in capa rules](https://github.com/mandiant/capa-rules/tags) upon completion. +- [ ] Manually update capa rules major version rule branch + ```commandline + [capa/rules] $ git pull master + [capa/rules] $ git checkout v3 # create if new major version: git checkout -b vX + [capa/rules] $ git merge master + [capa/rules] $ git push origin v3 + ``` - [ ] [Spread the word](https://twitter.com) - [ ] Update internal service - diff --git a/doc/rules.md b/doc/rules.md new file mode 100644 index 00000000..be68e00b --- /dev/null +++ b/doc/rules.md @@ -0,0 +1,72 @@ +### rules + + +capa uses a collection of rules to identify capabilities within a program. +The [github.com/mandiant/capa-rules](https://github.com/mandiant/capa-rules) repository contains hundreds of standard library rules that are distributed with capa. + +When you download a standalone version of capa, this standard library is embedded within the executable and capa will use these rules by default: + +```console +$ capa suspicious.exe +``` + +However, you may want to modify the rules for a variety of reasons: + + - develop new rules to find behaviors, and/or + - tweak existing rules to reduce false positives, and/or + - collect a private selection of rules not shared publicly. + +Or, you may want to use capa as a Python library within another application. + +In these scenarios, you must provide the rule set to capa as a directory on your file system. Do this using the `-r`/`--rules` parameter: + +```console +$ capa --rules /local/path/to/rules suspicious.exe +``` + +You can collect the standard set of rules in two ways: + + - [download from the Github releases page](#download-release-archive), or + - [clone from Github](#clone-with-git). + +Note that you must use match the rules major version with the capa major version, +i.e., use `v1` rules with `v1` of capa. +This is so that new versions of capa can update rule syntax, such as by adding new fields and logic. + +Otherwise, using rules with a mismatched version of capa may lead to errors like: + +``` +$ capa --rules /path/to/mismatched/rules suspicious.exe +ERROR:lint:invalid rule: injection.yml: invalid rule: unexpected statement: instruction +``` + +You can check the version of capa you're currently using like this: + +```console +$ capa --version +capa 3.0.3 +``` + +#### download release archive + +The releases page is [here](https://github.com/mandiant/capa-rules/tags/). +Find the most recent release corresponding to your major version of capa and download the ZIP archive. +Here are some quick links: + - v1: [v1](https://github.com/mandiant/capa-rules/releases/tag/v1) + - v2: [v2](https://github.com/mandiant/capa-rules/releases/tag/v2) + - v3: [v3](https://github.com/mandiant/capa-rules/releases/tag/v3) + +#### clone with git + +To fetch with git, clone the appropriate branch like this: + +```console +$ git clone https://github.com/mandiant/capa-rules.git -b v3 /local/path/to/rules +``` + +Note that the branch name (`v3` in the example above) must match the major version of capa you're using. + + - [v1](https://github.com/mandiant/capa-rules/tree/v1): `v1` + - [v2](https://github.com/mandiant/capa-rules/tree/v2): `v2` + - [v3](https://github.com/mandiant/capa-rules/tree/v3): `v3` +