summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Miller <brandon@vector35.com>2025-05-28 08:33:30 -0400
committerBrandon Miller <brandon@vector35.com>2025-05-28 08:33:30 -0400
commit6e4c00a80fa86bcfefba9630a1ea8e2a47bef2de (patch)
tree94f891149263fe089d747c4baba7d20a80a7750b
parentb13d50bac18c341b98e6a3002ac9f17f6c8a8df4 (diff)
Support for Linux x86-64 x32 ABI
-rw-r--r--binaryninjaapi.h8
-rw-r--r--binaryninjacore.h5
-rw-r--r--platform.cpp22
-rw-r--r--platform/linux/platform_linux.cpp63
-rw-r--r--python/platform.py12
-rw-r--r--view/elf/elfview.cpp12
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
{