diff options
| author | Brandon Miller <brandon@vector35.com> | 2025-05-28 08:33:30 -0400 |
|---|---|---|
| committer | Brandon Miller <brandon@vector35.com> | 2025-05-28 08:33:30 -0400 |
| commit | 6e4c00a80fa86bcfefba9630a1ea8e2a47bef2de (patch) | |
| tree | 94f891149263fe089d747c4baba7d20a80a7750b | |
| parent | b13d50bac18c341b98e6a3002ac9f17f6c8a8df4 (diff) | |
Support for Linux x86-64 x32 ABI
| -rw-r--r-- | binaryninjaapi.h | 8 | ||||
| -rw-r--r-- | binaryninjacore.h | 5 | ||||
| -rw-r--r-- | platform.cpp | 22 | ||||
| -rw-r--r-- | platform/linux/platform_linux.cpp | 63 | ||||
| -rw-r--r-- | python/platform.py | 12 | ||||
| -rw-r--r-- | view/elf/elfview.cpp | 12 |
6 files changed, 105 insertions, 17 deletions
diff --git a/binaryninjaapi.h b/binaryninjaapi.h index ca5b630c..6d5c144c 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -15593,6 +15593,7 @@ namespace BinaryNinja { 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 size_t GetAddressSizeCallback(void* ctxt); static BNType* GetGlobalRegisterTypeCallback(void* ctxt, uint32_t reg); static void AdjustTypeParserInputCallback( void* ctxt, @@ -15777,6 +15778,12 @@ namespace BinaryNinja { */ virtual Ref<Type> GetGlobalRegisterType(uint32_t reg); + /*! Get the address size for this platform + + \return The address size for this platform + */ + virtual size_t GetAddressSize() const; + /*! Modify the input passed to the Type Parser with Platform-specific features. \param[in] parser Type Parser instance @@ -15904,6 +15911,7 @@ namespace BinaryNinja { std::vector<std::string>& arguments, std::vector<std::pair<std::string, std::string>>& sourceFiles ) override; + virtual size_t GetAddressSize() const override; }; /*! diff --git a/binaryninjacore.h b/binaryninjacore.h index ec03c1dd..505e10e2 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -37,7 +37,7 @@ // Current ABI version for linking to the core. This is incremented any time // there are changes to the API that affect linking, including new functions, // new types, or modifications to existing functions or types. -#define BN_CURRENT_CORE_ABI_VERSION 107 +#define BN_CURRENT_CORE_ABI_VERSION 108 // Minimum ABI version that is supported for loading of plugins. Plugins that // are linked to an ABI version less than this will not be able to load and @@ -1935,6 +1935,8 @@ extern "C" BNType* (*getGlobalRegisterType)(void* ctxt, uint32_t reg); + size_t (*getAddressSize)(void* ctxt); + void (*adjustTypeParserInput)( void* ctxt, BNTypeParser* parser, @@ -6972,6 +6974,7 @@ extern "C" BINARYNINJACOREAPI uint32_t* BNGetPlatformGlobalRegisters(BNPlatform* platform, size_t* count); BINARYNINJACOREAPI BNType* BNGetPlatformGlobalRegisterType(BNPlatform* platform, uint32_t reg); + BINARYNINJACOREAPI size_t BNGetPlatformAddressSize(BNPlatform* platform); BINARYNINJACOREAPI void BNPlatformAdjustTypeParserInput( BNPlatform* platform, BNTypeParser* parser, diff --git a/platform.cpp b/platform.cpp index e367f0c2..ef32e469 100644 --- a/platform.cpp +++ b/platform.cpp @@ -41,6 +41,7 @@ Platform::Platform(Architecture* arch, const string& name) plat.viewInit = InitViewCallback; plat.getGlobalRegisters = GetGlobalRegistersCallback; plat.freeRegisterList = FreeRegisterListCallback; + plat.getAddressSize = GetAddressSizeCallback; plat.getGlobalRegisterType = GetGlobalRegisterTypeCallback; plat.adjustTypeParserInput = AdjustTypeParserInputCallback; plat.freeTypeParserInput = FreeTypeParserInputCallback; @@ -59,6 +60,7 @@ Platform::Platform(Architecture* arch, const string& name, const string& typeFil plat.getGlobalRegisters = GetGlobalRegistersCallback; plat.freeRegisterList = FreeRegisterListCallback; plat.getGlobalRegisterType = GetGlobalRegisterTypeCallback; + plat.getAddressSize = GetAddressSizeCallback; plat.adjustTypeParserInput = AdjustTypeParserInputCallback; plat.freeTypeParserInput = FreeTypeParserInputCallback; plat.getFallbackEnabled = GetFallbackEnabledCallback; @@ -193,6 +195,14 @@ BNType* Platform::GetGlobalRegisterTypeCallback(void* ctxt, uint32_t reg) return BNNewTypeReference(result->GetObject()); } + +size_t Platform::GetAddressSizeCallback(void* ctxt) +{ + CallbackRef<Platform> plat(ctxt); + return plat->GetAddressSize(); +} + + bool Platform::GetFallbackEnabledCallback(void* ctxt) { CallbackRef<Platform> plat(ctxt); @@ -424,6 +434,12 @@ bool Platform::GetFallbackEnabled() } +size_t Platform::GetAddressSize() const +{ + return GetArchitecture()->GetAddressSize(); +} + + std::vector<uint32_t> CorePlatform::GetGlobalRegisters() { size_t count; @@ -448,6 +464,12 @@ Ref<Type> CorePlatform::GetGlobalRegisterType(uint32_t reg) } +size_t CorePlatform::GetAddressSize() const +{ + return BNGetPlatformAddressSize(m_object); +} + + void Platform::AdjustTypeParserInput( Ref<TypeParser> parser, vector<string>& arguments, diff --git a/platform/linux/platform_linux.cpp b/platform/linux/platform_linux.cpp index 0102fa42..20a258d6 100644 --- a/platform/linux/platform_linux.cpp +++ b/platform/linux/platform_linux.cpp @@ -3,6 +3,8 @@ using namespace BinaryNinja; using namespace std; +Ref<Platform> g_linuxX32; +#define EM_X86_64 62 // AMD x86-64 architecture class LinuxX86Platform: public Platform { @@ -103,6 +105,50 @@ public: }; +class LinuxX32Platform: public Platform +{ + public: + LinuxX32Platform(Architecture* arch): Platform(arch, "linux-x32") + { + Ref<CallingConvention> cc; + cc = arch->GetCallingConventionByName("sysv"); + if (cc) + { + RegisterDefaultCallingConvention(cc); + RegisterCdeclCallingConvention(cc); + RegisterFastcallCallingConvention(cc); + RegisterStdcallCallingConvention(cc); + } + + cc = arch->GetCallingConventionByName("linux-syscall"); + if (cc) + SetSystemCallConvention(cc); + } + + virtual size_t GetAddressSize() const override + { + return 4; + } + + static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata) + { + Ref<Metadata> fileClass = metadata->Get("EI_CLASS"); + + if (!fileClass || !fileClass->IsUnsignedInteger()) + return nullptr; + + Ref<Metadata> machine = metadata->Get("e_machine"); + if (!machine || !machine->IsUnsignedInteger()) + return nullptr; + + if (fileClass->GetUnsignedInteger() == 1 && machine->GetUnsignedInteger() == EM_X86_64) + return g_linuxX32; + + return nullptr; + } +}; + + class LinuxArmv7Platform: public Platform { public: @@ -314,13 +360,20 @@ extern "C" Ref<Architecture> x64 = Architecture::GetByName("x86_64"); if (x64) { - Ref<Platform> platform; + Ref<Platform> x64Platform = new LinuxX64Platform(x64); + g_linuxX32 = new LinuxX32Platform(x64); + + Platform::Register("linux", x64Platform); + Platform::Register("linux", g_linuxX32); - platform = new LinuxX64Platform(x64); - Platform::Register("linux", platform); // Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one - BinaryViewType::RegisterPlatform("ELF", 0, platform); - BinaryViewType::RegisterPlatform("ELF", 3, platform); + BinaryViewType::RegisterPlatform("ELF", 0, x64, x64Platform); + BinaryViewType::RegisterPlatform("ELF", 3, x64, x64Platform); + + + Ref<BinaryViewType> elf = BinaryViewType::GetByName("ELF"); + if (elf) + elf->RegisterPlatformRecognizer(EM_X86_64, LittleEndian, LinuxX32Platform::Recognize); } Ref<Architecture> armv7 = Architecture::GetByName("armv7"); diff --git a/python/platform.py b/python/platform.py index d7cdabe8..29eb81b0 100644 --- a/python/platform.py +++ b/python/platform.py @@ -113,6 +113,7 @@ class Platform(metaclass=_PlatformMetaClass): 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._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size) self._cb.adjustTypeParserInput = self._cb.adjustTypeParserInput.__class__(self._adjust_type_parser_input) self._cb.freeTypeParserInput = self._cb.freeTypeParserInput.__class__(self._free_type_parser_input) self._pending_reg_lists = {} @@ -149,6 +150,7 @@ class Platform(metaclass=_PlatformMetaClass): self.handle: ctypes.POINTER(core.BNPlatform) = _handle self._arch = _arch self._name = None + self._address_size = core.BNGetPlatformAddressSize(_handle) def _init(self, ctxt): pass @@ -196,6 +198,12 @@ class Platform(metaclass=_PlatformMetaClass): log_error(traceback.format_exc()) return None + def _get_address_size(self, ctxt): + try: + return self.address_size + except: + return self.arch.address_size + def _adjust_type_parser_input( self, ctxt, @@ -328,6 +336,10 @@ class Platform(metaclass=_PlatformMetaClass): self._name = core.BNGetPlatformName(self.handle) return self._name + @property + def address_size(self) -> int: + return self._address_size + @classmethod @property def os_list(cls) -> List[str]: diff --git a/view/elf/elfview.cpp b/view/elf/elfview.cpp index 6d19bc5f..bb193495 100644 --- a/view/elf/elfview.cpp +++ b/view/elf/elfview.cpp @@ -54,7 +54,7 @@ ElfView::ElfView(BinaryView* data, bool parseOnly): BinaryView("ELF", data->GetF CreateLogger("BinaryView"); m_logger = CreateLogger("BinaryView.ElfView"); m_elf32 = m_ident.fileClass == 1; - m_addressSize = (m_ident.fileClass == 1) ? 4 : 8; + m_addressSize = (m_ident.fileClass == 1 || (m_plat && m_plat->GetName() == "linux-32")) ? 4 : 8; m_endian = endian; m_relocatable = m_commonHeader.type == ET_DYN || m_commonHeader.type == ET_REL; m_objectFile = m_commonHeader.type == ET_REL; @@ -2874,16 +2874,6 @@ uint64_t ElfViewType::ParseHeaders(BinaryView* data, ElfIdent& ident, ElfCommonH commonHeader.arch = reader.Read16(); commonHeader.version = reader.Read32(); - // Promote the file class to 64-bit - // TODO potentially add a setting to allow the user to override header interpretation - if ((commonHeader.type == ET_EXEC) && (commonHeader.arch == EM_X86_64) && (ident.fileClass == 1)) - { - ident.fileClass = 2; - m_logger->LogWarn( - "Executable file claims to be 32-bit but specifies a 64-bit architecture. It is likely malformed or " - "malicious. Treating it as 64-bit."); - } - // parse Elf64Header if (ident.fileClass == 1) // 32-bit ELF { |
