From a5d9459c427a15a3790f61453afdb1c3c67cf35a Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Thu, 26 Sep 2024 14:15:21 -0600 Subject: [PATCH 1/5] dynamic: vmray: fix A/W API detection --- capa/features/extractors/vmray/call.py | 4 +++- tests/test_vmray_features.py | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/capa/features/extractors/vmray/call.py b/capa/features/extractors/vmray/call.py index 436b4bebb..6b87d7d89 100644 --- a/capa/features/extractors/vmray/call.py +++ b/capa/features/extractors/vmray/call.py @@ -8,6 +8,7 @@ import logging from typing import Tuple, Iterator +import capa.features.extractors.helpers from capa.features.insn import API, Number from capa.features.common import String, Feature from capa.features.address import Address @@ -41,7 +42,8 @@ def extract_call_features(ph: ProcessHandle, th: ThreadHandle, ch: CallHandle) - for param in call.params_in.params: yield from get_call_param_features(param, ch) - yield API(call.name), ch.address + for name in capa.features.extractors.helpers.generate_symbols("", call.name): + yield API(name), ch.address def extract_features(ph: ProcessHandle, th: ThreadHandle, ch: CallHandle) -> Iterator[Tuple[Feature, Address]]: diff --git a/tests/test_vmray_features.py b/tests/test_vmray_features.py index 02eb683ec..02dabafd9 100644 --- a/tests/test_vmray_features.py +++ b/tests/test_vmray_features.py @@ -19,8 +19,13 @@ ("93b2d1-vmray", "file", capa.features.common.String("\\Program Files\\WindowsApps\\does_not_exist"), False), # file/imports ("93b2d1-vmray", "file", capa.features.file.Import("GetAddrInfoW"), True), + ("93b2d1-vmray", "file", capa.features.file.Import("GetAddrInfo"), True), # thread/api calls + ("93b2d1-vmray", "process=(2176:0),thread=2180", capa.features.insn.API("LoadLibraryExA"), True), + ("93b2d1-vmray", "process=(2176:0),thread=2180", capa.features.insn.API("LoadLibraryEx"), True), ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("GetAddrInfoW"), True), + ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("GetAddrInfo"), True), + ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("GetAddrInfo"), True), ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("DoesNotExist"), False), # call/api ("93b2d1-vmray", "process=(2176:0),thread=2420,call=2361", capa.features.insn.API("GetAddrInfoW"), True), From 31ec208a9bfdab4cb1b482a49f92ca4cfd3c1a54 Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Thu, 26 Sep 2024 14:27:45 -0600 Subject: [PATCH 2/5] dynamic: cape: fix A/W API detection --- capa/features/extractors/cape/call.py | 4 +++- tests/test_cape_features.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/capa/features/extractors/cape/call.py b/capa/features/extractors/cape/call.py index 88680b3fa..0bee22fcc 100644 --- a/capa/features/extractors/cape/call.py +++ b/capa/features/extractors/cape/call.py @@ -9,6 +9,7 @@ import logging from typing import Tuple, Iterator +import capa.features.extractors.helpers from capa.helpers import assert_never from capa.features.insn import API, Number from capa.features.common import String, Feature @@ -50,7 +51,8 @@ def extract_call_features(ph: ProcessHandle, th: ThreadHandle, ch: CallHandle) - else: assert_never(value) - yield API(call.api), ch.address + for name in capa.features.extractors.helpers.generate_symbols("", call.api): + yield API(name), ch.address def extract_features(ph: ProcessHandle, th: ThreadHandle, ch: CallHandle) -> Iterator[Tuple[Feature, Address]]: diff --git a/tests/test_cape_features.py b/tests/test_cape_features.py index d72caa9ab..ade933e73 100644 --- a/tests/test_cape_features.py +++ b/tests/test_cape_features.py @@ -37,6 +37,8 @@ ), ("0000a657", "process=(1180:3052)", capa.features.common.String("nope"), False), # thread/api calls + ("0000a657", "process=(2900:2852),thread=2904", capa.features.insn.API("RegQueryValueExA"), True), + ("0000a657", "process=(2900:2852),thread=2904", capa.features.insn.API("RegQueryValueEx"), True), ("0000a657", "process=(2852:3052),thread=2804", capa.features.insn.API("NtQueryValueKey"), True), ("0000a657", "process=(2852:3052),thread=2804", capa.features.insn.API("GetActiveWindow"), False), # thread/number call argument From 834150ad1d9ea4f86459acd3314ee34422511942 Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Thu, 26 Sep 2024 14:36:16 -0600 Subject: [PATCH 3/5] dynamic: drakvuf: fix A/W API detection --- capa/features/extractors/drakvuf/call.py | 4 +++- tests/test_drakvuf_features.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/capa/features/extractors/drakvuf/call.py b/capa/features/extractors/drakvuf/call.py index 34e877acc..7d0e2a5ee 100644 --- a/capa/features/extractors/drakvuf/call.py +++ b/capa/features/extractors/drakvuf/call.py @@ -9,6 +9,7 @@ import logging from typing import Tuple, Iterator +import capa.features.extractors.helpers from capa.features.insn import API, Number from capa.features.common import String, Feature from capa.features.address import Address @@ -44,7 +45,8 @@ def extract_call_features(ph: ProcessHandle, th: ThreadHandle, ch: CallHandle) - # but yielding the entire string would be helpful for an analyst looking at the verbose output yield String(arg_value), ch.address - yield API(call.name), ch.address + for name in capa.features.extractors.helpers.generate_symbols("", call.name): + yield API(name), ch.address def extract_features(ph: ProcessHandle, th: ThreadHandle, ch: CallHandle) -> Iterator[Tuple[Feature, Address]]: diff --git a/tests/test_drakvuf_features.py b/tests/test_drakvuf_features.py index 61fe69442..132b02ddc 100644 --- a/tests/test_drakvuf_features.py +++ b/tests/test_drakvuf_features.py @@ -22,6 +22,8 @@ ("93b2d1-drakvuf", "process=(3564:4852),thread=6592", capa.features.insn.API("LdrLoadDll"), True), ("93b2d1-drakvuf", "process=(3564:4852),thread=6592", capa.features.insn.API("DoesNotExist"), False), # call/api + ("93b2d1-drakvuf", "process=(3564:4852),thread=4716,call=17", capa.features.insn.API("CreateWindowExW"), True), + ("93b2d1-drakvuf", "process=(3564:4852),thread=4716,call=17", capa.features.insn.API("CreateWindowEx"), True), ("93b2d1-drakvuf", "process=(3564:4852),thread=6592,call=1", capa.features.insn.API("LdrLoadDll"), True), ("93b2d1-drakvuf", "process=(3564:4852),thread=6592,call=1", capa.features.insn.API("DoesNotExist"), False), # call/string argument From bfcc7051173f9eac441a86fff17b0c1db0d2cc27 Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Thu, 26 Sep 2024 14:42:08 -0600 Subject: [PATCH 4/5] dynamic: vmray: remove redundant test --- tests/test_vmray_features.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_vmray_features.py b/tests/test_vmray_features.py index 02dabafd9..e0803236d 100644 --- a/tests/test_vmray_features.py +++ b/tests/test_vmray_features.py @@ -25,7 +25,6 @@ ("93b2d1-vmray", "process=(2176:0),thread=2180", capa.features.insn.API("LoadLibraryEx"), True), ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("GetAddrInfoW"), True), ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("GetAddrInfo"), True), - ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("GetAddrInfo"), True), ("93b2d1-vmray", "process=(2176:0),thread=2420", capa.features.insn.API("DoesNotExist"), False), # call/api ("93b2d1-vmray", "process=(2176:0),thread=2420,call=2361", capa.features.insn.API("GetAddrInfoW"), True), From 80e007787c58313d8d4171947aa67063eb03433b Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Thu, 26 Sep 2024 14:43:20 -0600 Subject: [PATCH 5/5] dynamic: update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2edd08c5c..bdd3e6248 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - use Python 3.12 to build extra standalone build on Linux #2383 @williballenthin - bump minimum Python version to 3.8.1 to satisfy uv #2387 @williballenthin - vmray: collect more process information from flog.xml #2394 @mr-tz @mike-hunhoff +- dynamic: emit complete features for A/W APIs #2409 @mike-hunhoff ### capa explorer IDA Pro plugin