diff options
| author | Ryan Snyder <ryan@vector35.com> | 2024-05-24 14:47:15 -0400 |
|---|---|---|
| committer | Ryan Snyder <ryan@vector35.com> | 2024-05-24 17:14:46 -0400 |
| commit | 56115aecf186bc720dae9a20cc4c6aef248ba07f (patch) | |
| tree | 1754beaa4e8601be328de689c0f6dc9d05851b35 | |
| parent | 74920c190c5c6230833be6d50536119ce5e44c98 (diff) | |
platform: initial BNCustomPlatform support
| -rw-r--r-- | architecture.cpp | 2 | ||||
| -rw-r--r-- | binaryninjaapi.h | 40 | ||||
| -rw-r--r-- | binaryninjacore.h | 19 | ||||
| -rw-r--r-- | binaryview.cpp | 4 | ||||
| -rw-r--r-- | debuginfo.cpp | 2 | ||||
| -rw-r--r-- | function.cpp | 2 | ||||
| -rw-r--r-- | platform.cpp | 130 | ||||
| -rw-r--r-- | platform/windows/platform_windows.cpp | 42 | ||||
| -rw-r--r-- | python/platform.py | 90 | ||||
| -rw-r--r-- | typearchive.cpp | 4 | ||||
| -rw-r--r-- | typecontainer.cpp | 2 | ||||
| -rw-r--r-- | typeparser.cpp | 6 |
12 files changed, 319 insertions, 24 deletions
diff --git a/architecture.cpp b/architecture.cpp index 979ba3e2..90d18d06 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -1372,7 +1372,7 @@ Ref<CallingConvention> Architecture::GetFastcallCallingConvention() Ref<Platform> Architecture::GetStandalonePlatform() { - return new Platform(BNGetArchitectureStandalonePlatform(m_object)); + return new CorePlatform(BNGetArchitectureStandalonePlatform(m_object)); } diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 477d1b60..8eb3cdaf 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -14495,6 +14495,12 @@ namespace BinaryNinja { Platform(Architecture* arch, const std::string& name, const std::string& typeFile, const std::vector<std::string>& includeDirs = std::vector<std::string>()); + static void InitCallback(void *ctxt, BNPlatform*); + static void InitViewCallback(void* ctxt, BNBinaryView* view); + static uint32_t* GetGlobalRegistersCallback(void* ctxt, size_t* count); + static void FreeRegisterListCallback(void* ctxt, uint32_t* regs, size_t count); + static BNType* GetGlobalRegisterTypeCallback(void* ctxt, uint32_t reg); + public: Platform(BNPlatform* platform); @@ -14630,6 +14636,30 @@ namespace BinaryNinja { */ void SetSystemCallConvention(CallingConvention* cc); + /*! Callback that will be called when the platform of a binaryview + * is set. Allows for the Platform to to do platform-specific + * processing of views just after finalization. + * + * \param view BinaryView that was just set to this Platform + */ + virtual void BinaryViewInit(BinaryView* view); + + /*! Get the global register list for this Platform + * + * Allows the Platform to override the global register list + * used by analysis. + */ + virtual std::vector<uint32_t> GetGlobalRegisters(); + + /*! Get the type of a global register + * + * Called by analysis when the incoming register value of a + * global register is observed. + * + * \param reg The register being queried for type information. + */ + virtual Ref<Type> GetGlobalRegisterType(uint32_t reg); + Ref<Platform> GetRelatedPlatform(Architecture* arch); void AddRelatedPlatform(Architecture* arch, Platform* platform); Ref<Platform> GetAssociatedPlatformByAddress(uint64_t& addr); @@ -14720,6 +14750,16 @@ namespace BinaryNinja { const std::string& autoTypeSource = ""); }; + + class CorePlatform : public Platform + { + public: + CorePlatform(BNPlatform* plat); + + virtual std::vector<uint32_t> GetGlobalRegisters() override; + virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override; + }; + /*! \ingroup typeparser */ diff --git a/binaryninjacore.h b/binaryninjacore.h index d7d6244a..68dde467 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1872,6 +1872,18 @@ extern "C" bool (*skipAndReturnValue)(void* ctxt, uint8_t* data, uint64_t addr, size_t len, uint64_t value); } BNCustomArchitecture; + typedef struct BNCustomPlatform + { + void* context; + void (*init)(void* ctxt, BNPlatform* obj); + void (*viewInit)(void* ctxt, BNBinaryView* view); + + uint32_t* (*getGlobalRegisters)(void* ctxt, size_t* count); + void (*freeRegisterList)(void* ctxt, uint32_t* regs, size_t len); + + BNType* (*getGlobalRegisterType)(void* ctxt, uint32_t reg); + } BNCustomPlatform; + typedef struct BNBasicBlockEdge { BNBranchType type; @@ -6360,6 +6372,10 @@ extern "C" BINARYNINJACOREAPI BNPlatform* BNCreatePlatform(BNArchitecture* arch, const char* name); BINARYNINJACOREAPI BNPlatform* BNCreatePlatformWithTypes( BNArchitecture* arch, const char* name, const char* typeFile, const char** includeDirs, size_t includeDirCount); + BINARYNINJACOREAPI BNPlatform* BNCreateCustomPlatform(BNArchitecture* arch, const char* name, BNCustomPlatform* impl); + BINARYNINJACOREAPI BNPlatform* BNCreateCustomPlatformWithTypes( + BNArchitecture* arch, const char* name, BNCustomPlatform* impl, + const char* typeFile, const char** includeDirs, size_t includeDirCount); BINARYNINJACOREAPI void BNRegisterPlatform(const char* os, BNPlatform* platform); BINARYNINJACOREAPI BNPlatform* BNNewPlatformReference(BNPlatform* platform); BINARYNINJACOREAPI void BNFreePlatform(BNPlatform* platform); @@ -6391,6 +6407,9 @@ extern "C" BINARYNINJACOREAPI void BNRegisterPlatformFastcallCallingConvention(BNPlatform* platform, BNCallingConvention* cc); BINARYNINJACOREAPI void BNSetPlatformSystemCallConvention(BNPlatform* platform, BNCallingConvention* cc); + BINARYNINJACOREAPI uint32_t* BNGetPlatformGlobalRegisters(BNPlatform* platform, size_t* count); + BINARYNINJACOREAPI BNType* BNGetPlatformGlobalRegisterType(BNPlatform* platform, uint32_t reg); + BINARYNINJACOREAPI BNPlatform* BNGetArchitectureStandalonePlatform(BNArchitecture* arch); BINARYNINJACOREAPI BNPlatform* BNGetRelatedPlatform(BNPlatform* platform, BNArchitecture* arch); diff --git a/binaryview.cpp b/binaryview.cpp index 98124fe5..83ed3f3b 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1920,7 +1920,7 @@ Ref<Platform> BinaryView::GetDefaultPlatform() const BNPlatform* platform = BNGetDefaultPlatform(m_object); if (!platform) return nullptr; - return new Platform(platform); + return new CorePlatform(platform); } @@ -4177,7 +4177,7 @@ std::optional<std::pair<Ref<Platform>, QualifiedName>> BinaryView::LookupImporte return std::nullopt; QualifiedName targetName = QualifiedName::FromAPIObject(&resultName); BNFreeQualifiedName(&resultName); - return std::make_pair(new Platform(resultLib), targetName); + return std::make_pair(new CorePlatform(resultLib), targetName); } diff --git a/debuginfo.cpp b/debuginfo.cpp index 2af16525..412d44bb 100644 --- a/debuginfo.cpp +++ b/debuginfo.cpp @@ -100,7 +100,7 @@ vector<DebugFunctionInfo> DebugInfo::GetFunctions(const string& parserName) cons functions[i].fullName ? functions[i].fullName : "", functions[i].rawName ? functions[i].rawName : "", functions[i].address, functions[i].type ? new Type(BNNewTypeReference(functions[i].type)) : nullptr, - functions[i].platform ? new Platform(BNNewPlatformReference(functions[i].platform)) : nullptr, components); + functions[i].platform ? new CorePlatform(BNNewPlatformReference(functions[i].platform)) : nullptr, components); } BNFreeDebugFunctions(functions, count); diff --git a/function.cpp b/function.cpp index 27a91952..2838f079 100644 --- a/function.cpp +++ b/function.cpp @@ -192,7 +192,7 @@ Ref<BinaryView> Function::GetView() const Ref<Platform> Function::GetPlatform() const { - return new Platform(BNGetFunctionPlatform(m_object)); + return new CorePlatform(BNGetFunctionPlatform(m_object)); } diff --git a/platform.cpp b/platform.cpp index 7a6e2129..f123b76d 100644 --- a/platform.cpp +++ b/platform.cpp @@ -30,20 +30,89 @@ Platform::Platform(BNPlatform* platform) } +CorePlatform::CorePlatform(BNPlatform* platform) : Platform(platform) {} + + Platform::Platform(Architecture* arch, const string& name) { - m_object = BNCreatePlatform(arch->GetObject(), name.c_str()); + BNCustomPlatform plat; + plat.context = this; + plat.init = InitCallback; + plat.viewInit = InitViewCallback; + plat.getGlobalRegisters = GetGlobalRegistersCallback; + plat.freeRegisterList = FreeRegisterListCallback; + plat.getGlobalRegisterType = GetGlobalRegisterTypeCallback; + m_object = BNCreateCustomPlatform(arch->GetObject(), name.c_str(), &plat); + AddRefForRegistration(); } Platform::Platform(Architecture* arch, const string& name, const string& typeFile, const vector<string>& includeDirs) { + BNCustomPlatform plat; + plat.context = this; + plat.init = InitCallback; + plat.viewInit = InitViewCallback; + plat.getGlobalRegisters = GetGlobalRegistersCallback; + plat.freeRegisterList = FreeRegisterListCallback; + plat.getGlobalRegisterType = GetGlobalRegisterTypeCallback; const char** includeDirList = new const char*[includeDirs.size()]; for (size_t i = 0; i < includeDirs.size(); i++) includeDirList[i] = includeDirs[i].c_str(); - m_object = BNCreatePlatformWithTypes( - arch->GetObject(), name.c_str(), typeFile.c_str(), includeDirList, includeDirs.size()); + m_object = BNCreateCustomPlatformWithTypes( + arch->GetObject(), name.c_str(), &plat, + typeFile.c_str(), includeDirList, includeDirs.size()); delete[] includeDirList; + AddRefForRegistration(); +} + + + + +void Platform::InitCallback(void* ctxt, BNPlatform* plat) +{ +} + + +void Platform::InitViewCallback(void* ctxt, BNBinaryView* view) +{ + CallbackRef<Platform> plat(ctxt); + Ref<BinaryView> viewObj = new BinaryView(BNNewViewReference(view)); + plat->BinaryViewInit(viewObj); +} + + +uint32_t* Platform::GetGlobalRegistersCallback(void* ctxt, size_t* count) +{ + CallbackRef<Platform> plat(ctxt); + + std::vector<uint32_t> regs = plat->GetGlobalRegisters(); + *count = regs.size(); + + uint32_t* result = new uint32_t[regs.size()]; + for (size_t i = 0; i < regs.size(); i++) + result[i] = regs[i]; + + return result; +} + + +void Platform::FreeRegisterListCallback(void*, uint32_t* regs, size_t) +{ + delete[] regs; +} + + +BNType* Platform::GetGlobalRegisterTypeCallback(void* ctxt, uint32_t reg) +{ + CallbackRef<Platform> plat(ctxt); + + Ref<Type> result = plat->GetGlobalRegisterType(reg); + + if (!result) + return nullptr; + + return BNNewTypeReference(result->GetObject()); } @@ -73,7 +142,7 @@ Ref<Platform> Platform::GetByName(const string& name) BNPlatform* platform = BNGetPlatformByName(name.c_str()); if (!platform) return nullptr; - return new Platform(platform); + return new CorePlatform(platform); } @@ -85,7 +154,7 @@ vector<Ref<Platform>> Platform::GetList() vector<Ref<Platform>> result; result.reserve(count); for (size_t i = 0; i < count; i++) - result.push_back(new Platform(BNNewPlatformReference(list[i]))); + result.push_back(new CorePlatform(BNNewPlatformReference(list[i]))); BNFreePlatformList(list, count); return result; @@ -100,7 +169,7 @@ vector<Ref<Platform>> Platform::GetList(Architecture* arch) vector<Ref<Platform>> result; result.reserve(count); for (size_t i = 0; i < count; i++) - result.push_back(new Platform(BNNewPlatformReference(list[i]))); + result.push_back(new CorePlatform(BNNewPlatformReference(list[i]))); BNFreePlatformList(list, count); return result; @@ -115,7 +184,7 @@ vector<Ref<Platform>> Platform::GetList(const string& os) vector<Ref<Platform>> result; result.reserve(count); for (size_t i = 0; i < count; i++) - result.push_back(new Platform(BNNewPlatformReference(list[i]))); + result.push_back(new CorePlatform(BNNewPlatformReference(list[i]))); BNFreePlatformList(list, count); return result; @@ -130,7 +199,7 @@ vector<Ref<Platform>> Platform::GetList(const string& os, Architecture* arch) vector<Ref<Platform>> result; result.reserve(count); for (size_t i = 0; i < count; i++) - result.push_back(new Platform(BNNewPlatformReference(list[i]))); + result.push_back(new CorePlatform(BNNewPlatformReference(list[i]))); BNFreePlatformList(list, count); return result; @@ -248,12 +317,53 @@ void Platform::SetSystemCallConvention(CallingConvention* cc) } +void Platform::BinaryViewInit(BinaryView*) +{ +} + + +std::vector<uint32_t> Platform::GetGlobalRegisters() +{ + return GetArchitecture()->GetGlobalRegisters(); +} + + +Ref<Type> Platform::GetGlobalRegisterType(uint32_t reg) +{ + return nullptr; +} + + +std::vector<uint32_t> CorePlatform::GetGlobalRegisters() +{ + size_t count; + uint32_t* regs = BNGetPlatformGlobalRegisters(m_object, &count); + + std::vector<uint32_t> result; + for (size_t i = 0; i < count; i++) + result.push_back(regs[i]); + + BNFreeRegisterList(regs); + + return result; +} + + +Ref<Type> CorePlatform::GetGlobalRegisterType(uint32_t reg) +{ + BNType* res = BNGetPlatformGlobalRegisterType(m_object, reg); + if (!res) + return nullptr; + return new Type(res); +} + + Ref<Platform> Platform::GetRelatedPlatform(Architecture* arch) { BNPlatform* platform = BNGetRelatedPlatform(m_object, arch->GetObject()); if (!platform) return nullptr; - return new Platform(platform); + return new CorePlatform(platform); } @@ -268,7 +378,7 @@ Ref<Platform> Platform::GetAssociatedPlatformByAddress(uint64_t& addr) BNPlatform* platform = BNGetAssociatedPlatformByAddress(m_object, &addr); if (!platform) return nullptr; - return new Platform(platform); + return new CorePlatform(platform); } diff --git a/platform/windows/platform_windows.cpp b/platform/windows/platform_windows.cpp index 2b0a427f..cb256660 100644 --- a/platform/windows/platform_windows.cpp +++ b/platform/windows/platform_windows.cpp @@ -7,11 +7,16 @@ using namespace std; class WindowsX86Platform: public Platform { + uint32_t m_fsbase; + Ref<Type> m_teb; + public: WindowsX86Platform(Architecture* arch): Platform(arch, "windows-x86") { Ref<CallingConvention> cc; + m_fsbase = arch->GetRegisterByName("fsbase"); + cc = arch->GetCallingConventionByName("cdecl"); if (cc) { @@ -36,14 +41,35 @@ public: if (cc) RegisterCallingConvention(cc); } + + + virtual void BinaryViewInit(BinaryView* view) override + { + if (!m_teb) + m_teb = Type::PointerType(GetArchitecture()->GetAddressSize(), Type::NamedType(QualifiedName("TEB"), GetTypeByName(QualifiedName("TEB")))); + } + + + virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override + { + if (reg == m_fsbase) + return m_teb; + + return nullptr; + } }; class WindowsX64Platform: public Platform { + uint32_t m_gsbase; + Ref<Type> m_teb; + public: WindowsX64Platform(Architecture* arch): Platform(arch, "windows-x86_64") { + m_gsbase = arch->GetRegisterByName("gsbase"); + Ref<CallingConvention> cc; cc = arch->GetCallingConventionByName("win64"); @@ -55,6 +81,22 @@ public: RegisterStdcallCallingConvention(cc); } } + + + virtual void BinaryViewInit(BinaryView* view) override + { + if (!m_teb) + m_teb = Type::PointerType(GetArchitecture()->GetAddressSize(), Type::NamedType(QualifiedName("TEB"), GetTypeByName(QualifiedName("TEB")))); + } + + + virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override + { + if (reg == m_gsbase) + return m_teb; + + return nullptr; + } }; diff --git a/python/platform.py b/python/platform.py index d67f4901..0fd54e52 100644 --- a/python/platform.py +++ b/python/platform.py @@ -20,6 +20,7 @@ import os import ctypes +import traceback from typing import List, Dict, Optional # Binary Ninja components @@ -31,6 +32,8 @@ from . import callingconvention from . import typelibrary from . import architecture from . import typecontainer +from . import binaryview +from .log import log_error class _PlatformMetaClass(type): @@ -61,6 +64,10 @@ class Platform(metaclass=_PlatformMetaClass): name = None type_file_path = None # path to platform types file type_include_dirs = [] # list of directories available to #include from type_file_path + global_regs = [] # list of global registers. if empty, it populated with the arch global reg list + global_reg_types = {} # opportunity for plugin to provide default types for the entry value of global registers + + _registered_platforms = [] def __init__(self, arch: Optional['architecture.Architecture'] = None, handle=None): if handle is None: @@ -68,27 +75,92 @@ class Platform(metaclass=_PlatformMetaClass): raise ValueError("platform must have an associated architecture") assert self.__class__.name is not None, "Can not instantiate Platform directly, you probably want arch.standalone_platform" _arch = arch + if len(self.global_regs) == 0: + self.__dict__["global_regs"] = arch.global_regs + self._cb = core.BNCustomPlatform() + self._cb.context = 0 + self._cb.init = self._cb.init.__class__(self._init) + self._cb.viewInit = self._cb.viewInit.__class__(self._view_init) + self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_regs) + self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list) + self._cb.getGlobalRegisterType = self._cb.getGlobalRegisterType.__class__(self._get_global_reg_type) + self._pending_reg_lists = {} if self.__class__.type_file_path is None: - _handle = core.BNCreatePlatform(arch.handle, self.__class__.name) + _handle = core.BNCreateCustomPlatform(arch.handle, self.__class__.name, self._cb) assert _handle is not None else: dir_buf = (ctypes.c_char_p * len(self.__class__.type_include_dirs))() for (i, dir) in enumerate(self.__class__.type_include_dirs): dir_buf[i] = dir.encode('charmap') - _handle = core.BNCreatePlatformWithTypes( - arch.handle, self.__class__.name, self.__class__.type_file_path, dir_buf, + _handle = core.BNCreateCustomPlatformWithTypes( + arch.handle, self.__class__.name, self._cb, self.__class__.type_file_path, dir_buf, len(self.__class__.type_include_dirs) ) assert _handle is not None + self.__class__._registered_platforms.append(self) else: _handle = handle _arch = architecture.CoreArchitecture._from_cache(core.BNGetPlatformArchitecture(_handle)) + count = ctypes.c_ulonglong() + regs = core.BNGetPlatformGlobalRegisters(handle, count) + result = [] + for i in range(0, count.value): + result.append(_arch.get_reg_name(regs[i])) + core.BNFreeRegisterList(regs) + self.__dict__["global_regs"] = result assert _handle is not None assert _arch is not None self.handle: ctypes.POINTER(core.BNPlatform) = _handle self._arch = _arch self._name = None + def _init(self, ctxt): + pass + + def _view_init(self, ctxt, view): + try: + view_obj = binaryview.BinaryView(handle=core.BNNewViewReference(view)) + self.view_init(view) + except: + log_error(traceback.format_exc()) + + def _get_global_regs(self, ctxt, count): + try: + regs = self.global_regs + count[0] = len(regs) + reg_buf = (ctypes.c_uint * len(regs))() + for i in range(0, len(regs)): + reg_buf[i] = self.arch.regs[regs[i]].index + result = ctypes.cast(reg_buf, ctypes.c_void_p) + self._pending_reg_lists[result.value] = (result, reg_buf) + return result.value + except: + log_error(traceback.format_exc()) + count[0] = 0 + return None + + def _free_register_list(self, ctxt, regs, size): + try: + buf = ctypes.cast(regs, ctypes.c_void_p) + if buf.value not in self._pending_reg_lists: + raise ValueError("freeing register list that wasn't allocated") + del self._pending_reg_lists[buf.value] + except: + log_error(traceback.format_exc()) + + def _get_global_reg_type(self, ctxt, reg): + try: + reg_name = self.arch.get_reg_name(reg) + if reg_name in self.global_reg_types: + type_obj = self.global_reg_types[reg_name] + log_error(f"aaaa {type_obj}") + handle = core.BNNewTypeReference(type_obj.handle) + return ctypes.cast(handle, ctypes.c_void_p).value + return None + except: + log_error(traceback.format_exc()) + return None + def __del__(self): if core is not None: core.BNFreePlatform(self.handle) @@ -253,6 +325,18 @@ class Platform(metaclass=_PlatformMetaClass): core.BNFreeCallingConventionList(cc, count.value) return result + def get_global_register_type(self, reg: 'architecture.RegisterType'): + reg = self.arch.get_reg_index(reg) + type_obj = core.BNGetPlatformGlobalRegisterType(self.handle, reg) + if type_obj is None: + return None + return types.Type.create(type_obj, platform=self) + + def view_init(self, view): + pass + #raise NotImplementedError + + @property def types(self): """List of platform-specific types (read-only)""" diff --git a/typearchive.cpp b/typearchive.cpp index 29dd0d6a..151564db 100644 --- a/typearchive.cpp +++ b/typearchive.cpp @@ -148,7 +148,7 @@ Ref<Platform> TypeArchive::GetPlatform() const BNPlatform* platform = BNGetTypeArchivePlatform(m_object); if (!platform) return nullptr; - return new Platform(platform); + return new CorePlatform(platform); } @@ -632,4 +632,4 @@ std::optional<std::string> TypeArchive::MergeSnapshots( } return resultCpp; -}
\ No newline at end of file +} diff --git a/typecontainer.cpp b/typecontainer.cpp index 6050fde3..b6fd54f3 100644 --- a/typecontainer.cpp +++ b/typecontainer.cpp @@ -128,7 +128,7 @@ Ref<Platform> TypeContainer::GetPlatform() const BNPlatform* platform = BNTypeContainerGetPlatform(m_object); if (!platform) return nullptr; - return new Platform(platform); + return new CorePlatform(platform); } diff --git a/typeparser.cpp b/typeparser.cpp index 8aaf02c4..67dadd95 100644 --- a/typeparser.cpp +++ b/typeparser.cpp @@ -147,7 +147,7 @@ bool TypeParser::PreprocessSourceCallback(void* ctxt, bool success = parser->PreprocessSource( source, fileName, - new Platform(platform), + new CorePlatform(platform), TypeContainer{BNDuplicateTypeContainer(existingTypes)}, optionsCpp, includeDirsCpp, @@ -207,7 +207,7 @@ bool TypeParser::ParseTypesFromSourceCallback(void* ctxt, bool success = parser->ParseTypesFromSource( source, fileName, - new Platform(platform), + new CorePlatform(platform), TypeContainer{BNDuplicateTypeContainer(existingTypes)}, optionsCpp, includeDirsCpp, @@ -278,7 +278,7 @@ bool TypeParser::ParseTypeStringCallback(void* ctxt, vector<TypeParserError> errorsCpp; bool success = parser->ParseTypeString( source, - new Platform(platform), + new CorePlatform(platform), TypeContainer{BNDuplicateTypeContainer(existingTypes)}, resultCpp, errorsCpp |
