-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
155 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
from __future__ import annotations | ||
|
||
import io | ||
import logging | ||
|
||
from .binfmt_tool import BinFmtTool | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class Binary(BinFmtTool): | ||
def __init__(self, p, binary_path: str) -> None: | ||
super().__init__(p, binary_path) | ||
self._file = open(binary_path, "rb") | ||
self.file_size = self._file.seek(0, io.SEEK_END) | ||
self._file.seek(0) | ||
self.file_updates = [] | ||
|
||
def __del__(self) -> None: | ||
self._file.close() | ||
|
||
def _init_memory_analysis(self) -> None: | ||
pass | ||
|
||
def finalize(self) -> None: | ||
pass | ||
|
||
def save_binary(self, filename: str | None = None) -> None: | ||
if filename is None: | ||
filename = f"{self.binary_path}.patched" | ||
with open(filename, "wb") as f: | ||
self._file.seek(0) | ||
f.write(self._file.read()) | ||
# apply the updates | ||
for update in self.file_updates: | ||
f.seek(update["offset"]) | ||
f.write(update["content"]) | ||
|
||
def update_binary_content(self, offset: int, new_content: bytes) -> None: | ||
logger.debug( | ||
f"Updating offset {hex(offset)} with content ({len(new_content)} bytes) {new_content}" | ||
) | ||
for update in self.file_updates: | ||
if offset >= update["offset"] and offset < update["offset"] + len( | ||
update["content"] | ||
): | ||
raise ValueError( | ||
f"Cannot update offset {hex(offset)} with content {new_content}, it overlaps with a previous update" | ||
) | ||
self.file_updates.append({"offset": offset, "content": new_content}) | ||
if offset + len(new_content) > self.file_size: | ||
self.file_size = offset + len(new_content) | ||
|
||
def get_binary_content(self, offset: int, size: int) -> bytes: | ||
# FIXME: content partially in the file and partially in the updates (check other binfmt tools as well) | ||
# check if it's in the file updates | ||
for update in self.file_updates: | ||
if offset >= update["offset"] and offset + size <= update["offset"] + len( | ||
update["content"] | ||
): | ||
return update["content"][ | ||
offset - update["offset"] : offset - update["offset"] + size | ||
] | ||
# otherwise read from the file | ||
self._file.seek(offset) | ||
return self._file.read(size) | ||
|
||
def append_to_binary_content(self, new_content: bytes) -> None: | ||
self.file_updates.append({"offset": self.file_size, "content": new_content}) | ||
self.file_size += len(new_content) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import logging | ||
|
||
from ..components.allocation_managers.allocation_manager import AllocationManager | ||
from ..components.archinfo.arm import ArmInfo | ||
from ..components.assemblers.keystone_arm import KeystoneArm | ||
from ..components.binary_analyzers.angr import Angr | ||
from ..components.binfmt_tools.binary import Binary | ||
from ..components.compilers.clang_arm import ClangArm | ||
from ..components.disassemblers.capstone_arm import CapstoneArm | ||
from ..components.utils.utils import Utils | ||
from .target import Target | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class BinArmBare(Target): | ||
@staticmethod | ||
def detect_target(binary_path): | ||
return False | ||
|
||
def get_assembler(self, assembler): | ||
assembler = assembler or "keystone" | ||
if assembler == "keystone": | ||
return KeystoneArm(self.p) | ||
raise NotImplementedError() | ||
|
||
def get_allocation_manager(self, allocation_manager): | ||
allocation_manager = allocation_manager or "default" | ||
if allocation_manager == "default": | ||
return AllocationManager(self.p) | ||
raise NotImplementedError() | ||
|
||
def get_compiler(self, compiler): | ||
compiler = compiler or "clang" | ||
if compiler == "clang": | ||
return ClangArm(self.p, compiler_flags=["-target", "arm-linux-gnueabihf"]) | ||
elif compiler == "clang19": | ||
return ClangArm( | ||
self.p, | ||
compiler_flags=["-target", "arm-linux-gnueabihf"], | ||
clang_version=19, | ||
) | ||
raise NotImplementedError() | ||
|
||
def get_disassembler(self, disassembler): | ||
disassembler = disassembler or "capstone" | ||
if disassembler == "capstone": | ||
return CapstoneArm(self.p) | ||
raise NotImplementedError() | ||
|
||
def get_binfmt_tool(self, binfmt_tool): | ||
binfmt_tool = binfmt_tool or "default" | ||
if binfmt_tool == "default": | ||
return Binary(self.p, self.binary_path) | ||
raise NotImplementedError() | ||
|
||
def get_binary_analyzer(self, binary_analyzer): | ||
binary_analyzer = binary_analyzer or "angr" | ||
if binary_analyzer == "angr": | ||
return Angr( | ||
self.binary_path, | ||
angr_kwargs={ | ||
"arch": "ARMEL", | ||
"auto_load_libs": False, | ||
}, | ||
angr_cfg_kwargs={ | ||
"normalize": True, | ||
"data_references": True, | ||
}, | ||
) | ||
raise NotImplementedError() | ||
|
||
def get_utils(self, utils): | ||
utils = utils or "default" | ||
if utils == "default": | ||
return Utils(self.p, self.binary_path) | ||
raise NotImplementedError() | ||
|
||
def get_archinfo(self, archinfo): | ||
archinfo = archinfo or "default" | ||
if archinfo == "default": | ||
return ArmInfo() | ||
raise NotImplementedError() |