Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add bin_arm_bare target
Browse files Browse the repository at this point in the history
DennyDai committed Dec 17, 2024

Verified

This commit was signed with the committer’s verified signature.
Lipen Konstantin Chukharev
1 parent 6038c10 commit 53824e5
Showing 4 changed files with 155 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/patcherex2/components/binary_analyzers/angr.py
Original file line number Diff line number Diff line change
@@ -70,7 +70,7 @@ def mem_addr_to_file_offset(self, addr: int) -> int:

def get_basic_block(self, addr: int) -> dict[str, int | list[int]]:
# NOTE: angr splits basic blocks at call instructions, so we need to handle this
if self.is_thumb(addr):
if self.is_thumb(addr) and addr % 2 == 0:
addr += 1
addr = self.denormalize_addr(addr)

70 changes: 70 additions & 0 deletions src/patcherex2/components/binfmt_tools/binary.py
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)
1 change: 1 addition & 0 deletions src/patcherex2/targets/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .bin_arm_bare import BinArmBare
from .elf_aarch64_linux import ElfAArch64Linux
from .elf_amd64_linux import ElfAmd64Linux
from .elf_amd64_linux_recomp import ElfAmd64LinuxRecomp
83 changes: 83 additions & 0 deletions src/patcherex2/targets/bin_arm_bare.py
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()

0 comments on commit 53824e5

Please sign in to comment.