diff --git a/src/patcherex2/components/allocation_managers/allocation_manager.py b/src/patcherex2/components/allocation_managers/allocation_manager.py index 15af2ba..192ba17 100644 --- a/src/patcherex2/components/allocation_managers/allocation_manager.py +++ b/src/patcherex2/components/allocation_managers/allocation_manager.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import enum import logging -from typing import List logger = logging.getLogger(__name__) @@ -17,13 +18,13 @@ def __init__(self, addr: int, size: int, is_free=True) -> None: self.size = size self.is_free = is_free - def __lt__(self, other: "Block") -> bool: + def __lt__(self, other: Block) -> bool: return self.addr < other.addr def __repr__(self) -> str: return f"<{self.__class__.__name__} addr={hex(self.addr)} size={hex(self.size)} is_free={self.is_free}>" - def coalesce(self, other: "Block") -> bool: + def coalesce(self, other: Block) -> bool: if self.is_free == other.is_free and self.addr + self.size == other.addr: self.size += other.size return True @@ -61,13 +62,13 @@ def __init__( self.mem_addr = mem_addr self.flag = flag - def __lt__(self, other: "MappedBlock") -> bool: + def __lt__(self, other: MappedBlock) -> bool: return self.mem_addr < other.mem_addr def __repr__(self) -> str: return f"<{self.__class__.__name__} file_addr={hex(self.file_addr)} mem_addr={hex(self.mem_addr)} size={hex(self.size)} is_free={self.is_free} flag={str(self.flag)}>" - def coalesce(self, other: "MappedBlock") -> bool: + def coalesce(self, other: MappedBlock) -> bool: if ( self.flag == other.flag and self.is_free == other.is_free @@ -206,7 +207,7 @@ def free(self, block: Block) -> None: block.is_free = True self.coalesce(self.blocks[type(block)]) - def coalesce(self, blocks: List[Block]) -> None: + def coalesce(self, blocks: list[Block]) -> None: for curr, next in zip(blocks, blocks[1:]): if curr.coalesce(next): blocks.remove(next) diff --git a/src/patcherex2/components/binary_analyzers/angr.py b/src/patcherex2/components/binary_analyzers/angr.py index d3ce7e6..837484a 100644 --- a/src/patcherex2/components/binary_analyzers/angr.py +++ b/src/patcherex2/components/binary_analyzers/angr.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import logging -from typing import Dict, List, Optional, Union import angr from archinfo import ArchARM @@ -66,7 +67,7 @@ def mem_addr_to_file_offset(self, addr: int) -> int: return addr return file_addr - def get_basic_block(self, addr: int) -> Dict[str, Union[int, List[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): addr += 1 @@ -112,7 +113,7 @@ def get_instr_bytes_at(self, addr: int, num_instr=1) -> angr.Block: # angr will return both instrs, even when num_instr is 1 return self.p.factory.block(addr, num_inst=num_instr).bytes - def get_unused_funcs(self) -> List[Dict[str, int]]: + def get_unused_funcs(self) -> list[dict[str, int]]: logger.info("Getting unused functions with angr") unused_funcs = [] assert self.cfg is not None @@ -132,7 +133,7 @@ def get_unused_funcs(self) -> List[Dict[str, int]]: ) return unused_funcs - def get_all_symbols(self) -> Dict[str, int]: + def get_all_symbols(self) -> dict[str, int]: assert self.cfg is not None logger.info("Getting all symbols with angr") symbols = {} @@ -146,7 +147,7 @@ def get_all_symbols(self) -> Dict[str, int]: symbols[func.name] = self.normalize_addr(func.addr) return symbols - def get_function(self, name_or_addr: Union[int, str]) -> Optional[Dict[str, int]]: + def get_function(self, name_or_addr: int | str) -> dict[str, int] | None: assert self.cfg is not None if isinstance(name_or_addr, (str, int)): if isinstance(name_or_addr, int): diff --git a/src/patcherex2/components/binary_analyzers/ida.py b/src/patcherex2/components/binary_analyzers/ida.py index 17e1e93..4d7512a 100644 --- a/src/patcherex2/components/binary_analyzers/ida.py +++ b/src/patcherex2/components/binary_analyzers/ida.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Union +from __future__ import annotations from headless_ida import HeadlessIdaRemote @@ -44,7 +44,7 @@ def __init__(self, binary_path: str, **kwargs) -> None: def mem_addr_to_file_offset(self, addr: int) -> int: return self.ida_loader.get_fileregion_offset(addr) - def get_basic_block(self, addr: int) -> Dict[str, Union[int, List[int]]]: + def get_basic_block(self, addr: int) -> dict[str, int | list[int]]: func = self.ida_funcs.get_func(addr) instr_addrs = list(func.code_items()) assert addr in instr_addrs, "Invalid address" diff --git a/src/patcherex2/components/binfmt_tools/elf.py b/src/patcherex2/components/binfmt_tools/elf.py index 5e289e9..3145895 100644 --- a/src/patcherex2/components/binfmt_tools/elf.py +++ b/src/patcherex2/components/binfmt_tools/elf.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import logging import os -from typing import Optional from elftools.construct.lib import Container from elftools.elf.constants import P_FLAGS, SH_FLAGS @@ -457,7 +458,7 @@ def finalize(self) -> None: new_ehdr = self._elf.structs.Elf_Ehdr.build(ehdr) self.p.binfmt_tool.update_binary_content(0, new_ehdr) - def save_binary(self, filename: Optional[str] = None) -> None: + def save_binary(self, filename: str | None = None) -> None: self.updated_binary_content = self.updated_binary_content.ljust( self.file_size, b"\x00" ) diff --git a/src/patcherex2/components/binfmt_tools/ihex.py b/src/patcherex2/components/binfmt_tools/ihex.py index 61b1c58..da253c4 100644 --- a/src/patcherex2/components/binfmt_tools/ihex.py +++ b/src/patcherex2/components/binfmt_tools/ihex.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import io import logging -from typing import Optional import intelhex @@ -26,7 +27,7 @@ def _init_memory_analysis(self) -> None: def finalize(self) -> None: pass - def save_binary(self, filename: Optional[str] = None) -> None: + def save_binary(self, filename: str | None = None) -> None: for update in self.file_updates: self._ihex.puts(update["offset"], update["content"]) if filename is None: diff --git a/src/patcherex2/components/compilers/clang.py b/src/patcherex2/components/compilers/clang.py index 4ad5a24..7286c5c 100644 --- a/src/patcherex2/components/compilers/clang.py +++ b/src/patcherex2/components/compilers/clang.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import logging -from typing import List, Optional from .compiler import Compiler @@ -8,7 +9,7 @@ class Clang(Compiler): def __init__( - self, p, clang_version=15, compiler_flags: Optional[List[str]] = None + self, p, clang_version=15, compiler_flags: list[str] | None = None ) -> None: super().__init__(p) if compiler_flags is None: diff --git a/src/patcherex2/components/compilers/clang_arm.py b/src/patcherex2/components/compilers/clang_arm.py index 056b8e8..dd37f4d 100644 --- a/src/patcherex2/components/compilers/clang_arm.py +++ b/src/patcherex2/components/compilers/clang_arm.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import logging -from typing import Dict, List, Optional from .compiler import Compiler @@ -8,7 +9,7 @@ class ClangArm(Compiler): def __init__( - self, p, clang_version=15, compiler_flags: Optional[List[str]] = None + self, p, clang_version=15, compiler_flags: list[str] | None = None ) -> None: super().__init__(p) if compiler_flags is None: @@ -21,8 +22,8 @@ def compile( self, code: str, base=0, - symbols: Optional[Dict[str, int]] = None, - extra_compiler_flags: Optional[List[str]] = None, + symbols: dict[str, int] | None = None, + extra_compiler_flags: list[str] | None = None, is_thumb=False, **kwargs, ) -> bytes: diff --git a/src/patcherex2/components/compilers/compiler.py b/src/patcherex2/components/compilers/compiler.py index 79444e4..e630da4 100644 --- a/src/patcherex2/components/compilers/compiler.py +++ b/src/patcherex2/components/compilers/compiler.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import logging import os import subprocess import tempfile -from typing import Dict, List, Optional import cle @@ -17,8 +18,8 @@ def compile( self, code: str, base=0, - symbols: Optional[Dict[str, int]] = None, - extra_compiler_flags: Optional[List[str]] = None, + symbols: dict[str, int] | None = None, + extra_compiler_flags: list[str] | None = None, **kwargs, ) -> bytes: if symbols is None: diff --git a/src/patcherex2/components/compilers/llvm_recomp.py b/src/patcherex2/components/compilers/llvm_recomp.py index 15fd7a7..89da7b5 100644 --- a/src/patcherex2/components/compilers/llvm_recomp.py +++ b/src/patcherex2/components/compilers/llvm_recomp.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import json import logging import os import subprocess import tempfile -from typing import Dict, List, Optional import cle @@ -15,7 +16,7 @@ class LLVMRecomp(Clang): def __init__( - self, p, clang_version=15, compiler_flags: Optional[List[str]] = None + self, p, clang_version=15, compiler_flags: list[str] | None = None ) -> None: super().__init__(p, clang_version, compiler_flags) self._clang_version = clang_version @@ -25,8 +26,8 @@ def compile( self, code: str, base=0, - symbols: Optional[Dict[str, int]] = None, - extra_compiler_flags: Optional[List[str]] = None, + symbols: dict[str, int] | None = None, + extra_compiler_flags: list[str] | None = None, is_thumb=False, **kwargs, ) -> bytes: diff --git a/src/patcherex2/components/compilers/llvm_recomp_arm.py b/src/patcherex2/components/compilers/llvm_recomp_arm.py index 9957e02..4d92f82 100644 --- a/src/patcherex2/components/compilers/llvm_recomp_arm.py +++ b/src/patcherex2/components/compilers/llvm_recomp_arm.py @@ -1,5 +1,6 @@ +from __future__ import annotations + import logging -from typing import Dict, List, Optional from .llvm_recomp import LLVMRecomp @@ -11,8 +12,8 @@ def compile( self, code: str, base=0, - symbols: Optional[Dict[str, int]] = None, - extra_compiler_flags: Optional[List[str]] = None, + symbols: dict[str, int] | None = None, + extra_compiler_flags: list[str] | None = None, is_thumb=False, **kwargs, ) -> bytes: diff --git a/src/patcherex2/components/disassemblers/capstone.py b/src/patcherex2/components/disassemblers/capstone.py index 7fa3798..e8f7796 100644 --- a/src/patcherex2/components/disassemblers/capstone.py +++ b/src/patcherex2/components/disassemblers/capstone.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Union +from __future__ import annotations import capstone @@ -9,9 +9,7 @@ class Capstone(Disassembler): def __init__(self, arch: int, mode: int) -> None: self.cs = capstone.Cs(arch, mode) - def disassemble( - self, input: bytes, base=0, **kwargs - ) -> List[Dict[str, Union[int, str]]]: + def disassemble(self, input: bytes, base=0, **kwargs) -> list[dict[str, int | str]]: cs_insns = self.cs.disasm(input, base) result = [] for insn in cs_insns: diff --git a/src/patcherex2/components/disassemblers/capstone_arm.py b/src/patcherex2/components/disassemblers/capstone_arm.py index c24eec9..b0fb0c8 100644 --- a/src/patcherex2/components/disassemblers/capstone_arm.py +++ b/src/patcherex2/components/disassemblers/capstone_arm.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Union +from __future__ import annotations import capstone @@ -18,7 +18,7 @@ def __init__(self, p) -> None: def disassemble( self, input: bytes, base=0, is_thumb=False, **kwargs - ) -> List[Dict[str, Union[int, str]]]: + ) -> list[dict[str, int | str]]: cs = self.cs_thumb if is_thumb else self.cs_arm cs_insns = cs.disasm(input, base) result = [] diff --git a/src/patcherex2/components/disassemblers/disassembler.py b/src/patcherex2/components/disassemblers/disassembler.py index 711fc2f..09e1117 100644 --- a/src/patcherex2/components/disassemblers/disassembler.py +++ b/src/patcherex2/components/disassemblers/disassembler.py @@ -1,4 +1,4 @@ -from typing import Dict, Union +from __future__ import annotations class Disassembler: @@ -8,5 +8,5 @@ def __init__(self, p) -> None: def disassemble(self, input: bytes, base=0, **kwargs) -> None: raise NotImplementedError() - def to_asm_string(self, insn: Dict[str, Union[int, str]]) -> str: + def to_asm_string(self, insn: dict[str, int | str]) -> str: return "{} {}".format(insn["mnemonic"], insn["op_str"]) diff --git a/src/patcherex2/components/disassemblers/ppc_vle.py b/src/patcherex2/components/disassemblers/ppc_vle.py index 7a24786..7671df2 100644 --- a/src/patcherex2/components/disassemblers/ppc_vle.py +++ b/src/patcherex2/components/disassemblers/ppc_vle.py @@ -1,9 +1,10 @@ +from __future__ import annotations + import logging import os import re import subprocess import tempfile -from typing import Dict, List, Union from ..assets.assets import Assets from .disassembler import Disassembler @@ -16,9 +17,7 @@ def __init__(self, p) -> None: self.p = p self.assets_path = Assets("ppc_vle").path - def disassemble( - self, input: bytes, base=0, **kwargs - ) -> List[Dict[str, Union[str, int]]]: + def disassemble(self, input: bytes, base=0, **kwargs) -> list[dict[str, str | int]]: if isinstance(input, str): input = bytes(map(ord, input)) with tempfile.TemporaryDirectory() as td: diff --git a/src/patcherex2/components/patch_managers/patch_manager.py b/src/patcherex2/components/patch_managers/patch_manager.py index 1eef0af..59ffa8d 100644 --- a/src/patcherex2/components/patch_managers/patch_manager.py +++ b/src/patcherex2/components/patch_managers/patch_manager.py @@ -1,4 +1,4 @@ -from typing import List +from __future__ import annotations from patcherex2.patches import Patch @@ -12,7 +12,7 @@ def add_patch(self, patch: Patch) -> None: self.analyzed = False self.patches.append(patch) - def add_patches(self, patches: List[Patch]) -> None: + def add_patches(self, patches: list[Patch]) -> None: for patch in patches: self.add_patch(patch) diff --git a/src/patcherex2/components/utils/utils.py b/src/patcherex2/components/utils/utils.py index c37213d..0850af5 100644 --- a/src/patcherex2/components/utils/utils.py +++ b/src/patcherex2/components/utils/utils.py @@ -1,6 +1,7 @@ +from __future__ import annotations + import logging import re -from typing import Dict, Optional from ..allocation_managers.allocation_manager import MemoryFlag @@ -18,7 +19,7 @@ def insert_trampoline_code( instrs: str, force_insert=False, detour_pos=-1, - symbols: Dict[str, int] = None, + symbols: dict[str, int] = None, ) -> None: logger.debug(f"Inserting trampoline code at {hex(addr)}: {instrs}") symbols = symbols if symbols else {} @@ -93,9 +94,7 @@ def insert_trampoline_code( self.p.binary_analyzer.mem_addr_to_file_offset(addr), jmp_to_trampoline ) - def get_instrs_to_be_moved( - self, addr: int, ignore_unmovable=False - ) -> Optional[str]: + def get_instrs_to_be_moved(self, addr: int, ignore_unmovable=False) -> str | None: basic_block = self.p.binary_analyzer.get_basic_block(addr) idx = basic_block["instruction_addrs"].index(addr) end = addr + self.p.archinfo.jmp_size diff --git a/src/patcherex2/patcherex.py b/src/patcherex2/patcherex.py index af644c4..af6476b 100644 --- a/src/patcherex2/patcherex.py +++ b/src/patcherex2/patcherex.py @@ -1,6 +1,7 @@ # ruff: noqa: F403, F405 +from __future__ import annotations + import logging -from typing import Dict, Optional, Type from .patches import * from .patches import __all__ as all_patches @@ -17,9 +18,9 @@ class Patcherex: def __init__( self, binary_path: str, - target_cls: Optional[Type[Target]] = None, - target_opts: Optional[Dict[str, str]] = None, - components_opts: Optional[Dict[str, Dict[str, str]]] = None, + target_cls: type[Target] | None = None, + target_opts: dict[str, str] | None = None, + components_opts: dict[str, dict[str, str]] | None = None, ) -> None: """ Constructor.