Skip to content
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

Bugfix: Only list discovered components in the GUI #313

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions ofrak_core/ofrak/core/elf/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class ElfBasicHeaderAttributesAnalyzer(Analyzer[None, ElfBasicHeader]):
<https://man7.org/linux/man-pages/man5/elf.5.html> for details.
"""

id = b"ElfHeaderMetadataAttributesAnalyzer"
targets = (ElfBasicHeader,)
outputs = (ElfBasicHeader,)

Expand Down Expand Up @@ -218,7 +217,6 @@ class ElfSymbolAttributesAnalyzer(Analyzer[None, ElfSymbol]):
table.
"""

id = b"ElfSymbolAnalyzer"
targets = (ElfSymbol,)
outputs = (ElfSymbol,)

Expand Down
69 changes: 41 additions & 28 deletions ofrak_core/ofrak/gui/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from enum import Enum
import functools
import itertools
import json
import logging

import typing_inspect
Expand Down Expand Up @@ -38,7 +37,14 @@
from dataclasses import fields

from ofrak.component.interface import ComponentInterface
from ofrak.model.component_filters import (
ComponentOrMetaFilter,
ComponentTypeFilter,
ComponentTargetFilter,
ComponentAndMetaFilter,
)
from ofrak.ofrak_context import get_current_ofrak_context
from ofrak.service.component_locator_i import ComponentFilter
from ofrak_patch_maker.toolchain.abstract import Toolchain
from ofrak_type.error import NotFoundError
from ofrak_type.range import Range
Expand Down Expand Up @@ -87,7 +93,6 @@
from ofrak.gui.script_builder import ActionType, ScriptBuilder
from ofrak.service.serialization.pjson_types import PJSONType
from ofrak.core.entropy import DataSummaryAnalyzer
from ofrak.cli.ofrak_cli import OFRAKEnvironment

T = TypeVar("T")
LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -139,7 +144,6 @@ def __init__(
self.resource_view_context: ResourceViewContext = ResourceViewContext()
self.component_context: ComponentContext = ClientComponentContext()
self.script_builder: ScriptBuilder = ScriptBuilder()
self.env = OFRAKEnvironment()
self._app.add_routes(
[
web.post("/create_root_resource", self.create_root_resource),
Expand Down Expand Up @@ -199,6 +203,8 @@ def __init__(
self._job_ids: Dict[str, bytes] = defaultdict(
lambda: ofrak_context.id_service.generate_id()
)
self._all_tags: Dict[str, ResourceTag] = {tag.__name__: tag for tag in ResourceTag.all_tags}

if enable_cors:
try:
import aiohttp_cors # type: ignore
Expand Down Expand Up @@ -686,7 +692,7 @@ async def add_tag(self, request: Request) -> Response:
@exceptions_to_http(SerializedError)
async def get_all_tags(self, request: Request) -> Response:
return json_response(
self._serializer.to_pjson(self._ofrak_context.get_all_tags(), Set[ResourceTag])
self._serializer.to_pjson(set(self._all_tags.values()), Set[ResourceTag])
)

@exceptions_to_http(SerializedError)
Expand Down Expand Up @@ -735,8 +741,10 @@ async def get_components(self, request: Request) -> Response:
async def get_config_for_component(self, request: Request) -> Response:
component_string = request.query.get("component")
if component_string is not None:
component = self.env.components[component_string]
config = self._get_config_for_component(component)
component = self._ofrak_context.component_locator.get_by_id(
component_string.encode("ascii")
)
config = self._get_config_for_component(type(component))
else:
return json_response([])
if (
Expand Down Expand Up @@ -778,7 +786,9 @@ async def run_component(self, request: Request) -> Response:
resource: Resource = await self._get_resource_for_request(request)
component_string = request.query.get("component")
if component_string is not None:
component = self.env.components[component_string]
component = type(
self._ofrak_context.component_locator.get_by_id(component_string.encode("ascii"))
)
config_type = self._get_config_for_component(component)
else:
return json_response([])
Expand Down Expand Up @@ -815,7 +825,7 @@ async def get_tags_and_num_components(self, request: Request):
incl_unpackers = options["unpackers"]
all_resource_tags: Set[Tuple[str, int]] = set()
for specific_tag in resource.get_most_specific_tags():
for tag in inspect.getmro(specific_tag):
for tag in specific_tag.tag_classes():
components = self._get_specific_components(
resource,
only_target,
Expand Down Expand Up @@ -948,29 +958,32 @@ def _get_specific_components(
) -> List[str]:
selected_components = []
tags = resource.get_tags()
if show_all_components and len(set(tags)) == 0:
return []

requested_components = [incl_analyzers, incl_modifiers, incl_packers, incl_unpackers]
all_categories = (Analyzer, Modifier, Packer, Unpacker)
categories: Tuple[Type[ComponentInterface], ...] = (Analyzer, Modifier, Packer, Unpacker)
if any(requested_components):
categories = tuple(itertools.compress(all_categories, requested_components))
else:
categories = all_categories

for component_name, component in self.env.components.items():
if issubclass(component, categories):
if (
# mypy does not see CC.targets as iterable
len([tag for tag in tags if show_all_components or tag in component.targets]) # type: ignore
> 0
):
if (
show_all_components
or target_filter is None
or target_filter in [target.__qualname__ for target in component.targets] # type: ignore
):
# TODO: Get Angr components to work in gui
if "Angr" not in component_name:
selected_components.append(component_name)
categories = tuple(itertools.compress(categories, requested_components))

component_filters: List[ComponentFilter] = [
ComponentOrMetaFilter(*(ComponentTypeFilter(cat) for cat in categories)),
]
if not show_all_components:
component_filters.append(ComponentTargetFilter(*tags))
if target_filter is not None:
component_filters.append(ComponentTargetFilter(self._all_tags[target_filter]))

for component in self._ofrak_context.component_locator.get_components_matching_filter(
ComponentAndMetaFilter(*component_filters)
):
if type(component).__name__ != component.get_id().decode("ascii"):
# TODO: The server lookups for these components won't work yet
continue
if type(component).__name__ == "AngrAnalyzer":
# TODO: The config for this includes some angr types and can't be serialized
continue
rbs-jacob marked this conversation as resolved.
Show resolved Hide resolved
selected_components.append(type(component).__name__)

return selected_components

Expand Down
4 changes: 0 additions & 4 deletions ofrak_core/ofrak/ofrak_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,6 @@ async def shutdown_context(self):
await asyncio.gather(*(service.shutdown() for service in self._all_ofrak_services))
logging.shutdown()

def get_all_tags(self) -> Iterable[ResourceTag]:
all_tags = ResourceTag.all_tags
return all_tags


class OFRAK:
DEFAULT_LOG_LEVEL = logging.WARNING
Expand Down
9 changes: 0 additions & 9 deletions ofrak_core/test_ofrak/unit/test_ofrak_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
import pytest

from ofrak import OFRAK, OFRAKContext
from ofrak.core import BasicBlock
from ofrak.core.apk import ApkIdentifier
from ofrak.model.viewable_tag_model import ViewableResourceTag
from ofrak.ofrak_context import get_current_ofrak_context
from ofrak_type.error import NotFoundError, InvalidStateError
from pytest_ofrak import mock_library3
Expand Down Expand Up @@ -85,10 +83,3 @@ async def test_get_ofrak_context_fixture(ofrak_context: OFRAKContext):
current_ofrak_context = get_current_ofrak_context()
assert current_ofrak_context is not None
assert current_ofrak_context is ofrak_context


async def test_get_all_tags(ofrak_context: OFRAKContext):
tags = set(ofrak_context.get_all_tags())
print(tags)
assert BasicBlock in tags
assert ViewableResourceTag not in tags
25 changes: 15 additions & 10 deletions ofrak_core/test_ofrak/unit/test_ofrak_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@

from aiohttp.test_utils import TestClient

from ofrak import Analyzer, Unpacker, Modifier, Packer
from ofrak.core import File
from ofrak.core.entropy import DataSummaryAnalyzer
from ofrak.gui.server import AiohttpOFRAKServer, start_server
from ofrak.cli.ofrak_cli import OFRAKEnvironment
from ofrak.component.identifier import Identifier
from ofrak.model.component_filters import ComponentOrMetaFilter, ComponentTypeFilter
from ofrak.service.serialization.pjson import (
PJSONSerializationService,
)
Expand Down Expand Up @@ -715,7 +715,7 @@ async def test_clear_action_queue(ofrak_client: TestClient, hello_world_elf):
]


async def test_get_components(ofrak_client: TestClient, hello_world_elf):
async def test_get_components(ofrak_client: TestClient, hello_world_elf, ofrak_context):
create_resp = await ofrak_client.post(
"/create_root_resource", params={"name": "hello_world_elf"}, data=hello_world_elf
)
Expand All @@ -732,13 +732,18 @@ async def test_get_components(ofrak_client: TestClient, hello_world_elf):
"unpackers": True,
},
)
components = await resp.json()
env = OFRAKEnvironment()
assert components == [
comp
for (comp, comp_class) in env.components.items()
if not issubclass(comp_class, Identifier) and "Angr" not in comp
]
components = set(await resp.json())
expected_components = ofrak_context.component_locator.get_components_matching_filter(
ComponentOrMetaFilter(
ComponentTypeFilter(Analyzer),
ComponentTypeFilter(Unpacker),
ComponentTypeFilter(Modifier),
ComponentTypeFilter(Packer),
)
)
assert components == {
type(comp).__name__ for comp in expected_components if "Angr" not in type(comp).__name__
}


async def test_get_config(ofrak_client: TestClient, hello_world_elf):
Expand Down