Skip to content

Commit

Permalink
Merge pull request #955 from ooprathamm/embedded_pe
Browse files Browse the repository at this point in the history
Identify XOR Encoded PE files
  • Loading branch information
mr-tz authored Mar 7, 2024
2 parents d8646a1 + 1643ebe commit 88a3485
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 8 deletions.
54 changes: 47 additions & 7 deletions floss/qs/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -694,6 +701,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]

Expand All @@ -703,13 +713,16 @@ 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)

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,
)
Expand All @@ -733,7 +746,7 @@ class ResourceLayout(Layout):
pass


def compute_pe_layout(slice: Slice) -> Layout:
def compute_pe_layout(slice: Slice, xor_key: Union[int, None]) -> Layout:
data = slice.data

try:
Expand Down Expand Up @@ -774,6 +787,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,
Expand Down Expand Up @@ -897,16 +911,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(1, 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)
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
# Fall back to using the default binary layout
pass

return SegmentLayout(
Expand Down Expand Up @@ -1051,6 +1089,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: 0x{layout.xor_key:x})"
if name_hint:
name = f"{name_hint} ({name})"

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down

0 comments on commit 88a3485

Please sign in to comment.