mirror of
https://github.com/mandiant/capa.git
synced 2026-01-10 04:05:32 -08:00
dotnet: support property feature extraction (#1168)
This commit is contained in:
@@ -36,6 +36,7 @@ from capa.features.common import (
|
||||
Arch,
|
||||
Format,
|
||||
Feature,
|
||||
FeatureAccess,
|
||||
)
|
||||
from capa.features.address import Address
|
||||
from capa.features.extractors.base_extractor import BBHandle, InsnHandle, FunctionHandle
|
||||
@@ -279,6 +280,10 @@ def get_data_path_by_name(name):
|
||||
return os.path.join(CD, "data", "dotnet", "1c444ebeba24dcba8628b7dfe5fec7c6.exe_")
|
||||
elif name.startswith("_692f"):
|
||||
return os.path.join(CD, "data", "dotnet", "692f7fd6d198e804d6af98eb9e390d61.exe_")
|
||||
elif name.startswith("_0953c"):
|
||||
return os.path.join(CD, "data", "0953cc3b77ed2974b09e3a00708f88de931d681e2d0cb64afbaf714610beabe6.exe_")
|
||||
elif name.startswith("_039a6"):
|
||||
return os.path.join(CD, "data", "039a6336d0802a2255669e6867a5679c7eb83313dbc61fb1c7232147379bd304.exe_")
|
||||
else:
|
||||
raise ValueError("unexpected sample fixture: %s" % name)
|
||||
|
||||
@@ -758,6 +763,106 @@ FEATURE_PRESENCE_TESTS_DOTNET = sorted(
|
||||
True,
|
||||
),
|
||||
("_1c444", "function=0x1F68, bb=0x1F68, insn=0x1FF9", capa.features.insn.API("FromHbitmap"), False),
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x600002B",
|
||||
capa.features.insn.Property("System.IO.FileInfo::Length", access=FeatureAccess.READ),
|
||||
True,
|
||||
), # MemberRef method
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x600002B",
|
||||
capa.features.insn.Property("System.IO.FileInfo::Length"),
|
||||
True,
|
||||
), # MemberRef method
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x6000081",
|
||||
capa.features.insn.API("System.Diagnostics.Process::Start"),
|
||||
True,
|
||||
), # MemberRef method
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x6000081",
|
||||
capa.features.insn.Property(
|
||||
"System.Diagnostics.ProcessStartInfo::UseShellExecute", access=FeatureAccess.WRITE
|
||||
), # MemberRef method
|
||||
True,
|
||||
),
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x6000081",
|
||||
capa.features.insn.Property(
|
||||
"System.Diagnostics.ProcessStartInfo::WorkingDirectory", access=FeatureAccess.WRITE
|
||||
), # MemberRef method
|
||||
True,
|
||||
),
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x6000081",
|
||||
capa.features.insn.Property(
|
||||
"System.Diagnostics.ProcessStartInfo::FileName", access=FeatureAccess.WRITE
|
||||
), # MemberRef method
|
||||
True,
|
||||
),
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x6000087",
|
||||
capa.features.insn.Property("Sockets.MySocket::reConnectionDelay", access=FeatureAccess.WRITE), # Field
|
||||
True,
|
||||
),
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x600008A",
|
||||
capa.features.insn.Property("Sockets.MySocket::isConnected", access=FeatureAccess.WRITE), # Field
|
||||
True,
|
||||
),
|
||||
(
|
||||
"_1c444",
|
||||
"token=0x600008A",
|
||||
capa.features.insn.Property("Sockets.MySocket::onConnected", access=FeatureAccess.READ), # Field
|
||||
True,
|
||||
),
|
||||
(
|
||||
"_0953c",
|
||||
"token=0x6000004",
|
||||
capa.features.insn.Property("System.Diagnostics.Debugger::IsAttached", access=FeatureAccess.READ),
|
||||
True,
|
||||
), # MemberRef method
|
||||
(
|
||||
"_692f",
|
||||
"token=0x6000006",
|
||||
capa.features.insn.Property(
|
||||
"System.Management.Automation.PowerShell::Streams", access=FeatureAccess.READ
|
||||
), # MemberRef method
|
||||
False,
|
||||
),
|
||||
(
|
||||
"_039a6",
|
||||
"token=0x6000007",
|
||||
capa.features.insn.API("System.Reflection.Assembly::Load"),
|
||||
True,
|
||||
),
|
||||
(
|
||||
"_039a6",
|
||||
"token=0x600001D",
|
||||
capa.features.insn.Property("StagelessHollow.Arac::Marka", access=FeatureAccess.READ), # MethodDef method
|
||||
True,
|
||||
),
|
||||
(
|
||||
"_039a6",
|
||||
"token=0x600001C",
|
||||
capa.features.insn.Property("StagelessHollow.Arac::Marka", access=FeatureAccess.READ), # MethodDef method
|
||||
False,
|
||||
),
|
||||
(
|
||||
"_039a6",
|
||||
"token=0x6000023",
|
||||
capa.features.insn.Property(
|
||||
"System.Runtime.CompilerServices.AsyncTaskMethodBuilder::Task", access=FeatureAccess.READ
|
||||
), # MemberRef method
|
||||
False,
|
||||
),
|
||||
],
|
||||
# order tests by (file, item)
|
||||
# so that our LRU cache is most effective.
|
||||
@@ -904,3 +1009,13 @@ def _1c444_dotnetfile_extractor():
|
||||
@pytest.fixture
|
||||
def _692f_dotnetfile_extractor():
|
||||
return get_dnfile_extractor(get_data_path_by_name("_692f"))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _0953c_dotnetfile_extractor():
|
||||
return get_dnfile_extractor(get_data_path_by_name("_0953c"))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def _039a6_dotnetfile_extractor():
|
||||
return get_dnfile_extractor(get_data_path_by_name("_039a6"))
|
||||
|
||||
@@ -147,6 +147,10 @@ def test_serialize_features():
|
||||
roundtrip_feature(capa.features.file.Import("kernel32.IsWow64Process"))
|
||||
roundtrip_feature(capa.features.file.Import("#11"))
|
||||
roundtrip_feature(capa.features.insn.OperandOffset(0, 0x8))
|
||||
roundtrip_feature(
|
||||
capa.features.insn.Property("System.IO.FileInfo::Length", access=capa.features.common.FeatureAccess.READ)
|
||||
)
|
||||
roundtrip_feature(capa.features.insn.Property("System.IO.FileInfo::Length"))
|
||||
|
||||
|
||||
def test_freeze_sample(tmpdir, z9324d_extractor):
|
||||
|
||||
@@ -11,7 +11,12 @@ import textwrap
|
||||
|
||||
import fixtures
|
||||
from fixtures import *
|
||||
from fixtures import _692f_dotnetfile_extractor, _1c444_dotnetfile_extractor
|
||||
from fixtures import (
|
||||
_692f_dotnetfile_extractor,
|
||||
_1c444_dotnetfile_extractor,
|
||||
_039a6_dotnetfile_extractor,
|
||||
_0953c_dotnetfile_extractor,
|
||||
)
|
||||
|
||||
import capa.main
|
||||
import capa.rules
|
||||
@@ -469,3 +474,23 @@ def test_main_dotnet2(_692f_dotnetfile_extractor):
|
||||
assert capa.main.main([path, "-j"]) == 0
|
||||
assert capa.main.main([path, "-q"]) == 0
|
||||
assert capa.main.main([path]) == 0
|
||||
|
||||
|
||||
def test_main_dotnet3(_0953c_dotnetfile_extractor):
|
||||
# tests rules can be loaded successfully and all output modes
|
||||
path = _0953c_dotnetfile_extractor.path
|
||||
assert capa.main.main([path, "-vv"]) == 0
|
||||
assert capa.main.main([path, "-v"]) == 0
|
||||
assert capa.main.main([path, "-j"]) == 0
|
||||
assert capa.main.main([path, "-q"]) == 0
|
||||
assert capa.main.main([path]) == 0
|
||||
|
||||
|
||||
def test_main_dotnet4(_039a6_dotnetfile_extractor):
|
||||
# tests rules can be loaded successfully and all output modes
|
||||
path = _039a6_dotnetfile_extractor.path
|
||||
assert capa.main.main([path, "-vv"]) == 0
|
||||
assert capa.main.main([path, "-v"]) == 0
|
||||
assert capa.main.main([path, "-j"]) == 0
|
||||
assert capa.main.main([path, "-q"]) == 0
|
||||
assert capa.main.main([path]) == 0
|
||||
|
||||
@@ -585,3 +585,44 @@ def test_match_operand_offset():
|
||||
# mismatching value
|
||||
_, matches = match([r], {capa.features.insn.OperandOffset(0, 0x11): {1, 2}}, 0x0)
|
||||
assert "test rule" not in matches
|
||||
|
||||
|
||||
def test_match_property_access():
|
||||
rule = textwrap.dedent(
|
||||
"""
|
||||
rule:
|
||||
meta:
|
||||
name: test rule
|
||||
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 {
|
||||
capa.features.insn.Property("System.IO.FileInfo::Length", capa.features.common.FeatureAccess.READ)
|
||||
}
|
||||
|
||||
_, matches = match(
|
||||
[r],
|
||||
{capa.features.insn.Property("System.IO.FileInfo::Length", capa.features.common.FeatureAccess.READ): {1, 2}},
|
||||
0x0,
|
||||
)
|
||||
assert "test rule" in matches
|
||||
|
||||
# mismatching access
|
||||
_, matches = match(
|
||||
[r],
|
||||
{capa.features.insn.Property("System.IO.FileInfo::Length", capa.features.common.FeatureAccess.WRITE): {1, 2}},
|
||||
0x0,
|
||||
)
|
||||
assert "test rule" not in matches
|
||||
|
||||
# mismatching value
|
||||
_, matches = match(
|
||||
[r],
|
||||
{capa.features.insn.Property("System.IO.FileInfo::Size", capa.features.common.FeatureAccess.READ): {1, 2}},
|
||||
0x0,
|
||||
)
|
||||
assert "test rule" not in matches
|
||||
|
||||
@@ -15,6 +15,13 @@ def test_render_offset():
|
||||
assert str(capa.features.insn.Offset(1)) == "offset(0x1)"
|
||||
|
||||
|
||||
def test_render_property():
|
||||
assert (
|
||||
str(capa.features.insn.Property("System.IO.FileInfo::Length", access=capa.features.common.FeatureAccess.READ))
|
||||
== "property/read(System.IO.FileInfo::Length)"
|
||||
)
|
||||
|
||||
|
||||
def test_render_meta_attack():
|
||||
# Persistence::Boot or Logon Autostart Execution::Registry Run Keys / Startup Folder [T1547.001]
|
||||
id = "T1543.003"
|
||||
|
||||
@@ -14,7 +14,7 @@ import capa.rules
|
||||
import capa.engine
|
||||
import capa.features.common
|
||||
from capa.features.file import FunctionName
|
||||
from capa.features.insn import Number, Offset
|
||||
from capa.features.insn import Number, Offset, Property
|
||||
from capa.features.common import (
|
||||
OS,
|
||||
OS_LINUX,
|
||||
@@ -27,6 +27,7 @@ from capa.features.common import (
|
||||
Format,
|
||||
String,
|
||||
Substring,
|
||||
FeatureAccess,
|
||||
)
|
||||
|
||||
|
||||
@@ -951,3 +952,41 @@ def test_arch_features():
|
||||
children = list(r.statement.get_children())
|
||||
assert (Arch(ARCH_AMD64) in children) == True
|
||||
assert (Arch(ARCH_I386) not in children) == True
|
||||
|
||||
|
||||
def test_property_access():
|
||||
r = capa.rules.Rule.from_yaml(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
rule:
|
||||
meta:
|
||||
name: test rule
|
||||
features:
|
||||
- property/read: System.IO.FileInfo::Length
|
||||
"""
|
||||
)
|
||||
)
|
||||
assert r.evaluate({Property("System.IO.FileInfo::Length", access=FeatureAccess.READ): {1}}) == True
|
||||
|
||||
assert r.evaluate({Property("System.IO.FileInfo::Length"): {1}}) == False
|
||||
assert r.evaluate({Property("System.IO.FileInfo::Length", access=FeatureAccess.WRITE): {1}}) == False
|
||||
|
||||
|
||||
def test_property_access_symbol():
|
||||
r = capa.rules.Rule.from_yaml(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
rule:
|
||||
meta:
|
||||
name: test rule
|
||||
features:
|
||||
- property/read: System.IO.FileInfo::Length = some property
|
||||
"""
|
||||
)
|
||||
)
|
||||
assert (
|
||||
r.evaluate(
|
||||
{Property("System.IO.FileInfo::Length", access=FeatureAccess.READ, description="some property"): {1}}
|
||||
)
|
||||
== True
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user