style: auto-format with black and isort

This commit is contained in:
Capa Bot
2026-03-10 11:48:04 +00:00
committed by mr-tz
parent 23156c6d86
commit ef2cd1df11
37 changed files with 399 additions and 1021 deletions

View File

@@ -20,6 +20,7 @@ Proto files generated via protobuf v24.4:
from BinExport2 at 6916731d5f6693c4a4f0a052501fd3bd92cfd08b
https://github.com/google/binexport/blob/6916731/binexport2.proto
"""
import io
import hashlib
import logging

View File

@@ -84,16 +84,14 @@ def extract_insn_number_features(
yield OperandOffset(i, value), ih.address
OFFSET_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
OFFSET_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
ldr|ldrb|ldrh|ldrsb|ldrsh|ldrex|ldrd|str|strb|strh|strex|strd reg, [reg(not-stack), #int] ; capture #int
ldr|ldrb|ldrh|ldrsb|ldrsh|ldrex|ldrd|str|strb|strh|strex|strd reg, [reg(not-stack), #int]! ; capture #int
ldr|ldrb|ldrh|ldrsb|ldrsh|ldrex|ldrd|str|strb|strh|strex|strd reg, [reg(not-stack)], #int ; capture #int
ldp|ldpd|stp|stpd reg, reg, [reg(not-stack), #int] ; capture #int
ldp|ldpd|stp|stpd reg, reg, [reg(not-stack), #int]! ; capture #int
ldp|ldpd|stp|stpd reg, reg, [reg(not-stack)], #int ; capture #int
"""
)
""")
def extract_insn_offset_features(
@@ -117,12 +115,10 @@ def extract_insn_offset_features(
yield OperandOffset(match.operand_index, value), ih.address
NZXOR_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
NZXOR_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
eor reg, reg, reg
eor reg, reg, #int
"""
)
""")
def extract_insn_nzxor_characteristic_features(
@@ -144,11 +140,9 @@ def extract_insn_nzxor_characteristic_features(
yield Characteristic("nzxor"), ih.address
INDIRECT_CALL_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
INDIRECT_CALL_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
blx|bx|blr reg
"""
)
""")
def extract_function_indirect_call_characteristic_features(

View File

@@ -34,17 +34,14 @@ from capa.features.extractors.binexport2.arch.intel.helpers import SECURITY_COOK
logger = logging.getLogger(__name__)
IGNORE_NUMBER_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
IGNORE_NUMBER_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
ret #int
retn #int
add reg(stack), #int
sub reg(stack), #int
"""
)
""")
NUMBER_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
NUMBER_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
push #int0 ; capture #int0
# its a little tedious to enumerate all the address forms
@@ -64,8 +61,7 @@ NUMBER_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
# imagine reg is zero'd out, then this is like `mov reg, #int`
# which is not uncommon.
lea reg, [reg + #int] ; capture #int
"""
)
""")
def extract_insn_number_features(
@@ -100,8 +96,7 @@ def extract_insn_number_features(
yield OperandOffset(match.operand_index, value), ih.address
OFFSET_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
OFFSET_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
mov|movzx|movsb|cmp [reg + reg * #int + #int0], #int ; capture #int0
mov|movzx|movsb|cmp [reg * #int + #int0], #int ; capture #int0
mov|movzx|movsb|cmp [reg + reg + #int0], #int ; capture #int0
@@ -114,18 +109,15 @@ OFFSET_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
mov|movzx|movsb|cmp|lea reg, [reg * #int + #int0] ; capture #int0
mov|movzx|movsb|cmp|lea reg, [reg + reg + #int0] ; capture #int0
mov|movzx|movsb|cmp|lea reg, [reg(not-stack) + #int0] ; capture #int0
"""
)
""")
# these are patterns that access offset 0 from some pointer
# (pointer is not the stack pointer).
OFFSET_ZERO_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
OFFSET_ZERO_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
mov|movzx|movsb [reg(not-stack)], reg
mov|movzx|movsb [reg(not-stack)], #int
lea reg, [reg(not-stack)]
"""
)
""")
def extract_insn_offset_features(
@@ -189,12 +181,10 @@ def is_security_cookie(
return False
NZXOR_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
NZXOR_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
xor|xorpd|xorps|pxor reg, reg
xor|xorpd|xorps|pxor reg, #int
"""
)
""")
def extract_insn_nzxor_characteristic_features(
@@ -228,8 +218,7 @@ def extract_insn_nzxor_characteristic_features(
yield Characteristic("nzxor"), ih.address
INDIRECT_CALL_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
"""
INDIRECT_CALL_PATTERNS = BinExport2InstructionPatternMatcher.from_str("""
call|jmp reg0
call|jmp [reg + reg * #int + #int]
call|jmp [reg + reg * #int]
@@ -237,8 +226,7 @@ INDIRECT_CALL_PATTERNS = BinExport2InstructionPatternMatcher.from_str(
call|jmp [reg + reg + #int]
call|jmp [reg + #int]
call|jmp [reg]
"""
)
""")
def extract_function_indirect_call_characteristic_features(

View File

@@ -56,7 +56,7 @@ def get_previous_instructions(vw: VivWorkspace, va: int) -> list[int]:
if ploc is not None:
# from vivisect.const:
# location: (L_VA, L_SIZE, L_LTYPE, L_TINFO)
(pva, _, ptype, pinfo) = ploc
pva, _, ptype, pinfo = ploc
if ptype == LOC_OP and not (pinfo & IF_NOFALL):
ret.append(pva)

View File

@@ -176,7 +176,7 @@ def extract_insn_api_features(fh: FunctionHandle, bb, ih: InsnHandle) -> Iterato
elif isinstance(insn.opers[0], envi.archs.i386.disasm.i386RegOper):
try:
(_, target) = resolve_indirect_call(f.vw, insn.va, insn=insn)
_, target = resolve_indirect_call(f.vw, insn.va, insn=insn)
except NotFoundError:
# not able to resolve the indirect call, sorry
return

View File

@@ -945,8 +945,7 @@ def main(argv: Optional[list[str]] = None):
argv = sys.argv[1:]
desc = "The FLARE team's open-source tool to identify capabilities in executable files."
epilog = textwrap.dedent(
"""
epilog = textwrap.dedent("""
By default, capa uses a default set of embedded rules.
You can see the rule set here:
https://github.com/mandiant/capa-rules
@@ -973,8 +972,7 @@ def main(argv: Optional[list[str]] = None):
filter rules by meta fields, e.g. rule name or namespace
capa -t "create TCP socket" suspicious.exe
"""
)
""")
parser = argparse.ArgumentParser(
description=desc, epilog=epilog, formatter_class=argparse.RawDescriptionHelpFormatter

View File

@@ -31,6 +31,7 @@ $ protoc.exe --python_out=. --mypy_out=. <path_to_proto> (e.g. capa/render/proto
Alternatively, --pyi_out=. can be used to generate a Python Interface file that supports development
"""
import datetime
from typing import Any, Union

View File

@@ -61,6 +61,7 @@ usage:
parallelism factor
--no-mp disable subprocesses
"""
import sys
import json
import logging

View File

@@ -28,6 +28,7 @@ Requires:
- sarif_om 1.0.4
- jschema_to_python 1.2.3
"""
import sys
import json
import logging

View File

@@ -32,6 +32,7 @@ Example:
│00000070│ 39 31 37 36 61 64 36 38 ┊ 32 66 66 64 64 36 35 66 │9176ad68┊2ffdd65f│
│00000080│ 30 61 36 36 39 12 28 61 ┊ 34 62 33 35 64 65 37 31 │0a669•(a┊4b35de71│
"""
import sys
import logging
import argparse

View File

@@ -18,6 +18,7 @@ detect-elf-os
Attempt to detect the underlying OS that the given ELF file targets.
"""
import sys
import logging
import argparse

View File

@@ -36,6 +36,7 @@ Check the log window for any errors, and/or the summary of changes.
Derived from: https://github.com/mandiant/capa/blob/master/scripts/import-to-ida.py
"""
import os
import json
from pathlib import Path

View File

@@ -54,6 +54,7 @@ Example::
0x44cb60: ?
0x44cba0: __guard_icall_checks_enforced
"""
import sys
import logging
import argparse

View File

@@ -16,6 +16,7 @@
"""
Extract files relevant to capa analysis from VMRay Analysis Archive and create a new ZIP file.
"""
import sys
import logging
import zipfile

View File

@@ -43,6 +43,7 @@ example:
^^^ --label or git hash
"""
import sys
import timeit
import logging

View File

@@ -34,6 +34,7 @@ Example:
│00000080│ 30 61 36 36 39 12 28 61 ┊ 34 62 33 35 64 65 37 31 │0a669•(a┊4b35de71│
"""
import sys
import logging
import argparse

View File

@@ -37,6 +37,7 @@ Example:
────┴────────────────────────────────────────────────────
"""
import sys
import logging
import argparse

View File

@@ -46,6 +46,7 @@ Example:
2022-01-24 22:35:39,839 [INFO] Starting extraction...
2022-01-24 22:35:42,632 [INFO] Writing results to linter-data.json
"""
import json
import logging
import argparse

View File

@@ -54,6 +54,7 @@ Example::
- connect TCP socket
...
"""
import sys
import logging
import argparse

View File

@@ -70,6 +70,7 @@ Example::
insn: 0x10001027: mnemonic(shl)
...
"""
import sys
import logging
import argparse

View File

@@ -458,9 +458,7 @@ def test_pattern_parsing():
capture="#int",
)
assert (
BinExport2InstructionPatternMatcher.from_str(
"""
assert BinExport2InstructionPatternMatcher.from_str("""
# comment
br reg
br reg(not-stack)
@@ -481,10 +479,7 @@ def test_pattern_parsing():
call [reg * #int + #int]
call [reg + reg + #int]
call [reg + #int]
"""
).queries
is not None
)
""").queries is not None
def match_address(extractor: BinExport2FeatureExtractor, queries: BinExport2InstructionPatternMatcher, address: int):
@@ -507,8 +502,7 @@ def match_address_with_be2(
def test_pattern_matching():
queries = BinExport2InstructionPatternMatcher.from_str(
"""
queries = BinExport2InstructionPatternMatcher.from_str("""
br reg(stack) ; capture reg
br reg(not-stack) ; capture reg
mov reg0, reg1 ; capture reg0
@@ -522,8 +516,7 @@ def test_pattern_matching():
ldp|stp reg, reg, [reg, #int]! ; capture #int
ldp|stp reg, reg, [reg], #int ; capture #int
ldrb reg0, [reg1(not-stack), reg2] ; capture reg2
"""
)
""")
# 0x210184: ldrb w2, [x0, x1]
# query: ldrb reg0, [reg1(not-stack), reg2] ; capture reg2"
@@ -550,11 +543,9 @@ BE2_EXTRACTOR_687 = fixtures.get_binexport_extractor(
def test_pattern_matching_exclamation():
queries = BinExport2InstructionPatternMatcher.from_str(
"""
queries = BinExport2InstructionPatternMatcher.from_str("""
stp reg, reg, [reg, #int]! ; capture #int
"""
)
""")
# note this captures the sp
# 0x107918: stp x20, x19, [sp,0xFFFFFFFFFFFFFFE0]!
@@ -564,11 +555,9 @@ def test_pattern_matching_exclamation():
def test_pattern_matching_stack():
queries = BinExport2InstructionPatternMatcher.from_str(
"""
queries = BinExport2InstructionPatternMatcher.from_str("""
stp reg, reg, [reg(stack), #int]! ; capture #int
"""
)
""")
# note this does capture the sp
# compare this with the test above (exclamation)
@@ -579,11 +568,9 @@ def test_pattern_matching_stack():
def test_pattern_matching_not_stack():
queries = BinExport2InstructionPatternMatcher.from_str(
"""
queries = BinExport2InstructionPatternMatcher.from_str("""
stp reg, reg, [reg(not-stack), #int]! ; capture #int
"""
)
""")
# note this does not capture the sp
# compare this with the test above (exclamation)
@@ -597,11 +584,9 @@ BE2_EXTRACTOR_MIMI = fixtures.get_binexport_extractor(CD / "data" / "binexport2"
def test_pattern_matching_x86():
queries = BinExport2InstructionPatternMatcher.from_str(
"""
queries = BinExport2InstructionPatternMatcher.from_str("""
cmp|lea reg, [reg(not-stack) + #int0] ; capture #int0
"""
)
""")
# 0x4018c0: LEA ECX, [EBX+0x2]
# query: cmp|lea reg, [reg(not-stack) + #int0] ; capture #int0

View File

@@ -23,9 +23,7 @@ def test_match_across_scopes_file_function(z9324d_extractor):
rules = capa.rules.RuleSet(
[
# this rule should match on a function (0x4073F0)
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: install service
@@ -39,13 +37,9 @@ def test_match_across_scopes_file_function(z9324d_extractor):
- api: advapi32.OpenSCManagerA
- api: advapi32.CreateServiceA
- api: advapi32.StartServiceA
"""
)
),
""")),
# this rule should match on a file feature
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: .text section
@@ -56,15 +50,11 @@ def test_match_across_scopes_file_function(z9324d_extractor):
- 9324d1a8ae37a36ae560c37448c9705a
features:
- section: .text
"""
)
),
""")),
# this rule should match on earlier rule matches:
# - install service, with function scope
# - .text section, with file scope
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: .text section and install service
@@ -77,9 +67,7 @@ def test_match_across_scopes_file_function(z9324d_extractor):
- and:
- match: install service
- match: .text section
"""
)
),
""")),
]
)
capabilities = capa.capabilities.common.find_capabilities(rules, z9324d_extractor)
@@ -92,9 +80,7 @@ def test_match_across_scopes(z9324d_extractor):
rules = capa.rules.RuleSet(
[
# this rule should match on a basic block (including at least 0x403685)
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: tight loop
@@ -105,14 +91,10 @@ def test_match_across_scopes(z9324d_extractor):
- 9324d1a8ae37a36ae560c37448c9705a:0x403685
features:
- characteristic: tight loop
"""
)
),
""")),
# this rule should match on a function (0x403660)
# based on API, as well as prior basic block rule match
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: kill thread loop
@@ -126,13 +108,9 @@ def test_match_across_scopes(z9324d_extractor):
- api: kernel32.TerminateThread
- api: kernel32.CloseHandle
- match: tight loop
"""
)
),
""")),
# this rule should match on a file feature and a prior function rule match
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: kill thread program
@@ -145,9 +123,7 @@ def test_match_across_scopes(z9324d_extractor):
- and:
- section: .text
- match: kill thread loop
"""
)
),
""")),
]
)
capabilities = capa.capabilities.common.find_capabilities(rules, z9324d_extractor)
@@ -157,11 +133,7 @@ def test_match_across_scopes(z9324d_extractor):
def test_subscope_bb_rules(z9324d_extractor):
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
rules = capa.rules.RuleSet([capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -172,22 +144,14 @@ def test_subscope_bb_rules(z9324d_extractor):
- and:
- basic block:
- characteristic: tight loop
"""
)
)
]
)
"""))])
# tight loop at 0x403685
capabilities = capa.capabilities.common.find_capabilities(rules, z9324d_extractor)
assert "test rule" in capabilities.matches
def test_match_specific_functions(z9324d_extractor):
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
rules = capa.rules.RuleSet([capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: receive data
@@ -199,11 +163,7 @@ def test_match_specific_functions(z9324d_extractor):
features:
- or:
- api: recv
"""
)
)
]
)
"""))])
extractor = FunctionFilter(z9324d_extractor, {0x4019C0})
capabilities = capa.capabilities.common.find_capabilities(rules, extractor)
matches = capabilities.matches["receive data"]
@@ -214,11 +174,7 @@ def test_match_specific_functions(z9324d_extractor):
def test_byte_matching(z9324d_extractor):
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
rules = capa.rules.RuleSet([capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: byte match test
@@ -228,21 +184,13 @@ def test_byte_matching(z9324d_extractor):
features:
- and:
- bytes: ED 24 9E F4 52 A9 07 47 55 8E E1 AB 30 8E 23 61
"""
)
)
]
)
"""))])
capabilities = capa.capabilities.common.find_capabilities(rules, z9324d_extractor)
assert "byte match test" in capabilities.matches
def test_com_feature_matching(z395eb_extractor):
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
rules = capa.rules.RuleSet([capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: initialize IWebBrowser2
@@ -254,21 +202,13 @@ def test_com_feature_matching(z395eb_extractor):
- api: ole32.CoCreateInstance
- com/class: InternetExplorer #bytes: 01 DF 02 00 00 00 00 00 C0 00 00 00 00 00 00 46 = CLSID_InternetExplorer
- com/interface: IWebBrowser2 #bytes: 61 16 0C D3 AF CD D0 11 8A 3E 00 C0 4F C9 E2 6E = IID_IWebBrowser2
"""
)
)
]
)
"""))])
capabilities = capa.main.find_capabilities(rules, z395eb_extractor)
assert "initialize IWebBrowser2" in capabilities.matches
def test_count_bb(z9324d_extractor):
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
rules = capa.rules.RuleSet([capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: count bb
@@ -279,22 +219,14 @@ def test_count_bb(z9324d_extractor):
features:
- and:
- count(basic blocks): 1 or more
"""
)
)
]
)
"""))])
capabilities = capa.capabilities.common.find_capabilities(rules, z9324d_extractor)
assert "count bb" in capabilities.matches
def test_instruction_scope(z9324d_extractor):
# .text:004071A4 68 E8 03 00 00 push 3E8h
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
rules = capa.rules.RuleSet([capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: push 1000
@@ -306,11 +238,7 @@ def test_instruction_scope(z9324d_extractor):
- and:
- mnemonic: push
- number: 1000
"""
)
)
]
)
"""))])
capabilities = capa.capabilities.common.find_capabilities(rules, z9324d_extractor)
assert "push 1000" in capabilities.matches
assert 0x4071A4 in {result[0] for result in capabilities.matches["push 1000"]}
@@ -320,11 +248,7 @@ def test_instruction_subscope(z9324d_extractor):
# .text:00406F60 sub_406F60 proc near
# [...]
# .text:004071A4 68 E8 03 00 00 push 3E8h
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
rules = capa.rules.RuleSet([capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: push 1000 on i386
@@ -338,11 +262,7 @@ def test_instruction_subscope(z9324d_extractor):
- instruction:
- mnemonic: push
- number: 1000
"""
)
)
]
)
"""))])
capabilities = capa.capabilities.common.find_capabilities(rules, z9324d_extractor)
assert "push 1000 on i386" in capabilities.matches
assert 0x406F60 in {result[0] for result in capabilities.matches["push 1000 on i386"]}

View File

@@ -81,8 +81,7 @@ def test_cape_extractor(version: str, filename: str, exception: Type[BaseExcepti
def test_cape_model_argument():
call = Call.model_validate_json(
"""
call = Call.model_validate_json("""
{
"timestamp": "2023-10-20 12:30:14,015",
"thread_id": "2380",
@@ -105,7 +104,6 @@ def test_cape_model_argument():
"repeated": 19,
"id": 0
}
"""
)
""")
assert call.arguments[0].value == 30
assert call.arguments[1].value == 0x30

View File

@@ -18,8 +18,7 @@ from capa.features.extractors.drakvuf.models import SystemCall
def test_syscall_argument_construction():
call_dictionary = json.loads(
r"""
call_dictionary = json.loads(r"""
{
"Plugin": "syscall",
"TimeStamp": "1716999134.581449",
@@ -43,8 +42,7 @@ def test_syscall_argument_construction():
"Timeout": "0xfffff506a02846d8",
"Alertable": "0x0"
}
"""
)
""")
call = SystemCall(**call_dictionary)
assert len(call.arguments) == call.nargs
assert call.arguments["IoCompletionHandle"] == "0xffffffff80001ac0"

View File

@@ -83,8 +83,7 @@ def get_call_ids(matches) -> Iterator[int]:
def test_dynamic_call_scope():
extractor = get_0000a657_thread3064()
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -93,8 +92,7 @@ def test_dynamic_call_scope():
dynamic: call
features:
- api: GetSystemTimeAsFileTime
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
ruleset = capa.rules.RuleSet([r])
@@ -116,8 +114,7 @@ def test_dynamic_call_scope():
def test_dynamic_span_scope():
extractor = get_0000a657_thread3064()
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -131,8 +128,7 @@ def test_dynamic_span_scope():
- api: LdrGetDllHandle
- api: LdrGetProcedureAddress
- count(api(LdrGetDllHandle)): 2
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
ruleset = capa.rules.RuleSet([r])
@@ -158,8 +154,7 @@ def test_dynamic_span_scope():
def test_dynamic_span_scope_length():
extractor = get_0000a657_thread3064()
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -170,8 +165,7 @@ def test_dynamic_span_scope_length():
- and:
- api: GetSystemTimeAsFileTime
- api: RtlAddVectoredExceptionHandler
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
ruleset = capa.rules.RuleSet([r])
@@ -196,8 +190,7 @@ def test_dynamic_span_scope_length():
def test_dynamic_span_call_subscope():
extractor = get_0000a657_thread3064()
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -210,8 +203,7 @@ def test_dynamic_span_call_subscope():
- and:
- api: LdrGetProcedureAddress
- string: AddVectoredExceptionHandler
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
ruleset = capa.rules.RuleSet([r])
@@ -234,8 +226,7 @@ def test_dynamic_span_call_subscope():
def test_dynamic_span_scope_span_subscope():
extractor = get_0000a657_thread3064()
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -256,8 +247,7 @@ def test_dynamic_span_scope_span_subscope():
- api: LdrGetDllHandle
- api: LdrGetProcedureAddress
- string: RemoveVectoredExceptionHandler
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
ruleset = capa.rules.RuleSet([r])
@@ -269,8 +259,7 @@ def test_dynamic_span_scope_span_subscope():
# show that you can't use thread subscope in span rules.
def test_dynamic_span_scope_thread_subscope():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -281,8 +270,7 @@ def test_dynamic_span_scope_thread_subscope():
- and:
- thread:
- string: "foo"
"""
)
""")
with pytest.raises(capa.rules.InvalidRule):
capa.rules.Rule.from_yaml(rule)
@@ -300,8 +288,7 @@ def test_dynamic_span_scope_thread_subscope():
def test_dynamic_span_example():
extractor = get_0000a657_thread3064()
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -319,8 +306,7 @@ def test_dynamic_span_example():
- api: LdrGetProcedureAddress
- string: "AddVectoredExceptionHandler"
- api: RtlAddVectoredExceptionHandler
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
ruleset = capa.rules.RuleSet([r])
@@ -345,8 +331,7 @@ def test_dynamic_span_example():
def test_dynamic_span_multiple_spans_overlapping_single_event():
extractor = get_0000a657_thread3064()
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -359,8 +344,7 @@ def test_dynamic_span_multiple_spans_overlapping_single_event():
- and:
- api: LdrGetProcedureAddress
- string: "AddVectoredExceptionHandler"
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
ruleset = capa.rules.RuleSet([r])
@@ -386,9 +370,7 @@ def test_dynamic_span_scope_match_statements():
ruleset = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: resolve add VEH
@@ -401,12 +383,8 @@ def test_dynamic_span_scope_match_statements():
- api: LdrGetDllHandle
- api: LdrGetProcedureAddress
- string: AddVectoredExceptionHandler
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: resolve remove VEH
@@ -419,12 +397,8 @@ def test_dynamic_span_scope_match_statements():
- api: LdrGetDllHandle
- api: LdrGetProcedureAddress
- string: RemoveVectoredExceptionHandler
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: resolve add and remove VEH
@@ -435,12 +409,8 @@ def test_dynamic_span_scope_match_statements():
- and:
- match: resolve add VEH
- match: resolve remove VEH
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: has VEH runtime linking
@@ -450,9 +420,7 @@ def test_dynamic_span_scope_match_statements():
features:
- and:
- match: linking/runtime-linking/veh
"""
)
),
""")),
]
)

View File

@@ -17,8 +17,7 @@ import textwrap
import capa.rules
EXPECTED = textwrap.dedent(
"""\
EXPECTED = textwrap.dedent("""\
rule:
meta:
name: test rule
@@ -34,13 +33,11 @@ EXPECTED = textwrap.dedent(
- and:
- number: 1
- number: 2
"""
)
""")
def test_rule_reformat_top_level_elements():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
features:
- and:
@@ -56,15 +53,13 @@ def test_rule_reformat_top_level_elements():
examples:
- foo1234
- bar5678
"""
)
""")
assert capa.rules.Rule.from_yaml(rule).to_yaml() == EXPECTED
def test_rule_reformat_indentation():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -80,15 +75,13 @@ def test_rule_reformat_indentation():
- and:
- number: 1
- number: 2
"""
)
""")
assert capa.rules.Rule.from_yaml(rule).to_yaml() == EXPECTED
def test_rule_reformat_order():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
authors:
@@ -104,8 +97,7 @@ def test_rule_reformat_order():
- and:
- number: 1
- number: 2
"""
)
""")
assert capa.rules.Rule.from_yaml(rule).to_yaml() == EXPECTED
@@ -113,8 +105,7 @@ def test_rule_reformat_order():
def test_rule_reformat_meta_update():
# test updating the rule content after parsing
src = textwrap.dedent(
"""
src = textwrap.dedent("""
rule:
meta:
authors:
@@ -130,8 +121,7 @@ def test_rule_reformat_meta_update():
- and:
- number: 1
- number: 2
"""
)
""")
rule = capa.rules.Rule.from_yaml(src)
rule.name = "test rule"
@@ -141,8 +131,7 @@ def test_rule_reformat_meta_update():
def test_rule_reformat_string_description():
# the `description` should be aligned with the preceding feature name.
# see #263
src = textwrap.dedent(
"""
src = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -155,8 +144,7 @@ def test_rule_reformat_string_description():
- and:
- string: foo
description: bar
"""
).lstrip()
""").lstrip()
rule = capa.rules.Rule.from_yaml(src)
assert rule.to_yaml() == src

View File

@@ -108,9 +108,7 @@ def test_null_feature_extractor():
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: create file
@@ -120,9 +118,7 @@ def test_null_feature_extractor():
features:
- and:
- api: CreateFile
"""
)
),
""")),
]
)
capabilities = capa.main.find_capabilities(rules, EXTRACTOR)

View File

@@ -88,9 +88,7 @@ def test_null_feature_extractor():
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: xor loop
@@ -102,9 +100,7 @@ def test_null_feature_extractor():
- characteristic: tight loop
- mnemonic: xor
- characteristic: nzxor
"""
)
),
""")),
]
)
capabilities = capa.main.find_capabilities(rules, EXTRACTOR)

View File

@@ -38,8 +38,7 @@ def test_main(z9324d_extractor):
def test_main_single_rule(z9324d_extractor, tmpdir):
# tests a single rule can be loaded successfully
RULE_CONTENT = textwrap.dedent(
"""
RULE_CONTENT = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -50,8 +49,7 @@ def test_main_single_rule(z9324d_extractor, tmpdir):
- test
features:
- string: test
"""
)
""")
path = z9324d_extractor.path
rule_file = tmpdir.mkdir("capa").join("rule.yml")
rule_file.write(RULE_CONTENT)
@@ -100,9 +98,7 @@ def test_main_shellcode(z499c2_extractor):
def test_ruleset():
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: file rule
@@ -111,12 +107,8 @@ def test_ruleset():
dynamic: process
features:
- characteristic: embedded pe
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: function rule
@@ -125,12 +117,8 @@ def test_ruleset():
dynamic: process
features:
- characteristic: tight loop
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: basic block rule
@@ -139,12 +127,8 @@ def test_ruleset():
dynamic: process
features:
- characteristic: nzxor
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: process rule
@@ -153,12 +137,8 @@ def test_ruleset():
dynamic: process
features:
- string: "explorer.exe"
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: thread rule
@@ -167,12 +147,8 @@ def test_ruleset():
dynamic: thread
features:
- api: RegDeleteKey
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test call subscope
@@ -184,12 +160,8 @@ def test_ruleset():
- string: "explorer.exe"
- call:
- api: HttpOpenRequestW
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -207,9 +179,7 @@ def test_ruleset():
- number: 6 = IPPROTO_TCP
- number: 1 = SOCK_STREAM
- number: 2 = AF_INET
"""
)
),
""")),
]
)
assert len(rules.file_rules) == 2
@@ -322,9 +292,7 @@ def test_main_cape1(tmp_path):
# https://github.com/mandiant/capa/pull/1696
rules = tmp_path / "rules"
rules.mkdir()
(rules / "create-or-open-registry-key.yml").write_text(
textwrap.dedent(
"""
(rules / "create-or-open-registry-key.yml").write_text(textwrap.dedent("""
rule:
meta:
name: create or open registry key
@@ -354,9 +322,7 @@ def test_main_cape1(tmp_path):
- api: SHRegOpenUSKey
- api: SHRegCreateUSKey
- api: RtlCreateRegistryKey
"""
)
)
"""))
assert capa.main.main([str(path), "-r", str(rules)]) == 0
assert capa.main.main([str(path), "-q", "-r", str(rules)]) == 0

View File

@@ -46,8 +46,7 @@ def match(rules, features, va, scope=Scope.FUNCTION):
def test_match_simple():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -57,8 +56,7 @@ def test_match_simple():
namespace: testns1/testns2
features:
- number: 100
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
features, matches = match([r], {capa.features.insn.Number(100): {1, 2}}, 0x0)
@@ -69,8 +67,7 @@ def test_match_simple():
def test_match_range_exact():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -79,8 +76,7 @@ def test_match_range_exact():
dynamic: process
features:
- count(number(100)): 2
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
# just enough matches
@@ -97,8 +93,7 @@ def test_match_range_exact():
def test_match_range_range():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -107,8 +102,7 @@ def test_match_range_range():
dynamic: process
features:
- count(number(100)): (2, 3)
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
# just enough matches
@@ -129,8 +123,7 @@ def test_match_range_range():
def test_match_range_exact_zero():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -146,8 +139,7 @@ def test_match_range_exact_zero():
# so we have this additional trivial feature.
- mnemonic: mov
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
# feature isn't indexed - good.
@@ -165,8 +157,7 @@ def test_match_range_exact_zero():
def test_match_range_with_zero():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -181,8 +172,7 @@ def test_match_range_with_zero():
# since we don't support top level NOT statements.
# so we have this additional trivial feature.
- mnemonic: mov
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
# ok
@@ -200,8 +190,7 @@ def test_match_range_with_zero():
def test_match_adds_matched_rule_feature():
"""show that using `match` adds a feature for matched rules."""
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -210,8 +199,7 @@ def test_match_adds_matched_rule_feature():
dynamic: process
features:
- number: 100
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
features, _ = match([r], {capa.features.insn.Number(100): {1}}, 0x0)
assert capa.features.common.MatchedRule("test rule") in features
@@ -220,9 +208,7 @@ def test_match_adds_matched_rule_feature():
def test_match_matched_rules():
"""show that using `match` adds a feature for matched rules."""
rules = [
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule1
@@ -231,12 +217,8 @@ def test_match_matched_rules():
dynamic: process
features:
- number: 100
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule2
@@ -245,9 +227,7 @@ def test_match_matched_rules():
dynamic: process
features:
- match: test rule1
"""
)
),
""")),
]
features, _ = match(
@@ -271,9 +251,7 @@ def test_match_matched_rules():
def test_match_namespace():
rules = [
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: CreateFile API
@@ -283,12 +261,8 @@ def test_match_namespace():
namespace: file/create/CreateFile
features:
- api: CreateFile
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: WriteFile API
@@ -298,12 +272,8 @@ def test_match_namespace():
namespace: file/write
features:
- api: WriteFile
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: file-create
@@ -312,12 +282,8 @@ def test_match_namespace():
dynamic: process
features:
- match: file/create
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: filesystem-any
@@ -326,9 +292,7 @@ def test_match_namespace():
dynamic: process
features:
- match: file
"""
)
),
""")),
]
features, matches = match(
@@ -355,9 +319,7 @@ def test_match_namespace():
def test_match_substring():
rules = [
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -367,9 +329,7 @@ def test_match_substring():
features:
- and:
- substring: abc
"""
)
),
""")),
]
features, _ = match(
capa.rules.topologically_order_rules(rules),
@@ -409,9 +369,7 @@ def test_match_substring():
def test_match_regex():
rules = [
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -421,12 +379,8 @@ def test_match_regex():
features:
- and:
- string: /.*bbbb.*/
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: rule with implied wildcards
@@ -436,12 +390,8 @@ def test_match_regex():
features:
- and:
- string: /bbbb/
"""
)
),
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
""")),
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: rule with anchor
@@ -451,9 +401,7 @@ def test_match_regex():
features:
- and:
- string: /^bbbb/
"""
)
),
""")),
]
features, _ = match(
capa.rules.topologically_order_rules(rules),
@@ -488,9 +436,7 @@ def test_match_regex():
def test_match_regex_ignorecase():
rules = [
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -500,9 +446,7 @@ def test_match_regex_ignorecase():
features:
- and:
- string: /.*bbbb.*/i
"""
)
),
""")),
]
features, _ = match(
capa.rules.topologically_order_rules(rules),
@@ -514,9 +458,7 @@ def test_match_regex_ignorecase():
def test_match_regex_complex():
rules = [
capa.rules.Rule.from_yaml(
textwrap.dedent(
r"""
capa.rules.Rule.from_yaml(textwrap.dedent(r"""
rule:
meta:
name: test rule
@@ -526,9 +468,7 @@ def test_match_regex_complex():
features:
- or:
- string: /.*HARDWARE\\Key\\key with spaces\\.*/i
"""
)
),
""")),
]
features, _ = match(
capa.rules.topologically_order_rules(rules),
@@ -540,9 +480,7 @@ def test_match_regex_complex():
def test_match_regex_values_always_string():
rules = [
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -553,9 +491,7 @@ def test_match_regex_values_always_string():
- or:
- string: /123/
- string: /0x123/
"""
)
),
""")),
]
features, _ = match(
capa.rules.topologically_order_rules(rules),
@@ -587,8 +523,7 @@ def test_regex_get_value_str(pattern):
@pytest.mark.xfail(reason="can't have top level NOT")
def test_match_only_not():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -599,8 +534,7 @@ def test_match_only_not():
features:
- not:
- number: 99
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
_, matches = match([r], {capa.features.insn.Number(100): {1, 2}}, 0x0)
@@ -608,8 +542,7 @@ def test_match_only_not():
def test_match_not():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -622,8 +555,7 @@ def test_match_not():
- mnemonic: mov
- not:
- number: 99
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
_, matches = match([r], {capa.features.insn.Number(100): {1, 2}, capa.features.insn.Mnemonic("mov"): {1, 2}}, 0x0)
@@ -632,8 +564,7 @@ def test_match_not():
@pytest.mark.xfail(reason="can't have nested NOT")
def test_match_not_not():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -645,8 +576,7 @@ def test_match_not_not():
- not:
- not:
- number: 100
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
_, matches = match([r], {capa.features.insn.Number(100): {1, 2}}, 0x0)
@@ -654,8 +584,7 @@ def test_match_not_not():
def test_match_operand_number():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -665,8 +594,7 @@ def test_match_operand_number():
features:
- and:
- operand[0].number: 0x10
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
assert capa.features.insn.OperandNumber(0, 0x10) in {capa.features.insn.OperandNumber(0, 0x10)}
@@ -684,8 +612,7 @@ def test_match_operand_number():
def test_match_operand_offset():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -695,8 +622,7 @@ def test_match_operand_offset():
features:
- and:
- operand[0].offset: 0x10
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
assert capa.features.insn.OperandOffset(0, 0x10) in {capa.features.insn.OperandOffset(0, 0x10)}
@@ -714,8 +640,7 @@ def test_match_operand_offset():
def test_match_property_access():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -725,8 +650,7 @@ def test_match_property_access():
features:
- and:
- property/read: System.IO.FileInfo::Length
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
assert capa.features.insn.Property("System.IO.FileInfo::Length", capa.features.common.FeatureAccess.READ) in {
@@ -758,8 +682,7 @@ def test_match_property_access():
def test_match_os_any():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -777,8 +700,7 @@ def test_match_os_any():
- and:
- os: any
- string: "Goodbye world"
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
_, matches = match(
@@ -812,8 +734,7 @@ def test_match_os_any():
# this test demonstrates the behavior of unstable features that may change before the next major release.
def test_index_features_and_unstable():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -824,8 +745,7 @@ def test_index_features_and_unstable():
- and:
- mnemonic: mov
- api: CreateFileW
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
rr = capa.rules.RuleSet([r])
index: capa.rules.RuleSet._RuleFeatureIndex = rr._feature_indexes_by_scopes[capa.rules.Scope.FUNCTION]
@@ -841,8 +761,7 @@ def test_index_features_and_unstable():
# this test demonstrates the behavior of unstable features that may change before the next major release.
def test_index_features_or_unstable():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -853,8 +772,7 @@ def test_index_features_or_unstable():
- or:
- mnemonic: mov
- api: CreateFileW
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
rr = capa.rules.RuleSet([r])
index: capa.rules.RuleSet._RuleFeatureIndex = rr._feature_indexes_by_scopes[capa.rules.Scope.FUNCTION]
@@ -871,8 +789,7 @@ def test_index_features_or_unstable():
# this test demonstrates the behavior of unstable features that may change before the next major release.
def test_index_features_nested_unstable():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -885,8 +802,7 @@ def test_index_features_nested_unstable():
- or:
- api: CreateFileW
- string: foo
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
rr = capa.rules.RuleSet([r])
index: capa.rules.RuleSet._RuleFeatureIndex = rr._feature_indexes_by_scopes[capa.rules.Scope.FUNCTION]

View File

@@ -25,8 +25,7 @@ from capa.features.common import Arch, Substring
def test_optimizer_order():
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -44,8 +43,7 @@ def test_optimizer_order():
- or:
- number: 1
- offset: 4
"""
)
""")
r = capa.rules.Rule.from_yaml(rule)
# before optimization

View File

@@ -56,8 +56,7 @@ def test_render_meta_attack():
subtechnique = "Windows Service"
canonical = "{:s}::{:s}::{:s} [{:s}]".format(tactic, technique, subtechnique, id)
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -70,10 +69,7 @@ def test_render_meta_attack():
- {:s}
features:
- number: 1
""".format(
canonical
)
)
""".format(canonical))
r = capa.rules.Rule.from_yaml(rule)
rule_meta = capa.render.result_document.RuleMetadata.from_capa(r)
attack = rule_meta.attack[0]
@@ -94,8 +90,7 @@ def test_render_meta_mbc():
method = "Heavens Gate"
canonical = "{:s}::{:s}::{:s} [{:s}]".format(objective, behavior, method, id)
rule = textwrap.dedent(
"""
rule = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -108,10 +103,7 @@ def test_render_meta_mbc():
- {:s}
features:
- number: 1
""".format(
canonical
)
)
""".format(canonical))
r = capa.rules.Rule.from_yaml(rule)
rule_meta = capa.render.result_document.RuleMetadata.from_capa(r)
mbc = rule_meta.mbc[0]
@@ -129,8 +121,7 @@ def test_render_meta_maec():
malware_category = "downloader"
analysis_conclusion = "malicious"
rule_yaml = textwrap.dedent(
"""
rule_yaml = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -144,10 +135,7 @@ def test_render_meta_maec():
maec/analysis-conclusion: {:s}
features:
- number: 1
""".format(
malware_family, malware_category, analysis_conclusion
)
)
""".format(malware_family, malware_category, analysis_conclusion))
rule = capa.rules.Rule.from_yaml(rule_yaml)
rm = capa.render.result_document.RuleMatches(
meta=capa.render.result_document.RuleMetadata.from_capa(rule),
@@ -220,8 +208,7 @@ def test_render_vverbose_feature(feature, expected):
layout = capa.render.result_document.StaticLayout(functions=())
src = textwrap.dedent(
"""
src = textwrap.dedent("""
rule:
meta:
name: test rule
@@ -237,8 +224,7 @@ def test_render_vverbose_feature(feature, expected):
- and:
- number: 1
- number: 2
"""
)
""")
rule = capa.rules.Rule.from_yaml(src)
rm = capa.render.result_document.RuleMatches(

View File

@@ -22,9 +22,7 @@ import capa.rules
import capa.helpers
import capa.rules.cache
R1 = capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
R1 = capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -40,13 +38,9 @@ R1 = capa.rules.Rule.from_yaml(
- and:
- number: 1
- number: 2
"""
)
)
"""))
R2 = capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
R2 = capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule 2
@@ -62,9 +56,7 @@ R2 = capa.rules.Rule.from_yaml(
- and:
- number: 3
- number: 4
"""
)
)
"""))
def test_ruleset_cache_ids():

File diff suppressed because it is too large Load Diff

View File

@@ -21,9 +21,7 @@ import capa.rules
def test_rule_scope_instruction():
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -35,14 +33,10 @@ def test_rule_scope_instruction():
- mnemonic: mov
- arch: i386
- os: windows
"""
)
)
"""))
with pytest.raises(capa.rules.InvalidRule):
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -51,17 +45,11 @@ def test_rule_scope_instruction():
dynamic: unsupported
features:
- characteristic: embedded pe
"""
)
)
"""))
def test_rule_subscope_instruction():
rules = capa.rules.RuleSet(
[
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
rules = capa.rules.RuleSet([capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -75,11 +63,7 @@ def test_rule_subscope_instruction():
- mnemonic: mov
- arch: i386
- os: windows
"""
)
)
]
)
"""))])
# the function rule scope will have one rules:
# - `test rule`
assert len(rules.function_rules) == 1
@@ -90,9 +74,7 @@ def test_rule_subscope_instruction():
def test_scope_instruction_implied_and():
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -105,15 +87,11 @@ def test_scope_instruction_implied_and():
- mnemonic: mov
- arch: i386
- os: windows
"""
)
)
"""))
def test_scope_instruction_description():
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -127,13 +105,9 @@ def test_scope_instruction_description():
- mnemonic: mov
- arch: i386
- os: windows
"""
)
)
"""))
capa.rules.Rule.from_yaml(
textwrap.dedent(
"""
capa.rules.Rule.from_yaml(textwrap.dedent("""
rule:
meta:
name: test rule
@@ -147,6 +121,4 @@ def test_scope_instruction_description():
- mnemonic: mov
- arch: i386
- os: windows
"""
)
)
"""))

View File

@@ -142,8 +142,7 @@ def test_proto_conversion(tmp_path):
def test_detect_duplicate_features(tmpdir):
TEST_RULE_0 = textwrap.dedent(
"""
TEST_RULE_0 = textwrap.dedent("""
rule:
meta:
name: Test Rule 0
@@ -155,12 +154,10 @@ def test_detect_duplicate_features(tmpdir):
- number: 1
- not:
- string: process
"""
)
""")
TEST_RULESET = {
"rule_1": textwrap.dedent(
"""
"rule_1": textwrap.dedent("""
rule:
meta:
name: Test Rule 1
@@ -179,10 +176,8 @@ def test_detect_duplicate_features(tmpdir):
- count(mnemonic(xor)): 5
- not:
- os: linux
"""
),
"rule_2": textwrap.dedent(
"""
"""),
"rule_2": textwrap.dedent("""
rule:
meta:
name: Test Rule 2
@@ -196,10 +191,8 @@ def test_detect_duplicate_features(tmpdir):
- and:
- api: CreateFile
- mnemonic: xor
"""
),
"rule_3": textwrap.dedent(
"""
"""),
"rule_3": textwrap.dedent("""
rule:
meta:
name: Test Rule 3
@@ -214,8 +207,7 @@ def test_detect_duplicate_features(tmpdir):
- and:
- api: bind
- number: 2
"""
),
"""),
}
"""

View File

@@ -26,11 +26,9 @@ from capa.features.extractors.vmray.models import (
def test_vmray_model_param():
param_str = textwrap.dedent(
"""
param_str = textwrap.dedent("""
<param name="addrlen" type="signed_32bit" value="16"/>
"""
)
""")
param: Param = Param.model_validate(xml_to_dict(param_str)["param"])
assert param.value is not None
@@ -38,13 +36,11 @@ def test_vmray_model_param():
def test_vmray_model_param_deref():
param_str = textwrap.dedent(
"""
param_str = textwrap.dedent("""
<param name="buf" type="ptr" value="0xaaaaaaaa">
<deref type="str" value="Hello world"/>
</param>
"""
)
""")
param: Param = Param.model_validate(xml_to_dict(param_str)["param"])
assert param.deref is not None
@@ -52,8 +48,7 @@ def test_vmray_model_param_deref():
def test_vmray_model_function_call():
function_call_str = textwrap.dedent(
"""
function_call_str = textwrap.dedent("""
<fncall fncall_id="18" process_id="1" thread_id="1" name="sys_time">
<in>
<param name="tloc" type="unknown" value="0x0"/>
@@ -62,8 +57,7 @@ def test_vmray_model_function_call():
<param name="ret_val" type="unknown" value="0xaaaaaaaa"/>
</out>
</fncall>
"""
)
""")
function_call: FunctionCall = FunctionCall.model_validate(xml_to_dict(function_call_str)["fncall"])
assert function_call.fncall_id == 18
@@ -81,22 +75,19 @@ def test_vmray_model_function_call():
def test_vmray_model_analysis_metadata():
analysis_metadata: AnalysisMetadata = AnalysisMetadata.model_validate_json(
"""
analysis_metadata: AnalysisMetadata = AnalysisMetadata.model_validate_json("""
{
"sample_type": "Linux ELF Executable (x86-64)",
"submission_filename": "abcd1234"
}
"""
)
""")
assert analysis_metadata.sample_type == "Linux ELF Executable (x86-64)"
assert analysis_metadata.submission_filename == "abcd1234"
def test_vmray_model_elffile():
elffile: ElfFile = ElfFile.model_validate_json(
"""
elffile: ElfFile = ElfFile.model_validate_json("""
{
"sections": [
{
@@ -107,16 +98,14 @@ def test_vmray_model_elffile():
}
]
}
"""
)
""")
assert elffile.sections[0].header.sh_name == "abcd1234"
assert elffile.sections[0].header.sh_addr == 2863311530
def test_vmray_model_pefile():
pefile: PEFile = PEFile.model_validate_json(
"""
pefile: PEFile = PEFile.model_validate_json("""
{
"basic_info": {
"image_base": 2863311530
@@ -150,8 +139,7 @@ def test_vmray_model_pefile():
}
]
}
"""
)
""")
assert pefile.basic_info.image_base == 2863311530