Skip to content
Open
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ lib/
# Pyenv file
.python-version
.venv
floss-venv/

# Test executables
bin/
Expand All @@ -33,3 +34,4 @@ flare_floss.egg-info
.direnv/
.env/
.envrc
*.code-workspace
19 changes: 19 additions & 0 deletions floss/language/go/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,25 @@ def get_static_strings_from_blob_range(sample: pathlib.Path, static_strings: Lis
return list(filter(lambda s: string_blob_start <= s.offset < string_blob_end, static_strings))


def get_file_offset_in_blob(sample: pathlib.Path) -> int:
pe = pefile.PE(data=pathlib.Path(sample).read_bytes(), fast_load=True)

struct_strings = list(sorted(set(get_struct_string_candidates(pe)), key=lambda s: s.address))
if not struct_strings:
return []

try:
string_blob_start, _ = find_string_blob_range(pe, struct_strings)
except ValueError as e:
raise ValueError("Failed to find string blob range") from e

image_base = pe.OPTIONAL_HEADER.ImageBase
virtual_address = string_blob_start - image_base
raw_data_offset = pe.get_offset_from_rva(string_blob_start - image_base)

return image_base + virtual_address - raw_data_offset


def main(argv=None):
parser = argparse.ArgumentParser(description="Get Go strings")
parser.add_argument("path", help="file or path to analyze")
Expand Down
15 changes: 15 additions & 0 deletions floss/language/rust/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,21 @@ def get_static_strings_from_rdata(sample, static_strings) -> List[StaticString]:
return list(filter(lambda s: start_rdata <= s.offset < end_rdata, static_strings))


def get_file_offset_in_rdata(sample: pathlib.Path) -> int:
pe = pefile.PE(data=pathlib.Path(sample).read_bytes(), fast_load=True)

try:
rdata_section = get_rdata_section(pe)
except ValueError as e:
raise ValueError("Failed to find .rdata section") from e

image_base = pe.OPTIONAL_HEADER.ImageBase
virtual_address = rdata_section.VirtualAddress
raw_data_offset = rdata_section.PointerToRawData

return image_base + virtual_address - raw_data_offset


def get_string_blob_strings(pe: pefile.PE, min_length: int) -> Iterable[StaticString]:
image_base = pe.OPTIONAL_HEADER.ImageBase

Expand Down
7 changes: 7 additions & 0 deletions floss/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,9 @@ def main(argv=None) -> int:
string_blob_strings, results.strings.language_strings, args.min_length
)

if args.verbose:
results.metadata.file_offset = floss.language.go.extract.get_file_offset_in_blob(sample)

elif results.metadata.language == Language.RUST.value:
logger.info("extracting language-specific Rust strings")

Expand All @@ -703,6 +706,10 @@ def main(argv=None) -> int:
results.strings.language_strings_missed = floss.language.utils.get_missed_strings(
rdata_strings, results.strings.language_strings, args.min_length
)

if args.verbose:
results.metadata.file_offset = floss.language.rust.extract.get_file_offset_in_rdata(sample)

if (
results.analysis.enable_decoded_strings
or results.analysis.enable_stack_strings
Expand Down
35 changes: 29 additions & 6 deletions floss/render/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,16 +171,38 @@ def strtime(seconds):
return f"{m:02.0f}:{s:02.0f}"


def render_language_strings(language, language_strings, language_strings_missed, console, verbose, disable_headers):
def render_language_strings(
language, language_strings, language_strings_missed, file_offset, console, verbose, disable_headers
):
strings = sorted(language_strings + language_strings_missed, key=lambda s: s.offset)
render_heading(f"FLOSS {language.upper()} STRINGS ({len(strings)})", console, verbose, disable_headers)
offset_len = len(f"{strings[-1].offset}")
for s in strings:
if verbose == Verbosity.DEFAULT:
va_offset_len = len(f"{strings[-1].offset + file_offset}")

if verbose != Verbosity.DEFAULT:
# add column headers
table = Table(
"Offset",
"VirtAddr",
"String",
show_header=not (disable_headers),
box=box.ASCII2,
show_edge=False,
)

# add rows
for s in strings:
table.add_row(
f"0x{s.offset:>0{offset_len}x}",
f"0x{s.offset + file_offset:>0{va_offset_len}x}",
string_style(sanitize(s.string, is_ascii_only=False)),
)

console.print(table)

else:
for s in strings:
console.print(sanitize(s.string, is_ascii_only=False), markup=False)
else:
colored_string = string_style(sanitize(s.string, is_ascii_only=False))
console.print(f"0x{s.offset:>0{offset_len}x} {colored_string}")


def render_static_substrings(strings, encoding, offset_len, console, verbose, disable_headers):
Expand Down Expand Up @@ -353,6 +375,7 @@ def render(results: floss.results.ResultDocument, verbose, disable_headers, colo
results.metadata.language,
results.strings.language_strings,
results.strings.language_strings_missed,
results.metadata.file_offset,
console,
verbose,
disable_headers,
Expand Down
3 changes: 2 additions & 1 deletion floss/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import json
import datetime
from enum import Enum
from typing import Dict, List
from typing import Dict, List, Optional
from pathlib import Path
from dataclasses import field

Expand Down Expand Up @@ -207,6 +207,7 @@ class Metadata:
language: str = ""
language_version: str = ""
language_selected: str = "" # configured by user
file_offset: Optional[int] = None


@dataclass
Expand Down