Skip to content

Conversation

@michalkrzem
Copy link
Contributor

Your checklist for this pull request

  • I've read the contributing guideline.
  • I've tested my changes by building and running mquery, and testing changed functionality (if applicable)
  • I've added automated tests for my change (if applicable, optional)
  • I've updated documentation to reflect my change (if applicable)

What is the current behaviour?

What is the new behaviour?

Test plan

Closing issues

fixes #issuenumber

@michalkrzem michalkrzem linked an issue Nov 22, 2024 that may be closed by this pull request
@michalkrzem michalkrzem requested a review from msm-cert December 1, 2024 23:23
src/tasks.py Outdated
Comment on lines 121 to 131
"""Reads a specific range of bytes from the already loaded file content around a given offset.
Args:
data (bytes): Data to read.
matched_length (int): Number of bytes to read.
offset (int): The offset in bytes from which to start reading.
byte_range (int): The range in bytes to read around the offset (default is 32).
Returns:
bytes: A chunk of bytes from the file, starting from the given offset minus bit_range
and ending at offset plus matched_length and byte_range.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generated by chatgpt? 😀

I don't think the docstrings here are very good (some parts are actually plain wrong), and we don't generally use that docstring format for arguments, so I think argument docs can/should be removed. Maybe:

Suggested change
"""Reads a specific range of bytes from the already loaded file content around a given offset.
Args:
data (bytes): Data to read.
matched_length (int): Number of bytes to read.
offset (int): The offset in bytes from which to start reading.
byte_range (int): The range in bytes to read around the offset (default is 32).
Returns:
bytes: A chunk of bytes from the file, starting from the given offset minus bit_range
and ending at offset plus matched_length and byte_range.
"""Return `matched_length` bytes from `offset`, along with `byte_range` bytes before and after the match.

src/tasks.py Outdated
Comment on lines 107 to 115
@staticmethod
def read_file(file_path: str) -> bytes:
"""Reads the entire file content.
Returns:
bytes: The content of the file.
"""
with open(file_path, "rb") as file:
return file.read()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this method is necessary - you can just inline this.

Even if you prefer to keep it, it doesn't belong in this class (Agent). But IMO it's best to inline it.

src/tasks.py Outdated
return file.read()

@staticmethod
def read_bytes_from_offset(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a very good method name. Maybe read_bytes_with_context?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also there's no reason to use @staticmethod here - it's generic, and has no relation to the Agent class. Please make it a global method

src/tasks.py Outdated
"after": base64.b64encode(after).decode("utf-8"),
}
)
context.update({str(yara_match): match_context})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

str(yara_match)? Probably better to avoid relying on str() representation and to use something like yara_match.rule (or .name? I don't remember)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing that's missing is that you don't put string name anywhere - this makes it impossible to tell which string matched. In most cases there is a single yara rule per query, but multiple strings.

It definitely must be stored somewhere. Probably the easiest way is to use a dict for contetx instead of a list:

{
    "rule_name_1": {
        "string_1": {
            "before": "CgkJCQkJcHJpbnQgU1RERVJSICRtc2c7CgkJCQkJdW4=",
            "match": "AbcDe9f=",
            "after": "CgkJCQkJcHJpbnQgU1RERVJSICRtc2c7CgkJCQkJdW4=",
        },
        "string_2": {
            "before": "CgkJCQkJcHJpbnQgU1RERVJSICRtc2c7CgkJCQkJdW4=",
            "match": "AbcDe9f=",
            "after": "CgkJCQkJcHJpbnQgU1RERVJSICRtc2c7CgkJCQkJdW4=",
        }
    },
    "rule_name_2": {
        "string_1": {
            "before": "CgkJCQkJcHJpbnQgU1RERVJSICRtc2c7CgkJCQkJdW4=",
            "match": "AbcDe9f=",
            "after": "CgkJCQkJcHJpbnQgU1RERVJSICRtc2c7CgkJCQkJdW4=",
        },
        "string_2": {
            "before": "CgkJCQkJcHJpbnQgU1RERVJSICRtc2c7CgkJCQkJdW4=",
            "match": "AbcDe9f=",
            "after": "CgkJCQkJcHJpbnQgU1RERVJSICRtc2c7CgkJCQkJdW4=",
        }
    }
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, this expression is overly complicated - I believe

context.update({A: B})

is equivalent to

context[A] = B

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, in the match key, we have information about the string we are searching for. But okay, I’ll replace the list with a dictionry.

src/tasks.py Outdated
for string_match in yara_match.strings:
expression_keys = []
for expression_key in string_match.instances:
if expression_key in expression_keys:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is a no-op - for (regular, with no eq override) python object object in SOMETHING will always be false.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully get the idea behind this. If the intention was to only add a single match to the context (as originally planned, I think) then you should check if string_match was already added instead.

Or even better, just take the first instance - no loop necessary

src/tasks.py Outdated
for yara_match in matches:
match_context = []
for string_match in yara_match.strings:
expression_keys = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is only used for presence checking, this should be a set instead of a list. But I think it's not necessary at all (see next comment)

src/tasks.py Outdated
Comment on lines 209 to 213
(before, matching, after,) = self.read_bytes_from_offset(
data=data,
offset=expression_key.offset,
matched_length=expression_key.matched_length,
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(before, matching, after,) = self.read_bytes_from_offset(
data=data,
offset=expression_key.offset,
matched_length=expression_key.matched_length,
)
(before, matching, after) = self.read_bytes_from_offset(
data,
expression_key.offset,
expression_key.matched_length,
)

src/tasks.py Outdated

def get_match_context(
self, data: bytes, matches: List[yara.Match]
) -> dict:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for now we use typing classes everywhere (and also misses key/value types)

Suggested change
) -> dict:
) -> Dict[str, ???]:

(value type to be fixed depending on how other comments are resolved)

src/tasks.py Outdated
self.update_metadata(
job.id, orig_name, path, [r.rule for r in matches]
job=job.id,
orig_name=orig_name,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why explicit parameter names everywhere? It's a bit verbose, but OK - just wondering.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read somewhere that when we use such a notation, we don’t have to worry about the order of the arguments, and we already know during the function call what variables are being assigned to (if the naming differs). That was someone’s opinion; I’ll adapt to the project then. :)

Copy link
Member

@msm-cert msm-cert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks good. Sorry for waiting

src/tasks.py Outdated
(before, matching, after) = read_bytes_with_context(
data, expression_key.matched_length, expression_key.offset
)
match_context[expression_key] = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix the style in a second but... expression_key is an object. So match_context is not a Dict[str, ...], so context is not Dict[..., Dict[str, ...]], so something's wrong

@msm-cert
Copy link
Member

msm-cert commented Dec 19, 2024

I guess the PR was not fully tested, because:

                expression_key = string_match.instances[0]
                # ...
                match_context[expression_key] = { ... }

You're using a StringMatchInstance object as a key in JSON. This would raise a type error when trying to serialize...

...but it was not serialized, because typing on context model didn't match (it should be context: Dict[str, Dict[str, Dict[str, str]]]). It was then quietly dropped (so in the database context was always null).

Fixed both.

@msm-cert msm-cert marked this pull request as ready for review December 19, 2024 13:02
@msm-cert msm-cert merged commit 291a041 into master Dec 19, 2024
10 checks passed
@msm-cert msm-cert deleted the 395-add-the-information-about-match-context-to-the-database branch December 19, 2024 13:05
mickol34 pushed a commit that referenced this pull request Dec 19, 2024
Add the information about match context to the database
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add the information about match context to the database

4 participants