Skip to content

Commit 248bf05

Browse files
committed
Fixes issue mandiant#937: Show Offset and VirtAddr for language-specific strings
1 parent 8691768 commit 248bf05

File tree

6 files changed

+72
-7
lines changed

6 files changed

+72
-7
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ lib/
1717
# Pyenv file
1818
.python-version
1919
.venv
20+
floss-venv/
2021

2122
# Test executables
2223
bin/
@@ -33,3 +34,4 @@ flare_floss.egg-info
3334
.direnv/
3435
.env/
3536
.envrc
37+
*.code-workspace

floss/language/go/extract.py

+19
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,25 @@ def get_static_strings_from_blob_range(sample: pathlib.Path, static_strings: Lis
424424
return list(filter(lambda s: string_blob_start <= s.offset < string_blob_end, static_strings))
425425

426426

427+
def get_file_offset_in_blob(sample: pathlib.Path) -> int:
428+
pe = pefile.PE(data=pathlib.Path(sample).read_bytes(), fast_load=True)
429+
430+
struct_strings = list(sorted(set(get_struct_string_candidates(pe)), key=lambda s: s.address))
431+
if not struct_strings:
432+
return -1
433+
434+
try:
435+
string_blob_start, _ = find_string_blob_range(pe, struct_strings)
436+
except ValueError:
437+
return -1
438+
439+
image_base = pe.OPTIONAL_HEADER.ImageBase
440+
virtual_address = string_blob_start - image_base
441+
pointer_to_raw_data = pe.get_offset_from_rva(string_blob_start - image_base)
442+
443+
return image_base + virtual_address - pointer_to_raw_data
444+
445+
427446
def main(argv=None):
428447
parser = argparse.ArgumentParser(description="Get Go strings")
429448
parser.add_argument("path", help="file or path to analyze")

floss/language/rust/extract.py

+15
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,21 @@ def get_static_strings_from_rdata(sample, static_strings) -> List[StaticString]:
148148
return list(filter(lambda s: start_rdata <= s.offset < end_rdata, static_strings))
149149

150150

151+
def get_file_offset_in_rdata(sample: pathlib.Path) -> int:
152+
pe = pefile.PE(data=pathlib.Path(sample).read_bytes(), fast_load=True)
153+
154+
try:
155+
rdata_section = get_rdata_section(pe)
156+
except ValueError:
157+
return -1
158+
159+
image_base = pe.OPTIONAL_HEADER.ImageBase
160+
virtual_address = rdata_section.VirtualAddress
161+
pointer_to_raw_data = rdata_section.PointerToRawData
162+
163+
return image_base + virtual_address - pointer_to_raw_data
164+
165+
151166
def get_string_blob_strings(pe: pefile.PE, min_length: int) -> Iterable[StaticString]:
152167
image_base = pe.OPTIONAL_HEADER.ImageBase
153168

floss/main.py

+7
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,9 @@ def main(argv=None) -> int:
691691
string_blob_strings, results.strings.language_strings, args.min_length
692692
)
693693

694+
if args.verbose:
695+
results.metadata.file_offset = floss.language.go.extract.get_file_offset_in_blob(sample)
696+
694697
elif results.metadata.language == Language.RUST.value:
695698
logger.info("extracting language-specific Rust strings")
696699

@@ -703,6 +706,10 @@ def main(argv=None) -> int:
703706
results.strings.language_strings_missed = floss.language.utils.get_missed_strings(
704707
rdata_strings, results.strings.language_strings, args.min_length
705708
)
709+
710+
if args.verbose:
711+
results.metadata.file_offset = floss.language.rust.extract.get_file_offset_in_rdata(sample)
712+
706713
if (
707714
results.analysis.enable_decoded_strings
708715
or results.analysis.enable_stack_strings

floss/render/default.py

+27-6
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,36 @@ def strtime(seconds):
171171
return f"{m:02.0f}:{s:02.0f}"
172172

173173

174-
def render_language_strings(language, language_strings, language_strings_missed, console, verbose, disable_headers):
174+
def render_language_strings(language, language_strings, language_strings_missed, file_offset, console, verbose, disable_headers):
175175
strings = sorted(language_strings + language_strings_missed, key=lambda s: s.offset)
176176
render_heading(f"FLOSS {language.upper()} STRINGS ({len(strings)})", console, verbose, disable_headers)
177177
offset_len = len(f"{strings[-1].offset}")
178-
for s in strings:
179-
if verbose == Verbosity.DEFAULT:
178+
va_offset_len = len(f"{strings[-1].offset + file_offset}")
179+
180+
if verbose != Verbosity.DEFAULT:
181+
# add column headers
182+
table = Table(
183+
"Offset",
184+
"VirtAddr",
185+
"String",
186+
show_header=not (disable_headers),
187+
box=box.ASCII2,
188+
show_edge=False,
189+
)
190+
191+
# add rows
192+
for s in strings:
193+
table.add_row(
194+
f"0x{s.offset:>0{offset_len}x}",
195+
f"0x{s.offset + file_offset:>0{va_offset_len}x}",
196+
string_style(sanitize(s.string, is_ascii_only=False)),
197+
)
198+
199+
console.print(table)
200+
201+
else:
202+
for s in strings:
180203
console.print(sanitize(s.string, is_ascii_only=False), markup=False)
181-
else:
182-
colored_string = string_style(sanitize(s.string, is_ascii_only=False))
183-
console.print(f"0x{s.offset:>0{offset_len}x} {colored_string}")
184204

185205

186206
def render_static_substrings(strings, encoding, offset_len, console, verbose, disable_headers):
@@ -353,6 +373,7 @@ def render(results: floss.results.ResultDocument, verbose, disable_headers, colo
353373
results.metadata.language,
354374
results.strings.language_strings,
355375
results.strings.language_strings_missed,
376+
results.metadata.file_offset,
356377
console,
357378
verbose,
358379
disable_headers,

floss/results.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import json
1818
import datetime
1919
from enum import Enum
20-
from typing import Dict, List
20+
from typing import Dict, List, Optional
2121
from pathlib import Path
2222
from dataclasses import field
2323

@@ -207,6 +207,7 @@ class Metadata:
207207
language: str = ""
208208
language_version: str = ""
209209
language_selected: str = "" # configured by user
210+
file_offset: Optional[int] = None
210211

211212

212213
@dataclass

0 commit comments

Comments
 (0)