mirror of
https://github.com/vee1e/flare-floss.git
synced 2026-09-01 17:57:06 +00:00
Replace the header from source code files using the following script:
```Python
for dir_path, dir_names, file_names in os.walk("flare-floss"):
for file_name in file_names:
try:
file_path = f"{dir_path}/{file_name}"
f = open(file_path, "rb+")
content = f.read()
m = re.search(OLD_HEADER, content)
if not m:
continue
print(f"{file_path}: {m.group('year')}")
content = content.replace(m.group(0), NEW_HEADER % m.group("year"))
f.seek(0)
f.write(content)
except:
continue
```
Some files had the copyright headers inside a `"""` comment and needed
manual changes before applying the script.
The old header had the confusing sentence `All rights reserved`, which
does not make sense for an open source license. Replace the header by
the default Google header that corrects this issue and keep floss
consistent with other Google projects.
137 lines
5.9 KiB
Python
137 lines
5.9 KiB
Python
# Copyright 2021 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
|
|
from typing import Set, List, Tuple, Iterator, Optional
|
|
|
|
import tqdm
|
|
import envi.exc
|
|
import viv_utils
|
|
import tqdm.contrib.logging
|
|
import viv_utils.emulator_drivers
|
|
|
|
import floss.utils
|
|
import floss.features.features
|
|
from floss.const import TS_MAX_INSN_COUNT, DS_MAX_ADDRESS_REVISITS_EMULATION
|
|
from floss.utils import extract_strings
|
|
from floss.render import Verbosity
|
|
from floss.results import TightString
|
|
from floss.stackstrings import CallContext, StackstringContextMonitor
|
|
|
|
logger = floss.logging_.getLogger(__name__)
|
|
|
|
|
|
class TightstringContextMonitor(StackstringContextMonitor):
|
|
def __init__(self, sp, min_length):
|
|
super().__init__(sp, [])
|
|
self.min_length = min_length
|
|
|
|
def apicall(self, emu, api, argv):
|
|
# override base and do nothing here
|
|
pass
|
|
|
|
def get_pre_ctx_strings(self, emu) -> Set[str]:
|
|
try:
|
|
stack_buf = self.get_call_context(emu, emu.getProgramCounter()).stack_memory
|
|
return set(map(lambda s: s.string, extract_strings(stack_buf, self.min_length)))
|
|
except ValueError as e:
|
|
logger.debug("%s", e)
|
|
return set()
|
|
|
|
def get_context(self, emu, va, pre_ctx_strings: Optional[Set[str]]) -> Iterator[CallContext]:
|
|
try:
|
|
yield self.get_call_context(emu, va, pre_ctx_strings)
|
|
except ValueError as e:
|
|
logger.debug("%s", e)
|
|
|
|
|
|
def extract_tightstring_contexts(vw, fva, min_length, tloops) -> Iterator[CallContext]:
|
|
emu = floss.utils.make_emulator(vw)
|
|
monitor = TightstringContextMonitor(emu.getStackCounter(), min_length)
|
|
driver_single_path = viv_utils.emulator_drivers.SinglePathEmulatorDriver(emu, repmax=256)
|
|
driver_single_path.add_monitor(monitor)
|
|
driver = viv_utils.emulator_drivers.DebuggerEmulatorDriver(
|
|
emu, max_hit=DS_MAX_ADDRESS_REVISITS_EMULATION, max_insn=TS_MAX_INSN_COUNT
|
|
)
|
|
|
|
for t in tloops:
|
|
try:
|
|
# find and emulate single path to start of tight loop
|
|
driver_single_path.run_to_va(fva, t.startva)
|
|
except Exception as e:
|
|
logger.debug("error emulating path 0x%x to 0x%x: %s", fva, t.startva, e)
|
|
continue
|
|
|
|
# find existing (FP) stackstrings before tightstring loop executes
|
|
pre_ctx_strings = monitor.get_pre_ctx_strings(emu)
|
|
try:
|
|
# emulate tight loop
|
|
driver.run_to_va(t.endva)
|
|
except viv_utils.emulator_drivers.BreakpointHit as e:
|
|
logger.debug("hit breakpoint at 0x%x (reason: %s) in function 0x%x", e.va, e.reason, fva)
|
|
except Exception as e:
|
|
logger.debug("error emulating tight loop starting at 0x%x in function 0x%x: %s", t.startva, fva, e)
|
|
yield from monitor.get_context(emu, t.startva, pre_ctx_strings)
|
|
|
|
|
|
def extract_tightstrings(
|
|
vw, tightloop_functions, min_length, verbosity=Verbosity.DEFAULT, disable_progress=False
|
|
) -> List[TightString]:
|
|
"""
|
|
Extracts tightstrings from functions that contain tight loops.
|
|
Tightstrings are a special form of stackstrings. Their bytes are loaded on the stack and then modified in a
|
|
tight loop. To extract tightstrings we use a mix between the string decoding and stackstring algorithms.
|
|
|
|
To reduce computation time we only run this on previously identified functions that contain tight loops.
|
|
|
|
:param vw: The vivisect workspace
|
|
:param tightloop_functions: functions containing tight loops
|
|
:param min_length: minimum string length
|
|
:param verbosity: verbosity level
|
|
:param disable_progress: do NOT show progress bar
|
|
"""
|
|
logger.info("extracting tightstrings from %d functions...", len(tightloop_functions))
|
|
|
|
tight_strings = list()
|
|
pb = floss.utils.get_progress_bar(
|
|
tightloop_functions.items(), disable_progress, desc="extracting tightstrings", unit=" functions"
|
|
)
|
|
with tqdm.contrib.logging.logging_redirect_tqdm(), floss.utils.redirecting_print_to_tqdm():
|
|
for fva, tloops in pb:
|
|
with floss.utils.timing(f"0x{fva:x}"):
|
|
logger.debug("extracting tightstrings from function 0x%x", fva)
|
|
if isinstance(pb, tqdm.tqdm):
|
|
pb.set_description(f"extracting tightstrings from function 0x{fva:x}")
|
|
|
|
ctxs = extract_tightstring_contexts(vw, fva, min_length, tloops)
|
|
for n, ctx in enumerate(ctxs, 1):
|
|
logger.trace(
|
|
"extracting tightstring at checkpoint: 0x%x stacksize: 0x%x", ctx.pc, ctx.init_sp - ctx.sp
|
|
)
|
|
logger.trace("pre_ctx strings: %s", ctx.pre_ctx_strings)
|
|
for s in extract_strings(ctx.stack_memory, min_length, exclude=ctx.pre_ctx_strings):
|
|
frame_offset = (ctx.init_sp - ctx.sp) - s.offset - floss.utils.getPointerSize(vw)
|
|
ts = TightString(
|
|
function=fva,
|
|
string=s.string,
|
|
encoding=s.encoding,
|
|
program_counter=ctx.pc,
|
|
stack_pointer=ctx.sp,
|
|
original_stack_pointer=ctx.init_sp,
|
|
offset=s.offset,
|
|
frame_offset=frame_offset,
|
|
)
|
|
floss.results.log_result(ts, verbosity)
|
|
tight_strings.append(ts)
|
|
return tight_strings
|