fix and enable binary ninja fake string segment support
This commit is contained in:
@@ -1,6 +1,21 @@
|
|||||||
from binaryninja import *
|
from binaryninja import (
|
||||||
|
BinaryView,
|
||||||
|
Component,
|
||||||
|
Type,
|
||||||
|
PointerType,
|
||||||
|
TypeParser,
|
||||||
|
Platform,
|
||||||
|
Endianness,
|
||||||
|
ArrayType,
|
||||||
|
BackgroundTaskThread,
|
||||||
|
demangle_gnu3,
|
||||||
|
get_qualified_name,
|
||||||
|
SegmentFlag,
|
||||||
|
SectionSemantics,
|
||||||
|
)
|
||||||
|
from binaryninja.log import log_error
|
||||||
|
|
||||||
#try:
|
# try:
|
||||||
# from typing import TYPE_CHECKING
|
# from typing import TYPE_CHECKING
|
||||||
# if TYPE_CHECKING:
|
# if TYPE_CHECKING:
|
||||||
# from ..shared_base import BaseStatusHandler, BaseDisassemblerInterface, ScriptContext
|
# from ..shared_base import BaseStatusHandler, BaseDisassemblerInterface, ScriptContext
|
||||||
@@ -10,16 +25,14 @@ from binaryninja import *
|
|||||||
# from datetime import datetime
|
# from datetime import datetime
|
||||||
# from typing import Literal
|
# from typing import Literal
|
||||||
# bv: BinaryView = None # type: ignore
|
# bv: BinaryView = None # type: ignore
|
||||||
#except:
|
# except:
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
CURRENT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
||||||
# this is implemented,
|
supports_fake_string_segment: bool = True
|
||||||
# however the write API does not seem to work properly here (possibly a bug),
|
|
||||||
# so this is disabled for now
|
|
||||||
supports_fake_string_segment: bool = False
|
|
||||||
|
|
||||||
_status: BaseStatusHandler
|
_status: BaseStatusHandler
|
||||||
|
|
||||||
@@ -32,20 +45,16 @@ class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
|||||||
_address_size: int
|
_address_size: int
|
||||||
_endianness: Literal["little", "big"]
|
_endianness: Literal["little", "big"]
|
||||||
|
|
||||||
TYPE_PARSER_OPTIONS = [
|
TYPE_PARSER_OPTIONS = ["--target=x86_64-pc-linux", "-x", "c++", "-D_BINARYNINJA_=1"]
|
||||||
"--target=x86_64-pc-linux",
|
|
||||||
"-x", "c++",
|
|
||||||
"-D_BINARYNINJA_=1"
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, status: BaseStatusHandler):
|
def __init__(self, status: BaseStatusHandler):
|
||||||
self._status = status
|
self._status = status
|
||||||
|
|
||||||
def _get_or_create_type(self, type: str) -> Type:
|
def _get_or_create_type(self, type: str) -> Type:
|
||||||
if type.startswith("struct "):
|
if type.startswith("struct "):
|
||||||
type = type[len("struct "):]
|
type = type[len("struct ") :]
|
||||||
elif type.startswith("class "):
|
elif type.startswith("class "):
|
||||||
type = type[len("class "):]
|
type = type[len("class ") :]
|
||||||
|
|
||||||
if type in self._type_cache:
|
if type in self._type_cache:
|
||||||
return self._type_cache[type]
|
return self._type_cache[type]
|
||||||
@@ -66,9 +75,11 @@ class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
|||||||
parsed_types, errors = TypeParser.default.parse_types_from_source(
|
parsed_types, errors = TypeParser.default.parse_types_from_source(
|
||||||
types,
|
types,
|
||||||
filename if filename else "types.hpp",
|
filename if filename else "types.hpp",
|
||||||
self._view.platform if self._view.platform is not None else Platform["windows-x86_64"],
|
self._view.platform
|
||||||
|
if self._view.platform is not None
|
||||||
|
else Platform["windows-x86_64"],
|
||||||
self._view,
|
self._view,
|
||||||
self.TYPE_PARSER_OPTIONS
|
self.TYPE_PARSER_OPTIONS,
|
||||||
)
|
)
|
||||||
|
|
||||||
if parsed_types is None:
|
if parsed_types is None:
|
||||||
@@ -90,7 +101,9 @@ class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
|||||||
self._function_type_cache = {}
|
self._function_type_cache = {}
|
||||||
|
|
||||||
self._address_size = self._view.address_size
|
self._address_size = self._view.address_size
|
||||||
self._endianness = "little" if self._view.endianness == Endianness.LittleEndian else "big"
|
self._endianness = (
|
||||||
|
"little" if self._view.endianness == Endianness.LittleEndian else "big"
|
||||||
|
)
|
||||||
|
|
||||||
self._status.update_step("Parsing header")
|
self._status.update_step("Parsing header")
|
||||||
|
|
||||||
@@ -105,7 +118,9 @@ class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
|||||||
self._status.update_progress(1)
|
self._status.update_progress(1)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
self._view.define_user_types([(x.name, x.type) for x in parsed_types.types], import_progress_func)
|
self._view.define_user_types(
|
||||||
|
[(x.name, x.type) for x in parsed_types.types], import_progress_func
|
||||||
|
)
|
||||||
|
|
||||||
def on_finish(self):
|
def on_finish(self):
|
||||||
self._view.commit_undo_actions(self._undo_id)
|
self._view.commit_undo_actions(self._undo_id)
|
||||||
@@ -143,8 +158,8 @@ class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
|||||||
if type in self._function_type_cache:
|
if type in self._function_type_cache:
|
||||||
function.type = self._function_type_cache[type] # type: ignore
|
function.type = self._function_type_cache[type] # type: ignore
|
||||||
else:
|
else:
|
||||||
#log_info(f"skipping function type setting for {address}, {type}")
|
# log_info(f"skipping function type setting for {address}, {type}")
|
||||||
#pass
|
# pass
|
||||||
function.type = type.replace("this", "`this`")
|
function.type = type.replace("this", "`this`")
|
||||||
|
|
||||||
def set_data_comment(self, address: int, cmt: str):
|
def set_data_comment(self, address: int, cmt: str):
|
||||||
@@ -176,7 +191,7 @@ class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
|||||||
if name.startswith("_Z"):
|
if name.startswith("_Z"):
|
||||||
type, demangled = demangle_gnu3(self._view.arch, name, self._view)
|
type, demangled = demangle_gnu3(self._view.arch, name, self._view)
|
||||||
function.name = get_qualified_name(demangled)
|
function.name = get_qualified_name(demangled)
|
||||||
#function.type = type - this does not work due to the generated types not being namespaced. :(
|
# function.type = type - this does not work due to the generated types not being namespaced. :(
|
||||||
else:
|
else:
|
||||||
function.name = name
|
function.name = name
|
||||||
|
|
||||||
@@ -230,10 +245,19 @@ class BinaryNinjaDisassemblerInterface(BaseDisassemblerInterface):
|
|||||||
def create_fake_segment(self, name: str, size: int) -> int:
|
def create_fake_segment(self, name: str, size: int) -> int:
|
||||||
last_end_addr = self._view.mapped_address_ranges[-1].end
|
last_end_addr = self._view.mapped_address_ranges[-1].end
|
||||||
if last_end_addr % 0x1000 != 0:
|
if last_end_addr % 0x1000 != 0:
|
||||||
last_end_addr += (0x1000 - (last_end_addr % 0x1000))
|
last_end_addr += 0x1000 - (last_end_addr % 0x1000)
|
||||||
|
|
||||||
|
self._view.memory_map.add_memory_region(
|
||||||
|
f"mem_{name}",
|
||||||
|
last_end_addr,
|
||||||
|
bytes(size),
|
||||||
|
SegmentFlag.SegmentContainsData | SegmentFlag.SegmentReadable,
|
||||||
|
)
|
||||||
|
|
||||||
|
self._view.add_user_section(
|
||||||
|
name, last_end_addr, size, SectionSemantics.ReadOnlyDataSectionSemantics
|
||||||
|
)
|
||||||
|
|
||||||
self._view.add_user_segment(last_end_addr, size, 0, 0, SegmentFlag.SegmentContainsData)
|
|
||||||
self._view.add_user_section(name, last_end_addr, size, SectionSemantics.ReadOnlyDataSectionSemantics)
|
|
||||||
return last_end_addr
|
return last_end_addr
|
||||||
|
|
||||||
def write_string(self, address: int, value: str) -> int:
|
def write_string(self, address: int, value: str) -> int:
|
||||||
@@ -255,7 +279,8 @@ class BinaryNinjaStatusHandler(BaseStatusHandler):
|
|||||||
self.last_updated_time = datetime.min
|
self.last_updated_time = datetime.min
|
||||||
self._thread = thread
|
self._thread = thread
|
||||||
|
|
||||||
def initialize(self): pass
|
def initialize(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
if self.was_cancelled():
|
if self.was_cancelled():
|
||||||
@@ -271,7 +296,7 @@ class BinaryNinjaStatusHandler(BaseStatusHandler):
|
|||||||
total_time = current_time - self.start_time
|
total_time = current_time - self.start_time
|
||||||
self._thread.progress = f"Processing IL2CPP metadata: {self.step} ({self.current_items}/{self.max_items}), elapsed: {step_time} ({total_time})"
|
self._thread.progress = f"Processing IL2CPP metadata: {self.step} ({self.current_items}/{self.max_items}), elapsed: {step_time} ({total_time})"
|
||||||
|
|
||||||
def update_step(self, step, max_items = 0):
|
def update_step(self, step, max_items=0):
|
||||||
self.step = step
|
self.step = step
|
||||||
self.max_items = max_items
|
self.max_items = max_items
|
||||||
self.current_items = 0
|
self.current_items = 0
|
||||||
@@ -279,15 +304,17 @@ class BinaryNinjaStatusHandler(BaseStatusHandler):
|
|||||||
self.last_updated_time = datetime.min
|
self.last_updated_time = datetime.min
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def update_progress(self, new_progress = 1):
|
def update_progress(self, new_progress=1):
|
||||||
self.current_items += new_progress
|
self.current_items += new_progress
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def was_cancelled(self): return False
|
def was_cancelled(self):
|
||||||
|
return False
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Entry point
|
# Entry point
|
||||||
class Il2CppTask(BackgroundTaskThread):
|
class Il2CppTask(BackgroundTaskThread):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -299,4 +326,5 @@ class Il2CppTask(BackgroundTaskThread):
|
|||||||
context = ScriptContext(backend, status)
|
context = ScriptContext(backend, status)
|
||||||
context.process()
|
context.process()
|
||||||
|
|
||||||
|
|
||||||
Il2CppTask().start()
|
Il2CppTask().start()
|
||||||
Reference in New Issue
Block a user