Skip to content

Commit 6e4c00a

Browse files
committed
Support for Linux x86-64 x32 ABI
1 parent b13d50b commit 6e4c00a

File tree

6 files changed

+105
-17
lines changed

6 files changed

+105
-17
lines changed

binaryninjaapi.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15593,6 +15593,7 @@ namespace BinaryNinja {
1559315593
static void InitViewCallback(void* ctxt, BNBinaryView* view);
1559415594
static uint32_t* GetGlobalRegistersCallback(void* ctxt, size_t* count);
1559515595
static void FreeRegisterListCallback(void* ctxt, uint32_t* regs, size_t count);
15596+
static size_t GetAddressSizeCallback(void* ctxt);
1559615597
static BNType* GetGlobalRegisterTypeCallback(void* ctxt, uint32_t reg);
1559715598
static void AdjustTypeParserInputCallback(
1559815599
void* ctxt,
@@ -15777,6 +15778,12 @@ namespace BinaryNinja {
1577715778
*/
1577815779
virtual Ref<Type> GetGlobalRegisterType(uint32_t reg);
1577915780

15781+
/*! Get the address size for this platform
15782+
15783+
\return The address size for this platform
15784+
*/
15785+
virtual size_t GetAddressSize() const;
15786+
1578015787
/*! Modify the input passed to the Type Parser with Platform-specific features.
1578115788

1578215789
\param[in] parser Type Parser instance
@@ -15904,6 +15911,7 @@ namespace BinaryNinja {
1590415911
std::vector<std::string>& arguments,
1590515912
std::vector<std::pair<std::string, std::string>>& sourceFiles
1590615913
) override;
15914+
virtual size_t GetAddressSize() const override;
1590715915
};
1590815916

1590915917
/*!

binaryninjacore.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
// Current ABI version for linking to the core. This is incremented any time
3838
// there are changes to the API that affect linking, including new functions,
3939
// new types, or modifications to existing functions or types.
40-
#define BN_CURRENT_CORE_ABI_VERSION 107
40+
#define BN_CURRENT_CORE_ABI_VERSION 108
4141

4242
// Minimum ABI version that is supported for loading of plugins. Plugins that
4343
// are linked to an ABI version less than this will not be able to load and
@@ -1935,6 +1935,8 @@ extern "C"
19351935

19361936
BNType* (*getGlobalRegisterType)(void* ctxt, uint32_t reg);
19371937

1938+
size_t (*getAddressSize)(void* ctxt);
1939+
19381940
void (*adjustTypeParserInput)(
19391941
void* ctxt,
19401942
BNTypeParser* parser,
@@ -6972,6 +6974,7 @@ extern "C"
69726974

69736975
BINARYNINJACOREAPI uint32_t* BNGetPlatformGlobalRegisters(BNPlatform* platform, size_t* count);
69746976
BINARYNINJACOREAPI BNType* BNGetPlatformGlobalRegisterType(BNPlatform* platform, uint32_t reg);
6977+
BINARYNINJACOREAPI size_t BNGetPlatformAddressSize(BNPlatform* platform);
69756978
BINARYNINJACOREAPI void BNPlatformAdjustTypeParserInput(
69766979
BNPlatform* platform,
69776980
BNTypeParser* parser,

platform.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Platform::Platform(Architecture* arch, const string& name)
4141
plat.viewInit = InitViewCallback;
4242
plat.getGlobalRegisters = GetGlobalRegistersCallback;
4343
plat.freeRegisterList = FreeRegisterListCallback;
44+
plat.getAddressSize = GetAddressSizeCallback;
4445
plat.getGlobalRegisterType = GetGlobalRegisterTypeCallback;
4546
plat.adjustTypeParserInput = AdjustTypeParserInputCallback;
4647
plat.freeTypeParserInput = FreeTypeParserInputCallback;
@@ -59,6 +60,7 @@ Platform::Platform(Architecture* arch, const string& name, const string& typeFil
5960
plat.getGlobalRegisters = GetGlobalRegistersCallback;
6061
plat.freeRegisterList = FreeRegisterListCallback;
6162
plat.getGlobalRegisterType = GetGlobalRegisterTypeCallback;
63+
plat.getAddressSize = GetAddressSizeCallback;
6264
plat.adjustTypeParserInput = AdjustTypeParserInputCallback;
6365
plat.freeTypeParserInput = FreeTypeParserInputCallback;
6466
plat.getFallbackEnabled = GetFallbackEnabledCallback;
@@ -193,6 +195,14 @@ BNType* Platform::GetGlobalRegisterTypeCallback(void* ctxt, uint32_t reg)
193195
return BNNewTypeReference(result->GetObject());
194196
}
195197

198+
199+
size_t Platform::GetAddressSizeCallback(void* ctxt)
200+
{
201+
CallbackRef<Platform> plat(ctxt);
202+
return plat->GetAddressSize();
203+
}
204+
205+
196206
bool Platform::GetFallbackEnabledCallback(void* ctxt)
197207
{
198208
CallbackRef<Platform> plat(ctxt);
@@ -424,6 +434,12 @@ bool Platform::GetFallbackEnabled()
424434
}
425435

426436

437+
size_t Platform::GetAddressSize() const
438+
{
439+
return GetArchitecture()->GetAddressSize();
440+
}
441+
442+
427443
std::vector<uint32_t> CorePlatform::GetGlobalRegisters()
428444
{
429445
size_t count;
@@ -448,6 +464,12 @@ Ref<Type> CorePlatform::GetGlobalRegisterType(uint32_t reg)
448464
}
449465

450466

467+
size_t CorePlatform::GetAddressSize() const
468+
{
469+
return BNGetPlatformAddressSize(m_object);
470+
}
471+
472+
451473
void Platform::AdjustTypeParserInput(
452474
Ref<TypeParser> parser,
453475
vector<string>& arguments,

platform/linux/platform_linux.cpp

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using namespace BinaryNinja;
44
using namespace std;
55

6+
Ref<Platform> g_linuxX32;
7+
#define EM_X86_64 62 // AMD x86-64 architecture
68

79
class LinuxX86Platform: public Platform
810
{
@@ -103,6 +105,50 @@ class LinuxX64Platform: public Platform
103105
};
104106

105107

108+
class LinuxX32Platform: public Platform
109+
{
110+
public:
111+
LinuxX32Platform(Architecture* arch): Platform(arch, "linux-x32")
112+
{
113+
Ref<CallingConvention> cc;
114+
cc = arch->GetCallingConventionByName("sysv");
115+
if (cc)
116+
{
117+
RegisterDefaultCallingConvention(cc);
118+
RegisterCdeclCallingConvention(cc);
119+
RegisterFastcallCallingConvention(cc);
120+
RegisterStdcallCallingConvention(cc);
121+
}
122+
123+
cc = arch->GetCallingConventionByName("linux-syscall");
124+
if (cc)
125+
SetSystemCallConvention(cc);
126+
}
127+
128+
virtual size_t GetAddressSize() const override
129+
{
130+
return 4;
131+
}
132+
133+
static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata)
134+
{
135+
Ref<Metadata> fileClass = metadata->Get("EI_CLASS");
136+
137+
if (!fileClass || !fileClass->IsUnsignedInteger())
138+
return nullptr;
139+
140+
Ref<Metadata> machine = metadata->Get("e_machine");
141+
if (!machine || !machine->IsUnsignedInteger())
142+
return nullptr;
143+
144+
if (fileClass->GetUnsignedInteger() == 1 && machine->GetUnsignedInteger() == EM_X86_64)
145+
return g_linuxX32;
146+
147+
return nullptr;
148+
}
149+
};
150+
151+
106152
class LinuxArmv7Platform: public Platform
107153
{
108154
public:
@@ -314,13 +360,20 @@ extern "C"
314360
Ref<Architecture> x64 = Architecture::GetByName("x86_64");
315361
if (x64)
316362
{
317-
Ref<Platform> platform;
363+
Ref<Platform> x64Platform = new LinuxX64Platform(x64);
364+
g_linuxX32 = new LinuxX32Platform(x64);
365+
366+
Platform::Register("linux", x64Platform);
367+
Platform::Register("linux", g_linuxX32);
318368

319-
platform = new LinuxX64Platform(x64);
320-
Platform::Register("linux", platform);
321369
// Linux binaries sometimes have an OS identifier of zero, even though 3 is the correct one
322-
BinaryViewType::RegisterPlatform("ELF", 0, platform);
323-
BinaryViewType::RegisterPlatform("ELF", 3, platform);
370+
BinaryViewType::RegisterPlatform("ELF", 0, x64, x64Platform);
371+
BinaryViewType::RegisterPlatform("ELF", 3, x64, x64Platform);
372+
373+
374+
Ref<BinaryViewType> elf = BinaryViewType::GetByName("ELF");
375+
if (elf)
376+
elf->RegisterPlatformRecognizer(EM_X86_64, LittleEndian, LinuxX32Platform::Recognize);
324377
}
325378

326379
Ref<Architecture> armv7 = Architecture::GetByName("armv7");

python/platform.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ def __init__(self, arch: Optional['architecture.Architecture'] = None, handle=No
113113
self._cb.getGlobalRegisters = self._cb.getGlobalRegisters.__class__(self._get_global_regs)
114114
self._cb.freeRegisterList = self._cb.freeRegisterList.__class__(self._free_register_list)
115115
self._cb.getGlobalRegisterType = self._cb.getGlobalRegisterType.__class__(self._get_global_reg_type)
116+
self._cb.getAddressSize = self._cb.getAddressSize.__class__(self._get_address_size)
116117
self._cb.adjustTypeParserInput = self._cb.adjustTypeParserInput.__class__(self._adjust_type_parser_input)
117118
self._cb.freeTypeParserInput = self._cb.freeTypeParserInput.__class__(self._free_type_parser_input)
118119
self._pending_reg_lists = {}
@@ -149,6 +150,7 @@ def __init__(self, arch: Optional['architecture.Architecture'] = None, handle=No
149150
self.handle: ctypes.POINTER(core.BNPlatform) = _handle
150151
self._arch = _arch
151152
self._name = None
153+
self._address_size = core.BNGetPlatformAddressSize(_handle)
152154

153155
def _init(self, ctxt):
154156
pass
@@ -196,6 +198,12 @@ def _get_global_reg_type(self, ctxt, reg):
196198
log_error(traceback.format_exc())
197199
return None
198200

201+
def _get_address_size(self, ctxt):
202+
try:
203+
return self.address_size
204+
except:
205+
return self.arch.address_size
206+
199207
def _adjust_type_parser_input(
200208
self,
201209
ctxt,
@@ -328,6 +336,10 @@ def name(self) -> str:
328336
self._name = core.BNGetPlatformName(self.handle)
329337
return self._name
330338

339+
@property
340+
def address_size(self) -> int:
341+
return self._address_size
342+
331343
@classmethod
332344
@property
333345
def os_list(cls) -> List[str]:

view/elf/elfview.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ ElfView::ElfView(BinaryView* data, bool parseOnly): BinaryView("ELF", data->GetF
5454
CreateLogger("BinaryView");
5555
m_logger = CreateLogger("BinaryView.ElfView");
5656
m_elf32 = m_ident.fileClass == 1;
57-
m_addressSize = (m_ident.fileClass == 1) ? 4 : 8;
57+
m_addressSize = (m_ident.fileClass == 1 || (m_plat && m_plat->GetName() == "linux-32")) ? 4 : 8;
5858
m_endian = endian;
5959
m_relocatable = m_commonHeader.type == ET_DYN || m_commonHeader.type == ET_REL;
6060
m_objectFile = m_commonHeader.type == ET_REL;
@@ -2874,16 +2874,6 @@ uint64_t ElfViewType::ParseHeaders(BinaryView* data, ElfIdent& ident, ElfCommonH
28742874
commonHeader.arch = reader.Read16();
28752875
commonHeader.version = reader.Read32();
28762876

2877-
// Promote the file class to 64-bit
2878-
// TODO potentially add a setting to allow the user to override header interpretation
2879-
if ((commonHeader.type == ET_EXEC) && (commonHeader.arch == EM_X86_64) && (ident.fileClass == 1))
2880-
{
2881-
ident.fileClass = 2;
2882-
m_logger->LogWarn(
2883-
"Executable file claims to be 32-bit but specifies a 64-bit architecture. It is likely malformed or "
2884-
"malicious. Treating it as 64-bit.");
2885-
}
2886-
28872877
// parse Elf64Header
28882878
if (ident.fileClass == 1) // 32-bit ELF
28892879
{

0 commit comments

Comments
 (0)