From afe5dba92ae42b6ef663240817b39df603ec38f6 Mon Sep 17 00:00:00 2001 From: Moritz Raabe Date: Tue, 30 Jun 2020 22:11:57 +0200 Subject: [PATCH 1/2] document signed vs unsigned --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b1883c18..af597b04 100644 --- a/README.md +++ b/README.md @@ -348,7 +348,8 @@ Examples: number: 0x10 number: 0x40 = PAGE_EXECUTE_READWRITE -TODO: signed vs unsigned. +Note that capa treats all numbers as unsigned values. A negative number is not a valid feature value. +To match a negative number you may specify its two's complement representation. For example, `0xFFFFFFF0` (`-2`) in a 32-bit file. ### string A string referenced by the logic of the program. @@ -402,6 +403,8 @@ Examples: offset: 0xC offset: 0x14 +Note that capa treats all offsets as unsigned values. A negative number is not a valid feature value. + ### mnemonic An instruction mnemonic found in the given function. From 5cee0d9b800ec307ea0716d256b1c9ea8628bdad Mon Sep 17 00:00:00 2001 From: Moritz Raabe Date: Tue, 30 Jun 2020 22:17:42 +0200 Subject: [PATCH 2/2] add lint negative numbers and cleanup tests --- scripts/lint.py | 16 ++++++++++++++++ tests/test_rules.py | 5 ++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/scripts/lint.py b/scripts/lint.py index 0a25f731..7a156bc4 100644 --- a/scripts/lint.py +++ b/scripts/lint.py @@ -20,6 +20,7 @@ import argparse import capa.main import capa.engine import capa.features +import capa.features.insn logger = logging.getLogger('capa.lint') @@ -215,6 +216,20 @@ class FeatureStringTooShort(Lint): return False +class FeatureNegativeNumberOrOffset(Lint): + name = 'feature value is negative' + recommendation = 'capa treats all numbers as unsigned values; you may specify the number\'s two\'s complement ' \ + 'representation; will not match on "{:d}"' + + def check_features(self, ctx, features): + for feature in features: + if isinstance(feature, (capa.features.insn.Number, capa.features.insn.Offset)): + if feature.value < 0: + self.recommendation = self.recommendation.format(feature.value) + return True + return False + + def run_lints(lints, ctx, rule): for lint in lints: if lint.check_rule(ctx, rule): @@ -264,6 +279,7 @@ def lint_meta(ctx, rule): FEATURE_LINTS = ( FeatureStringTooShort(), + FeatureNegativeNumberOrOffset(), ) diff --git a/tests/test_rules.py b/tests/test_rules.py index e67ff780..7a85eb11 100644 --- a/tests/test_rules.py +++ b/tests/test_rules.py @@ -250,7 +250,7 @@ def test_number_symbol(): features: - and: - number: 1 - - number: -1 + - number: 0xFFFFFFFF - number: 2 = symbol name - number: 3 = symbol name - number: 4 = symbol name = another name @@ -260,7 +260,7 @@ def test_number_symbol(): r = capa.rules.Rule.from_yaml(rule) children = list(r.statement.get_children()) assert (Number(1) in children) == True - assert (Number(-1) in children) == True + assert (Number(0xFFFFFFFF) in children) == True assert (Number(2, 'symbol name') in children) == True assert (Number(3, 'symbol name') in children) == True assert (Number(4, 'symbol name = another name') in children) == True @@ -323,7 +323,6 @@ def test_offset_symbol(): features: - and: - offset: 1 - # what about negative offsets? - offset: 2 = symbol name - offset: 3 = symbol name - offset: 4 = symbol name = another name