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.
138 lines
4.3 KiB
Python
138 lines
4.3 KiB
Python
# Copyright 2017 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.
|
|
|
|
|
|
import contextlib
|
|
from typing import Set, List
|
|
from collections import namedtuple
|
|
|
|
import envi
|
|
import vivisect
|
|
import viv_utils
|
|
import viv_utils.emulator_drivers
|
|
|
|
import floss.utils
|
|
import floss.logging_
|
|
import floss.api_hooks
|
|
|
|
FunctionContext = namedtuple("FunctionContext", ["emu_snap", "return_address", "decoded_at_va"])
|
|
|
|
|
|
logger = floss.logging_.getLogger(__name__)
|
|
|
|
|
|
class CallMonitor(viv_utils.emulator_drivers.Monitor):
|
|
"""collect call arguments to a target function during emulation"""
|
|
|
|
def __init__(self, call_site_va: int):
|
|
super().__init__()
|
|
self.call_site_va = call_site_va
|
|
self.function_contexts: List[FunctionContext] = list()
|
|
|
|
def prehook(self, emu, op, pc):
|
|
logger.trace("%s: %s", hex(pc), op)
|
|
if pc == self.call_site_va:
|
|
# strictly calls here, return address should always be next instruction
|
|
return_address = pc + len(op)
|
|
self.function_contexts.append(FunctionContext(emu.getEmuSnap(), return_address, pc))
|
|
|
|
def get_contexts(self) -> List[FunctionContext]:
|
|
return self.function_contexts
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def installed_monitor(driver, monitor):
|
|
try:
|
|
driver.add_monitor(monitor)
|
|
yield
|
|
finally:
|
|
driver.remove_monitor(monitor)
|
|
|
|
|
|
def extract_decoding_contexts(
|
|
vw: vivisect.VivWorkspace, decoder_fva: int, index: viv_utils.InstructionFunctionIndex
|
|
) -> List[FunctionContext]:
|
|
"""
|
|
Extract the CPU and memory contexts of all calls to the given function.
|
|
Under the hood, we brute-force emulate all code paths to extract the
|
|
state of the stack, registers, and global memory at each call to
|
|
the given address.
|
|
"""
|
|
logger.trace("Getting function context for function at 0x%08x...", decoder_fva)
|
|
|
|
emu = floss.utils.make_emulator(vw)
|
|
driver = viv_utils.emulator_drivers.FullCoverageEmulatorDriver(emu, repmax=1024)
|
|
|
|
contexts = list()
|
|
for caller_va in get_caller_vas(vw, decoder_fva):
|
|
contexts.extend(get_contexts_via_monitor(driver, caller_va, decoder_fva, index))
|
|
|
|
logger.trace("Got %d function contexts for function at 0x%08x.", len(contexts), decoder_fva)
|
|
return contexts
|
|
|
|
|
|
def get_caller_vas(vw, fva) -> Set[int]:
|
|
"""
|
|
return all unique VAs where function is called from
|
|
"""
|
|
caller_vas = set()
|
|
for caller_va in vw.getCallers(fva):
|
|
if not is_call(vw, caller_va):
|
|
continue
|
|
if caller_va == fva:
|
|
# ignore recursive functions
|
|
continue
|
|
caller_vas.add(caller_va)
|
|
return caller_vas
|
|
|
|
|
|
def is_call(vw: vivisect.VivWorkspace, va: int) -> bool:
|
|
try:
|
|
op = vw.parseOpcode(va)
|
|
except (envi.UnsupportedInstruction, envi.InvalidInstruction) as e:
|
|
logger.trace(" not a call instruction: failed to decode instruction: %s", e.message)
|
|
return False
|
|
|
|
if op.iflags & envi.IF_CALL:
|
|
return True
|
|
|
|
logger.trace(" not a call instruction: %s", op)
|
|
return False
|
|
|
|
|
|
def get_contexts_via_monitor(driver, caller_va, decoder_fva: int, index: viv_utils.InstructionFunctionIndex):
|
|
"""
|
|
run the given function while collecting arguments to a target function
|
|
"""
|
|
try:
|
|
caller_fva = index[caller_va]
|
|
except KeyError:
|
|
logger.trace(" unknown function")
|
|
return []
|
|
|
|
logger.trace("emulating: %s, watching %s" % (hex(caller_fva), hex(decoder_fva)))
|
|
monitor = CallMonitor(caller_va)
|
|
with installed_monitor(driver, monitor):
|
|
with floss.api_hooks.defaultHooks(driver):
|
|
try:
|
|
driver.run(caller_fva)
|
|
except Exception as e:
|
|
logger.debug("error during emulation of function: %s", str(e))
|
|
contexts = monitor.get_contexts()
|
|
|
|
logger.trace(" results:")
|
|
for _ in contexts:
|
|
logger.trace(" <context>")
|
|
|
|
return contexts
|