-
Notifications
You must be signed in to change notification settings - Fork 642
dynamic: add extractor for VMRay dynamic sandbox traces #2208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
125 commits
Select commit
Hold shift + click to select a range
3141e94
Add vmray text to JSON parser.
mid-life-crustacean bdc94c1
Merge branch 'master' into vmray_extractor
mid-life-crustacean a9dafe2
example using pydantic-xml to parse flog.xml
mr-tz a797405
vmray: add example models for summary_v2.json
mike-hunhoff ca02b4a
vmray: expand extractor to emit file export features
mike-hunhoff 970b184
vmray: add stubs for file imports
mike-hunhoff 7d0ac71
vmray: cleanup pydantic models and implement file section extraction
mike-hunhoff 8d3f032
vmray: clean up pydantic models and implement base address extraction
mike-hunhoff 346a069
vmray: clean up VMRayAnalysis
mike-hunhoff 7e079d4
vmray: restrict analysis to PE files
mike-hunhoff 00cb792
vmray: clean up pydantic models and add sample hash extraction
mike-hunhoff 8b913e0
vmray: extract global features for PE files
mike-hunhoff 6548048
vmray: clean up global_.py debug output
mike-hunhoff 51656fe
vmray: merge upstream
mike-hunhoff f3d6952
vmray: invoke VMRay feature extractor from capa.main
mike-hunhoff 8f32b7f
vmray: emit process handles
mike-hunhoff b3ebf80
vmray: emit process name
mike-hunhoff be274d1
Merge branch 'mandiant:master' into vmray_extractor
mid-life-crustacean e5fa800
vmray: emit empty thread features
mike-hunhoff d26a806
vmray: update scripts/show-features.py to emit process name from extr…
mike-hunhoff 2b70086
Add VMRayanalysis model and call parser
mid-life-crustacean 3cca808
Add VMRayanalysis model and call parser
mid-life-crustacean 574d61a
Add VMRayanalysis model and call parser
mid-life-crustacean 85a85e9
vmray: emit recorded artifacts as strings
mike-hunhoff 789332e
Merge branch 'vmray-extractor' into vmray_extractor
mid-life-crustacean 21887d1
vmray: merge upstream
mike-hunhoff a1a1712
Merge branch 'vmray-extractor' into vmray_extractor
mr-tz a544aed
add vmray-extractor branch for tests
mr-tz d10b396
add pydantic-xml dependency
mr-tz 453a640
formatting
mr-tz fbdfea1
add testing code
mr-tz d256cc8
update model and re-add summary_v2.json models
mr-tz 740c739
remove file
mr-tz 0c9d3d0
fix ruff
mr-tz 8757dad
Merge pull request #2155 from r-sm2024/vmray_extractor
mr-tz 5be68d0
vmray: remove debug code and update call features entry point
mike-hunhoff ec21f3b
vmray: use xmltodict instead of pydantic_xml to improve performance
mike-hunhoff 19502ef
vmray: connect process, thread, and call
mike-hunhoff 9ef705a
vmray: remove old comments
mike-hunhoff 544899a
vmray: add os v. monitor id comment
mike-hunhoff 4b08e62
vmray: fix flake8 lints
mike-hunhoff 29fa315
vmray: fix deptry lints
mike-hunhoff 9df611f
vmray: add comments
mike-hunhoff ec6c9c9
vmray: remove unused fields from summary_v2 pydantic models
mike-hunhoff 9be35f9
vmray: remove unneeded unpacking
mike-hunhoff d1f6bb3
Merge branch 'master' into vmray-extractor
mr-tz 194017b
vmray: merge upstream
mike-hunhoff 81581fe
vmray: emit string file featureS
mike-hunhoff cbf6ecb
Merge branch 'vmray-extractor' of github.com:mandiant/capa into vmray…
mike-hunhoff aad4854
vmray: use process OS PID instead of monitor ID
mike-hunhoff bcdaa80
vmray: emit file import features
mike-hunhoff da05457
vmray: emit number call features for input parameters
mike-hunhoff 5b7a0ca
vmray: emit number call features for output parameters
mike-hunhoff e2f5eb7
vmray: clean up models
mike-hunhoff 4bbe9e1
vmray: emit number and string call features for pointer dereference
mike-hunhoff 06631fc
vmray: remove call feature extraction for out parameters
mike-hunhoff 931a9b9
vmray: clean up models
mike-hunhoff 85632f6
vmray: clean up models
mike-hunhoff 253d70e
vmray: add comments
mike-hunhoff 307b0cc
vmray: add comments
mike-hunhoff 1f5b6ec
vmray: improve comments
mike-hunhoff 26b5870
vmray: improve comments
mike-hunhoff 28c278b
vmray: improve comments
mike-hunhoff 4f2467c
vmray: update CHANGELOG
mike-hunhoff 5214675
vmray: update tests.yml
mike-hunhoff 42fddfb
vmray: improve comments
mike-hunhoff af26bef
vmray: fix lints
mike-hunhoff 1588974
vmray: merge upstream
mike-hunhoff b68a91e
vmray: validate supported flog version
mike-hunhoff ec7e431
vmray: update comment for extract_process_features
mike-hunhoff cc87ef3
vmray: remove and document extract_call_features comments
mike-hunhoff 100df45
vmray: add logging for skipped deref param types
mike-hunhoff 19a6f3a
vmray: improve supported file type validation
mike-hunhoff 330c77a
vmray: implement get_call_name
mike-hunhoff fd7bd94
vmray: remove outdated comments
mike-hunhoff 5afea29
vmray: update CHANGELOG release notes with VMRay integration
mike-hunhoff 998537d
vmray: remove outdated comments
mike-hunhoff 64a09d3
vmray: remove broken assert for unique OS PIDs
mike-hunhoff 6f7cc7c
vmray: improve detections for unsupported input files
mike-hunhoff 24a31a8
vmray: add comments to __init__.py
mike-hunhoff 8bf0d16
vmray: add init support for ELF files
mike-hunhoff 6e0dc83
vmray: refactor global_.py
mike-hunhoff 673f7cc
vmray: refactor models.py
mike-hunhoff 658927c
vmray: refactor models.py
mike-hunhoff 28792ec
vmray: add model tests for FunctionCall
mike-hunhoff 2ba2a2b
vmray: remove unneeded json.loads from __init__.py
mike-hunhoff 4490097
vmray: add summary_v2.json model tests
mike-hunhoff 98939f8
vmray: improve FunctionCall model
mike-hunhoff 4dfc53a
vmray: refactor model tests
mike-hunhoff 6ef485f
vmray: refactor model tests
mike-hunhoff 3b94961
vmray: complete pefile model tests
mike-hunhoff 46b68d1
vmray: improve models.py comments
mike-hunhoff cbdc744
vmray: merge upstream
mike-hunhoff 31e53fa
vmray: improve models.py comments
mike-hunhoff f471386
vmray: merge upstream and fix conflicts
mike-hunhoff f6d12bc
vmray: fix lints
mike-hunhoff 85373a7
cape: add explicit check for CAPE report format file extension
mike-hunhoff 6e146bb
vmray: fix lints
mike-hunhoff 9a1364c
vmray: document vmray support in README
mike-hunhoff b8d3d77
vmray: document vmray support in README
mike-hunhoff 5b7a2be
vmray: remove outdated comments __init__.py
mike-hunhoff 7b3812a
vmray: improve error reporting
mike-hunhoff 05fb8f6
vmray: fix flake8 lints
mike-hunhoff b967213
vmray: improve comments __init__.py
mike-hunhoff 3043fd6
vmray: merge upstream
mike-hunhoff 51b853d
vmray: remove bad print statements
mike-hunhoff 1a3cf4a
vmray: update extractor.py format_params
mike-hunhoff 8cba23b
vmray: improve extract_import_names
mike-hunhoff 87dfa50
scripts: remove old code from show-features.py
mike-hunhoff 7bf0b39
core: improve error message for vmray
mike-hunhoff 139dcc4
vmray: improve logging
mike-hunhoff 71c515d
vmray: improve comments __init__.py
mike-hunhoff a8d849e
vmray: improve comments models.py
mike-hunhoff 3982356
load gzipped rd, see capa-testfiles#245
mr-tz e83f289
add script to minimize vmray archive to only relevant files
mr-tz e476354
add dynamic vmray feature tests
mr-tz afb7286
assert sample analysis data is present
mr-tz c0a7f76
Merge branch 'master' into vmray-extractor
mr-tz 6ff08ae
Merge branch 'master' into vmray-extractor
yelhamer d98c315
Merge branch 'master' into vmray-extractor
mr-tz e8550f2
rename using dashes for consistency
mr-tz 9eab7eb
update names
mr-tz 6ce130e
Merge branch 'master' into vmray-extractor
mr-tz e468116
Merge branch 'vmray-extractor' of github.com:mandiant/capa into vmray…
mr-tz fa92cfd
Merge branch 'master' into vmray-extractor
mr-tz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| # Copyright (C) 2024 Mandiant, Inc. All Rights Reserved. | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at: [package root]/LICENSE.txt | ||
| # Unless required by applicable law or agreed to in writing, software distributed under the License | ||
| # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and limitations under the License. | ||
| import logging | ||
| from typing import Dict, List, Tuple, Optional | ||
| from pathlib import Path | ||
| from zipfile import ZipFile | ||
| from collections import defaultdict | ||
|
|
||
| from capa.exceptions import UnsupportedFormatError | ||
| from capa.features.extractors.vmray.models import File, Flog, SummaryV2, StaticData, FunctionCall, xml_to_dict | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| DEFAULT_ARCHIVE_PASSWORD = b"infected" | ||
|
|
||
| SUPPORTED_FLOG_VERSIONS = ("2",) | ||
|
|
||
|
|
||
| class VMRayAnalysis: | ||
| def __init__(self, zipfile_path: Path): | ||
| self.zipfile = ZipFile(zipfile_path, "r") | ||
|
|
||
| # summary_v2.json is the entry point to the entire VMRay archive and | ||
| # we use its data to find everything else that we need for capa | ||
mike-hunhoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self.sv2 = SummaryV2.model_validate_json( | ||
| self.zipfile.read("logs/summary_v2.json", pwd=DEFAULT_ARCHIVE_PASSWORD) | ||
| ) | ||
| self.file_type: str = self.sv2.analysis_metadata.sample_type | ||
|
|
||
| # flog.xml contains all of the call information that VMRay captured during execution | ||
| flog_xml = self.zipfile.read("logs/flog.xml", pwd=DEFAULT_ARCHIVE_PASSWORD) | ||
| flog_dict = xml_to_dict(flog_xml) | ||
| self.flog = Flog.model_validate(flog_dict) | ||
|
|
||
| if self.flog.analysis.log_version not in SUPPORTED_FLOG_VERSIONS: | ||
| raise UnsupportedFormatError( | ||
| "VMRay feature extractor does not support flog version %s" % self.flog.analysis.log_version | ||
| ) | ||
|
|
||
| self.exports: Dict[int, str] = {} | ||
| self.imports: Dict[int, Tuple[str, str]] = {} | ||
| self.sections: Dict[int, str] = {} | ||
| self.process_ids: Dict[int, int] = {} | ||
| self.process_threads: Dict[int, List[int]] = defaultdict(list) | ||
| self.process_calls: Dict[int, Dict[int, List[FunctionCall]]] = defaultdict(lambda: defaultdict(list)) | ||
| self.base_address: int | ||
|
|
||
| self.sample_file_name: Optional[str] = None | ||
| self.sample_file_analysis: Optional[File] = None | ||
| self.sample_file_static_data: Optional[StaticData] = None | ||
|
|
||
| self._find_sample_file() | ||
|
|
||
| # VMRay analysis archives in various shapes and sizes and file type does not definitively tell us what data | ||
| # we can expect to find in the archive, so to be explicit we check for the various pieces that we need at | ||
| # minimum to run capa analysis | ||
| if self.sample_file_name is None or self.sample_file_analysis is None: | ||
| raise UnsupportedFormatError("VMRay archive does not contain sample file (file_type: %s)" % self.file_type) | ||
|
|
||
| if not self.sample_file_static_data: | ||
| raise UnsupportedFormatError("VMRay archive does not contain static data (file_type: %s)" % self.file_type) | ||
|
|
||
| if not self.sample_file_static_data.pe and not self.sample_file_static_data.elf: | ||
| raise UnsupportedFormatError( | ||
| "VMRay feature extractor only supports PE and ELF at this time (file_type: %s)" % self.file_type | ||
| ) | ||
|
|
||
| # VMRay does not store static strings for the sample file so we must use the source file | ||
| # stored in the archive | ||
| sample_sha256: str = self.sample_file_analysis.hash_values.sha256.lower() | ||
| sample_file_path: str = f"internal/static_analyses/{sample_sha256}/objects/files/{sample_sha256}" | ||
|
|
||
| logger.debug("file_type: %s, file_path: %s", self.file_type, sample_file_path) | ||
|
|
||
| self.sample_file_buf: bytes = self.zipfile.read(sample_file_path, pwd=DEFAULT_ARCHIVE_PASSWORD) | ||
|
|
||
| self._compute_base_address() | ||
| self._compute_imports() | ||
| self._compute_exports() | ||
| self._compute_sections() | ||
| self._compute_process_ids() | ||
| self._compute_process_threads() | ||
| self._compute_process_calls() | ||
|
|
||
| def _find_sample_file(self): | ||
| for file_name, file_analysis in self.sv2.files.items(): | ||
| if file_analysis.is_sample: | ||
| # target the sample submitted for analysis | ||
| self.sample_file_name = file_name | ||
| self.sample_file_analysis = file_analysis | ||
|
|
||
| if file_analysis.ref_static_data: | ||
| # like "path": ["static_data","static_data_0"] where "static_data_0" is the summary_v2 static data | ||
| # key for the file's static data | ||
| self.sample_file_static_data = self.sv2.static_data[file_analysis.ref_static_data.path[1]] | ||
mike-hunhoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| break | ||
mike-hunhoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def _compute_base_address(self): | ||
| assert self.sample_file_static_data is not None | ||
mike-hunhoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if self.sample_file_static_data.pe: | ||
| self.base_address = self.sample_file_static_data.pe.basic_info.image_base | ||
|
|
||
| def _compute_exports(self): | ||
| assert self.sample_file_static_data is not None | ||
| if self.sample_file_static_data.pe: | ||
| for export in self.sample_file_static_data.pe.exports: | ||
| self.exports[export.address] = export.api.name | ||
|
|
||
| def _compute_imports(self): | ||
| assert self.sample_file_static_data is not None | ||
| if self.sample_file_static_data.pe: | ||
| for module in self.sample_file_static_data.pe.imports: | ||
| for api in module.apis: | ||
| self.imports[api.address] = (module.dll, api.api.name) | ||
|
|
||
| def _compute_sections(self): | ||
| assert self.sample_file_static_data is not None | ||
| if self.sample_file_static_data.pe: | ||
| for pefile_section in self.sample_file_static_data.pe.sections: | ||
| self.sections[pefile_section.virtual_address] = pefile_section.name | ||
| elif self.sample_file_static_data.elf: | ||
| for elffile_section in self.sample_file_static_data.elf.sections: | ||
| self.sections[elffile_section.header.sh_addr] = elffile_section.header.sh_name | ||
|
|
||
| def _compute_process_ids(self): | ||
| for process in self.sv2.processes.values(): | ||
| # we expect VMRay's monitor IDs to be unique, but OS PIDs may be reused | ||
| assert process.monitor_id not in self.process_ids.keys() | ||
| self.process_ids[process.monitor_id] = process.os_pid | ||
|
|
||
| def _compute_process_threads(self): | ||
| # logs/flog.xml appears to be the only file that contains thread-related data | ||
| # so we use it here to map processes to threads | ||
| for function_call in self.flog.analysis.function_calls: | ||
| pid: int = self.get_process_os_pid(function_call.process_id) # flog.xml uses process monitor ID, not OS PID | ||
| tid: int = function_call.thread_id | ||
|
|
||
| assert isinstance(pid, int) | ||
| assert isinstance(tid, int) | ||
|
|
||
| if tid not in self.process_threads[pid]: | ||
| self.process_threads[pid].append(tid) | ||
|
|
||
| def _compute_process_calls(self): | ||
| for function_call in self.flog.analysis.function_calls: | ||
| pid: int = self.get_process_os_pid(function_call.process_id) # flog.xml uses process monitor ID, not OS PID | ||
| tid: int = function_call.thread_id | ||
|
|
||
| assert isinstance(pid, int) | ||
| assert isinstance(tid, int) | ||
|
|
||
| self.process_calls[pid][tid].append(function_call) | ||
|
|
||
| def get_process_os_pid(self, monitor_id: int) -> int: | ||
| return self.process_ids[monitor_id] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| # Copyright (C) 2024 Mandiant, Inc. All Rights Reserved. | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at: [package root]/LICENSE.txt | ||
| # Unless required by applicable law or agreed to in writing, software distributed under the License | ||
| # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and limitations under the License. | ||
| import logging | ||
| from typing import Tuple, Iterator | ||
|
|
||
| from capa.features.insn import API, Number | ||
| from capa.features.common import String, Feature | ||
| from capa.features.address import Address | ||
| from capa.features.extractors.vmray.models import PARAM_TYPE_INT, PARAM_TYPE_STR, Param, FunctionCall, hexint | ||
| from capa.features.extractors.base_extractor import CallHandle, ThreadHandle, ProcessHandle | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| def get_call_param_features(param: Param, ch: CallHandle) -> Iterator[Tuple[Feature, Address]]: | ||
| if param.deref is not None: | ||
| # pointer types contain a special "deref" member that stores the deref'd value | ||
| # so we check for this first and ignore Param.value as this always contains the | ||
| # deref'd pointer value | ||
| if param.deref.value is not None: | ||
| if param.deref.type_ in PARAM_TYPE_INT: | ||
| yield Number(hexint(param.deref.value)), ch.address | ||
| elif param.deref.type_ in PARAM_TYPE_STR: | ||
| yield String(param.deref.value), ch.address | ||
mike-hunhoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| else: | ||
| logger.debug("skipping deref param type %s", param.deref.type_) | ||
| elif param.value is not None: | ||
| if param.type_ in PARAM_TYPE_INT: | ||
| yield Number(hexint(param.value)), ch.address | ||
|
|
||
|
|
||
| def extract_call_features(ph: ProcessHandle, th: ThreadHandle, ch: CallHandle) -> Iterator[Tuple[Feature, Address]]: | ||
| call: FunctionCall = ch.inner | ||
|
|
||
| if call.params_in: | ||
| for param in call.params_in.params: | ||
| yield from get_call_param_features(param, ch) | ||
|
|
||
| yield API(call.name), ch.address | ||
|
|
||
|
|
||
| def extract_features(ph: ProcessHandle, th: ThreadHandle, ch: CallHandle) -> Iterator[Tuple[Feature, Address]]: | ||
| for handler in CALL_HANDLERS: | ||
| for feature, addr in handler(ph, th, ch): | ||
| yield feature, addr | ||
|
|
||
|
|
||
| CALL_HANDLERS = (extract_call_features,) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| # Copyright (C) 2024 Mandiant, Inc. All Rights Reserved. | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at: [package root]/LICENSE.txt | ||
| # Unless required by applicable law or agreed to in writing, software distributed under the License | ||
| # is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and limitations under the License. | ||
|
|
||
|
|
||
| from typing import List, Tuple, Iterator | ||
| from pathlib import Path | ||
|
|
||
| import capa.helpers | ||
| import capa.features.extractors.vmray.call | ||
| import capa.features.extractors.vmray.file | ||
| import capa.features.extractors.vmray.global_ | ||
| from capa.features.common import Feature, Characteristic | ||
| from capa.features.address import NO_ADDRESS, Address, ThreadAddress, DynamicCallAddress, AbsoluteVirtualAddress | ||
| from capa.features.extractors.vmray import VMRayAnalysis | ||
| from capa.features.extractors.vmray.models import PARAM_TYPE_STR, Process, ParamList, FunctionCall | ||
| from capa.features.extractors.base_extractor import ( | ||
| CallHandle, | ||
| SampleHashes, | ||
| ThreadHandle, | ||
| ProcessHandle, | ||
| DynamicFeatureExtractor, | ||
| ) | ||
|
|
||
|
|
||
| def get_formatted_params(params: ParamList) -> List[str]: | ||
| params_list: List[str] = [] | ||
|
|
||
| for param in params: | ||
| if param.deref and param.deref.value is not None: | ||
| deref_value: str = f'"{param.deref.value}"' if param.deref.type_ in PARAM_TYPE_STR else param.deref.value | ||
| params_list.append(f"{param.name}: {deref_value}") | ||
| else: | ||
| value: str = "" if param.value is None else param.value | ||
| params_list.append(f"{param.name}: {value}") | ||
|
|
||
| return params_list | ||
|
|
||
|
|
||
| class VMRayExtractor(DynamicFeatureExtractor): | ||
| def __init__(self, analysis: VMRayAnalysis): | ||
| assert analysis.sample_file_analysis is not None | ||
|
|
||
| super().__init__( | ||
| hashes=SampleHashes( | ||
| md5=analysis.sample_file_analysis.hash_values.md5.lower(), | ||
| sha1=analysis.sample_file_analysis.hash_values.sha1.lower(), | ||
| sha256=analysis.sample_file_analysis.hash_values.sha256.lower(), | ||
| ) | ||
| ) | ||
|
|
||
| self.analysis = analysis | ||
|
|
||
| # pre-compute these because we'll yield them at *every* scope. | ||
| self.global_features = list(capa.features.extractors.vmray.global_.extract_features(self.analysis)) | ||
|
|
||
| def get_base_address(self) -> Address: | ||
| # value according to the PE header, the actual trace may use a different imagebase | ||
| return AbsoluteVirtualAddress(self.analysis.base_address) | ||
|
|
||
| def extract_file_features(self) -> Iterator[Tuple[Feature, Address]]: | ||
| yield from capa.features.extractors.vmray.file.extract_features(self.analysis) | ||
|
|
||
| def extract_global_features(self) -> Iterator[Tuple[Feature, Address]]: | ||
| yield from self.global_features | ||
|
|
||
| def get_processes(self) -> Iterator[ProcessHandle]: | ||
| yield from capa.features.extractors.vmray.file.get_processes(self.analysis) | ||
|
|
||
| def extract_process_features(self, ph: ProcessHandle) -> Iterator[Tuple[Feature, Address]]: | ||
| # we have not identified process-specific features for VMRay yet | ||
| yield from [] | ||
|
|
||
| def get_process_name(self, ph) -> str: | ||
| process: Process = ph.inner | ||
| return process.image_name | ||
|
|
||
| def get_threads(self, ph: ProcessHandle) -> Iterator[ThreadHandle]: | ||
| for thread in self.analysis.process_threads[ph.address.pid]: | ||
| address: ThreadAddress = ThreadAddress(process=ph.address, tid=thread) | ||
| yield ThreadHandle(address=address, inner={}) | ||
|
|
||
| def extract_thread_features(self, ph: ProcessHandle, th: ThreadHandle) -> Iterator[Tuple[Feature, Address]]: | ||
| if False: | ||
| # force this routine to be a generator, | ||
| # but we don't actually have any elements to generate. | ||
| yield Characteristic("never"), NO_ADDRESS | ||
| return | ||
|
|
||
| def get_calls(self, ph: ProcessHandle, th: ThreadHandle) -> Iterator[CallHandle]: | ||
| for function_call in self.analysis.process_calls[ph.address.pid][th.address.tid]: | ||
| addr = DynamicCallAddress(thread=th.address, id=function_call.fncall_id) | ||
| yield CallHandle(address=addr, inner=function_call) | ||
|
|
||
| def extract_call_features( | ||
| self, ph: ProcessHandle, th: ThreadHandle, ch: CallHandle | ||
| ) -> Iterator[Tuple[Feature, Address]]: | ||
| yield from capa.features.extractors.vmray.call.extract_features(ph, th, ch) | ||
|
|
||
| def get_call_name(self, ph, th, ch) -> str: | ||
| call: FunctionCall = ch.inner | ||
| call_formatted: str = call.name | ||
|
|
||
| # format input parameters | ||
| if call.params_in: | ||
| call_formatted += f"({', '.join(get_formatted_params(call.params_in.params))})" | ||
| else: | ||
| call_formatted += "()" | ||
|
|
||
| # format output parameters | ||
| if call.params_out: | ||
| call_formatted += f" -> {', '.join(get_formatted_params(call.params_out.params))}" | ||
|
|
||
| return call_formatted | ||
|
|
||
| @classmethod | ||
| def from_zipfile(cls, zipfile_path: Path): | ||
| return cls(VMRayAnalysis(zipfile_path)) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.