diff options
Diffstat (limited to 'plugins/warp/api/python')
| -rw-r--r-- | plugins/warp/api/python/CMakeLists.txt | 50 | ||||
| -rw-r--r-- | plugins/warp/api/python/__init__.py | 7 | ||||
| -rw-r--r-- | plugins/warp/api/python/_warpcore.py | 1081 | ||||
| -rw-r--r-- | plugins/warp/api/python/_warpcore_template.py | 58 | ||||
| -rw-r--r-- | plugins/warp/api/python/generator.cpp | 652 | ||||
| -rw-r--r-- | plugins/warp/api/python/warp.py | 384 | ||||
| -rw-r--r-- | plugins/warp/api/python/warp_enums.py | 1 |
7 files changed, 2233 insertions, 0 deletions
diff --git a/plugins/warp/api/python/CMakeLists.txt b/plugins/warp/api/python/CMakeLists.txt new file mode 100644 index 00000000..8e6003c0 --- /dev/null +++ b/plugins/warp/api/python/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.9...3.15 FATAL_ERROR) + +project(warp-python-api) + +file(GLOB PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/*.py) +list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/_warpcore.py) +list(REMOVE_ITEM PYTHON_SOURCES ${PROJECT_SOURCE_DIR}/enums.py) + +add_executable(warp_generator + ${PROJECT_SOURCE_DIR}/generator.cpp) +target_link_libraries(warp_generator binaryninjaapi) +target_include_directories(warp_generator PUBLIC {PROJECT_SOURCE_DIR}/../../api) + +set_target_properties(warp_generator PROPERTIES + CXX_STANDARD 17 + CXX_STANDARD_REQUIRED ON + BUILD_WITH_INSTALL_RPATH OFF + RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + +if(BN_INTERNAL_BUILD) + set(PYTHON_OUTPUT_DIRECTORY ${BN_RESOURCE_DIR}/python/binaryninja/warp/) +else() + set(PYTHON_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out/plugins/warp/) +endif() + +if(WIN32) + if (BN_INTERNAL_BUILD) + add_custom_command(TARGET warp_generator PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${BN_CORE_OUTPUT_DIR}/binaryninjacore.dll ${PROJECT_BINARY_DIR}/) + else() + add_custom_command(TARGET warp_generator PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${BN_INSTALL_DIR}/binaryninjacore.dll ${PROJECT_BINARY_DIR}/) + endif() +endif() + +add_custom_target(warp_generator_copy ALL + BYPRODUCTS ${PROJECT_SOURCE_DIR}/_warpcore.py ${PROJECT_SOURCE_DIR}/enums.py + DEPENDS ${PYTHON_SOURCES} ${PROJECT_SOURCE_DIR}/../warpcore.h $<TARGET_FILE:warp_generator> + COMMAND ${CMAKE_COMMAND} -E echo "Copying WARP Python Sources" + COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTHON_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E env ASAN_OPTIONS=detect_leaks=0 $<TARGET_FILE:warp_generator> + ${PROJECT_SOURCE_DIR}/../warpcore.h + ${PROJECT_SOURCE_DIR}/_warpcore.py + ${PROJECT_SOURCE_DIR}/_warpcore_template.py + ${PROJECT_SOURCE_DIR}/warp_enums.py + + COMMAND ${CMAKE_COMMAND} -E copy ${PYTHON_SOURCES} ${PYTHON_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/_warpcore.py ${PYTHON_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/warp_enums.py ${PYTHON_OUTPUT_DIRECTORY}) + diff --git a/plugins/warp/api/python/__init__.py b/plugins/warp/api/python/__init__.py new file mode 100644 index 00000000..f4bc8e83 --- /dev/null +++ b/plugins/warp/api/python/__init__.py @@ -0,0 +1,7 @@ +import os + +from binaryninja._binaryninjacore import BNGetUserPluginDirectory +user_plugin_dir = os.path.realpath(BNGetUserPluginDirectory()) +current_path = os.path.realpath(__file__) + +from .warp import *
\ No newline at end of file diff --git a/plugins/warp/api/python/_warpcore.py b/plugins/warp/api/python/_warpcore.py new file mode 100644 index 00000000..c53feefa --- /dev/null +++ b/plugins/warp/api/python/_warpcore.py @@ -0,0 +1,1081 @@ +import binaryninja +import ctypes, os + +from typing import Optional +from . import warp_enums +# Load core module +import platform +core = None +core_platform = platform.system() + +from binaryninja import Settings +if Settings().get_bool("corePlugins.warp"): + from binaryninja._binaryninjacore import BNGetBundledPluginDirectory + if core_platform == "Darwin": + _base_path = BNGetBundledPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "libwarp_ninja.dylib")) + + elif core_platform == "Linux": + _base_path = BNGetBundledPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "libwarp_ninja.so")) + + elif (core_platform == "Windows") or (core_platform.find("CYGWIN_NT") == 0): + _base_path = BNGetBundledPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "warp_ninja.dll")) + else: + raise Exception("OS not supported") +else: + from binaryninja._binaryninjacore import BNGetUserPluginDirectory + if core_platform == "Darwin": + _base_path = BNGetUserPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "libwarp_ninja.dylib")) + + elif core_platform == "Linux": + _base_path = BNGetUserPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "libwarp_ninja.so")) + + elif (core_platform == "Windows") or (core_platform.find("CYGWIN_NT") == 0): + _base_path = BNGetUserPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "warp_ninja.dll")) + else: + raise Exception("OS not supported") + +def cstr(var) -> Optional[ctypes.c_char_p]: + if var is None: + return None + if isinstance(var, bytes): + return var + return var.encode("utf-8") + +def pyNativeStr(arg): + if isinstance(arg, str): + return arg + else: + return arg.decode('utf8') + +def free_string(value:ctypes.c_char_p) -> None: + BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte))) + +from binaryninja._binaryninjacore import BNFreeString +# Type definitions +from binaryninja._binaryninjacore import BNArchitecture, BNArchitectureHandle +from binaryninja._binaryninjacore import BNBasicBlock, BNBasicBlockHandle +from binaryninja._binaryninjacore import BNBinaryView, BNBinaryViewHandle +from binaryninja._binaryninjacore import BNFunction, BNFunctionHandle +from binaryninja._binaryninjacore import BNLowLevelILFunction, BNLowLevelILFunctionHandle +from binaryninja._binaryninjacore import BNPlatform, BNPlatformHandle +from binaryninja._binaryninjacore import BNSymbol, BNSymbolHandle +from binaryninja._binaryninjacore import BNType, BNTypeHandle +class BNWARPConstraint(ctypes.Structure): + pass +BNWARPConstraintHandle = ctypes.POINTER(BNWARPConstraint) +class BNWARPContainer(ctypes.Structure): + pass +BNWARPContainerHandle = ctypes.POINTER(BNWARPContainer) +class BNWARPFunction(ctypes.Structure): + pass +BNWARPFunctionHandle = ctypes.POINTER(BNWARPFunction) +class BNWARPFunctionComment(ctypes.Structure): + @property + def text(self): + return pyNativeStr(self._text) + @text.setter + def text(self, value): + self._text = cstr(value) +BNWARPFunctionCommentHandle = ctypes.POINTER(BNWARPFunctionComment) +class BNWARPTarget(ctypes.Structure): + pass +BNWARPTargetHandle = ctypes.POINTER(BNWARPTarget) +class BNWARPUUID(ctypes.Structure): + pass +BNWARPUUIDHandle = ctypes.POINTER(BNWARPUUID) + +# Structure definitions +BNWARPBasicBlockGUID = BNWARPUUID +BNWARPBasicBlockGUIDHandle = BNWARPUUIDHandle +BNWARPConstraintGUID = BNWARPUUID +BNWARPConstraintGUIDHandle = BNWARPUUIDHandle +BNWARPFunctionComment._fields_ = [ + ("_text", ctypes.c_char_p), + ("offset", ctypes.c_longlong), + ] +BNWARPFunctionGUID = BNWARPUUID +BNWARPFunctionGUIDHandle = BNWARPUUIDHandle +BNWARPSource = BNWARPUUID +BNWARPSourceHandle = BNWARPUUIDHandle +BNWARPTypeGUID = BNWARPUUID +BNWARPTypeGUIDHandle = BNWARPUUIDHandle +BNWARPUUID._fields_ = [ + ("uuid", ctypes.c_ubyte * 16), + ] +BNWARPConstraint._fields_ = [ + ("guid", BNWARPConstraintGUID), + ("offset", ctypes.c_longlong), + ] + +# Function definitions +# ------------------------------------------------------- +# _BNWARPContainerAddFunctions + +_BNWARPContainerAddFunctions = core.BNWARPContainerAddFunctions +_BNWARPContainerAddFunctions.restype = ctypes.c_bool +_BNWARPContainerAddFunctions.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPTarget), + ctypes.POINTER(BNWARPSource), + ctypes.POINTER(ctypes.POINTER(BNWARPFunction)), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPContainerAddFunctions( + container: ctypes.POINTER(BNWARPContainer), + target: ctypes.POINTER(BNWARPTarget), + source: ctypes.POINTER(BNWARPSource), + functions: ctypes.POINTER(ctypes.POINTER(BNWARPFunction)), + count: int + ) -> bool: + return _BNWARPContainerAddFunctions(container, target, source, functions, count) + + +# ------------------------------------------------------- +# _BNWARPContainerAddSource + +_BNWARPContainerAddSource = core.BNWARPContainerAddSource +_BNWARPContainerAddSource.restype = ctypes.c_bool +_BNWARPContainerAddSource.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.c_char_p, + ctypes.POINTER(BNWARPSource), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerAddSource( + container: ctypes.POINTER(BNWARPContainer), + sourcePath: Optional[str], + result: ctypes.POINTER(BNWARPSource) + ) -> bool: + return _BNWARPContainerAddSource(container, cstr(sourcePath), result) + + +# ------------------------------------------------------- +# _BNWARPContainerAddTypes + +_BNWARPContainerAddTypes = core.BNWARPContainerAddTypes +_BNWARPContainerAddTypes.restype = ctypes.c_bool +_BNWARPContainerAddTypes.argtypes = [ + ctypes.POINTER(BNBinaryView), + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPSource), + ctypes.POINTER(ctypes.POINTER(BNType)), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPContainerAddTypes( + view: ctypes.POINTER(BNBinaryView), + container: ctypes.POINTER(BNWARPContainer), + source: ctypes.POINTER(BNWARPSource), + types: ctypes.POINTER(ctypes.POINTER(BNType)), + count: int + ) -> bool: + return _BNWARPContainerAddTypes(view, container, source, types, count) + + +# ------------------------------------------------------- +# _BNWARPContainerCommitSource + +_BNWARPContainerCommitSource = core.BNWARPContainerCommitSource +_BNWARPContainerCommitSource.restype = ctypes.c_bool +_BNWARPContainerCommitSource.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPSource), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerCommitSource( + container: ctypes.POINTER(BNWARPContainer), + source: ctypes.POINTER(BNWARPSource) + ) -> bool: + return _BNWARPContainerCommitSource(container, source) + + +# ------------------------------------------------------- +# _BNWARPContainerGetFunctionsWithGUID + +_BNWARPContainerGetFunctionsWithGUID = core.BNWARPContainerGetFunctionsWithGUID +_BNWARPContainerGetFunctionsWithGUID.restype = ctypes.POINTER(ctypes.POINTER(BNWARPFunction)) +_BNWARPContainerGetFunctionsWithGUID.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPTarget), + ctypes.POINTER(BNWARPSource), + ctypes.POINTER(BNWARPFunctionGUID), + ctypes.POINTER(ctypes.c_ulonglong), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerGetFunctionsWithGUID( + container: ctypes.POINTER(BNWARPContainer), + target: ctypes.POINTER(BNWARPTarget), + source: ctypes.POINTER(BNWARPSource), + guid: ctypes.POINTER(BNWARPFunctionGUID), + count: ctypes.POINTER(ctypes.c_ulonglong) + ) -> Optional[ctypes.POINTER(ctypes.POINTER(BNWARPFunction))]: + result = _BNWARPContainerGetFunctionsWithGUID(container, target, source, guid, count) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPContainerGetName + +_BNWARPContainerGetName = core.BNWARPContainerGetName +_BNWARPContainerGetName.restype = ctypes.POINTER(ctypes.c_byte) +_BNWARPContainerGetName.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerGetName( + container: ctypes.POINTER(BNWARPContainer) + ) -> Optional[Optional[str]]: + result = _BNWARPContainerGetName(container) + if not result: + return None + string = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value)) + BNFreeString(result) + return string + + +# ------------------------------------------------------- +# _BNWARPContainerGetSourcePath + +_BNWARPContainerGetSourcePath = core.BNWARPContainerGetSourcePath +_BNWARPContainerGetSourcePath.restype = ctypes.POINTER(ctypes.c_byte) +_BNWARPContainerGetSourcePath.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPSource), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerGetSourcePath( + container: ctypes.POINTER(BNWARPContainer), + source: ctypes.POINTER(BNWARPSource) + ) -> Optional[Optional[str]]: + result = _BNWARPContainerGetSourcePath(container, source) + if not result: + return None + string = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value)) + BNFreeString(result) + return string + + +# ------------------------------------------------------- +# _BNWARPContainerGetSources + +_BNWARPContainerGetSources = core.BNWARPContainerGetSources +_BNWARPContainerGetSources.restype = ctypes.POINTER(BNWARPSource) +_BNWARPContainerGetSources.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(ctypes.c_ulonglong), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerGetSources( + container: ctypes.POINTER(BNWARPContainer), + count: ctypes.POINTER(ctypes.c_ulonglong) + ) -> Optional[ctypes.POINTER(BNWARPSource)]: + result = _BNWARPContainerGetSources(container, count) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPContainerGetSourcesWithFunctionGUID + +_BNWARPContainerGetSourcesWithFunctionGUID = core.BNWARPContainerGetSourcesWithFunctionGUID +_BNWARPContainerGetSourcesWithFunctionGUID.restype = ctypes.POINTER(BNWARPSource) +_BNWARPContainerGetSourcesWithFunctionGUID.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPTarget), + ctypes.POINTER(BNWARPFunctionGUID), + ctypes.POINTER(ctypes.c_ulonglong), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerGetSourcesWithFunctionGUID( + container: ctypes.POINTER(BNWARPContainer), + target: ctypes.POINTER(BNWARPTarget), + guid: ctypes.POINTER(BNWARPFunctionGUID), + count: ctypes.POINTER(ctypes.c_ulonglong) + ) -> Optional[ctypes.POINTER(BNWARPSource)]: + result = _BNWARPContainerGetSourcesWithFunctionGUID(container, target, guid, count) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPContainerGetSourcesWithTypeGUID + +_BNWARPContainerGetSourcesWithTypeGUID = core.BNWARPContainerGetSourcesWithTypeGUID +_BNWARPContainerGetSourcesWithTypeGUID.restype = ctypes.POINTER(BNWARPSource) +_BNWARPContainerGetSourcesWithTypeGUID.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPTypeGUID), + ctypes.POINTER(ctypes.c_ulonglong), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerGetSourcesWithTypeGUID( + container: ctypes.POINTER(BNWARPContainer), + guid: ctypes.POINTER(BNWARPTypeGUID), + count: ctypes.POINTER(ctypes.c_ulonglong) + ) -> Optional[ctypes.POINTER(BNWARPSource)]: + result = _BNWARPContainerGetSourcesWithTypeGUID(container, guid, count) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPContainerGetTypeGUIDsWithName + +_BNWARPContainerGetTypeGUIDsWithName = core.BNWARPContainerGetTypeGUIDsWithName +_BNWARPContainerGetTypeGUIDsWithName.restype = ctypes.POINTER(BNWARPTypeGUID) +_BNWARPContainerGetTypeGUIDsWithName.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPSource), + ctypes.c_char_p, + ctypes.POINTER(ctypes.c_ulonglong), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerGetTypeGUIDsWithName( + container: ctypes.POINTER(BNWARPContainer), + source: ctypes.POINTER(BNWARPSource), + name: Optional[str], + count: ctypes.POINTER(ctypes.c_ulonglong) + ) -> Optional[ctypes.POINTER(BNWARPTypeGUID)]: + result = _BNWARPContainerGetTypeGUIDsWithName(container, source, cstr(name), count) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPContainerGetTypeWithGUID + +_BNWARPContainerGetTypeWithGUID = core.BNWARPContainerGetTypeWithGUID +_BNWARPContainerGetTypeWithGUID.restype = ctypes.POINTER(BNType) +_BNWARPContainerGetTypeWithGUID.argtypes = [ + ctypes.POINTER(BNArchitecture), + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPSource), + ctypes.POINTER(BNWARPTypeGUID), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerGetTypeWithGUID( + arch: ctypes.POINTER(BNArchitecture), + container: ctypes.POINTER(BNWARPContainer), + source: ctypes.POINTER(BNWARPSource), + guid: ctypes.POINTER(BNWARPTypeGUID) + ) -> Optional[ctypes.POINTER(BNType)]: + result = _BNWARPContainerGetTypeWithGUID(arch, container, source, guid) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPContainerIsSourceUncommitted + +_BNWARPContainerIsSourceUncommitted = core.BNWARPContainerIsSourceUncommitted +_BNWARPContainerIsSourceUncommitted.restype = ctypes.c_bool +_BNWARPContainerIsSourceUncommitted.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPSource), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerIsSourceUncommitted( + container: ctypes.POINTER(BNWARPContainer), + source: ctypes.POINTER(BNWARPSource) + ) -> bool: + return _BNWARPContainerIsSourceUncommitted(container, source) + + +# ------------------------------------------------------- +# _BNWARPContainerIsSourceWritable + +_BNWARPContainerIsSourceWritable = core.BNWARPContainerIsSourceWritable +_BNWARPContainerIsSourceWritable.restype = ctypes.c_bool +_BNWARPContainerIsSourceWritable.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPSource), + ] + + +# noinspection PyPep8Naming +def BNWARPContainerIsSourceWritable( + container: ctypes.POINTER(BNWARPContainer), + source: ctypes.POINTER(BNWARPSource) + ) -> bool: + return _BNWARPContainerIsSourceWritable(container, source) + + +# ------------------------------------------------------- +# _BNWARPContainerRemoveFunctions + +_BNWARPContainerRemoveFunctions = core.BNWARPContainerRemoveFunctions +_BNWARPContainerRemoveFunctions.restype = ctypes.c_bool +_BNWARPContainerRemoveFunctions.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPTarget), + ctypes.POINTER(BNWARPSource), + ctypes.POINTER(ctypes.POINTER(BNWARPFunction)), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPContainerRemoveFunctions( + container: ctypes.POINTER(BNWARPContainer), + target: ctypes.POINTER(BNWARPTarget), + source: ctypes.POINTER(BNWARPSource), + functions: ctypes.POINTER(ctypes.POINTER(BNWARPFunction)), + count: int + ) -> bool: + return _BNWARPContainerRemoveFunctions(container, target, source, functions, count) + + +# ------------------------------------------------------- +# _BNWARPContainerRemoveTypes + +_BNWARPContainerRemoveTypes = core.BNWARPContainerRemoveTypes +_BNWARPContainerRemoveTypes.restype = ctypes.c_bool +_BNWARPContainerRemoveTypes.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ctypes.POINTER(BNWARPSource), + ctypes.POINTER(BNWARPTypeGUID), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPContainerRemoveTypes( + container: ctypes.POINTER(BNWARPContainer), + source: ctypes.POINTER(BNWARPSource), + types: ctypes.POINTER(BNWARPTypeGUID), + count: int + ) -> bool: + return _BNWARPContainerRemoveTypes(container, source, types, count) + + +# ------------------------------------------------------- +# _BNWARPFreeConstraintList + +_BNWARPFreeConstraintList = core.BNWARPFreeConstraintList +_BNWARPFreeConstraintList.restype = None +_BNWARPFreeConstraintList.argtypes = [ + ctypes.POINTER(BNWARPConstraint), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPFreeConstraintList( + constraints: ctypes.POINTER(BNWARPConstraint), + count: int + ) -> None: + return _BNWARPFreeConstraintList(constraints, count) + + +# ------------------------------------------------------- +# _BNWARPFreeContainerList + +_BNWARPFreeContainerList = core.BNWARPFreeContainerList +_BNWARPFreeContainerList.restype = None +_BNWARPFreeContainerList.argtypes = [ + ctypes.POINTER(ctypes.POINTER(BNWARPContainer)), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPFreeContainerList( + containers: ctypes.POINTER(ctypes.POINTER(BNWARPContainer)), + count: int + ) -> None: + return _BNWARPFreeContainerList(containers, count) + + +# ------------------------------------------------------- +# _BNWARPFreeContainerReference + +_BNWARPFreeContainerReference = core.BNWARPFreeContainerReference +_BNWARPFreeContainerReference.restype = None +_BNWARPFreeContainerReference.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ] + + +# noinspection PyPep8Naming +def BNWARPFreeContainerReference( + container: ctypes.POINTER(BNWARPContainer) + ) -> None: + return _BNWARPFreeContainerReference(container) + + +# ------------------------------------------------------- +# _BNWARPFreeFunctionCommentList + +_BNWARPFreeFunctionCommentList = core.BNWARPFreeFunctionCommentList +_BNWARPFreeFunctionCommentList.restype = None +_BNWARPFreeFunctionCommentList.argtypes = [ + ctypes.POINTER(BNWARPFunctionComment), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPFreeFunctionCommentList( + comments: ctypes.POINTER(BNWARPFunctionComment), + count: int + ) -> None: + return _BNWARPFreeFunctionCommentList(comments, count) + + +# ------------------------------------------------------- +# _BNWARPFreeFunctionList + +_BNWARPFreeFunctionList = core.BNWARPFreeFunctionList +_BNWARPFreeFunctionList.restype = None +_BNWARPFreeFunctionList.argtypes = [ + ctypes.POINTER(ctypes.POINTER(BNWARPFunction)), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPFreeFunctionList( + functions: ctypes.POINTER(ctypes.POINTER(BNWARPFunction)), + count: int + ) -> None: + return _BNWARPFreeFunctionList(functions, count) + + +# ------------------------------------------------------- +# _BNWARPFreeFunctionReference + +_BNWARPFreeFunctionReference = core.BNWARPFreeFunctionReference +_BNWARPFreeFunctionReference.restype = None +_BNWARPFreeFunctionReference.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPFreeFunctionReference( + function: ctypes.POINTER(BNWARPFunction) + ) -> None: + return _BNWARPFreeFunctionReference(function) + + +# ------------------------------------------------------- +# _BNWARPFreeTargetReference + +_BNWARPFreeTargetReference = core.BNWARPFreeTargetReference +_BNWARPFreeTargetReference.restype = None +_BNWARPFreeTargetReference.argtypes = [ + ctypes.POINTER(BNWARPTarget), + ] + + +# noinspection PyPep8Naming +def BNWARPFreeTargetReference( + target: ctypes.POINTER(BNWARPTarget) + ) -> None: + return _BNWARPFreeTargetReference(target) + + +# ------------------------------------------------------- +# _BNWARPFreeUUIDList + +_BNWARPFreeUUIDList = core.BNWARPFreeUUIDList +_BNWARPFreeUUIDList.restype = None +_BNWARPFreeUUIDList.argtypes = [ + ctypes.POINTER(BNWARPUUID), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPFreeUUIDList( + uuids: ctypes.POINTER(BNWARPUUID), + count: int + ) -> None: + return _BNWARPFreeUUIDList(uuids, count) + + +# ------------------------------------------------------- +# _BNWARPFunctionApply + +_BNWARPFunctionApply = core.BNWARPFunctionApply +_BNWARPFunctionApply.restype = None +_BNWARPFunctionApply.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ctypes.POINTER(BNFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPFunctionApply( + function: ctypes.POINTER(BNWARPFunction), + analysisFunction: ctypes.POINTER(BNFunction) + ) -> None: + return _BNWARPFunctionApply(function, analysisFunction) + + +# ------------------------------------------------------- +# _BNWARPFunctionGetComments + +_BNWARPFunctionGetComments = core.BNWARPFunctionGetComments +_BNWARPFunctionGetComments.restype = ctypes.POINTER(BNWARPFunctionComment) +_BNWARPFunctionGetComments.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ctypes.POINTER(ctypes.c_ulonglong), + ] + + +# noinspection PyPep8Naming +def BNWARPFunctionGetComments( + function: ctypes.POINTER(BNWARPFunction), + count: ctypes.POINTER(ctypes.c_ulonglong) + ) -> Optional[ctypes.POINTER(BNWARPFunctionComment)]: + result = _BNWARPFunctionGetComments(function, count) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPFunctionGetConstraints + +_BNWARPFunctionGetConstraints = core.BNWARPFunctionGetConstraints +_BNWARPFunctionGetConstraints.restype = ctypes.POINTER(BNWARPConstraint) +_BNWARPFunctionGetConstraints.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ctypes.POINTER(ctypes.c_ulonglong), + ] + + +# noinspection PyPep8Naming +def BNWARPFunctionGetConstraints( + function: ctypes.POINTER(BNWARPFunction), + count: ctypes.POINTER(ctypes.c_ulonglong) + ) -> Optional[ctypes.POINTER(BNWARPConstraint)]: + result = _BNWARPFunctionGetConstraints(function, count) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPFunctionGetGUID + +_BNWARPFunctionGetGUID = core.BNWARPFunctionGetGUID +_BNWARPFunctionGetGUID.restype = BNWARPFunctionGUID +_BNWARPFunctionGetGUID.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPFunctionGetGUID( + function: ctypes.POINTER(BNWARPFunction) + ) -> BNWARPFunctionGUID: + return _BNWARPFunctionGetGUID(function) + + +# ------------------------------------------------------- +# _BNWARPFunctionGetSymbol + +_BNWARPFunctionGetSymbol = core.BNWARPFunctionGetSymbol +_BNWARPFunctionGetSymbol.restype = ctypes.POINTER(BNSymbol) +_BNWARPFunctionGetSymbol.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ctypes.POINTER(BNFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPFunctionGetSymbol( + function: ctypes.POINTER(BNWARPFunction), + analysisFunction: ctypes.POINTER(BNFunction) + ) -> Optional[ctypes.POINTER(BNSymbol)]: + result = _BNWARPFunctionGetSymbol(function, analysisFunction) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPFunctionGetSymbolName + +_BNWARPFunctionGetSymbolName = core.BNWARPFunctionGetSymbolName +_BNWARPFunctionGetSymbolName.restype = ctypes.POINTER(ctypes.c_byte) +_BNWARPFunctionGetSymbolName.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPFunctionGetSymbolName( + function: ctypes.POINTER(BNWARPFunction) + ) -> Optional[Optional[str]]: + result = _BNWARPFunctionGetSymbolName(function) + if not result: + return None + string = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value)) + BNFreeString(result) + return string + + +# ------------------------------------------------------- +# _BNWARPFunctionGetType + +_BNWARPFunctionGetType = core.BNWARPFunctionGetType +_BNWARPFunctionGetType.restype = ctypes.POINTER(BNType) +_BNWARPFunctionGetType.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ctypes.POINTER(BNFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPFunctionGetType( + function: ctypes.POINTER(BNWARPFunction), + analysisFunction: ctypes.POINTER(BNFunction) + ) -> Optional[ctypes.POINTER(BNType)]: + result = _BNWARPFunctionGetType(function, analysisFunction) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPFunctionsEqual + +_BNWARPFunctionsEqual = core.BNWARPFunctionsEqual +_BNWARPFunctionsEqual.restype = ctypes.c_bool +_BNWARPFunctionsEqual.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ctypes.POINTER(BNWARPFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPFunctionsEqual( + functionA: ctypes.POINTER(BNWARPFunction), + functionB: ctypes.POINTER(BNWARPFunction) + ) -> bool: + return _BNWARPFunctionsEqual(functionA, functionB) + + +# ------------------------------------------------------- +# _BNWARPGetAnalysisFunctionGUID + +_BNWARPGetAnalysisFunctionGUID = core.BNWARPGetAnalysisFunctionGUID +_BNWARPGetAnalysisFunctionGUID.restype = ctypes.c_bool +_BNWARPGetAnalysisFunctionGUID.argtypes = [ + ctypes.POINTER(BNFunction), + ctypes.POINTER(BNWARPFunctionGUID), + ] + + +# noinspection PyPep8Naming +def BNWARPGetAnalysisFunctionGUID( + analysisFunction: ctypes.POINTER(BNFunction), + result: ctypes.POINTER(BNWARPFunctionGUID) + ) -> bool: + return _BNWARPGetAnalysisFunctionGUID(analysisFunction, result) + + +# ------------------------------------------------------- +# _BNWARPGetBasicBlockGUID + +_BNWARPGetBasicBlockGUID = core.BNWARPGetBasicBlockGUID +_BNWARPGetBasicBlockGUID.restype = ctypes.c_bool +_BNWARPGetBasicBlockGUID.argtypes = [ + ctypes.POINTER(BNBasicBlock), + ctypes.POINTER(BNWARPBasicBlockGUID), + ] + + +# noinspection PyPep8Naming +def BNWARPGetBasicBlockGUID( + basicBlock: ctypes.POINTER(BNBasicBlock), + result: ctypes.POINTER(BNWARPBasicBlockGUID) + ) -> bool: + return _BNWARPGetBasicBlockGUID(basicBlock, result) + + +# ------------------------------------------------------- +# _BNWARPGetContainers + +_BNWARPGetContainers = core.BNWARPGetContainers +_BNWARPGetContainers.restype = ctypes.POINTER(ctypes.POINTER(BNWARPContainer)) +_BNWARPGetContainers.argtypes = [ + ctypes.POINTER(ctypes.c_ulonglong), + ] + + +# noinspection PyPep8Naming +def BNWARPGetContainers( + count: ctypes.POINTER(ctypes.c_ulonglong) + ) -> Optional[ctypes.POINTER(ctypes.POINTER(BNWARPContainer))]: + result = _BNWARPGetContainers(count) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPGetFunction + +_BNWARPGetFunction = core.BNWARPGetFunction +_BNWARPGetFunction.restype = ctypes.POINTER(BNWARPFunction) +_BNWARPGetFunction.argtypes = [ + ctypes.POINTER(BNFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPGetFunction( + analysisFunction: ctypes.POINTER(BNFunction) + ) -> Optional[ctypes.POINTER(BNWARPFunction)]: + result = _BNWARPGetFunction(analysisFunction) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPGetMatchedFunction + +_BNWARPGetMatchedFunction = core.BNWARPGetMatchedFunction +_BNWARPGetMatchedFunction.restype = ctypes.POINTER(BNWARPFunction) +_BNWARPGetMatchedFunction.argtypes = [ + ctypes.POINTER(BNFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPGetMatchedFunction( + analysisFunction: ctypes.POINTER(BNFunction) + ) -> Optional[ctypes.POINTER(BNWARPFunction)]: + result = _BNWARPGetMatchedFunction(analysisFunction) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPGetTarget + +_BNWARPGetTarget = core.BNWARPGetTarget +_BNWARPGetTarget.restype = ctypes.POINTER(BNWARPTarget) +_BNWARPGetTarget.argtypes = [ + ctypes.POINTER(BNPlatform), + ] + + +# noinspection PyPep8Naming +def BNWARPGetTarget( + platform: ctypes.POINTER(BNPlatform) + ) -> Optional[ctypes.POINTER(BNWARPTarget)]: + result = _BNWARPGetTarget(platform) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPIsLiftedInstructionBlacklisted + +_BNWARPIsLiftedInstructionBlacklisted = core.BNWARPIsLiftedInstructionBlacklisted +_BNWARPIsLiftedInstructionBlacklisted.restype = ctypes.c_bool +_BNWARPIsLiftedInstructionBlacklisted.argtypes = [ + ctypes.POINTER(BNLowLevelILFunction), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPIsLiftedInstructionBlacklisted( + liftedFunction: ctypes.POINTER(BNLowLevelILFunction), + idx: int + ) -> bool: + return _BNWARPIsLiftedInstructionBlacklisted(liftedFunction, idx) + + +# ------------------------------------------------------- +# _BNWARPIsLiftedInstructionVariant + +_BNWARPIsLiftedInstructionVariant = core.BNWARPIsLiftedInstructionVariant +_BNWARPIsLiftedInstructionVariant.restype = ctypes.c_bool +_BNWARPIsLiftedInstructionVariant.argtypes = [ + ctypes.POINTER(BNLowLevelILFunction), + ctypes.c_ulonglong, + ] + + +# noinspection PyPep8Naming +def BNWARPIsLiftedInstructionVariant( + liftedFunction: ctypes.POINTER(BNLowLevelILFunction), + idx: int + ) -> bool: + return _BNWARPIsLiftedInstructionVariant(liftedFunction, idx) + + +# ------------------------------------------------------- +# _BNWARPNewContainerReference + +_BNWARPNewContainerReference = core.BNWARPNewContainerReference +_BNWARPNewContainerReference.restype = ctypes.POINTER(BNWARPContainer) +_BNWARPNewContainerReference.argtypes = [ + ctypes.POINTER(BNWARPContainer), + ] + + +# noinspection PyPep8Naming +def BNWARPNewContainerReference( + container: ctypes.POINTER(BNWARPContainer) + ) -> Optional[ctypes.POINTER(BNWARPContainer)]: + result = _BNWARPNewContainerReference(container) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPNewFunctionReference + +_BNWARPNewFunctionReference = core.BNWARPNewFunctionReference +_BNWARPNewFunctionReference.restype = ctypes.POINTER(BNWARPFunction) +_BNWARPNewFunctionReference.argtypes = [ + ctypes.POINTER(BNWARPFunction), + ] + + +# noinspection PyPep8Naming +def BNWARPNewFunctionReference( + function: ctypes.POINTER(BNWARPFunction) + ) -> Optional[ctypes.POINTER(BNWARPFunction)]: + result = _BNWARPNewFunctionReference(function) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPNewTargetReference + +_BNWARPNewTargetReference = core.BNWARPNewTargetReference +_BNWARPNewTargetReference.restype = ctypes.POINTER(BNWARPTarget) +_BNWARPNewTargetReference.argtypes = [ + ctypes.POINTER(BNWARPTarget), + ] + + +# noinspection PyPep8Naming +def BNWARPNewTargetReference( + target: ctypes.POINTER(BNWARPTarget) + ) -> Optional[ctypes.POINTER(BNWARPTarget)]: + result = _BNWARPNewTargetReference(target) + if not result: + return None + return result + + +# ------------------------------------------------------- +# _BNWARPRunMatcher + +_BNWARPRunMatcher = core.BNWARPRunMatcher +_BNWARPRunMatcher.restype = None +_BNWARPRunMatcher.argtypes = [ + ctypes.POINTER(BNBinaryView), + ] + + +# noinspection PyPep8Naming +def BNWARPRunMatcher( + view: ctypes.POINTER(BNBinaryView) + ) -> None: + return _BNWARPRunMatcher(view) + + +# ------------------------------------------------------- +# _BNWARPUUIDEqual + +_BNWARPUUIDEqual = core.BNWARPUUIDEqual +_BNWARPUUIDEqual.restype = ctypes.c_bool +_BNWARPUUIDEqual.argtypes = [ + ctypes.POINTER(BNWARPUUID), + ctypes.POINTER(BNWARPUUID), + ] + + +# noinspection PyPep8Naming +def BNWARPUUIDEqual( + a: ctypes.POINTER(BNWARPUUID), + b: ctypes.POINTER(BNWARPUUID) + ) -> bool: + return _BNWARPUUIDEqual(a, b) + + +# ------------------------------------------------------- +# _BNWARPUUIDGetString + +_BNWARPUUIDGetString = core.BNWARPUUIDGetString +_BNWARPUUIDGetString.restype = ctypes.POINTER(ctypes.c_byte) +_BNWARPUUIDGetString.argtypes = [ + ctypes.POINTER(BNWARPUUID), + ] + + +# noinspection PyPep8Naming +def BNWARPUUIDGetString( + uuid: ctypes.POINTER(BNWARPUUID) + ) -> Optional[Optional[str]]: + result = _BNWARPUUIDGetString(uuid) + if not result: + return None + string = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value)) + BNFreeString(result) + return string + + + +# Helper functions +def handle_of_type(value, handle_type): + if isinstance(value, ctypes.POINTER(handle_type)) or isinstance(value, ctypes.c_void_p): + return ctypes.cast(value, ctypes.POINTER(handle_type)) + raise ValueError('expected pointer to %s' % str(handle_type)) diff --git a/plugins/warp/api/python/_warpcore_template.py b/plugins/warp/api/python/_warpcore_template.py new file mode 100644 index 00000000..fd923450 --- /dev/null +++ b/plugins/warp/api/python/_warpcore_template.py @@ -0,0 +1,58 @@ +import binaryninja +import ctypes, os + +from typing import Optional +from . import warp_enums +# Load core module +import platform +core = None +core_platform = platform.system() + +from binaryninja import Settings +if Settings().get_bool("corePlugins.warp"): + from binaryninja._binaryninjacore import BNGetBundledPluginDirectory + if core_platform == "Darwin": + _base_path = BNGetBundledPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "libwarp_ninja.dylib")) + + elif core_platform == "Linux": + _base_path = BNGetBundledPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "libwarp_ninja.so")) + + elif (core_platform == "Windows") or (core_platform.find("CYGWIN_NT") == 0): + _base_path = BNGetBundledPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "warp_ninja.dll")) + else: + raise Exception("OS not supported") +else: + from binaryninja._binaryninjacore import BNGetUserPluginDirectory + if core_platform == "Darwin": + _base_path = BNGetUserPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "libwarp_ninja.dylib")) + + elif core_platform == "Linux": + _base_path = BNGetUserPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "libwarp_ninja.so")) + + elif (core_platform == "Windows") or (core_platform.find("CYGWIN_NT") == 0): + _base_path = BNGetUserPluginDirectory() + core = ctypes.CDLL(os.path.join(_base_path, "warp_ninja.dll")) + else: + raise Exception("OS not supported") + +def cstr(var) -> Optional[ctypes.c_char_p]: + if var is None: + return None + if isinstance(var, bytes): + return var + return var.encode("utf-8") + +def pyNativeStr(arg): + if isinstance(arg, str): + return arg + else: + return arg.decode('utf8') + +def free_string(value:ctypes.c_char_p) -> None: + BNFreeString(ctypes.cast(value, ctypes.POINTER(ctypes.c_byte))) + diff --git a/plugins/warp/api/python/generator.cpp b/plugins/warp/api/python/generator.cpp new file mode 100644 index 00000000..f40fc01a --- /dev/null +++ b/plugins/warp/api/python/generator.cpp @@ -0,0 +1,652 @@ +/* +Copyright 2020-2025 Vector 35 Inc. + +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. +*/ + + + +#include <stdio.h> +#include <inttypes.h> +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace std; + + +map<string, string> g_pythonKeywordReplacements = { + {"False", "False_"}, + {"True", "True_"}, + {"None", "None_"}, + {"and", "and_"}, + {"as", "as_"}, + {"assert", "assert_"}, + {"async", "async_"}, + {"await", "await_"}, + {"break", "break_"}, + {"class", "class_"}, + {"continue", "continue_"}, + {"def", "def_"}, + {"del", "del_"}, + {"elif", "elif_"}, + {"else", "else_"}, + {"except", "except_"}, + {"finally", "finally_"}, + {"for", "for_"}, + {"from", "from_"}, + {"global", "global_"}, + {"if", "if_"}, + {"import", "import_"}, + {"in", "in_"}, + {"is", "is_"}, + {"lambda", "lambda_"}, + {"nonlocal", "nonlocal_"}, + {"not", "not_"}, + {"or", "or_"}, + {"pass", "pass_"}, + {"raise", "raise_"}, + {"return", "return_"}, + {"try", "try_"}, + {"while", "while_"}, + {"with", "with_"}, + {"yield", "yield_"}, +}; + + +void OutputType(FILE* out, Type* type, bool isReturnType = false, bool isCallback = false) +{ + switch (type->GetClass()) + { + case BoolTypeClass: + fprintf(out, "ctypes.c_bool"); + break; + case IntegerTypeClass: + switch (type->GetWidth()) + { + case 1: + if (type->IsSigned()) + fprintf(out, "ctypes.c_byte"); + else + fprintf(out, "ctypes.c_ubyte"); + break; + case 2: + if (type->IsSigned()) + fprintf(out, "ctypes.c_short"); + else + fprintf(out, "ctypes.c_ushort"); + break; + case 4: + if (type->IsSigned()) + fprintf(out, "ctypes.c_int"); + else + fprintf(out, "ctypes.c_uint"); + break; + default: + if (type->IsSigned()) + fprintf(out, "ctypes.c_longlong"); + else + fprintf(out, "ctypes.c_ulonglong"); + break; + } + break; + case FloatTypeClass: + if (type->GetWidth() == 4) + fprintf(out, "ctypes.c_float"); + else + fprintf(out, "ctypes.c_double"); + break; + case NamedTypeReferenceClass: + if (type->GetNamedTypeReference()->GetTypeReferenceClass() == EnumNamedTypeClass) + { + string name = type->GetNamedTypeReference()->GetName().GetString(); + if (name.size() > 16 && name.substr(0, 11) == "_BNDebugger") + name = name.substr(3); + else if (name.size() > 15 && name.substr(0, 10) == "BNDebugger") + name = name.substr(2); + else if (name.size() > 15 && name.substr(0, 7) == "BNDebug") + name = name.substr(2); + else if (name.size() > 2 && name.substr(0, 2) == "BN") + name = name.substr(2); + fprintf(out, "%sEnum", name.c_str()); + } + else + { + fprintf(out, "%s", type->GetNamedTypeReference()->GetName().GetString().c_str()); + } + break; + case PointerTypeClass: + if (isCallback || (type->GetChildType()->GetClass() == VoidTypeClass)) + { + fprintf(out, "ctypes.c_void_p"); + break; + } + else if ((type->GetChildType()->GetClass() == IntegerTypeClass) && + (type->GetChildType()->GetWidth() == 1) && (type->GetChildType()->IsSigned())) + { + if (isReturnType) + fprintf(out, "ctypes.POINTER(ctypes.c_byte)"); + else + fprintf(out, "ctypes.c_char_p"); + break; + } + else if (type->GetChildType()->GetClass() == FunctionTypeClass) + { + fprintf(out, "ctypes.CFUNCTYPE("); + OutputType(out, type->GetChildType()->GetChildType().GetValue(), true, true); + for (auto& i : type->GetChildType()->GetParameters()) + { + fprintf(out, ", "); + OutputType(out, i.type.GetValue()); + } + fprintf(out, ")"); + break; + } + fprintf(out, "ctypes.POINTER("); + OutputType(out, type->GetChildType().GetValue()); + fprintf(out, ")"); + break; + case ArrayTypeClass: + OutputType(out, type->GetChildType().GetValue()); + fprintf(out, " * %" PRId64, type->GetElementCount()); + break; + default: + fprintf(out, "None"); + break; + } +} + + +void OutputSwizzledType(FILE* out, Type* type) +{ + switch (type->GetClass()) + { + case BoolTypeClass: + fprintf(out, "bool"); + break; + case IntegerTypeClass: + fprintf(out, "int"); + break; + case FloatTypeClass: + fprintf(out, "float"); + break; + case NamedTypeReferenceClass: + if (type->GetNamedTypeReference()->GetTypeReferenceClass() == EnumNamedTypeClass) + { + string name = type->GetNamedTypeReference()->GetName().GetString(); + if (name.size() > 16 && name.substr(0, 11) == "_BNDebugger") + name = name.substr(3); + else if (name.size() > 15 && name.substr(0, 10) == "BNDebugger") + name = name.substr(2); + else if (name.size() > 15 && name.substr(0, 7) == "BNDebug") + name = name.substr(2); + else if (name.size() > 2 && name.substr(0, 2) == "BN") + name = name.substr(2); + fprintf(out, "%sEnum", name.c_str()); + } + else + { + fprintf(out, "%s", type->GetNamedTypeReference()->GetName().GetString().c_str()); + } + break; + case PointerTypeClass: + if (type->GetChildType()->GetClass() == VoidTypeClass) + { + fprintf(out, "Optional[ctypes.c_void_p]"); + break; + } + else if ((type->GetChildType()->GetClass() == IntegerTypeClass) && + (type->GetChildType()->GetWidth() == 1) && (type->GetChildType()->IsSigned())) + { + fprintf(out, "Optional[str]"); + break; + } + else if (type->GetChildType()->GetClass() == FunctionTypeClass) + { + fprintf(out, "ctypes.CFUNCTYPE("); + OutputType(out, type->GetChildType()->GetChildType().GetValue(), true, true); + for (auto& i : type->GetChildType()->GetParameters()) + { + fprintf(out, ", "); + OutputType(out, i.type.GetValue()); + } + fprintf(out, ")"); + break; + } + fprintf(out, "ctypes.POINTER("); + OutputType(out, type->GetChildType().GetValue()); + fprintf(out, ")"); + break; + case ArrayTypeClass: + OutputType(out, type->GetChildType().GetValue()); + fprintf(out, " * %" PRId64, type->GetElementCount()); + break; + default: + fprintf(out, "None"); + break; + } +} + + +int main(int argc, char* argv[]) +{ + if (argc < 5) + { + fprintf(stderr, "Usage: generator <header> <output> <output_template> <output_enum>\n"); + return 1; + } + + // Parse API header to get type and function information + map<QualifiedName, Ref<Type>> types, vars, funcs; + string errors; + auto arch = new CoreArchitecture(BNGetNativeTypeParserArchitecture()); + + // Enable ephemeral settings + Settings::Instance()->LoadSettingsFile(""); + Settings::Instance()->Set("analysis.types.parserName", "ClangTypeParser"); + bool ok = arch->GetStandalonePlatform()->ParseTypesFromSourceFile(argv[1], types, vars, funcs, errors); + + if (!ok) + { + fprintf(stderr, "Errors: %s\n", errors.c_str()); + return 1; + } + + FILE* out = fopen(argv[2], "w"); + FILE* out_template = fopen(argv[3], "r"); + FILE* enums = fopen(argv[4], "w"); + + fprintf(enums, "import enum\n"); + + // Copy the content of the template to the output file + int c; + while((c = fgetc(out_template)) != EOF) + fputc(c, out); + + // Create type objects + fprintf(out, "from binaryninja._binaryninjacore import BNFreeString\n"); + fprintf(out, "# Type definitions\n"); + for (auto& i : types) + { + string name; + if (i.first.size() != 1) + continue; + name = i.first[0]; + if (name == "BNBinaryView") + { + fprintf(out, "from binaryninja._binaryninjacore import BNBinaryView, BNBinaryViewHandle\n"); + continue; + } + if (name == "BNArchitecture") + { + fprintf(out, "from binaryninja._binaryninjacore import BNArchitecture, BNArchitectureHandle\n"); + continue; + } + if (name == "BNBasicBlock") + { + fprintf(out, "from binaryninja._binaryninjacore import BNBasicBlock, BNBasicBlockHandle\n"); + continue; + } + if (name == "BNFunction") + { + fprintf(out, "from binaryninja._binaryninjacore import BNFunction, BNFunctionHandle\n"); + continue; + } + if (name == "BNLowLevelILFunction") + { + fprintf(out, "from binaryninja._binaryninjacore import BNLowLevelILFunction, BNLowLevelILFunctionHandle\n"); + continue; + } + if (name == "BNPlatform") + { + fprintf(out, "from binaryninja._binaryninjacore import BNPlatform, BNPlatformHandle\n"); + continue; + } + if (name == "BNSymbol") + { + fprintf(out, "from binaryninja._binaryninjacore import BNSymbol, BNSymbolHandle\n"); + continue; + } + if (name == "BNType") + { + fprintf(out, "from binaryninja._binaryninjacore import BNType, BNTypeHandle\n"); + continue; + } + if (i.second->GetClass() == StructureTypeClass) + { + fprintf(out, "class %s(ctypes.Structure):\n", name.c_str()); + + // python uses str's, C uses byte-arrays + bool stringField = false; + for (auto& arg : i.second->GetStructure()->GetMembers()) + { + if ((arg.type->GetClass() == PointerTypeClass) && + (arg.type->GetChildType()->GetWidth() == 1) && + (arg.type->GetChildType()->IsSigned())) + { + fprintf(out, "\t@property\n\tdef %s(self):\n\t\treturn pyNativeStr(self._%s)\n", arg.name.c_str(), arg.name.c_str()); + fprintf(out, "\t@%s.setter\n\tdef %s(self, value):\n\t\tself._%s = cstr(value)\n", arg.name.c_str(), arg.name.c_str(), arg.name.c_str()); + stringField = true; + } + } + + if (!stringField) + fprintf(out, "\tpass\n"); + + fprintf(out, "%sHandle = ctypes.POINTER(%s)\n", name.c_str(), name.c_str()); + } + else if (i.second->GetClass() == EnumerationTypeClass) + { + bool isBNAPIEnum = false; + if (name.size() > 16 && name.substr(0, 11) == "_BNDebugger") + name = name.substr(3); + else if (name.size() > 15 && name.substr(0, 10) == "BNDebugger") + name = name.substr(2); + else if (name.size() > 15 && name.substr(0, 7) == "BNDebug") + name = name.substr(2); + else if (name.size() > 2 && name.substr(0, 2) == "BN") + { + name = name.substr(2); + isBNAPIEnum = false; + } + else + continue; + + if (isBNAPIEnum) + { + fprintf(out, "from binaryninja._binaryninjacore import %sEnum\n", name.c_str()); + continue; + } + + fprintf(out, "%sEnum = ctypes.c_int\n", name.c_str()); + + fprintf(enums, "\n\nclass %s(enum.IntEnum):\n", name.c_str()); + for (auto& j : i.second->GetEnumeration()->GetMembers()) + { + fprintf(enums, "\t%s = %" PRId64 "\n", j.name.c_str(), j.value); + } + } + else if ((i.second->GetClass() == BoolTypeClass) || (i.second->GetClass() == IntegerTypeClass) || + (i.second->GetClass() == FloatTypeClass) || (i.second->GetClass() == ArrayTypeClass)) + { + fprintf(out, "%s = ", name.c_str()); + OutputType(out, i.second); + fprintf(out, "\n"); + } + } + + + fprintf(out, "\n# Structure definitions\n"); + set<QualifiedName> structsToProcess; + set<QualifiedName> finishedStructs; + for (auto& i : types) + structsToProcess.insert(i.first); + while (structsToProcess.size() != 0) + { + set<QualifiedName> currentStructList = structsToProcess; + structsToProcess.clear(); + bool processedSome = false; + for (auto& i : currentStructList) + { + string name; + if (i.size() != 1) + continue; + Ref<Type> type = types[i]; + name = i[0]; + if ((type->GetClass() == StructureTypeClass) && (type->GetStructure()->GetMembers().size() != 0)) + { + bool requiresDependency = false; + for (auto& j : type->GetStructure()->GetMembers()) + { + if ((j.type->GetClass() == NamedTypeReferenceClass) && + (finishedStructs.count(j.type->GetNamedTypeReference()->GetName()) == 0)) + { + // This structure needs another structure that isn't fully defined yet, need to wait + // for the dependencies to be defined + structsToProcess.insert(i); + requiresDependency = true; + break; + } + } + + if (requiresDependency) + continue; + fprintf(out, "%s._fields_ = [\n", name.c_str()); + for (auto& j : type->GetStructure()->GetMembers()) + { + // To help the python->C wrappers + if ((j.type->GetClass() == PointerTypeClass) && + (j.type->GetChildType()->GetWidth() == 1) && + (j.type->GetChildType()->IsSigned())) + { + fprintf(out, "\t\t(\"_%s\", ", j.name.c_str()); + } + else + fprintf(out, "\t\t(\"%s\", ", j.name.c_str()); + OutputType(out, j.type.GetValue()); + fprintf(out, "),\n"); + } + fprintf(out, "\t]\n"); + finishedStructs.insert(i); + processedSome = true; + } + else if (type->GetClass() == NamedTypeReferenceClass) + { + if (type->GetNamedTypeReference()->GetTypeReferenceClass() == StructNamedTypeClass) + { + fprintf(out, "%s = %s\n", name.c_str(), type->GetNamedTypeReference()->GetName().GetString().c_str()); + fprintf(out, "%sHandle = %sHandle\n", name.c_str(), type->GetNamedTypeReference()->GetName().GetString().c_str()); + } + else if (type->GetNamedTypeReference()->GetTypeReferenceClass() == EnumNamedTypeClass) + { + fprintf(out, "%s = ctypes.c_int\n", name.c_str()); + } + finishedStructs.insert(i); + processedSome = true; + } + } + + if (!processedSome && structsToProcess.size() != 0) + { + fprintf(stderr, "Detected dependency cycle in structures\n"); + for (auto& i : structsToProcess) + fprintf(stderr, "%s\n", i.GetString().c_str()); + return 1; + } + } + + fprintf(out, "\n# Function definitions\n"); + for (auto& i : funcs) + { + string name; + if (i.first.size() != 1) + continue; + name = i.first[0]; + + // Check for a string result, these will be automatically wrapped to free the string + // memory and return a Python string + bool stringResult = (i.second->GetChildType()->GetClass() == PointerTypeClass) && + (i.second->GetChildType()->GetChildType()->GetWidth() == 1) && + (i.second->GetChildType()->GetChildType()->IsSigned()); + // Pointer returns will be automatically wrapped to return None on null pointer + bool pointerResult = (i.second->GetChildType()->GetClass() == PointerTypeClass); + + // From python -> C python3 requires str -> str.encode('charmap') + bool swizzleArgs = true; + if (name == "BNFreeString") + swizzleArgs = false; + + bool callbackConvention = false; + if (name == "BNAllocString") + { + // Don't perform automatic wrapping of string allocation, and return a void + // pointer so that callback functions (which is the only valid use of BNDebuggerAllocString) + // can properly return the result + stringResult = false; + callbackConvention = true; + swizzleArgs = false; + } + + string funcName = string("_") + name; + + fprintf(out, "# -------------------------------------------------------\n"); + fprintf(out, "# %s\n\n", funcName.c_str()); + fprintf(out, "%s = core.%s\n", funcName.c_str(), name.c_str()); + fprintf(out, "%s.restype = ", funcName.c_str()); + OutputType(out, i.second->GetChildType().GetValue(), true, callbackConvention); + fprintf(out, "\n"); + if (!i.second->HasVariableArguments()) + { + fprintf(out, "%s.argtypes = [\n", funcName.c_str()); + for (auto& j : i.second->GetParameters()) + { + fprintf(out, "\t\t"); + if (name == "BNFreeString") + { + // BNDebuggerFreeString expects a pointer to a string allocated by the core, so do not use + // a c_char_p here, as that would be allocated by the Python runtime. This can + // be enforced by outputting like a return value. + OutputType(out, j.type.GetValue(), true); + } + else + { + OutputType(out, j.type.GetValue()); + } + fprintf(out, ",\n"); + } + fprintf(out, "\t]"); + } + else + { + // As of writing this, only BNLog's have variable instruction lengths, but in an attempt not to break in the future: + if (funcName.compare(0, 6, "_BNLog") == 0) + { + if (funcName != "_BNLog") + { + fprintf(out, "def %s(*args):\n", name.c_str()); + fprintf(out, "\treturn %s(*[cstr(arg) for arg in args])\n\n", funcName.c_str()); + continue; + } + else + { + fprintf(out, "def %s(level, *args):\n", name.c_str()); + fprintf(out, "\treturn %s(level, *[cstr(arg) for arg in args])\n\n", funcName.c_str()); + continue; + } + } + } + fprintf(out, "\n\n\n# noinspection PyPep8Naming\n"); + fprintf(out, "def %s(", name.c_str()); + if (!i.second->HasVariableArguments()) + { + size_t argN = 0; + for (auto& arg: i.second->GetParameters()) + { + string argName = arg.name; + if (g_pythonKeywordReplacements.find(argName) != g_pythonKeywordReplacements.end()) + argName = g_pythonKeywordReplacements[argName]; + + if (argName.empty()) + argName = "arg" + to_string(argN); + + if (argN > 0) + fprintf(out, ", "); + fprintf(out, "\n\t\t"); + fprintf(out, "%s: ", argName.c_str()); + if (swizzleArgs) + OutputSwizzledType(out, arg.type.GetValue()); + else + OutputType(out, arg.type.GetValue()); + argN ++; + } + } + fprintf(out, "\n\t\t) -> "); + if (swizzleArgs) + { + if (stringResult || pointerResult) + fprintf(out, "Optional["); + OutputSwizzledType(out, i.second->GetChildType().GetValue()); + if (stringResult || pointerResult) + fprintf(out, "]"); + } + else + { + OutputType(out, i.second->GetChildType().GetValue()); + } + fprintf(out, ":\n"); + + string stringArgFuncCall = funcName + "("; + size_t argN = 0; + for (auto& arg : i.second->GetParameters()) + { + string argName = arg.name; + if (g_pythonKeywordReplacements.find(argName) != g_pythonKeywordReplacements.end()) + argName = g_pythonKeywordReplacements[argName]; + + if (argName.empty()) + argName = "arg" + to_string(argN); + + if (swizzleArgs && (arg.type->GetClass() == PointerTypeClass) && + (arg.type->GetChildType()->GetClass() == IntegerTypeClass) && + (arg.type->GetChildType()->GetWidth() == 1) && + (arg.type->GetChildType()->IsSigned())) + { + stringArgFuncCall += string("cstr(") + argName + "), "; + } + else + { + stringArgFuncCall += argName + ", "; + } + argN++; + } + if (argN > 0) + stringArgFuncCall = stringArgFuncCall.substr(0, stringArgFuncCall.size()-2); + stringArgFuncCall += ")"; + + if (stringResult) + { + // Emit wrapper to get Python string and free native memory + fprintf(out, "\tresult = "); + fprintf(out, "%s\n", stringArgFuncCall.c_str()); + fprintf(out, "\tif not result:\n"); + fprintf(out, "\t\treturn None\n"); + fprintf(out, "\tstring = str(pyNativeStr(ctypes.cast(result, ctypes.c_char_p).value))\n"); + fprintf(out, "\tBNFreeString(result)\n"); + fprintf(out, "\treturn string\n"); + } + else if (pointerResult) + { + // Emit wrapper to return None on null pointer + fprintf(out, "\tresult = "); + fprintf(out, "%s\n", stringArgFuncCall.c_str()); + fprintf(out, "\tif not result:\n"); + fprintf(out, "\t\treturn None\n"); + fprintf(out, "\treturn result\n"); + } + else + { + fprintf(out, "\treturn "); + fprintf(out, "%s\n", stringArgFuncCall.c_str()); + } + fprintf(out, "\n\n"); + } + + fprintf(out, "\n# Helper functions\n"); + fprintf(out, "def handle_of_type(value, handle_type):\n"); + fprintf(out, "\tif isinstance(value, ctypes.POINTER(handle_type)) or isinstance(value, ctypes.c_void_p):\n"); + fprintf(out, "\t\treturn ctypes.cast(value, ctypes.POINTER(handle_type))\n"); + fprintf(out, "\traise ValueError('expected pointer to %%s' %% str(handle_type))\n"); + + fclose(out); + fclose(enums); + return 0; +} diff --git a/plugins/warp/api/python/warp.py b/plugins/warp/api/python/warp.py new file mode 100644 index 00000000..e0500215 --- /dev/null +++ b/plugins/warp/api/python/warp.py @@ -0,0 +1,384 @@ +import ctypes +import dataclasses +import uuid +from typing import List, Optional, Union + +import binaryninja +from binaryninja import BinaryView, Function, BasicBlock, Architecture, Platform, Type, Symbol, LowLevelILInstruction, LowLevelILFunction +from binaryninja._binaryninjacore import BNFreeString, BNAllocString, BNType + +from . import _warpcore as warpcore + + +class WarpUUID: + def __init__(self, _uuid: Union[warpcore.BNWARPUUID, str, uuid.UUID]): + if isinstance(_uuid, str): + _uuid = uuid.UUID(_uuid) + if isinstance(_uuid, uuid.UUID): + uuid_bytes = _uuid.bytes + _uuid = warpcore.BNWARPUUID() + _uuid.uuid = (ctypes.c_ubyte * 16).from_buffer_copy(uuid_bytes) + elif isinstance(_uuid, warpcore.BNWARPUUID): + # We must create a copy! + new_uuid = warpcore.BNWARPUUID() + new_uuid.uuid = (ctypes.c_ubyte * 16).from_buffer_copy(_uuid.uuid) + _uuid = new_uuid + self._uuid = _uuid + + def to_string(self) -> str: + return warpcore.BNWARPUUIDGetString(self._uuid) + + def __str__(self): + return self.to_string() + + def __repr__(self): + return f"<WarpUUID '{str(self)}'>" + + def __hash__(self): + # Hash based on the UUID bytes + return hash(bytes(self._uuid.uuid)) + + def __eq__(self, other): + if not isinstance(other, WarpUUID): + return False + return warpcore.BNWARPUUIDEqual(self._uuid, other._uuid) + + @property + def uuid(self): + return self._uuid + + +class Source(WarpUUID): + def __repr__(self): + return f"<Source '{str(self)}'>" + + +class BasicBlockGUID(WarpUUID): + def __repr__(self): + return f"<BasicBlockGUID '{str(self)}'>" + + +class FunctionGUID(WarpUUID): + def __repr__(self): + return f"<FunctionGUID '{str(self)}'>" + + +class ConstraintGUID(WarpUUID): + def __repr__(self): + return f"<ConstraintGUID '{str(self)}'>" + + +class TypeGUID(WarpUUID): + def __repr__(self): + return f"<TypeGUID '{str(self)}'>" + + +@dataclasses.dataclass +class WarpFunctionComment: + text: str + offset: int + + def __str__(self): + return repr(self) + + def __repr__(self): + return f"<WarpFunctionComment '{self.text}': {self.offset:#x}>" + + @staticmethod + def from_api(comment: warpcore.BNWARPFunctionComment) -> 'WarpFunctionComment': + return WarpFunctionComment( + text=comment.text.decode('utf-8'), + offset=comment.offset + ) + +@dataclasses.dataclass +class WarpConstraint: + guid: ConstraintGUID + offset: Optional[int] + + def __str__(self): + return repr(self) + + def __repr__(self): + if self.offset is None: + return f"<WarpConstraint '{self.guid}'>" + return f"<WarpConstraint '{self.guid}': {self.offset:#x}>" + + @staticmethod + def from_api(constraint: warpcore.BNWARPConstraint) -> 'WarpConstraint': + if constraint.offset == -1: + return WarpConstraint(guid=ConstraintGUID(constraint.guid), offset=None) + return WarpConstraint(guid=ConstraintGUID(constraint.guid), offset=constraint.offset) + +class WarpTarget: + def __init__(self, handle: Union[warpcore.BNWARPTarget, Platform]): + if isinstance(handle, Platform): + self.handle = warpcore.BNWARPGetTarget(handle.handle) + else: + self.handle = handle + + def __del__(self): + if self.handle is not None: + warpcore.BNWARPFreeTargetReference(self.handle) + + @staticmethod + def from_platform(platform: Platform) -> Optional['WarpTarget']: + handle = warpcore.BNWARPGetTarget(platform.handle) + if not handle: + return None + return WarpTarget(handle) + + +class WarpFunction: + def __init__(self, handle: Union[warpcore.BNWARPFunction, Function]): + if isinstance(handle, Function): + self.handle = warpcore.BNWARPGetFunction(handle.handle) + else: + self.handle = handle + def __del__(self): + if self.handle is not None: + warpcore.BNWARPFreeFunctionReference(self.handle) + + def __repr__(self): + return f"<WarpFunction '{self.name}': '{self.guid}'>" + + @property + def guid(self) -> FunctionGUID: + return FunctionGUID(warpcore.BNWARPFunctionGetGUID(self.handle)) + + @property + def name(self) -> str: + return warpcore.BNWARPFunctionGetSymbolName(self.handle) + + def get_symbol(self, function: Function) -> Symbol: + symbol_handle = warpcore.BNWARPFunctionGetSymbol(self.handle, function.handle) + return Symbol(symbol_handle) + + def get_type(self, function: Function) -> Optional[Type]: + type_handle = warpcore.BNWARPFunctionGetType(self.handle, function.handle) + if not type_handle: + return None + return Type(type_handle) + + @property + def constraints(self) -> List[WarpConstraint]: + count = ctypes.c_size_t() + constraints = warpcore.BNWARPFunctionGetConstraints(self.handle, count) + if not constraints: + return [] + result = [] + for i in range(count.value): + result.append(WarpConstraint.from_api(constraints[i])) + warpcore.BNWARPFreeConstraintList(constraints, count.value) + return result + + @property + def comments(self) -> List[WarpFunctionComment]: + count = ctypes.c_size_t() + comments = warpcore.BNWARPFunctionGetComments(self.handle, count) + if not comments: + return [] + result = [] + for i in range(count.value): + result.append(WarpFunctionComment.from_api(comments[i])) + warpcore.BNWARPFreeFunctionCommentList(comments, count.value) + return result + + @staticmethod + def get_matched(function: Function) -> Optional['WarpFunction']: + handle = warpcore.BNWARPGetMatchedFunction(function.handle) + if not handle: + return None + return WarpFunction(handle) + + def apply(self, function: Function): + warpcore.BNWARPFunctionApply(self.handle, function.handle) + + +class _WarpContainerMetaclass(type): + def __iter__(self): + binaryninja._init_plugins() + count = ctypes.c_ulonglong() + containers = warpcore.BNWARPGetContainers(count) + try: + for i in range(0, count.value): + yield WarpContainer(warpcore.BNWARPNewContainerReference(containers[i])) + finally: + warpcore.BNWARPFreeContainerList(containers, count.value) + + def __getitem__(self, value): + binaryninja._init_plugins() + count = ctypes.c_ulonglong() + containers = warpcore.BNWARPGetContainers(count) + try: + for i in range(0, count.value): + container = WarpContainer(warpcore.BNWARPNewContainerReference(containers[i])) + if container.name == str(value): + return container + raise KeyError(f"'{value}' is not a valid container name") + finally: + warpcore.BNWARPFreeContainerList(containers, count.value) + + +class WarpContainer(metaclass=_WarpContainerMetaclass): + def __init__(self, handle: warpcore.BNWARPContainer): + self.handle = handle + + def __del__(self): + if self.handle is not None: + warpcore.BNWARPFreeContainerReference(self.handle) + + def __repr__(self): + return f"<WarpContainer '{self.name}'>" + + @staticmethod + def all() -> List['WarpContainer']: + count = ctypes.c_size_t() + containers = warpcore.BNWARPGetContainers(count) + if not containers: + return [] + result = [] + for i in range(count.value): + result.append(WarpContainer(warpcore.BNWARPNewContainerReference(containers[i]))) + warpcore.BNWARPFreeContainerList(containers, count.value) + return result + + @property + def name(self) -> str: + return warpcore.BNWARPContainerGetName(self.handle) + + @property + def sources(self) -> List[Source]: + count = ctypes.c_size_t() + sources = warpcore.BNWARPContainerGetSources(self.handle, count) + if not sources: + return [] + result = [] + for i in range(count.value): + result.append(Source(sources[i])) + warpcore.BNWARPFreeUUIDList(sources, count.value) + return result + + def add_source(self, source_path: str) -> Optional[Source]: + source = warpcore.BNWARPUUID() + if not warpcore.BNWARPContainerAddSource(self.handle, source_path, source): + return None + return Source(source) + + def commit_source(self, source: Source) -> bool: + return warpcore.BNWARPContainerCommitSource(self.handle, source.uuid) + + def is_source_uncommitted(self, source: Source) -> bool: + return warpcore.BNWARPContainerIsSourceWritable(self.handle, source.uuid) + + def is_source_writable(self, source: Source) -> bool: + return warpcore.BNWARPContainerIsSourceWritable(self.handle, source.uuid) + + def get_source_path(self, source: Source) -> Optional[str]: + return warpcore.BNWARPContainerGetSourcePath(self.handle, source.uuid) + + def add_functions(self, target: WarpTarget, source: Source, functions: List[Function]) -> bool: + count = len(functions) + core_funcs = (ctypes.POINTER(warpcore.BNWARPFunction) * count)() + for i in range(count): + core_funcs[i] = functions[i].handle + return warpcore.BNWARPContainerAddFunctions(self.handle, target.handle, source.uuid, core_funcs, count) + + def add_types(self, view: BinaryView, source: Source, types: List[Type]) -> bool: + count = len(types) + core_types = (ctypes.POINTER(BNType) * count)() + for i in range(count): + core_types[i] = types[i].handle + return warpcore.BNWARPContainerAddTypes(view.handle, self.handle, source.uuid, core_types, count) + + def remove_functions(self, target: WarpTarget, source: Source, functions: List[Function]) -> bool: + count = len(functions) + core_funcs = (ctypes.POINTER(warpcore.BNWARPFunction) * count)() + for i in range(count): + core_funcs[i] = functions[i].handle + return warpcore.BNWARPContainerRemoveFunctions(self.handle, target.handle, source.uuid, core_funcs, count) + + def remove_types(self, source: Source, guids: List[TypeGUID]) -> bool: + count = len(guids) + core_guids = (ctypes.POINTER(warpcore.BNWARPTypeGUID) * count)() + for i in range(count): + core_guids[i] = guids[i].uuid + return warpcore.BNWARPContainerRemoveTypes(self.handle, source.uuid, core_guids, count) + + def get_sources_with_function_guid(self, target: WarpTarget, guid: FunctionGUID) -> List[Source]: + count = ctypes.c_size_t() + sources = warpcore.BNWARPContainerGetSourcesWithFunctionGUID(self.handle, target.handle, guid.uuid, count) + if not sources: + return [] + result = [] + for i in range(count.value): + result.append(Source(sources[i])) + warpcore.BNWARPFreeUUIDList(sources, count.value) + return result + + def get_sources_with_type_guid(self, guid: TypeGUID) -> List[Source]: + count = ctypes.c_size_t() + sources = warpcore.BNWARPContainerGetSourcesWithTypeGUID(self.handle, guid.uuid, count) + if not sources: + return [] + result = [] + for i in range(count.value): + result.append(Source(sources[i])) + warpcore.BNWARPFreeUUIDList(sources, count.value) + return result + + def get_functions_with_guid(self, target: WarpTarget, source: Source, guid: FunctionGUID) -> List[Function]: + count = ctypes.c_size_t() + funcs = warpcore.BNWARPContainerGetFunctionsWithGUID(self.handle, target.handle, source.uuid, guid.uuid, count) + if not funcs: + return [] + result = [] + for i in range(count.value): + result.append(WarpFunction(warpcore.BNWARPNewFunctionReference(funcs[i]))) + warpcore.BNWARPFreeFunctionList(funcs, count.value) + return result + + def get_type_with_guid(self, arch: Architecture, source: Source, guid: TypeGUID) -> Optional[Type]: + ty = warpcore.BNWARPContainerGetTypeWithGUID(self.handle, arch.handle, source.uuid, guid.uuid) + if not ty: + return None + return Type(ty) + + def get_type_guids_with_name(self, source: Source, name: str) -> List[TypeGUID]: + count = ctypes.c_size_t() + guids = warpcore.BNWARPContainerGetTypeGUIDsWithName(self.handle, source.uuid, name, count) + if not guids: + return [] + result = [] + for i in range(count.value): + result.append(TypeGUID(guids[i])) + warpcore.BNWARPFreeUUIDList(guids, count.value) + return result + + +def run_matcher(view: BinaryView): + warpcore.BNWARPRunMatcher(view.handle) + +def is_instruction_variant(function: LowLevelILFunction, variant: LowLevelILInstruction) -> bool: + return warpcore.BNWARPIsLiftedInstructionVariant(function.handle, variant.instr_index) + +def is_instruction_blacklisted(function: LowLevelILFunction, variant: LowLevelILInstruction) -> bool: + return warpcore.BNWARPIsLiftedInstructionBlacklisted(function.handle, variant.instr_index) + +def get_function_guid(function: Function) -> Optional[FunctionGUID]: + guid = warpcore.BNWARPUUID() + if not warpcore.BNWARPGetAnalysisFunctionGUID(function.handle, guid): + return None + return FunctionGUID(guid) + + +def get_basic_block_guid(basic_block: BasicBlock) -> Optional[BasicBlockGUID]: + # TODO: I believe this won't work for HLIL: https://github.com/Vector35/binaryninja-api/issues/6998 + if basic_block.is_il: + basic_block = basic_block.source_block + guid = warpcore.BNWARPUUID() + if not warpcore.BNWARPGetBasicBlockGUID(basic_block.handle, guid): + return None + return BasicBlockGUID(guid) + +# TODO: Magic matched_function, possible_functions
\ No newline at end of file diff --git a/plugins/warp/api/python/warp_enums.py b/plugins/warp/api/python/warp_enums.py new file mode 100644 index 00000000..e47ff1c3 --- /dev/null +++ b/plugins/warp/api/python/warp_enums.py @@ -0,0 +1 @@ +import enum |
