From f8871a3e7b681fc15bf72bde91a6aabb0e9c1019 Mon Sep 17 00:00:00 2001 From: ooprathamm-college Date: Mon, 4 Mar 2024 13:23:24 +0530 Subject: [PATCH 1/5] Modified compute_layout to identify XOR encoded PE --- floss/qs/main.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/floss/qs/main.py b/floss/qs/main.py index 02b2409ee..a38c2d0aa 100644 --- a/floss/qs/main.py +++ b/floss/qs/main.py @@ -897,16 +897,40 @@ def collect_pe_resources(dir_data: pefile.ResourceDirData, path: Tuple[str, ...] return layout +def xor_static(data: bytes, i: int) -> bytes: + return bytes(c ^ i for c in data) + + def compute_layout(slice: Slice) -> Layout: - data = slice.data - # try to parse as PE file - if data.startswith(b"MZ"): + mz_xor = [ + ( + xor_static(b"MZ", key), + key, + ) + for key in range(256) + ] + + xor_key = None + + # Try to find the XOR key + for mz, key in mz_xor: + if slice.data.startswith(mz): + xor_key = key + break + + # If XOR key is found, apply XOR decoding + if xor_key is not None: + decoded_data = xor_static(slice.data, xor_key) + slice = Slice(decoded_data, Range(0, len(decoded_data))) + + # Try to parse as PE file + if slice.data.startswith(b"MZ"): try: return compute_pe_layout(slice) except ValueError as e: logger.debug("failed to parse as PE file: %s", e) - # fall back to using the default binary layout + # Fall back to using the default binary layout pass return SegmentLayout( From ed84ef04f0a3345e8cec6a276555cf19d3dd65af Mon Sep 17 00:00:00 2001 From: ooprathamm Date: Mon, 4 Mar 2024 23:38:54 +0530 Subject: [PATCH 2/5] Rendering pe was xor decoded with key --- floss/qs/main.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/floss/qs/main.py b/floss/qs/main.py index a38c2d0aa..8aa440576 100644 --- a/floss/qs/main.py +++ b/floss/qs/main.py @@ -694,6 +694,9 @@ class SegmentLayout(Layout): @dataclass class PELayout(Layout): + # xor key if the file was xor decoded + xor_key: None + # file offsets of bytes that are part of the relocation table reloc_offsets: Set[int] @@ -733,7 +736,7 @@ class ResourceLayout(Layout): pass -def compute_pe_layout(slice: Slice) -> Layout: +def compute_pe_layout(slice: Slice, xor_key: int) -> Layout: data = slice.data try: @@ -774,6 +777,7 @@ def compute_pe_layout(slice: Slice) -> Layout: layout = PELayout( slice=slice, name="pe", + xor_key=xor_key, reloc_offsets=reloc_offsets, code_offsets=code_offsets, structures_by_address=structures_by_address, @@ -927,7 +931,7 @@ def compute_layout(slice: Slice) -> Layout: # Try to parse as PE file if slice.data.startswith(b"MZ"): try: - return compute_pe_layout(slice) + return compute_pe_layout(slice, xor_key) except ValueError as e: logger.debug("failed to parse as PE file: %s", e) # Fall back to using the default binary layout @@ -1075,6 +1079,8 @@ def render_strings( BORDER_STYLE = MUTED_STYLE name = layout.name + if isinstance(layout, PELayout) and layout.xor_key: # Check if the layout is PELayout and is xored + name += f" (XOR decoded with key: {layout.xor_key})" if name_hint: name = f"{name_hint} ({name})" From 44574d566ee0e96beadd85e7152b7ab852096f1b Mon Sep 17 00:00:00 2001 From: ooprathamm Date: Wed, 6 Mar 2024 02:07:22 +0530 Subject: [PATCH 3/5] #duplicate for xor_decoded strings --- floss/qs/main.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/floss/qs/main.py b/floss/qs/main.py index 8aa440576..457b3bdac 100644 --- a/floss/qs/main.py +++ b/floss/qs/main.py @@ -11,7 +11,7 @@ import functools import itertools import contextlib -from typing import Set, Dict, List, Tuple, Literal, Callable, Iterable, Optional, Sequence +from typing import Set, Dict, List, Union, Tuple, Literal, Callable, Iterable, Optional, Sequence from dataclasses import field, dataclass import pefile @@ -378,6 +378,13 @@ def get_reloc_offsets(slice: Slice, pe: pefile.PE) -> Set[int]: return ret +def check_is_xor(xor_key: Union[int, None]): + if isinstance(xor_key, int): + return ("#decoded",) + + return () + + def check_is_reloc(reloc_offsets: Set[int], string: ExtractedString): for addr in string.slice.range: if addr in reloc_offsets: @@ -706,6 +713,8 @@ class PELayout(Layout): structures_by_address: Dict[int, Structure] def tag_strings(self, taggers: Sequence[Tagger]): + def check_is_xor_tagger(s: ExtractedString) -> Sequence[Tag]: + return check_is_xor(self.xor_key) def check_is_reloc_tagger(s: ExtractedString) -> Sequence[Tag]: return check_is_reloc(self.reloc_offsets, s) @@ -713,6 +722,7 @@ def check_is_code_tagger(s: ExtractedString) -> Sequence[Tag]: return check_is_code(self.code_offsets, s) taggers = tuple(taggers) + ( + check_is_xor_tagger, check_is_reloc_tagger, check_is_code_tagger, ) @@ -736,7 +746,7 @@ class ResourceLayout(Layout): pass -def compute_pe_layout(slice: Slice, xor_key: int) -> Layout: +def compute_pe_layout(slice: Slice, xor_key: Union[int, None]) -> Layout: data = slice.data try: @@ -912,7 +922,7 @@ def compute_layout(slice: Slice) -> Layout: xor_static(b"MZ", key), key, ) - for key in range(256) + for key in range(1, 256) ] xor_key = None From 28a7c7718b13a694d2661918c379ab4d0280fee5 Mon Sep 17 00:00:00 2001 From: ooprathamm Date: Wed, 6 Mar 2024 21:38:06 +0530 Subject: [PATCH 4/5] Downgrading lancelot [Temporary fix] --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index be133c29b..a0b8a3f6f 100644 --- a/setup.py +++ b/setup.py @@ -59,7 +59,7 @@ "dnfile==0.13.0", "colorama==0.4.6", "msgspec==0.14.2", - "python-lancelot==0.8.8", + "python-lancelot==0.8.7", ], "dev": [ "pyyaml==6.0", From 1643ebe3260ca97d6ad63cbc8eaa769b3a631e15 Mon Sep 17 00:00:00 2001 From: ooprathamm <89736193+ooprathamm@users.noreply.github.com> Date: Wed, 6 Mar 2024 22:12:46 +0530 Subject: [PATCH 5/5] update floss/qs/main.py Co-authored-by: Moritz --- floss/qs/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/floss/qs/main.py b/floss/qs/main.py index 457b3bdac..355c033e8 100644 --- a/floss/qs/main.py +++ b/floss/qs/main.py @@ -1090,7 +1090,7 @@ def render_strings( name = layout.name if isinstance(layout, PELayout) and layout.xor_key: # Check if the layout is PELayout and is xored - name += f" (XOR decoded with key: {layout.xor_key})" + name += f" (XOR decoded with key: 0x{layout.xor_key:x})" if name_hint: name = f"{name_hint} ({name})"