extractor: remove characteristic(switch)

Get rid of the `characteristic(switch)` feature as any of our rules use
it and its analysis is not very easy. Analysis results most likely
differ across backends, leading to inconsistency.
This commit is contained in:
Ana María Martínez Gómez
2020-08-13 16:37:01 +02:00
parent 199cccaef9
commit adaac03d1d
11 changed files with 7 additions and 92 deletions

View File

@@ -196,7 +196,7 @@ class NullFeatureExtractor(FeatureExtractor):
'functions': {
0x401000: {
'features': [
(0x401000, capa.features.Characteristic('switch')),
(0x401000, capa.features.Characteristic('nzxor')),
],
'basic blocks': {
0x401000: {

View File

@@ -14,16 +14,6 @@ from capa.features import Characteristic
from capa.features.extractors import loops
def extract_function_switch(f):
""" extract switch indicators from a function
arg:
f (IDA func_t)
"""
if capa.features.extractors.ida.helpers.is_function_switch_statement(f):
yield Characteristic("switch"), f.start_ea
def extract_function_calls_to(f):
""" extract callers to a function
@@ -72,7 +62,7 @@ def extract_features(f):
yield feature, ea
FUNCTION_HANDLERS = (extract_function_calls_to, extract_function_switch, extract_function_loop, extract_recursive_call)
FUNCTION_HANDLERS = (extract_function_calls_to, extract_function_loop, extract_recursive_call)
def main():

View File

@@ -300,22 +300,6 @@ def is_function_recursive(f):
return False
def is_function_switch_statement(f):
""" check a function for switch statement indicators
adapted from:
https://reverseengineering.stackexchange.com/questions/17548/calc-switch-cases-in-idapython-cant-iterate-over-results?rq=1
arg:
f (IDA func_t)
"""
for (start, end) in idautils.Chunks(f.start_ea):
for head in idautils.Heads(start, end):
if idaapi.get_switch_info(head):
return True
return False
def is_basic_block_tight_loop(bb):
""" check basic block loops to self

View File

@@ -25,45 +25,6 @@ def interface_extract_function_XXX(f):
yield NotImplementedError("feature"), NotImplementedError("virtual address")
def get_switches(vw):
"""
caching accessor to vivisect workspace switch constructs.
"""
if "switches" in vw.metadata:
return vw.metadata["switches"]
else:
# addresses of switches in the program
switches = set()
for case_va, _ in filter(lambda t: "case" in t[1], vw.getNames()):
# assume that the xref to a case location is a switch construct
for switch_va, _, _, _ in vw.getXrefsTo(case_va):
switches.add(switch_va)
vw.metadata["switches"] = switches
return switches
def get_functions_with_switch(vw):
if "functions_with_switch" in vw.metadata:
return vw.metadata["functions_with_switch"]
else:
functions = set()
for switch in get_switches(vw):
functions.add(vw.getFunction(switch))
vw.metadata["functions_with_switch"] = functions
return functions
def extract_function_switch(f):
"""
parse if a function contains a switch statement based on location names
method can be optimized
"""
if f.va in get_functions_with_switch(f.vw):
yield Characteristic("switch"), f.va
def extract_function_calls_to(f):
for src, _, _, _ in f.vw.getXrefsTo(f.va, rtype=vivisect.const.REF_CODE):
yield Characteristic("calls to"), src
@@ -106,4 +67,4 @@ def extract_features(f):
yield feature, va
FUNCTION_HANDLERS = (extract_function_switch, extract_function_calls_to, extract_function_loop)
FUNCTION_HANDLERS = (extract_function_calls_to, extract_function_loop)

View File

@@ -528,7 +528,7 @@ class CapaExplorerDataModel(QtCore.QAbstractItemModel):
if feature[feature["type"]] in ("embedded pe",):
return CapaExplorerByteViewItem(parent, display, location)
if feature[feature["type"]] in ("loop", "recursive call", "tight loop", "switch"):
if feature[feature["type"]] in ("loop", "recursive call", "tight loop"):
return CapaExplorerFeatureItem(parent, display=display)
# default to instruction view for all other characteristics

View File

@@ -69,7 +69,6 @@ SUPPORTED_FEATURES = {
FUNCTION_SCOPE: {
# plus basic block scope features, see below
capa.features.basicblock.BasicBlock,
capa.features.Characteristic("switch"),
capa.features.Characteristic("calls from"),
capa.features.Characteristic("calls to"),
capa.features.Characteristic("loop"),

View File

@@ -23,7 +23,7 @@ EXTRACTOR = capa.features.extractors.NullFeatureExtractor(
"file features": [(0x402345, capa.features.Characteristic("embedded pe")),],
"functions": {
0x401000: {
"features": [(0x401000, capa.features.Characteristic("switch")),],
"features": [(0x401000, capa.features.Characteristic("indirect call")),],
"basic blocks": {
0x401000: {
"features": [(0x401000, capa.features.Characteristic("tight loop")),],

View File

@@ -243,17 +243,6 @@ def test_stackstring_features():
assert capa.features.Characteristic("stack string") in features
@pytest.mark.skip(reason="IDA Pro tests must be run within IDA")
def test_switch_features():
f = get_extractor().get_function(0x409411)
features = extract_function_features(f)
assert capa.features.Characteristic("switch") in features
f = get_extractor().get_function(0x409393)
features = extract_function_features(f)
assert capa.features.Characteristic("switch") not in features
@pytest.mark.skip(reason="IDA Pro tests must be run within IDA")
def test_function_calls_to():
# this function is used in a function pointer

View File

@@ -73,7 +73,7 @@ def test_ruleset():
name: function rule
scope: function
features:
- characteristic: switch
- characteristic: tight loop
"""
)
),

View File

@@ -267,7 +267,7 @@ def test_subscope_rules():
- function:
- and:
- characteristic: nzxor
- characteristic: switch
- characteristic: loop
"""
)
)

View File

@@ -272,14 +272,6 @@ def test_stackstring_features(mimikatz):
assert capa.features.Characteristic("stack string") in features
def test_switch_features(mimikatz):
features = extract_function_features(viv_utils.Function(mimikatz.vw, 0x409411))
assert capa.features.Characteristic("switch") in features
features = extract_function_features(viv_utils.Function(mimikatz.vw, 0x409393))
assert capa.features.Characteristic("switch") not in features
def test_recursive_call_feature(sample_39c05b15e9834ac93f206bc114d0a00c357c888db567ba8f5345da0529cbed41):
features = extract_function_features(
viv_utils.Function(sample_39c05b15e9834ac93f206bc114d0a00c357c888db567ba8f5345da0529cbed41.vw, 0x10003100)