From a5c1c475fb73bc4f3e7383f7fe06485efeadabb4 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Mon, 17 Jun 2024 15:59:51 -0400 Subject: [PATCH 01/14] Start VxWorks view; find and process v5 symtab Scanning backwards for symbol table. Creating sections from symbol types. Applying symbols to function and data variables --- view/vxworks/CMakeLists.txt | 33 +++ view/vxworks/LICENSE | 13 + view/vxworks/vxworksview.cpp | 465 +++++++++++++++++++++++++++++++++++ view/vxworks/vxworksview.h | 168 +++++++++++++ 4 files changed, 679 insertions(+) create mode 100644 view/vxworks/CMakeLists.txt create mode 100644 view/vxworks/LICENSE create mode 100644 view/vxworks/vxworksview.cpp create mode 100644 view/vxworks/vxworksview.h diff --git a/view/vxworks/CMakeLists.txt b/view/vxworks/CMakeLists.txt new file mode 100644 index 0000000000..a1df4492a0 --- /dev/null +++ b/view/vxworks/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.9 FATAL_ERROR) + +project(view_vxworks) + +if(NOT BN_INTERNAL_BUILD) + add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api) +endif() + +file(GLOB SOURCES + *.cpp + *.h) + +if(DEMO) + add_library(view_vxworks STATIC ${SOURCES}) +else() + add_library(view_vxworks SHARED ${SOURCES}) +endif() + +target_link_libraries(view_vxworks binaryninjaapi) + +set_target_properties(view_vxworks PROPERTIES + CXX_STANDARD 17 + CXX_VISIBILITY_PRESET hidden + CXX_STANDARD_REQUIRED ON + VISIBILITY_INLINES_HIDDEN ON + POSITION_INDEPENDENT_CODE ON) + +if(BN_INTERNAL_BUILD) + plugin_rpath(view_vxworks) + set_target_properties(view_vxworks PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR} + RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}) +endif() diff --git a/view/vxworks/LICENSE b/view/vxworks/LICENSE new file mode 100644 index 0000000000..265bf79a65 --- /dev/null +++ b/view/vxworks/LICENSE @@ -0,0 +1,13 @@ +Copyright 2021-2024 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. diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp new file mode 100644 index 0000000000..3c08568f4c --- /dev/null +++ b/view/vxworks/vxworksview.cpp @@ -0,0 +1,465 @@ +// BinaryView for VxWorks Real-Time Operating System (RTOS) images + +#include "vxworksview.h" + +using namespace BinaryNinja; +using namespace std; + +static VxWorksViewType* g_vxWorksViewType = nullptr; + +#define NEW_CDM_SIGNATURE_OFFSET 0x0 +#define NEW_CDM_SIGNATURE_SIZE 0xb +#define PACKAGED_CDM_SIGNATURE_SIZE 0x3 +#define PACKAGED_CDM_SIGNATURE_OFFSET 0x50 +static VxWorksImageType IdentifyVxWorksImageType(BinaryReader* reader) +{ + reader->Seek(0); + uint32_t magic; + if (!reader->TryRead32(magic)) + return VxWorksUnsupportedImageType; + + if (magic == 0x7c6000a6 || magic == 0x7c631a78) + return VxWorksStandardImageType; + + uint8_t newCDMSignature[NEW_CDM_SIGNATURE_SIZE]; + reader->Seek(NEW_CDM_SIGNATURE_OFFSET); + if (!reader->TryRead(newCDMSignature, NEW_CDM_SIGNATURE_SIZE)) + return VxWorksUnsupportedImageType; + if (memcmp(newCDMSignature, "vxWorks.pkg", NEW_CDM_SIGNATURE_SIZE) == 0) + return VxWorksCDMNewImageType; + + uint8_t oldCMSSignature[PACKAGED_CDM_SIGNATURE_SIZE]; + reader->Seek(PACKAGED_CDM_SIGNATURE_OFFSET); + if (!reader->TryRead(oldCMSSignature, PACKAGED_CDM_SIGNATURE_SIZE)) + return VxWorksUnsupportedImageType; + if (memcmp(oldCMSSignature, "CDM", PACKAGED_CDM_SIGNATURE_SIZE) == 0) + return VxWorksCDMPackagedImageType; + + return VxWorksUnsupportedImageType; +} + + +void BinaryNinja::InitVxWorksViewType() +{ + static VxWorksViewType type; + BinaryViewType::Register(&type); + g_vxWorksViewType = &type; +} + + +VxWorksView::VxWorksView(BinaryView* data, bool parseOnly): BinaryView("VxWorks", data->GetFile(), data), + m_parseOnly(parseOnly) +{ + CreateLogger("BinaryView"); + m_logger = CreateLogger("BinaryView.VxWorksView"); +} + + +bool VxWorksView::DetermineImageBase(BinaryReader *reader) +{ + VxWorksImageType imageType = IdentifyVxWorksImageType(reader); + switch (imageType) + { + case VxWorksStandardImageType: + { + uint32_t magic; + reader->Seek(0); + if (!reader->TryRead32(magic)) + return 0; + + // TODO: dynamically determine the image base + switch (magic) + { + case 0x7c6000a6: // vx5_ppc_big_endian_0x10000.bin + m_imageBase = 0x10000; + return true; + case 0x7810a0e3: // vx5_arm_little_endian_0x1000.bin + m_imageBase = 0x1000; + case 0x7c631a78: + m_imageBase = 0x400000; + return true; + default: + m_logger->LogError("Unsupported standard VxWorks image magic"); + return false; + } + } + case VxWorksCDMPackagedImageType: + return false; // TODO - not implemented yet + case VxWorksCDMNewImageType: + return false; // TODO - not implemented yet + default: + m_logger->LogError("Unsupported VxWorks image type!?"); + return 0; + } +} + + +bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader) +{ + uint64_t endDataAddress = m_imageBase + parentView->GetLength(); + VxWorks5SymbolTableEntry entry; + uint64_t startOffset = parentView->GetLength() - sizeof(entry); + uint64_t endOffset = 0; + if (parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) + endOffset = parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; + uint64_t searchPos = startOffset; + + m_logger->LogDebug("Scanning backwards for VxWorks 5 symbol table (0x%016x-0x%016x)...", + m_imageBase + startOffset, m_imageBase + endOffset); + while (searchPos > endOffset) + { + reader->Seek(searchPos + 4); // Skip the unknown field + if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address) || !reader->TryRead32(entry.flags)) + break; + + if ((entry.name >= m_imageBase && entry.name < endDataAddress) && + (entry.address >= m_imageBase && entry.address < endDataAddress)) + { + // Name and symbol address pointers are within file + m_symbolTable5.push_back(entry); + searchPos -= sizeof(entry); + continue; + } + + if (m_symbolTable5.size() > MIN_VALID_SYMBOL_ENTRIES) + break; + + searchPos -= 4; + m_symbolTable5.clear(); + } + + if (m_symbolTable5.size() < MIN_VALID_SYMBOL_ENTRIES) + { + m_symbolTable5.clear(); + return false; + } + + m_version = VxWorksVersion5; + m_logger->LogDebug("Found %d VxWorks 5 symbol table entries", m_symbolTable5.size()); + return true; +} + + +bool VxWorksView::ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader *reader) +{ + // TODO scan for VxWorks 6 symbol table + return ScanForVxWorks5SymbolTable(parentView, reader); +} + + +#define MAX_SYMBOL_NAME_LENGTH 128 +void VxWorksView::ProcessSymbolTable(BinaryReader *reader) +{ + std::set textSymbolAddresses; + std::set dataSymbolAddresses; + std::set roDataSymbolAddresses; + std::set externSymbolAddresses; + + switch (m_version) + { + case VxWorksVersion5: + { + for (const auto& entry : m_symbolTable5) + { + reader->Seek(entry.name - m_imageBase); + string symbolName = reader->ReadCString(MAX_SYMBOL_NAME_LENGTH); + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); + if (it == VxWorks5SymbolTypeMap.end()) + { + m_logger->LogError("Unknown VxWorks 5 symbol type: 0x%02x (%s)", type, symbolName.c_str()); + continue; + } + + auto symbolType = it->second; + switch (symbolType) + { + case FunctionSymbol: + textSymbolAddresses.insert(entry.address); + break; + case DataSymbol: + if (type == VxWorks5GlobalAbsoluteSymbolType) + roDataSymbolAddresses.insert(entry.address); + else + dataSymbolAddresses.insert(entry.address); + break; + case ExternalSymbol: + externSymbolAddresses.insert(entry.address); + break; + default: + break; + } + + DefineAutoSymbol(new Symbol(symbolType, symbolName, entry.address)); + if (symbolName == "usrRoot") + m_usrRoot = entry.address; + } + + break; + } + case VxWorksVersion6: + { + m_logger->LogError("VxWorks 6 symbol table not implemented yet"); + break; + } + case VxWorksUnknownVersion: + default: + // Shouldn't get here - we set the VxWorks version when we find the symbol table + m_logger->LogError( + "VxWorks version is unknown, cannot apply symbols." + "Please report this issue." + ); + return; + } + + if (textSymbolAddresses.size() > 1) + { + m_sections.push_back({ + { *textSymbolAddresses.begin(), *textSymbolAddresses.rbegin() }, + ".text", + ReadOnlyCodeSectionSemantics + }); + } + + if (dataSymbolAddresses.size() > 1) + { + m_sections.push_back({ + { *dataSymbolAddresses.begin(), *dataSymbolAddresses.rbegin() }, + ".data", + ReadWriteDataSectionSemantics + }); + } + + if (externSymbolAddresses.size() > 1) + { + m_sections.push_back({ + { *externSymbolAddresses.begin(), *externSymbolAddresses.rbegin() }, + ".extern", + ExternalSectionSemantics + }); + } + + if (roDataSymbolAddresses.size() > 1) + { + m_sections.push_back({ + { *roDataSymbolAddresses.begin(), *roDataSymbolAddresses.rbegin() }, + ".rodata", + ReadOnlyDataSectionSemantics + }); + } +} + + +void VxWorksView::AddSections(BinaryView *parentView) +{ + if (m_sections.empty()) + { + m_logger->LogDebug("No sections found, creating default section"); + AddAutoSection(".text", m_imageBase, parentView->GetLength(), ReadOnlyCodeSectionSemantics); + return; + } + + // Sort section information by start address (last first) + std::sort(m_sections.begin(), m_sections.end(), [](const VxWorksSectionInfo& a, const VxWorksSectionInfo& b) + { + return a.AddressRange.first > b.AddressRange.first; + }); + + uint64_t lastStart = 0; + bool lastSection = true; + for (const auto& section : m_sections) + { + uint64_t end = lastStart ? lastStart : section.AddressRange.second; + if (lastSection) + { + end = m_imageBase + parentView->GetLength(); + lastSection = false; + } + + m_logger->LogDebug("Creating section %s at 0x%016x-0x%016x", section.Name.c_str(), + section.AddressRange.first, end); + AddAutoSection(section.Name, section.AddressRange.first, end-section.AddressRange.first, section.Semantics); + lastStart = section.AddressRange.first; + } +} + + +void VxWorksView::DetermineEntryPoint() +{ + m_entryPoint = m_imageBase; + if (m_usrRoot) + { + // If we found the usrRoot function in the symbol table, use it + m_entryPoint = m_usrRoot; + return; + } + + for (const auto& section : m_sections) + { + // No symbol table, set the entry point to the start of .text, likely the _sysInit function + if (section.Name == ".text") + m_entryPoint = section.AddressRange.first; + } +} + + +bool VxWorksView::Init() +{ + try + { + auto parentView = GetParentView(); + if (!parentView) + { + m_logger->LogError("Failed to get parent view"); + return false; + } + + // TODO: identify the platform dynamically + auto platform = Platform::GetByName("ppc"); + if (!platform) + { + m_logger->LogError("Failed to get platform"); + return false; + } + + m_arch = platform->GetArchitecture(); + SetDefaultPlatform(platform); + SetDefaultArchitecture(m_arch); + + BinaryReader reader(parentView, m_endianness); + if (!DetermineImageBase(&reader)) + return false; + + AddAutoSegment(m_imageBase, parentView->GetLength(), 0, parentView->GetLength(), + SegmentReadable | SegmentWritable | SegmentExecutable); + + if (m_parseOnly) + return true; + + if (ScanForVxWorksSymbolTable(parentView, &reader)) + ProcessSymbolTable(&reader); + else + m_logger->LogWarn("Could not find VxWorks symbol table"); + + AddSections(parentView); + DetermineEntryPoint(); + AddEntryPointForAnalysis(platform, m_entryPoint); + return true; + } + catch (std::exception& e) + { + m_logger->LogError("Failed to load VxWorks image: %s", e.what()); + return false; + } + + return true; +} + + +uint64_t VxWorksView::PerformGetEntryPoint() const +{ + return m_entryPoint; +} + + +size_t VxWorksView::PerformGetAddressSize() const +{ + return m_arch->GetAddressSize(); +} + + +VxWorksViewType::VxWorksViewType(): BinaryViewType("VxWorks", "VxWorks") +{ + m_logger = LogRegistry::CreateLogger("BinaryView"); +} + + +Ref VxWorksViewType::Create(BinaryView* data) +{ + try + { + return new VxWorksView(data); + } + catch (std::exception& e) + { + m_logger->LogError("%s failed to create view! '%s'", GetName().c_str(), e.what()); + return nullptr; + } +} + + +Ref VxWorksViewType::Parse(BinaryView* data) +{ + try + { + return new VxWorksView(data, true); + } + catch (std::exception& e) + { + m_logger->LogError("%s failed to parse view! '%s'", GetName().c_str(), e.what()); + return nullptr; + } +} + + +bool VxWorksViewType::IsTypeValidForData(BinaryView* data) +{ + BinaryReader reader(data, BigEndian); + VxWorksImageType imageType = IdentifyVxWorksImageType(&reader); + switch (imageType) + { + case VxWorksStandardImageType: + m_logger->LogDebug("VxWorks standard image type detected"); + break; + case VxWorksCDMPackagedImageType: + m_logger->LogDebug("VxWorks packaged CDM image type detected"); + break; + case VxWorksCDMNewImageType: + m_logger->LogDebug("VxWorks new CDM image type detected"); + break; + case VxWorksUnsupportedImageType: + break; + default: + break; + } + + return imageType != VxWorksUnsupportedImageType; +} + + +Ref VxWorksViewType::GetLoadSettingsForData(BinaryView *data) +{ + Ref viewRef = Parse(data); + if (!viewRef || !viewRef->Init()) + { + m_logger->LogError("View type '%s' could not be created", GetName().c_str()); + return nullptr; + } + + // specify default load settings that can be overridden + Ref settings = GetDefaultLoadSettingsForData(viewRef); + vector overrides = {"loader.platform", "loader.imageBase"}; + for (const auto& override : overrides) + { + if (settings->Contains(override)) + settings->UpdateProperty(override, "readOnly", false); + } + + return settings; +} + + +extern "C" +{ + BN_DECLARE_CORE_ABI_VERSION + +#ifdef DEMO_VERSION + bool VxWorksPluginInit() +#else + BINARYNINJAPLUGIN bool CorePluginInit() +#endif + { + InitVxWorksViewType(); + return true; + } +} \ No newline at end of file diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h new file mode 100644 index 0000000000..3c67901cf0 --- /dev/null +++ b/view/vxworks/vxworksview.h @@ -0,0 +1,168 @@ +#pragma once + +#include "binaryninjaapi.h" + +#ifdef WIN32 +#pragma warning(disable: 4005) +#endif + +#define MAX_SYMBOL_TABLE_REGION_SIZE 0x2000000 +#define MIN_VALID_SYMBOL_ENTRIES 200 +#define VXWORKS_SYMBOL_ENTRY_TYPE(flags) ((flags >> 8) & 0xff) + +enum VxWorksVersion +{ + VxWorksUnknownVersion, + VxWorksVersion5, + VxWorksVersion6, +}; + +enum VxWorksImageType +{ + VxWorksUnsupportedImageType, + VxWorksStandardImageType, + VxWorksCDMPackagedImageType, + VxWorksCDMNewImageType, +}; + +enum VxWorks5SymbolType +{ + VxWorks5UndefinedSymbolType = 0x00, + VxWorks5GlobalExternalSymbolType = 0x01, + VxWorks5LocalAbsoluteSymbolType = 0x02, + VxWorks5GlobalAbsoluteSymbolType = 0x03, + VxWorks5LocalTextSymbolType = 0x04, + VxWorks5GlobalTextSymbolType = 0x05, + VxWorks5LocalDataSymbolType = 0x06, + VxWorks5GlobalDataSymbolType = 0x07, + VxWorks5LocalBSSSymbolType = 0x08, + VxWorks5GlobalBSSSymbolType = 0x09, + VxWorks5LocalCommonSymbolType = 0x12, + VxWorks5GlobalCommonSymbolType = 0x13, +}; + +std::map VxWorks5SymbolTypeMap = { + { VxWorks5UndefinedSymbolType, FunctionSymbol }, + { VxWorks5GlobalExternalSymbolType, ImportAddressSymbol }, + { VxWorks5LocalAbsoluteSymbolType, DataSymbol }, + { VxWorks5GlobalAbsoluteSymbolType, DataSymbol }, + { VxWorks5LocalTextSymbolType, FunctionSymbol }, + { VxWorks5GlobalTextSymbolType, FunctionSymbol }, + { VxWorks5LocalDataSymbolType, DataSymbol }, + { VxWorks5GlobalDataSymbolType, DataSymbol }, + { VxWorks5LocalBSSSymbolType, DataSymbol }, + { VxWorks5GlobalBSSSymbolType, DataSymbol }, + { VxWorks5LocalCommonSymbolType, DataSymbol }, + { VxWorks5GlobalCommonSymbolType, DataSymbol }, +}; + +enum VxWorks6SymbolType +{ + VxWorks6UndefinedSymbolType = 0x00, + VxWorks6GlobalExternalSymbolType = 0x01, + VxWorks6LocalAbsoluteSymbolType = 0x02, + VxWorks6GlobalAbsoluteSymbolType = 0x03, + VxWorks6LocalTextSymbolType = 0x04, + VxWorks6GlobalTextSymbolType = 0x05, + VxWorks6LocalDataSymbolType = 0x08, + VxWorks6GlobalDataSymbolType = 0x09, + VxWorks6LocalBSSSymbolType = 0x10, + VxWorks6GlobalBSSSymbolType = 0x11, + VxWorks6LocalCommonSymbolType = 0x20, + VxWorks6GlobalCommonSymbolType = 0x21, +}; + +std::map VxWorks6SymbolTypeMap = { + { VxWorks6UndefinedSymbolType, FunctionSymbol }, + { VxWorks6GlobalExternalSymbolType, ImportAddressSymbol }, + { VxWorks6LocalAbsoluteSymbolType, DataSymbol }, + { VxWorks6GlobalAbsoluteSymbolType, DataSymbol }, + { VxWorks6LocalTextSymbolType, FunctionSymbol }, + { VxWorks6GlobalTextSymbolType, FunctionSymbol }, + { VxWorks6LocalDataSymbolType, DataSymbol }, + { VxWorks6GlobalDataSymbolType, DataSymbol }, + { VxWorks6LocalBSSSymbolType, DataSymbol }, + { VxWorks6GlobalBSSSymbolType, DataSymbol }, + { VxWorks6LocalCommonSymbolType, DataSymbol }, + { VxWorks6GlobalCommonSymbolType, DataSymbol }, +}; + +struct VxWorks5SymbolTableEntry +{ + uint32_t unknown; + uint32_t name; + uint32_t address; + uint32_t flags; +}; + +struct VxWorks6SymbolTableEntry +{ + uint32_t unknown1; + uint32_t name; + uint32_t address; + uint32_t unknown2; + uint32_t flags; +}; + +struct VxWorksSectionInfo +{ + std::pair AddressRange; + std::string Name; + BNSectionSemantics Semantics; +}; + +namespace BinaryNinja +{ + class VxWorksView: public BinaryView + { + Ref m_logger; + bool m_parseOnly; + bool m_relocatable = false; + BNEndianness m_endianness = BigEndian; + Ref m_arch; + uint64_t m_entryPoint = 0; + uint64_t m_imageBase = 0; + uint64_t m_usrRoot = 0; // Entrypoint, if we find it in the symbol table + std::vector m_sections; + + VxWorksVersion m_version = VxWorksUnknownVersion; + std::vector m_symbolTable5; + std::vector m_symbolTable6; + + private: + void DetermineEntryPoint(); + void AddSections(BinaryView* parentView); + void ProcessSymbolTable(BinaryReader *reader); + bool ScanForVxWorks6SymbolTable(BinaryView* parentView, BinaryReader *reader); + bool ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader); + bool ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader *reader); + bool DetermineImageBase(BinaryReader *reader); + + protected: + virtual uint64_t PerformGetEntryPoint() const override; + virtual bool PerformIsExecutable() const override { return true; } + virtual BNEndianness PerformGetDefaultEndianness() const override { return m_endianness; } + virtual bool PerformIsRelocatable() const override { return m_relocatable; } + virtual size_t PerformGetAddressSize() const override; + + public: + VxWorksView(BinaryView* data, bool parseOnly = false); + virtual bool Init() override; + }; // class VxWorksView + + class VxWorksViewType: public BinaryViewType + { + Ref m_logger; + + + public: + VxWorksViewType(); + virtual Ref Create(BinaryView* data) override; + virtual Ref Parse(BinaryView* data) override; + virtual bool IsTypeValidForData(BinaryView* data) override; + virtual Ref GetLoadSettingsForData(BinaryView* data) override; + static enum VxWorksImageType IdentifyImageType(Ref& reader); + }; // class VxWorksViewType + + void InitVxWorksViewType(); +} // namespace BinaryNinja From 229ca4c4212c6ca75ca7de415a4459d5abe13018 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Thu, 20 Jun 2024 12:25:33 -0400 Subject: [PATCH 02/14] Loading little endian VxWorks 5 images Identifying base address and endianess dynamically from the symbol table entries --- view/vxworks/vxworksview.cpp | 660 +++++++++++++++++------------------ view/vxworks/vxworksview.h | 27 +- 2 files changed, 339 insertions(+), 348 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 3c08568f4c..c2c87db94f 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -7,364 +7,347 @@ using namespace std; static VxWorksViewType* g_vxWorksViewType = nullptr; -#define NEW_CDM_SIGNATURE_OFFSET 0x0 -#define NEW_CDM_SIGNATURE_SIZE 0xb -#define PACKAGED_CDM_SIGNATURE_SIZE 0x3 -#define PACKAGED_CDM_SIGNATURE_OFFSET 0x50 -static VxWorksImageType IdentifyVxWorksImageType(BinaryReader* reader) -{ - reader->Seek(0); - uint32_t magic; - if (!reader->TryRead32(magic)) - return VxWorksUnsupportedImageType; - - if (magic == 0x7c6000a6 || magic == 0x7c631a78) - return VxWorksStandardImageType; - - uint8_t newCDMSignature[NEW_CDM_SIGNATURE_SIZE]; - reader->Seek(NEW_CDM_SIGNATURE_OFFSET); - if (!reader->TryRead(newCDMSignature, NEW_CDM_SIGNATURE_SIZE)) - return VxWorksUnsupportedImageType; - if (memcmp(newCDMSignature, "vxWorks.pkg", NEW_CDM_SIGNATURE_SIZE) == 0) - return VxWorksCDMNewImageType; - - uint8_t oldCMSSignature[PACKAGED_CDM_SIGNATURE_SIZE]; - reader->Seek(PACKAGED_CDM_SIGNATURE_OFFSET); - if (!reader->TryRead(oldCMSSignature, PACKAGED_CDM_SIGNATURE_SIZE)) - return VxWorksUnsupportedImageType; - if (memcmp(oldCMSSignature, "CDM", PACKAGED_CDM_SIGNATURE_SIZE) == 0) - return VxWorksCDMPackagedImageType; - - return VxWorksUnsupportedImageType; -} - void BinaryNinja::InitVxWorksViewType() { - static VxWorksViewType type; - BinaryViewType::Register(&type); - g_vxWorksViewType = &type; + static VxWorksViewType type; + BinaryViewType::Register(&type); + g_vxWorksViewType = &type; } VxWorksView::VxWorksView(BinaryView* data, bool parseOnly): BinaryView("VxWorks", data->GetFile(), data), - m_parseOnly(parseOnly) + m_parseOnly(parseOnly) { - CreateLogger("BinaryView"); - m_logger = CreateLogger("BinaryView.VxWorksView"); + CreateLogger("BinaryView"); + m_logger = CreateLogger("BinaryView.VxWorksView"); } -bool VxWorksView::DetermineImageBase(BinaryReader *reader) +#define LOWEST_TEXT_SYMBOL_ADDRESS_START 0xffffffffffffffff +void VxWorksView::DetermineImageBaseFromSymbols() { - VxWorksImageType imageType = IdentifyVxWorksImageType(reader); - switch (imageType) - { - case VxWorksStandardImageType: - { - uint32_t magic; - reader->Seek(0); - if (!reader->TryRead32(magic)) - return 0; - - // TODO: dynamically determine the image base - switch (magic) - { - case 0x7c6000a6: // vx5_ppc_big_endian_0x10000.bin - m_imageBase = 0x10000; - return true; - case 0x7810a0e3: // vx5_arm_little_endian_0x1000.bin - m_imageBase = 0x1000; - case 0x7c631a78: - m_imageBase = 0x400000; - return true; - default: - m_logger->LogError("Unsupported standard VxWorks image magic"); - return false; - } - } - case VxWorksCDMPackagedImageType: - return false; // TODO - not implemented yet - case VxWorksCDMNewImageType: - return false; // TODO - not implemented yet - default: - m_logger->LogError("Unsupported VxWorks image type!?"); - return 0; - } + uint64_t lowestTextAddress = LOWEST_TEXT_SYMBOL_ADDRESS_START; + if (m_version == VxWorksVersion5) + { + for (const auto& entry : m_symbolTable5) + { + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + if (type == VxWorks5GlobalTextSymbolType && entry.address < lowestTextAddress) + lowestTextAddress = entry.address; + } + } + + if (lowestTextAddress == LOWEST_TEXT_SYMBOL_ADDRESS_START) + { + m_logger->LogWarn("Could not determine image base address, using default 0x%08x", DEFAULT_VXWORKS_BASE_ADDRESS); + m_imageBase = DEFAULT_VXWORKS_BASE_ADDRESS; + return; + } + + m_logger->LogDebug("Determined image base address: 0x%016x", lowestTextAddress); + m_imageBase = lowestTextAddress; } bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader) { - uint64_t endDataAddress = m_imageBase + parentView->GetLength(); - VxWorks5SymbolTableEntry entry; - uint64_t startOffset = parentView->GetLength() - sizeof(entry); - uint64_t endOffset = 0; - if (parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) - endOffset = parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; - uint64_t searchPos = startOffset; - - m_logger->LogDebug("Scanning backwards for VxWorks 5 symbol table (0x%016x-0x%016x)...", - m_imageBase + startOffset, m_imageBase + endOffset); - while (searchPos > endOffset) - { - reader->Seek(searchPos + 4); // Skip the unknown field - if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address) || !reader->TryRead32(entry.flags)) - break; - - if ((entry.name >= m_imageBase && entry.name < endDataAddress) && - (entry.address >= m_imageBase && entry.address < endDataAddress)) - { - // Name and symbol address pointers are within file - m_symbolTable5.push_back(entry); - searchPos -= sizeof(entry); - continue; - } - - if (m_symbolTable5.size() > MIN_VALID_SYMBOL_ENTRIES) - break; - - searchPos -= 4; - m_symbolTable5.clear(); - } - - if (m_symbolTable5.size() < MIN_VALID_SYMBOL_ENTRIES) - { - m_symbolTable5.clear(); - return false; - } - - m_version = VxWorksVersion5; - m_logger->LogDebug("Found %d VxWorks 5 symbol table entries", m_symbolTable5.size()); - return true; + VxWorks5SymbolTableEntry entry; + uint64_t startOffset = parentView->GetLength() - sizeof(entry); + uint64_t endOffset = 0; + if (parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) + endOffset = parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; + uint64_t searchPos = startOffset; + + m_logger->LogDebug("Scanning backwards for VxWorks 5 symbol table (0x%016x-0x%016x) (endianess=%s)...", + startOffset, endOffset, m_endianness == BigEndian ? "big" : "little"); + uint64_t lastNameAddress = 0; + while (searchPos > endOffset) + { + reader->Seek(searchPos + 4); // Skip the unknown field + if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address) || !reader->TryReadBE32(entry.flags)) + break; + + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); + if (entry.name >= lastNameAddress && entry.address != 0 && it != VxWorks5SymbolTypeMap.end()) + { + // Name address is greater than the last name address and flags has a valid symbol type + lastNameAddress = entry.name; + m_symbolTable5.push_back(entry); + searchPos -= sizeof(entry); + continue; + } + + if (m_symbolTable5.size() > MIN_VALID_SYMBOL_ENTRIES) + break; + + searchPos -= 4; + lastNameAddress = 0; + m_symbolTable5.clear(); + } + + if (m_symbolTable5.size() < MIN_VALID_SYMBOL_ENTRIES) + { + m_symbolTable5.clear(); + return false; + } + + m_version = VxWorksVersion5; + m_logger->LogDebug("Found %d VxWorks 5 symbol table entries", m_symbolTable5.size()); + return true; } bool VxWorksView::ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader *reader) { - // TODO scan for VxWorks 6 symbol table - return ScanForVxWorks5SymbolTable(parentView, reader); + if (ScanForVxWorks5SymbolTable(parentView, reader)) + return true; + + m_endianness = LittleEndian; + reader->SetEndianness(m_endianness); + if (ScanForVxWorks5SymbolTable(parentView, reader)) + return true; + + // TODO scan for VxWorks 6 symbol table + return false; } #define MAX_SYMBOL_NAME_LENGTH 128 void VxWorksView::ProcessSymbolTable(BinaryReader *reader) { - std::set textSymbolAddresses; - std::set dataSymbolAddresses; - std::set roDataSymbolAddresses; - std::set externSymbolAddresses; - - switch (m_version) - { - case VxWorksVersion5: - { - for (const auto& entry : m_symbolTable5) - { - reader->Seek(entry.name - m_imageBase); - string symbolName = reader->ReadCString(MAX_SYMBOL_NAME_LENGTH); - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); - if (it == VxWorks5SymbolTypeMap.end()) - { - m_logger->LogError("Unknown VxWorks 5 symbol type: 0x%02x (%s)", type, symbolName.c_str()); - continue; - } - - auto symbolType = it->second; - switch (symbolType) - { - case FunctionSymbol: - textSymbolAddresses.insert(entry.address); - break; - case DataSymbol: - if (type == VxWorks5GlobalAbsoluteSymbolType) - roDataSymbolAddresses.insert(entry.address); - else - dataSymbolAddresses.insert(entry.address); - break; - case ExternalSymbol: - externSymbolAddresses.insert(entry.address); - break; - default: - break; - } - - DefineAutoSymbol(new Symbol(symbolType, symbolName, entry.address)); - if (symbolName == "usrRoot") - m_usrRoot = entry.address; - } - - break; - } - case VxWorksVersion6: - { - m_logger->LogError("VxWorks 6 symbol table not implemented yet"); - break; - } - case VxWorksUnknownVersion: - default: - // Shouldn't get here - we set the VxWorks version when we find the symbol table - m_logger->LogError( - "VxWorks version is unknown, cannot apply symbols." - "Please report this issue." - ); - return; - } - - if (textSymbolAddresses.size() > 1) - { - m_sections.push_back({ - { *textSymbolAddresses.begin(), *textSymbolAddresses.rbegin() }, - ".text", - ReadOnlyCodeSectionSemantics - }); - } - - if (dataSymbolAddresses.size() > 1) - { - m_sections.push_back({ - { *dataSymbolAddresses.begin(), *dataSymbolAddresses.rbegin() }, - ".data", - ReadWriteDataSectionSemantics - }); - } - - if (externSymbolAddresses.size() > 1) - { - m_sections.push_back({ - { *externSymbolAddresses.begin(), *externSymbolAddresses.rbegin() }, - ".extern", - ExternalSectionSemantics - }); - } - - if (roDataSymbolAddresses.size() > 1) - { - m_sections.push_back({ - { *roDataSymbolAddresses.begin(), *roDataSymbolAddresses.rbegin() }, - ".rodata", - ReadOnlyDataSectionSemantics - }); - } + std::set textSymbolAddresses; + std::set dataSymbolAddresses; + std::set roDataSymbolAddresses; + std::set externSymbolAddresses; + + switch (m_version) + { + case VxWorksVersion5: + { + for (const auto& entry : m_symbolTable5) + { + reader->Seek(entry.name - m_imageBase); + string symbolName = reader->ReadCString(MAX_SYMBOL_NAME_LENGTH); + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); + if (it == VxWorks5SymbolTypeMap.end()) + { + m_logger->LogError("Unknown VxWorks 5 symbol type: 0x%02x (%s)", type, symbolName.c_str()); + continue; + } + + auto symbolType = it->second; + switch (symbolType) + { + case FunctionSymbol: + textSymbolAddresses.insert(entry.address); + AddFunctionForAnalysis(m_platform, entry.address); + break; + case DataSymbol: + if (type == VxWorks5GlobalAbsoluteSymbolType) + roDataSymbolAddresses.insert(entry.address); + else + dataSymbolAddresses.insert(entry.address); + break; + case ExternalSymbol: + externSymbolAddresses.insert(entry.address); + break; + default: + break; + } + + DefineAutoSymbol(new Symbol(symbolType, symbolName, entry.address)); + if (symbolName == "sysInit") + m_sysInit = entry.address; + } + + break; + } + case VxWorksVersion6: + { + m_logger->LogError("VxWorks 6 symbol table not implemented yet"); + break; + } + case VxWorksUnknownVersion: + default: + // Shouldn't get here - we set the VxWorks version when we find the symbol table + m_logger->LogError( + "VxWorks version is unknown, cannot apply symbols." + "Please report this issue." + ); + return; + } + + if (textSymbolAddresses.size() > 1) + { + m_sections.push_back({ + { *textSymbolAddresses.begin(), *textSymbolAddresses.rbegin() }, + ".text", + ReadOnlyCodeSectionSemantics + }); + } + + if (dataSymbolAddresses.size() > 1) + { + m_sections.push_back({ + { *dataSymbolAddresses.begin(), *dataSymbolAddresses.rbegin() }, + ".data", + ReadWriteDataSectionSemantics + }); + } + + if (externSymbolAddresses.size() > 1) + { + m_sections.push_back({ + { *externSymbolAddresses.begin(), *externSymbolAddresses.rbegin() }, + ".extern", + ExternalSectionSemantics + }); + } + + if (roDataSymbolAddresses.size() > 1) + { + m_sections.push_back({ + { *roDataSymbolAddresses.begin(), *roDataSymbolAddresses.rbegin() }, + ".rodata", + ReadOnlyDataSectionSemantics + }); + } } void VxWorksView::AddSections(BinaryView *parentView) { - if (m_sections.empty()) - { - m_logger->LogDebug("No sections found, creating default section"); - AddAutoSection(".text", m_imageBase, parentView->GetLength(), ReadOnlyCodeSectionSemantics); - return; - } - - // Sort section information by start address (last first) - std::sort(m_sections.begin(), m_sections.end(), [](const VxWorksSectionInfo& a, const VxWorksSectionInfo& b) - { - return a.AddressRange.first > b.AddressRange.first; - }); - - uint64_t lastStart = 0; - bool lastSection = true; - for (const auto& section : m_sections) - { - uint64_t end = lastStart ? lastStart : section.AddressRange.second; - if (lastSection) - { - end = m_imageBase + parentView->GetLength(); - lastSection = false; - } - - m_logger->LogDebug("Creating section %s at 0x%016x-0x%016x", section.Name.c_str(), - section.AddressRange.first, end); - AddAutoSection(section.Name, section.AddressRange.first, end-section.AddressRange.first, section.Semantics); - lastStart = section.AddressRange.first; - } + if (m_sections.empty()) + { + m_logger->LogDebug("No sections found, creating default section"); + AddAutoSection(".text", m_imageBase, parentView->GetLength(), ReadOnlyCodeSectionSemantics); + return; + } + + // Sort section information by start address (section w/ highest start address first) + std::sort(m_sections.begin(), m_sections.end(), [](const VxWorksSectionInfo& a, const VxWorksSectionInfo& b) + { + return a.AddressRange.first > b.AddressRange.first; + }); + + uint64_t lastStart = 0; + bool lastSection = true; + for (const auto& section : m_sections) + { + uint64_t end = lastStart ? lastStart : section.AddressRange.second; + if (lastSection) + { + end = m_imageBase + parentView->GetLength(); + lastSection = false; + } + + m_logger->LogDebug("Creating section %s at 0x%016x-0x%016x", section.Name.c_str(), + section.AddressRange.first, end); + AddAutoSection(section.Name, section.AddressRange.first, end-section.AddressRange.first, section.Semantics); + lastStart = section.AddressRange.first; + } } void VxWorksView::DetermineEntryPoint() { - m_entryPoint = m_imageBase; - if (m_usrRoot) - { - // If we found the usrRoot function in the symbol table, use it - m_entryPoint = m_usrRoot; - return; - } - - for (const auto& section : m_sections) - { - // No symbol table, set the entry point to the start of .text, likely the _sysInit function - if (section.Name == ".text") - m_entryPoint = section.AddressRange.first; - } + m_entryPoint = m_imageBase; + if (m_sysInit) + { + // If we found the sysInit function in the symbol table, use it + m_entryPoint = m_sysInit; + return; + } + + for (const auto& section : m_sections) + { + // No symbol table, set the entry point to the start of .text, likely the sysInit function + if (section.Name == ".text") + m_entryPoint = section.AddressRange.first; + } } bool VxWorksView::Init() { - try - { - auto parentView = GetParentView(); - if (!parentView) - { - m_logger->LogError("Failed to get parent view"); - return false; - } - - // TODO: identify the platform dynamically - auto platform = Platform::GetByName("ppc"); - if (!platform) - { - m_logger->LogError("Failed to get platform"); - return false; - } - - m_arch = platform->GetArchitecture(); - SetDefaultPlatform(platform); - SetDefaultArchitecture(m_arch); - - BinaryReader reader(parentView, m_endianness); - if (!DetermineImageBase(&reader)) - return false; - - AddAutoSegment(m_imageBase, parentView->GetLength(), 0, parentView->GetLength(), - SegmentReadable | SegmentWritable | SegmentExecutable); - - if (m_parseOnly) - return true; - - if (ScanForVxWorksSymbolTable(parentView, &reader)) - ProcessSymbolTable(&reader); - else - m_logger->LogWarn("Could not find VxWorks symbol table"); - - AddSections(parentView); - DetermineEntryPoint(); - AddEntryPointForAnalysis(platform, m_entryPoint); - return true; - } - catch (std::exception& e) - { - m_logger->LogError("Failed to load VxWorks image: %s", e.what()); - return false; - } - - return true; + try + { + auto parentView = GetParentView(); + if (!parentView) + { + m_logger->LogError("Failed to get parent view"); + return false; + } + + BinaryReader reader(parentView, m_endianness); + bool isSymTable = ScanForVxWorksSymbolTable(parentView, &reader); + if (isSymTable) + { + DetermineImageBaseFromSymbols(); + m_entryPoint = m_imageBase; // This will get updated later if the sysInit symbol is found + } + else + { + m_logger->LogWarn("Could not find VxWorks symbol table"); + m_imageBase = DEFAULT_VXWORKS_BASE_ADDRESS; + } + + AddAutoSegment(m_imageBase, parentView->GetLength(), 0, parentView->GetLength(), + SegmentReadable | SegmentWritable | SegmentExecutable); + + auto settings = GetLoadSettings(GetTypeName()); + if (!settings || settings->IsEmpty()) + { + m_endianness = BinaryView::GetDefaultEndianness(); + m_addressSize = BinaryView::GetAddressSize(); + return true; + } + + auto platformName = settings->Get("loader.platform"); + m_platform = Platform::GetByName(platformName); + if (!m_platform) + { + m_logger->LogError("Failed to get platform"); + return false; + } + + m_arch = m_platform->GetArchitecture(); + m_addressSize = m_arch->GetAddressSize(); + SetDefaultPlatform(m_platform); + SetDefaultArchitecture(m_arch); + + if (m_parseOnly) + return true; + + if (isSymTable) + ProcessSymbolTable(&reader); + AddSections(parentView); + DetermineEntryPoint(); + AddEntryPointForAnalysis(m_platform, m_entryPoint); + return true; + } + catch (std::exception& e) + { + m_logger->LogError("Failed to load VxWorks image: %s", e.what()); + return false; + } + + return true; } uint64_t VxWorksView::PerformGetEntryPoint() const { - return m_entryPoint; + return m_entryPoint; } size_t VxWorksView::PerformGetAddressSize() const { - return m_arch->GetAddressSize(); + return m_addressSize; } @@ -390,40 +373,42 @@ Ref VxWorksViewType::Create(BinaryView* data) Ref VxWorksViewType::Parse(BinaryView* data) { - try - { - return new VxWorksView(data, true); - } - catch (std::exception& e) - { - m_logger->LogError("%s failed to parse view! '%s'", GetName().c_str(), e.what()); - return nullptr; - } + try + { + return new VxWorksView(data, true); + } + catch (std::exception& e) + { + m_logger->LogError("%s failed to parse view! '%s'", GetName().c_str(), e.what()); + return nullptr; + } } bool VxWorksViewType::IsTypeValidForData(BinaryView* data) { - BinaryReader reader(data, BigEndian); - VxWorksImageType imageType = IdentifyVxWorksImageType(&reader); - switch (imageType) - { - case VxWorksStandardImageType: - m_logger->LogDebug("VxWorks standard image type detected"); - break; - case VxWorksCDMPackagedImageType: - m_logger->LogDebug("VxWorks packaged CDM image type detected"); - break; - case VxWorksCDMNewImageType: - m_logger->LogDebug("VxWorks new CDM image type detected"); - break; - case VxWorksUnsupportedImageType: - break; - default: - break; - } - - return imageType != VxWorksUnsupportedImageType; + std::stringstream ss; + ss << "{" + "\"pattern\":\"VxWorks\"," + "\"start\":0," + "\"end\":" << data->GetLength()-1 << "," + "\"raw\":false," + "\"ignoreCase\":false," + "\"overlap\":false," + "\"align\":1" + "}"; + + bool isValid = false;; + auto StringSearchCallback = [&isValid](size_t index, const DataBuffer& dataBuffer) -> bool + { + isValid = true; + return true; + }; + + if (!data->Search(string(ss.str()), StringSearchCallback)) + m_logger->LogWarn("Error while searching for VxWorks signatures in raw view"); + + return isValid; } @@ -438,13 +423,16 @@ Ref VxWorksViewType::GetLoadSettingsForData(BinaryView *data) // specify default load settings that can be overridden Ref settings = GetDefaultLoadSettingsForData(viewRef); - vector overrides = {"loader.platform", "loader.imageBase"}; + vector overrides = {"loader.platform", "loader.imageBase", "loader.entryPointOffset"}; for (const auto& override : overrides) { if (settings->Contains(override)) settings->UpdateProperty(override, "readOnly", false); } + if (settings->Contains("loader.entryPointOffset")) + settings->UpdateProperty("loader.entryPointOffset", "default", viewRef->GetEntryPoint()); + return settings; } @@ -454,7 +442,7 @@ extern "C" BN_DECLARE_CORE_ABI_VERSION #ifdef DEMO_VERSION - bool VxWorksPluginInit() + bool VxWorksPluginInit() #else BINARYNINJAPLUGIN bool CorePluginInit() #endif diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index 3c67901cf0..f88cfddd24 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -6,8 +6,9 @@ #pragma warning(disable: 4005) #endif +#define DEFAULT_VXWORKS_BASE_ADDRESS 0x10000 #define MAX_SYMBOL_TABLE_REGION_SIZE 0x2000000 -#define MIN_VALID_SYMBOL_ENTRIES 200 +#define MIN_VALID_SYMBOL_ENTRIES 256 #define VXWORKS_SYMBOL_ENTRY_TYPE(flags) ((flags >> 8) & 0xff) enum VxWorksVersion @@ -19,10 +20,10 @@ enum VxWorksVersion enum VxWorksImageType { - VxWorksUnsupportedImageType, - VxWorksStandardImageType, - VxWorksCDMPackagedImageType, - VxWorksCDMNewImageType, + VxWorksUnsupportedImageType, + VxWorksStandardImageType, + VxWorksCDMPackagedImageType, + VxWorksCDMNewImageType, }; enum VxWorks5SymbolType @@ -113,16 +114,18 @@ struct VxWorksSectionInfo namespace BinaryNinja { - class VxWorksView: public BinaryView - { + class VxWorksView: public BinaryView + { Ref m_logger; bool m_parseOnly; bool m_relocatable = false; - BNEndianness m_endianness = BigEndian; + BNEndianness m_endianness = BigEndian; + Ref m_platform; Ref m_arch; + size_t m_addressSize; uint64_t m_entryPoint = 0; uint64_t m_imageBase = 0; - uint64_t m_usrRoot = 0; // Entrypoint, if we find it in the symbol table + uint64_t m_sysInit = 0; // Entrypoint, if we find it in the symbol table std::vector m_sections; VxWorksVersion m_version = VxWorksUnknownVersion; @@ -136,7 +139,7 @@ namespace BinaryNinja bool ScanForVxWorks6SymbolTable(BinaryView* parentView, BinaryReader *reader); bool ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader); bool ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader *reader); - bool DetermineImageBase(BinaryReader *reader); + void DetermineImageBaseFromSymbols(); protected: virtual uint64_t PerformGetEntryPoint() const override; @@ -148,7 +151,7 @@ namespace BinaryNinja public: VxWorksView(BinaryView* data, bool parseOnly = false); virtual bool Init() override; - }; // class VxWorksView + }; // class VxWorksView class VxWorksViewType: public BinaryViewType { @@ -161,7 +164,7 @@ namespace BinaryNinja virtual Ref Parse(BinaryView* data) override; virtual bool IsTypeValidForData(BinaryView* data) override; virtual Ref GetLoadSettingsForData(BinaryView* data) override; - static enum VxWorksImageType IdentifyImageType(Ref& reader); + static enum VxWorksImageType IdentifyImageType(Ref& reader); }; // class VxWorksViewType void InitVxWorksViewType(); From bdedfea8336f6e9531a5b0a3c87cb673568f7a15 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Thu, 20 Jun 2024 16:17:36 -0400 Subject: [PATCH 03/14] Loading little endian VxWorks 6 images --- view/vxworks/vxworksview.cpp | 107 ++++++++++++++++++++++++++++++++++- view/vxworks/vxworksview.h | 4 ++ 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index c2c87db94f..85936b4bcd 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -38,6 +38,16 @@ void VxWorksView::DetermineImageBaseFromSymbols() } } + if (m_version == VxWorksVersion6) + { + for (const auto& entry : m_symbolTable6) + { + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + if (type == VxWorks6GlobalTextSymbolType && entry.address < lowestTextAddress) + lowestTextAddress = entry.address; + } + } + if (lowestTextAddress == LOWEST_TEXT_SYMBOL_ADDRESS_START) { m_logger->LogWarn("Could not determine image base address, using default 0x%08x", DEFAULT_VXWORKS_BASE_ADDRESS); @@ -50,6 +60,59 @@ void VxWorksView::DetermineImageBaseFromSymbols() } +bool VxWorksView::ScanForVxWorks6SymbolTable(BinaryView *parentView, BinaryReader *reader) +{ + VxWorks6SymbolTableEntry entry; + uint64_t startOffset = parentView->GetLength() - sizeof(entry); + uint64_t endOffset = 0; + if (parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) + endOffset = parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; + uint64_t searchPos = startOffset; + + m_logger->LogDebug("Scanning backwards for VxWorks 6 symbol table (0x%016x-0x%016x) (endianess=%s)...", + startOffset, endOffset, m_endianness == BigEndian ? "big" : "little"); + while (searchPos > endOffset) + { + reader->Seek(searchPos + 4); // Skip the first unknown field + if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address)) + break; + + reader->Seek(searchPos + 16); // Skip the second unknown field + if (!reader->TryReadBE32(entry.flags)) + break; + + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + auto it = VxWorks6SymbolTypeMap.find((VxWorks6SymbolType)type); + if (entry.name != 0 && + entry.address != 0 && + entry.name && it != VxWorks6SymbolTypeMap.end()) + { + // Name address is greater than the last name address and flags has a valid symbol type + m_logger->LogDebug("flags: %08x address: %08x name: %08x type: %02x", entry.flags, entry.address, entry.name, type); + m_symbolTable6.push_back(entry); + searchPos -= sizeof(entry); + continue; + } + + if (m_symbolTable6.size() > MIN_VALID_SYMBOL_ENTRIES) + break; + + searchPos -= 4; + m_symbolTable6.clear(); + } + + if (m_symbolTable6.size() < MIN_VALID_SYMBOL_ENTRIES) + { + m_symbolTable6.clear(); + return false; + } + + m_version = VxWorksVersion6; + m_logger->LogDebug("Found %d VxWorks 6 symbol table entries", m_symbolTable6.size()); + return true; +} + + bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader) { VxWorks5SymbolTableEntry entry; @@ -109,8 +172,11 @@ bool VxWorksView::ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader if (ScanForVxWorks5SymbolTable(parentView, reader)) return true; - // TODO scan for VxWorks 6 symbol table - return false; + if (ScanForVxWorks6SymbolTable(parentView, reader)) + return true; + m_endianness = BigEndian; + reader->SetEndianness(m_endianness); + return ScanForVxWorks6SymbolTable(parentView, reader); } @@ -167,7 +233,42 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) } case VxWorksVersion6: { - m_logger->LogError("VxWorks 6 symbol table not implemented yet"); + for (const auto& entry : m_symbolTable6) + { + reader->Seek(entry.name - m_imageBase); + string symbolName = reader->ReadCString(MAX_SYMBOL_NAME_LENGTH); + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + auto it = VxWorks6SymbolTypeMap.find((VxWorks6SymbolType)type); + if (it == VxWorks6SymbolTypeMap.end()) + { + m_logger->LogError("Unknown VxWorks 6 symbol type: 0x%02x (%s)", type, symbolName.c_str()); + continue; + } + + auto symbolType = it->second; + switch (symbolType) + { + case FunctionSymbol: + textSymbolAddresses.insert(entry.address); + AddFunctionForAnalysis(m_platform, entry.address); + break; + case DataSymbol: + if (type == VxWorks6GlobalAbsoluteSymbolType) + roDataSymbolAddresses.insert(entry.address); + else + dataSymbolAddresses.insert(entry.address); + break; + case ExternalSymbol: + externSymbolAddresses.insert(entry.address); + break; + default: + break; + } + + DefineAutoSymbol(new Symbol(symbolType, symbolName, entry.address)); + if (symbolName == "sysInit") + m_sysInit = entry.address; + } break; } case VxWorksUnknownVersion: diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index f88cfddd24..14719e7c18 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -71,6 +71,8 @@ enum VxWorks6SymbolType VxWorks6GlobalBSSSymbolType = 0x11, VxWorks6LocalCommonSymbolType = 0x20, VxWorks6GlobalCommonSymbolType = 0x21, + VxWorks6LocalSymbols = 0x40, + VxWorks6GlobalSymboks = 0x41, }; std::map VxWorks6SymbolTypeMap = { @@ -86,6 +88,8 @@ std::map VxWorks6SymbolTypeMap = { { VxWorks6GlobalBSSSymbolType, DataSymbol }, { VxWorks6LocalCommonSymbolType, DataSymbol }, { VxWorks6GlobalCommonSymbolType, DataSymbol }, + { VxWorks6LocalSymbols, DataSymbol }, + { VxWorks6GlobalSymboks, DataSymbol }, }; struct VxWorks5SymbolTableEntry From dffafbe914595f4fc7ea49410540d168431b3aaa Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Fri, 21 Jun 2024 15:34:54 -0400 Subject: [PATCH 04/14] VxWorks check on func symbol addresses --- view/vxworks/vxworksview.cpp | 62 +++++++++++++++++++++++++++++++----- view/vxworks/vxworksview.h | 19 ++++++++--- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 85936b4bcd..3110a5d9fe 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -59,6 +59,54 @@ void VxWorksView::DetermineImageBaseFromSymbols() m_imageBase = lowestTextAddress; } +#define MAX_ADDRESSES_ENDIANNESS_CHECK 10 +// Check least significant byte of the first 10 function symbol addresses to make sure they aren't all the same +bool VxWorksView::FunctionAddressesAreValid(VxWorksVersion version) +{ + size_t count = 0; + std::vector funcAddresses; + if (version == VxWorksVersion5) + { + for (const auto& entry : m_symbolTable5) + { + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + if (type == VxWorks5GlobalTextSymbolType) + { + funcAddresses.push_back(entry.address); + count++; + } + + if (count == MAX_ADDRESSES_ENDIANNESS_CHECK) + break; + } + } + + if (version == VxWorksVersion6) + { + m_logger->LogDebug("Checking VxWorks 6 function symbol addresses"); + for (const auto& entry : m_symbolTable6) + { + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + if (type == VxWorks6GlobalTextSymbolType) + { + funcAddresses.push_back(entry.address); + count++; + } + + if (count == MAX_ADDRESSES_ENDIANNESS_CHECK) + break; + } + } + + if (funcAddresses.size() < MAX_ADDRESSES_ENDIANNESS_CHECK) + return false; + + uint32_t val = 0; + for (const auto& addr : funcAddresses) + val ^= addr; + return (val & 0xff) != 0; +} + bool VxWorksView::ScanForVxWorks6SymbolTable(BinaryView *parentView, BinaryReader *reader) { @@ -87,14 +135,12 @@ bool VxWorksView::ScanForVxWorks6SymbolTable(BinaryView *parentView, BinaryReade entry.address != 0 && entry.name && it != VxWorks6SymbolTypeMap.end()) { - // Name address is greater than the last name address and flags has a valid symbol type - m_logger->LogDebug("flags: %08x address: %08x name: %08x type: %02x", entry.flags, entry.address, entry.name, type); m_symbolTable6.push_back(entry); searchPos -= sizeof(entry); continue; } - if (m_symbolTable6.size() > MIN_VALID_SYMBOL_ENTRIES) + if (m_symbolTable6.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(VxWorksVersion6)) break; searchPos -= 4; @@ -124,7 +170,6 @@ bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReade m_logger->LogDebug("Scanning backwards for VxWorks 5 symbol table (0x%016x-0x%016x) (endianess=%s)...", startOffset, endOffset, m_endianness == BigEndian ? "big" : "little"); - uint64_t lastNameAddress = 0; while (searchPos > endOffset) { reader->Seek(searchPos + 4); // Skip the unknown field @@ -133,20 +178,21 @@ bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReade uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); - if (entry.name >= lastNameAddress && entry.address != 0 && it != VxWorks5SymbolTypeMap.end()) + if (entry.name != 0 && + entry.address != 0 && + entry.flags != 0 && + it != VxWorks5SymbolTypeMap.end()) { // Name address is greater than the last name address and flags has a valid symbol type - lastNameAddress = entry.name; m_symbolTable5.push_back(entry); searchPos -= sizeof(entry); continue; } - if (m_symbolTable5.size() > MIN_VALID_SYMBOL_ENTRIES) + if (m_symbolTable5.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(VxWorksVersion5)) break; searchPos -= 4; - lastNameAddress = 0; m_symbolTable5.clear(); } diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index 14719e7c18..22bcf94d07 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -8,8 +8,8 @@ #define DEFAULT_VXWORKS_BASE_ADDRESS 0x10000 #define MAX_SYMBOL_TABLE_REGION_SIZE 0x2000000 -#define MIN_VALID_SYMBOL_ENTRIES 256 -#define VXWORKS_SYMBOL_ENTRY_TYPE(flags) ((flags >> 8) & 0xff) +#define MIN_VALID_SYMBOL_ENTRIES 1000 +#define VXWORKS_SYMBOL_ENTRY_TYPE(flags) (((flags >> 8) & 0xff)) enum VxWorksVersion { @@ -40,6 +40,10 @@ enum VxWorks5SymbolType VxWorks5GlobalBSSSymbolType = 0x09, VxWorks5LocalCommonSymbolType = 0x12, VxWorks5GlobalCommonSymbolType = 0x13, + VxWorks5PowerPCLocalSDASymbolType = 0x40, + VxWorks5PowerPCGlobalSDASymbolType = 0x41, + VxWorks5PowerPCLocalSDA2SymbolType = 0x80, + VxWorks5PowerPCGlobalSDA2SymbolType = 0x81, }; std::map VxWorks5SymbolTypeMap = { @@ -55,6 +59,10 @@ std::map VxWorks5SymbolTypeMap = { { VxWorks5GlobalBSSSymbolType, DataSymbol }, { VxWorks5LocalCommonSymbolType, DataSymbol }, { VxWorks5GlobalCommonSymbolType, DataSymbol }, + { VxWorks5PowerPCLocalSDASymbolType, DataSymbol }, + { VxWorks5PowerPCGlobalSDASymbolType, DataSymbol }, + { VxWorks5PowerPCLocalSDA2SymbolType, DataSymbol }, + { VxWorks5PowerPCGlobalSDA2SymbolType, DataSymbol }, }; enum VxWorks6SymbolType @@ -72,7 +80,7 @@ enum VxWorks6SymbolType VxWorks6LocalCommonSymbolType = 0x20, VxWorks6GlobalCommonSymbolType = 0x21, VxWorks6LocalSymbols = 0x40, - VxWorks6GlobalSymboks = 0x41, + VxWorks6GlobalSymbols = 0x41, }; std::map VxWorks6SymbolTypeMap = { @@ -89,7 +97,9 @@ std::map VxWorks6SymbolTypeMap = { { VxWorks6LocalCommonSymbolType, DataSymbol }, { VxWorks6GlobalCommonSymbolType, DataSymbol }, { VxWorks6LocalSymbols, DataSymbol }, - { VxWorks6GlobalSymboks, DataSymbol }, + { VxWorks6GlobalSymbols, DataSymbol }, + { VxWorks6LocalSymbols, DataSymbol }, + { VxWorks6GlobalSymbols, DataSymbol }, }; struct VxWorks5SymbolTableEntry @@ -140,6 +150,7 @@ namespace BinaryNinja void DetermineEntryPoint(); void AddSections(BinaryView* parentView); void ProcessSymbolTable(BinaryReader *reader); + bool FunctionAddressesAreValid(VxWorksVersion version); bool ScanForVxWorks6SymbolTable(BinaryView* parentView, BinaryReader *reader); bool ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader); bool ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader *reader); From 5dd16a127cd89a1ecc3a6806efe1ddbebb73f66e Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Mon, 24 Jun 2024 09:13:16 -0400 Subject: [PATCH 05/14] Combined VxWorks version-specific symbol entries --- view/vxworks/vxworksview.cpp | 360 +++++++++++++++++------------------ view/vxworks/vxworksview.h | 61 +----- 2 files changed, 184 insertions(+), 237 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 3110a5d9fe..3d4051f106 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -5,8 +5,62 @@ using namespace BinaryNinja; using namespace std; -static VxWorksViewType* g_vxWorksViewType = nullptr; +#define MAX_SYMBOL_TABLE_REGION_SIZE 0x2000000 +#define VXWORKS5_SYMBOL_ENTRY_SIZE 0x10 +#define VXWORKS6_SYMBOL_ENTRY_SIZE 0x14 +#define MAX_SYMBOL_NAME_LENGTH 128 +#define MIN_VALID_SYMBOL_ENTRIES 1000 +#define VXWORKS_SYMBOL_ENTRY_TYPE(flags) (((flags >> 8) & 0xff)) +#define LOWEST_TEXT_SYMBOL_ADDRESS_START 0xffffffffffffffff +#define DEFAULT_VXWORKS_BASE_ADDRESS 0x10000 +#define MAX_ADDRESSES_ENDIANNESS_CHECK 10 + +static const std::map VxWorks5SymbolTypeMap = { + { VxWorks5UndefinedSymbolType, FunctionSymbol }, + { VxWorks5GlobalExternalSymbolType, ImportAddressSymbol }, + { VxWorks5LocalAbsoluteSymbolType, DataSymbol }, + { VxWorks5GlobalAbsoluteSymbolType, DataSymbol }, + { VxWorks5LocalTextSymbolType, FunctionSymbol }, + { VxWorks5GlobalTextSymbolType, FunctionSymbol }, + { VxWorks5LocalDataSymbolType, DataSymbol }, + { VxWorks5GlobalDataSymbolType, DataSymbol }, + { VxWorks5LocalBSSSymbolType, DataSymbol }, + { VxWorks5GlobalBSSSymbolType, DataSymbol }, + { VxWorks5LocalCommonSymbolType, DataSymbol }, + { VxWorks5GlobalCommonSymbolType, DataSymbol }, + { VxWorks5PowerPCLocalSDASymbolType, DataSymbol }, + { VxWorks5PowerPCGlobalSDASymbolType, DataSymbol }, + { VxWorks5PowerPCLocalSDA2SymbolType, DataSymbol }, + { VxWorks5PowerPCGlobalSDA2SymbolType, DataSymbol }, +}; + +static const std::map VxWorks6SymbolTypeMap = { + { VxWorks6UndefinedSymbolType, FunctionSymbol }, + { VxWorks6GlobalExternalSymbolType, ImportAddressSymbol }, + { VxWorks6LocalAbsoluteSymbolType, DataSymbol }, + { VxWorks6GlobalAbsoluteSymbolType, DataSymbol }, + { VxWorks6LocalTextSymbolType, FunctionSymbol }, + { VxWorks6GlobalTextSymbolType, FunctionSymbol }, + { VxWorks6LocalDataSymbolType, DataSymbol }, + { VxWorks6GlobalDataSymbolType, DataSymbol }, + { VxWorks6LocalBSSSymbolType, DataSymbol }, + { VxWorks6GlobalBSSSymbolType, DataSymbol }, + { VxWorks6LocalCommonSymbolType, DataSymbol }, + { VxWorks6GlobalCommonSymbolType, DataSymbol }, + { VxWorks6LocalSymbols, DataSymbol }, + { VxWorks6GlobalSymbols, DataSymbol }, + { VxWorks6LocalSymbols, DataSymbol }, + { VxWorks6GlobalSymbols, DataSymbol }, +}; + +static const std::map VxWorksSectionSemanticsMap = { + { ".text", ReadOnlyCodeSectionSemantics }, + { ".data", ReadWriteDataSectionSemantics }, + { ".rodata", ReadOnlyDataSectionSemantics }, + { ".extern", ExternalSectionSemantics }, +}; +static VxWorksViewType* g_vxWorksViewType = nullptr; void BinaryNinja::InitVxWorksViewType() { @@ -24,28 +78,20 @@ VxWorksView::VxWorksView(BinaryView* data, bool parseOnly): BinaryView("VxWorks" } -#define LOWEST_TEXT_SYMBOL_ADDRESS_START 0xffffffffffffffff void VxWorksView::DetermineImageBaseFromSymbols() { uint64_t lowestTextAddress = LOWEST_TEXT_SYMBOL_ADDRESS_START; - if (m_version == VxWorksVersion5) + for (const auto& entry : m_symbols) { - for (const auto& entry : m_symbolTable5) - { - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - if (type == VxWorks5GlobalTextSymbolType && entry.address < lowestTextAddress) - lowestTextAddress = entry.address; - } - } + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + if (m_version == VxWorksVersion5 && type != VxWorks5GlobalTextSymbolType) + continue; - if (m_version == VxWorksVersion6) - { - for (const auto& entry : m_symbolTable6) - { - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - if (type == VxWorks6GlobalTextSymbolType && entry.address < lowestTextAddress) - lowestTextAddress = entry.address; - } + if (m_version == VxWorksVersion6 && type != VxWorks6GlobalTextSymbolType) + continue; + + if (entry.address < lowestTextAddress) + lowestTextAddress = entry.address; } if (lowestTextAddress == LOWEST_TEXT_SYMBOL_ADDRESS_START) @@ -59,59 +105,39 @@ void VxWorksView::DetermineImageBaseFromSymbols() m_imageBase = lowestTextAddress; } -#define MAX_ADDRESSES_ENDIANNESS_CHECK 10 + // Check least significant byte of the first 10 function symbol addresses to make sure they aren't all the same bool VxWorksView::FunctionAddressesAreValid(VxWorksVersion version) { - size_t count = 0; std::vector funcAddresses; - if (version == VxWorksVersion5) + for (const auto& entry : m_symbols) { - for (const auto& entry : m_symbolTable5) - { - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - if (type == VxWorks5GlobalTextSymbolType) - { - funcAddresses.push_back(entry.address); - count++; - } + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + if (version == VxWorksVersion5 && type != VxWorks5GlobalTextSymbolType) + continue; - if (count == MAX_ADDRESSES_ENDIANNESS_CHECK) - break; - } - } + if (version == VxWorksVersion6 && type != VxWorks6GlobalTextSymbolType) + continue; - if (version == VxWorksVersion6) - { - m_logger->LogDebug("Checking VxWorks 6 function symbol addresses"); - for (const auto& entry : m_symbolTable6) + funcAddresses.push_back(entry.address); + if (funcAddresses.size() == MAX_ADDRESSES_ENDIANNESS_CHECK) { - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - if (type == VxWorks6GlobalTextSymbolType) - { - funcAddresses.push_back(entry.address); - count++; - } - - if (count == MAX_ADDRESSES_ENDIANNESS_CHECK) - break; + uint32_t val = 0; + for (const auto& addr : funcAddresses) + val ^= addr; + return (val & 0xff) != 0; } } - if (funcAddresses.size() < MAX_ADDRESSES_ENDIANNESS_CHECK) - return false; - - uint32_t val = 0; - for (const auto& addr : funcAddresses) - val ^= addr; - return (val & 0xff) != 0; + // Too few function symbols for check + return false; } bool VxWorksView::ScanForVxWorks6SymbolTable(BinaryView *parentView, BinaryReader *reader) { - VxWorks6SymbolTableEntry entry; - uint64_t startOffset = parentView->GetLength() - sizeof(entry); + VxWorksSymbolEntry entry; + uint64_t startOffset = parentView->GetLength() - VXWORKS6_SYMBOL_ENTRY_SIZE; uint64_t endOffset = 0; if (parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) endOffset = parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; @@ -135,34 +161,34 @@ bool VxWorksView::ScanForVxWorks6SymbolTable(BinaryView *parentView, BinaryReade entry.address != 0 && entry.name && it != VxWorks6SymbolTypeMap.end()) { - m_symbolTable6.push_back(entry); - searchPos -= sizeof(entry); + m_symbols.push_back(entry); + searchPos -= VXWORKS6_SYMBOL_ENTRY_SIZE; continue; } - if (m_symbolTable6.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(VxWorksVersion6)) + if (m_symbols.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(VxWorksVersion6)) break; searchPos -= 4; - m_symbolTable6.clear(); + m_symbols.clear(); } - if (m_symbolTable6.size() < MIN_VALID_SYMBOL_ENTRIES) + if (m_symbols.size() < MIN_VALID_SYMBOL_ENTRIES) { - m_symbolTable6.clear(); + m_symbols.clear(); return false; } m_version = VxWorksVersion6; - m_logger->LogDebug("Found %d VxWorks 6 symbol table entries", m_symbolTable6.size()); + m_logger->LogDebug("Found %d VxWorks 6 symbol table entries", m_symbols.size()); return true; } bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader) { - VxWorks5SymbolTableEntry entry; - uint64_t startOffset = parentView->GetLength() - sizeof(entry); + VxWorksSymbolEntry entry; + uint64_t startOffset = parentView->GetLength() - VXWORKS5_SYMBOL_ENTRY_SIZE; uint64_t endOffset = 0; if (parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) endOffset = parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; @@ -184,26 +210,26 @@ bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReade it != VxWorks5SymbolTypeMap.end()) { // Name address is greater than the last name address and flags has a valid symbol type - m_symbolTable5.push_back(entry); - searchPos -= sizeof(entry); + m_symbols.push_back(entry); + searchPos -= VXWORKS5_SYMBOL_ENTRY_SIZE; continue; } - if (m_symbolTable5.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(VxWorksVersion5)) + if (m_symbols.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(VxWorksVersion5)) break; searchPos -= 4; - m_symbolTable5.clear(); + m_symbols.clear(); } - if (m_symbolTable5.size() < MIN_VALID_SYMBOL_ENTRIES) + if (m_symbols.size() < MIN_VALID_SYMBOL_ENTRIES) { - m_symbolTable5.clear(); + m_symbols.clear(); return false; } m_version = VxWorksVersion5; - m_logger->LogDebug("Found %d VxWorks 5 symbol table entries", m_symbolTable5.size()); + m_logger->LogDebug("Found %d VxWorks 5 symbol table entries", m_symbols.size()); return true; } @@ -226,140 +252,114 @@ bool VxWorksView::ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader } -#define MAX_SYMBOL_NAME_LENGTH 128 -void VxWorksView::ProcessSymbolTable(BinaryReader *reader) +void VxWorksView::AssignSymbolToSection(std::map>& sections, + BNSymbolType bnSymbolType, uint8_t vxSymbolType, uint64_t address) { - std::set textSymbolAddresses; - std::set dataSymbolAddresses; - std::set roDataSymbolAddresses; - std::set externSymbolAddresses; - - switch (m_version) + switch (bnSymbolType) { - case VxWorksVersion5: - { - for (const auto& entry : m_symbolTable5) + case FunctionSymbol: + sections[".text"].insert(address); + AddFunctionForAnalysis(m_platform, address); + break; + case DataSymbol: + if (m_version == VxWorksVersion5) { - reader->Seek(entry.name - m_imageBase); - string symbolName = reader->ReadCString(MAX_SYMBOL_NAME_LENGTH); - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); - if (it == VxWorks5SymbolTypeMap.end()) - { - m_logger->LogError("Unknown VxWorks 5 symbol type: 0x%02x (%s)", type, symbolName.c_str()); - continue; - } - - auto symbolType = it->second; - switch (symbolType) - { - case FunctionSymbol: - textSymbolAddresses.insert(entry.address); - AddFunctionForAnalysis(m_platform, entry.address); - break; - case DataSymbol: - if (type == VxWorks5GlobalAbsoluteSymbolType) - roDataSymbolAddresses.insert(entry.address); - else - dataSymbolAddresses.insert(entry.address); - break; - case ExternalSymbol: - externSymbolAddresses.insert(entry.address); - break; - default: - break; - } + if (vxSymbolType == VxWorks5GlobalAbsoluteSymbolType) + sections[".rodata"].insert(address); + else + sections[".data"].insert(address); + } - DefineAutoSymbol(new Symbol(symbolType, symbolName, entry.address)); - if (symbolName == "sysInit") - m_sysInit = entry.address; + if (m_version == VxWorksVersion6) + { + if (vxSymbolType == VxWorks6GlobalAbsoluteSymbolType) + sections[".rodata"].insert(address); + else + sections[".data"].insert(address); } + break; + case ExternalSymbol: + sections[".extern"].insert(address); + break; + default: + m_logger->LogWarn("Unknown symbol type: %d", bnSymbolType); break; } - case VxWorksVersion6: +} + + +void VxWorksView::ProcessSymbolTable(BinaryReader *reader) +{ + std::map> sections = { + { ".text", {} }, + { ".data", {} }, + { ".rodata", {} }, + { ".extern", {} } + }; + + for (const auto& entry : m_symbols) { - for (const auto& entry : m_symbolTable6) + reader->Seek(entry.name - m_imageBase); + string symbolName = reader->ReadCString(MAX_SYMBOL_NAME_LENGTH); + uint8_t vxSymbolType = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + BNSymbolType bnSymbolType; + + switch (m_version) { - reader->Seek(entry.name - m_imageBase); - string symbolName = reader->ReadCString(MAX_SYMBOL_NAME_LENGTH); - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - auto it = VxWorks6SymbolTypeMap.find((VxWorks6SymbolType)type); - if (it == VxWorks6SymbolTypeMap.end()) + case VxWorksVersion5: + { + auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)vxSymbolType); + if (it == VxWorks5SymbolTypeMap.end()) { - m_logger->LogError("Unknown VxWorks 6 symbol type: 0x%02x (%s)", type, symbolName.c_str()); + m_logger->LogWarn("Unknown VxWorks 5 symbol type: 0x%02x (%s)", vxSymbolType, symbolName.c_str()); continue; } - auto symbolType = it->second; - switch (symbolType) + bnSymbolType = it->second; + break; + } + case VxWorksVersion6: + { + auto it = VxWorks6SymbolTypeMap.find((VxWorks6SymbolType)vxSymbolType); + if (it == VxWorks6SymbolTypeMap.end()) { - case FunctionSymbol: - textSymbolAddresses.insert(entry.address); - AddFunctionForAnalysis(m_platform, entry.address); - break; - case DataSymbol: - if (type == VxWorks6GlobalAbsoluteSymbolType) - roDataSymbolAddresses.insert(entry.address); - else - dataSymbolAddresses.insert(entry.address); - break; - case ExternalSymbol: - externSymbolAddresses.insert(entry.address); - break; - default: - break; + m_logger->LogWarn("Unknown VxWorks 6 symbol type: 0x%02x (%s)", vxSymbolType, symbolName.c_str()); + continue; } - DefineAutoSymbol(new Symbol(symbolType, symbolName, entry.address)); - if (symbolName == "sysInit") - m_sysInit = entry.address; + bnSymbolType = it->second; + break; + } + default: + m_logger->LogError("VxWorks version is not set. Please report this issue."); + return; } - break; - } - case VxWorksUnknownVersion: - default: - // Shouldn't get here - we set the VxWorks version when we find the symbol table - m_logger->LogError( - "VxWorks version is unknown, cannot apply symbols." - "Please report this issue." - ); - return; - } - if (textSymbolAddresses.size() > 1) - { - m_sections.push_back({ - { *textSymbolAddresses.begin(), *textSymbolAddresses.rbegin() }, - ".text", - ReadOnlyCodeSectionSemantics - }); + AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); + DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address)); + if (symbolName == "sysInit") + m_sysInit = entry.address; } - if (dataSymbolAddresses.size() > 1) + // Build section info from address ranges of symbols and their types + for (const auto& section : sections) { - m_sections.push_back({ - { *dataSymbolAddresses.begin(), *dataSymbolAddresses.rbegin() }, - ".data", - ReadWriteDataSectionSemantics - }); - } + if (section.second.empty()) + continue; - if (externSymbolAddresses.size() > 1) - { - m_sections.push_back({ - { *externSymbolAddresses.begin(), *externSymbolAddresses.rbegin() }, - ".extern", - ExternalSectionSemantics - }); - } + auto it = VxWorksSectionSemanticsMap.find(section.first); + if (it == VxWorksSectionSemanticsMap.end()) + { + m_logger->LogWarn("Unknown section semantics for section: %s. Please report this issue.", + section.first.c_str()); + continue; + } - if (roDataSymbolAddresses.size() > 1) - { m_sections.push_back({ - { *roDataSymbolAddresses.begin(), *roDataSymbolAddresses.rbegin() }, - ".rodata", - ReadOnlyDataSectionSemantics + { *section.second.begin(), *section.second.rbegin() }, + section.first, + it->second }); } } diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index 22bcf94d07..1310e52d58 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -6,11 +6,6 @@ #pragma warning(disable: 4005) #endif -#define DEFAULT_VXWORKS_BASE_ADDRESS 0x10000 -#define MAX_SYMBOL_TABLE_REGION_SIZE 0x2000000 -#define MIN_VALID_SYMBOL_ENTRIES 1000 -#define VXWORKS_SYMBOL_ENTRY_TYPE(flags) (((flags >> 8) & 0xff)) - enum VxWorksVersion { VxWorksUnknownVersion, @@ -46,25 +41,6 @@ enum VxWorks5SymbolType VxWorks5PowerPCGlobalSDA2SymbolType = 0x81, }; -std::map VxWorks5SymbolTypeMap = { - { VxWorks5UndefinedSymbolType, FunctionSymbol }, - { VxWorks5GlobalExternalSymbolType, ImportAddressSymbol }, - { VxWorks5LocalAbsoluteSymbolType, DataSymbol }, - { VxWorks5GlobalAbsoluteSymbolType, DataSymbol }, - { VxWorks5LocalTextSymbolType, FunctionSymbol }, - { VxWorks5GlobalTextSymbolType, FunctionSymbol }, - { VxWorks5LocalDataSymbolType, DataSymbol }, - { VxWorks5GlobalDataSymbolType, DataSymbol }, - { VxWorks5LocalBSSSymbolType, DataSymbol }, - { VxWorks5GlobalBSSSymbolType, DataSymbol }, - { VxWorks5LocalCommonSymbolType, DataSymbol }, - { VxWorks5GlobalCommonSymbolType, DataSymbol }, - { VxWorks5PowerPCLocalSDASymbolType, DataSymbol }, - { VxWorks5PowerPCGlobalSDASymbolType, DataSymbol }, - { VxWorks5PowerPCLocalSDA2SymbolType, DataSymbol }, - { VxWorks5PowerPCGlobalSDA2SymbolType, DataSymbol }, -}; - enum VxWorks6SymbolType { VxWorks6UndefinedSymbolType = 0x00, @@ -83,39 +59,10 @@ enum VxWorks6SymbolType VxWorks6GlobalSymbols = 0x41, }; -std::map VxWorks6SymbolTypeMap = { - { VxWorks6UndefinedSymbolType, FunctionSymbol }, - { VxWorks6GlobalExternalSymbolType, ImportAddressSymbol }, - { VxWorks6LocalAbsoluteSymbolType, DataSymbol }, - { VxWorks6GlobalAbsoluteSymbolType, DataSymbol }, - { VxWorks6LocalTextSymbolType, FunctionSymbol }, - { VxWorks6GlobalTextSymbolType, FunctionSymbol }, - { VxWorks6LocalDataSymbolType, DataSymbol }, - { VxWorks6GlobalDataSymbolType, DataSymbol }, - { VxWorks6LocalBSSSymbolType, DataSymbol }, - { VxWorks6GlobalBSSSymbolType, DataSymbol }, - { VxWorks6LocalCommonSymbolType, DataSymbol }, - { VxWorks6GlobalCommonSymbolType, DataSymbol }, - { VxWorks6LocalSymbols, DataSymbol }, - { VxWorks6GlobalSymbols, DataSymbol }, - { VxWorks6LocalSymbols, DataSymbol }, - { VxWorks6GlobalSymbols, DataSymbol }, -}; - -struct VxWorks5SymbolTableEntry -{ - uint32_t unknown; - uint32_t name; - uint32_t address; - uint32_t flags; -}; - -struct VxWorks6SymbolTableEntry +struct VxWorksSymbolEntry { - uint32_t unknown1; uint32_t name; uint32_t address; - uint32_t unknown2; uint32_t flags; }; @@ -143,12 +90,13 @@ namespace BinaryNinja std::vector m_sections; VxWorksVersion m_version = VxWorksUnknownVersion; - std::vector m_symbolTable5; - std::vector m_symbolTable6; + std::vector m_symbols; private: void DetermineEntryPoint(); void AddSections(BinaryView* parentView); + void AssignSymbolToSection(std::map>& sections, + BNSymbolType bnSymbolType, uint8_t vxSymbolType, uint64_t address); void ProcessSymbolTable(BinaryReader *reader); bool FunctionAddressesAreValid(VxWorksVersion version); bool ScanForVxWorks6SymbolTable(BinaryView* parentView, BinaryReader *reader); @@ -172,7 +120,6 @@ namespace BinaryNinja { Ref m_logger; - public: VxWorksViewType(); virtual Ref Create(BinaryView* data) override; From 7cc82313824a125ece8d7b42b10ca609907e8917 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Mon, 24 Jun 2024 15:14:22 -0400 Subject: [PATCH 06/14] Defining VxWorks symbol table entries Also created a section for the symtab --- view/vxworks/vxworksview.cpp | 244 ++++++++++++++++++++--------------- view/vxworks/vxworksview.h | 12 +- 2 files changed, 148 insertions(+), 108 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 3d4051f106..4e147b2585 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -56,8 +56,8 @@ static const std::map VxWorks6SymbolTypeMap = static const std::map VxWorksSectionSemanticsMap = { { ".text", ReadOnlyCodeSectionSemantics }, { ".data", ReadWriteDataSectionSemantics }, - { ".rodata", ReadOnlyDataSectionSemantics }, { ".extern", ExternalSectionSemantics }, + { ".symtab", ReadOnlyDataSectionSemantics }, }; static VxWorksViewType* g_vxWorksViewType = nullptr; @@ -77,6 +77,45 @@ VxWorksView::VxWorksView(BinaryView* data, bool parseOnly): BinaryView("VxWorks" m_logger = CreateLogger("BinaryView.VxWorksView"); } +void VxWorksView::DefineSymbolTableDataVariable() +{ + StructureBuilder symbolTableEntry; + switch (m_version) + { + case VxWorksVersion5: + symbolTableEntry.AddMember(Type::IntegerType(4, false), "unknown"); + symbolTableEntry.AddMember(Type::PointerType(m_platform->GetArchitecture(), + Type::VoidType())->WithConfidence(BN_FULL_CONFIDENCE), "name"); + symbolTableEntry.AddMember(Type::PointerType(m_platform->GetArchitecture(), + Type::VoidType())->WithConfidence(BN_FULL_CONFIDENCE), "address"); + symbolTableEntry.AddMember(Type::IntegerType(4, false), "flags"); + break; + case VxWorksVersion6: + symbolTableEntry.AddMember(Type::IntegerType(4, false), "unknown1"); + symbolTableEntry.AddMember(Type::PointerType(m_platform->GetArchitecture(), + Type::VoidType())->WithConfidence(BN_FULL_CONFIDENCE), "name"); + symbolTableEntry.AddMember(Type::PointerType(m_platform->GetArchitecture(), + Type::VoidType())->WithConfidence(BN_FULL_CONFIDENCE), "address"); + symbolTableEntry.AddMember(Type::IntegerType(4, false), "unknown2"); + symbolTableEntry.AddMember(Type::IntegerType(4, false), "flags"); + break; + default: + m_logger->LogError("VxWorks version is not set. Please report this issue."); + return; + } + + auto symbolEntryStruct = symbolTableEntry.Finalize(); + auto symbolEntryType = Type::StructureType(symbolEntryStruct); + QualifiedName symbolEntryName = string("VxWorksSymbolEntry"); + auto symbolEntryTypeId = Type::GenerateAutoTypeId("VxWorks", symbolEntryName); + QualifiedName symbolEntryTypeName = DefineType(symbolEntryTypeId, symbolEntryName, symbolEntryType); + DefineDataVariable(m_imageBase + m_symbolTableOffset, + Type::ArrayType(Type::NamedType(this, symbolEntryTypeName), + m_symbols.size()) + ); + + DefineAutoSymbol(new Symbol(DataSymbol, "VxWorksSymbolTable", m_imageBase + m_symbolTableOffset)); +} void VxWorksView::DetermineImageBaseFromSymbols() { @@ -134,88 +173,81 @@ bool VxWorksView::FunctionAddressesAreValid(VxWorksVersion version) } -bool VxWorksView::ScanForVxWorks6SymbolTable(BinaryView *parentView, BinaryReader *reader) +bool VxWorksView::TryReadVxWorksSymbolEntry(BinaryReader *reader, uint64_t offset, + VxWorksSymbolEntry& entry, VxWorksVersion version) { - VxWorksSymbolEntry entry; - uint64_t startOffset = parentView->GetLength() - VXWORKS6_SYMBOL_ENTRY_SIZE; - uint64_t endOffset = 0; - if (parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) - endOffset = parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; - uint64_t searchPos = startOffset; - - m_logger->LogDebug("Scanning backwards for VxWorks 6 symbol table (0x%016x-0x%016x) (endianess=%s)...", - startOffset, endOffset, m_endianness == BigEndian ? "big" : "little"); - while (searchPos > endOffset) - { - reader->Seek(searchPos + 4); // Skip the first unknown field - if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address)) - break; + reader->Seek(offset + 4); // Skip first unknown field + if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address)) + return false; - reader->Seek(searchPos + 16); // Skip the second unknown field - if (!reader->TryReadBE32(entry.flags)) - break; + if (version == VxWorksVersion6) + reader->Seek(offset + 16); // Skip second unknown field (VxWorks 6 only) - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - auto it = VxWorks6SymbolTypeMap.find((VxWorks6SymbolType)type); - if (entry.name != 0 && - entry.address != 0 && - entry.name && it != VxWorks6SymbolTypeMap.end()) - { - m_symbols.push_back(entry); - searchPos -= VXWORKS6_SYMBOL_ENTRY_SIZE; - continue; - } + if (!reader->TryReadBE32(entry.flags)) + return false; - if (m_symbols.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(VxWorksVersion6)) - break; + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + switch (version) + { + case VxWorksVersion5: + { + auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); + if (entry.name != 0 && entry.flags != 0 && it != VxWorks5SymbolTypeMap.end()) + return true; - searchPos -= 4; - m_symbols.clear(); + return false; } - - if (m_symbols.size() < MIN_VALID_SYMBOL_ENTRIES) + case VxWorksVersion6: { - m_symbols.clear(); + auto it = VxWorks6SymbolTypeMap.find((VxWorks6SymbolType)type); + if (entry.name != 0 && it != VxWorks6SymbolTypeMap.end()) + return true; + + return false; + } + default: + m_logger->LogError("VxWorks version is not set. Please report this issue."); return false; } - - m_version = VxWorksVersion6; - m_logger->LogDebug("Found %d VxWorks 6 symbol table entries", m_symbols.size()); - return true; } -bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader) +bool VxWorksView::ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion version, BNEndianness endianness) { + size_t entrySize; + m_endianness = endianness; + reader->SetEndianness(m_endianness); + switch (version) + { + case VxWorksVersion5: + entrySize = VXWORKS5_SYMBOL_ENTRY_SIZE; + break; + case VxWorksVersion6: + entrySize = VXWORKS6_SYMBOL_ENTRY_SIZE; + break; + default: + m_logger->LogError("VxWorks version is not set. Please report this issue."); + return false; + } + VxWorksSymbolEntry entry; - uint64_t startOffset = parentView->GetLength() - VXWORKS5_SYMBOL_ENTRY_SIZE; - uint64_t endOffset = 0; - if (parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) - endOffset = parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; - uint64_t searchPos = startOffset; - - m_logger->LogDebug("Scanning backwards for VxWorks 5 symbol table (0x%016x-0x%016x) (endianess=%s)...", - startOffset, endOffset, m_endianness == BigEndian ? "big" : "little"); + ssize_t startOffset = m_parentView->GetLength() - entrySize; + ssize_t endOffset = 0; + if (m_parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) + endOffset = m_parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; + ssize_t searchPos = startOffset; + m_logger->LogDebug("Scanning backwards for VxWorks system table (0x%016x-0x%016x) (endianess=%s) (version=%d)...", + startOffset, endOffset, m_endianness == BigEndian ? "big" : "little", version == VxWorksVersion5 ? 5 : 6); while (searchPos > endOffset) { - reader->Seek(searchPos + 4); // Skip the unknown field - if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address) || !reader->TryReadBE32(entry.flags)) - break; - - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); - if (entry.name != 0 && - entry.address != 0 && - entry.flags != 0 && - it != VxWorks5SymbolTypeMap.end()) + if (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version)) { - // Name address is greater than the last name address and flags has a valid symbol type m_symbols.push_back(entry); - searchPos -= VXWORKS5_SYMBOL_ENTRY_SIZE; + searchPos -= entrySize; continue; } - if (m_symbols.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(VxWorksVersion5)) + if (m_symbols.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(version)) break; searchPos -= 4; @@ -228,27 +260,36 @@ bool VxWorksView::ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReade return false; } - m_version = VxWorksVersion5; - m_logger->LogDebug("Found %d VxWorks 5 symbol table entries", m_symbols.size()); + m_symbolTableOffset = searchPos + entrySize; + + // Scan algorithm is prone to missing a few entries at the end of the table + searchPos = m_symbolTableOffset + (entrySize * m_symbols.size()); + while (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version)) + { + m_symbols.push_back(entry); + searchPos += entrySize; + } + + m_version = version; + m_logger->LogDebug("Found %d VxWorks %d symbol table entries starting at offset 0x%016x", + m_symbols.size(), version == VxWorksVersion5 ? 5 : 6, m_symbolTableOffset); + return true; } -bool VxWorksView::ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader *reader) +bool VxWorksView::FindSymbolTable(BinaryReader *reader) { - if (ScanForVxWorks5SymbolTable(parentView, reader)) + if (ScanForVxWorksSystemTable(reader, VxWorksVersion5, BigEndian)) return true; - m_endianness = LittleEndian; - reader->SetEndianness(m_endianness); - if (ScanForVxWorks5SymbolTable(parentView, reader)) + if (ScanForVxWorksSystemTable(reader, VxWorksVersion5, LittleEndian)) return true; - if (ScanForVxWorks6SymbolTable(parentView, reader)) + if (ScanForVxWorksSystemTable(reader, VxWorksVersion6, LittleEndian)) return true; - m_endianness = BigEndian; - reader->SetEndianness(m_endianness); - return ScanForVxWorks6SymbolTable(parentView, reader); + + return ScanForVxWorksSystemTable(reader, VxWorksVersion6, BigEndian); } @@ -262,22 +303,7 @@ void VxWorksView::AssignSymbolToSection(std::map AddFunctionForAnalysis(m_platform, address); break; case DataSymbol: - if (m_version == VxWorksVersion5) - { - if (vxSymbolType == VxWorks5GlobalAbsoluteSymbolType) - sections[".rodata"].insert(address); - else - sections[".data"].insert(address); - } - - if (m_version == VxWorksVersion6) - { - if (vxSymbolType == VxWorks6GlobalAbsoluteSymbolType) - sections[".rodata"].insert(address); - else - sections[".data"].insert(address); - } - + sections[".data"].insert(address); break; case ExternalSymbol: sections[".extern"].insert(address); @@ -294,8 +320,8 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) std::map> sections = { { ".text", {} }, { ".data", {} }, - { ".rodata", {} }, - { ".extern", {} } + { ".extern", {} }, + { ".symtab", {} }, }; for (const auto& entry : m_symbols) @@ -336,13 +362,19 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) return; } - AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); - DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address)); - if (symbolName == "sysInit") - m_sysInit = entry.address; + if (m_parentView->IsOffsetBackedByFile(entry.address - m_imageBase)) + { + AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); + DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address)); + if (symbolName == "sysInit" || symbolName == "_sysInit") + m_sysInit = entry.address; + } } // Build section info from address ranges of symbols and their types + sections[".symtab"].insert(m_imageBase + m_symbolTableOffset); + sections[".symtab"].insert(m_imageBase + (m_symbolTableOffset + m_symbols.size() * + (m_version == VxWorksVersion5 ? VXWORKS5_SYMBOL_ENTRY_SIZE : VXWORKS6_SYMBOL_ENTRY_SIZE))); for (const auto& section : sections) { if (section.second.empty()) @@ -365,12 +397,12 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) } -void VxWorksView::AddSections(BinaryView *parentView) +void VxWorksView::AddSections() { if (m_sections.empty()) { m_logger->LogDebug("No sections found, creating default section"); - AddAutoSection(".text", m_imageBase, parentView->GetLength(), ReadOnlyCodeSectionSemantics); + AddAutoSection(".text", m_imageBase, m_parentView->GetLength(), ReadOnlyCodeSectionSemantics); return; } @@ -387,7 +419,7 @@ void VxWorksView::AddSections(BinaryView *parentView) uint64_t end = lastStart ? lastStart : section.AddressRange.second; if (lastSection) { - end = m_imageBase + parentView->GetLength(); + end = m_imageBase + m_parentView->GetLength(); lastSection = false; } @@ -422,15 +454,15 @@ bool VxWorksView::Init() { try { - auto parentView = GetParentView(); - if (!parentView) + m_parentView = GetParentView(); + if (!m_parentView) { m_logger->LogError("Failed to get parent view"); return false; } - BinaryReader reader(parentView, m_endianness); - bool isSymTable = ScanForVxWorksSymbolTable(parentView, &reader); + BinaryReader reader(m_parentView, m_endianness); + bool isSymTable = FindSymbolTable(&reader); if (isSymTable) { DetermineImageBaseFromSymbols(); @@ -442,7 +474,7 @@ bool VxWorksView::Init() m_imageBase = DEFAULT_VXWORKS_BASE_ADDRESS; } - AddAutoSegment(m_imageBase, parentView->GetLength(), 0, parentView->GetLength(), + AddAutoSegment(m_imageBase, m_parentView->GetLength(), 0, m_parentView->GetLength(), SegmentReadable | SegmentWritable | SegmentExecutable); auto settings = GetLoadSettings(GetTypeName()); @@ -470,8 +502,12 @@ bool VxWorksView::Init() return true; if (isSymTable) + { ProcessSymbolTable(&reader); - AddSections(parentView); + DefineSymbolTableDataVariable(); + } + + AddSections(); DetermineEntryPoint(); AddEntryPointForAnalysis(m_platform, m_entryPoint); return true; diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index 1310e52d58..e105dcb857 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -80,10 +80,12 @@ namespace BinaryNinja Ref m_logger; bool m_parseOnly; bool m_relocatable = false; + Ref m_parentView = nullptr; BNEndianness m_endianness = BigEndian; Ref m_platform; Ref m_arch; size_t m_addressSize; + uint64_t m_symbolTableOffset = 0; uint64_t m_entryPoint = 0; uint64_t m_imageBase = 0; uint64_t m_sysInit = 0; // Entrypoint, if we find it in the symbol table @@ -94,14 +96,16 @@ namespace BinaryNinja private: void DetermineEntryPoint(); - void AddSections(BinaryView* parentView); + void AddSections(); void AssignSymbolToSection(std::map>& sections, BNSymbolType bnSymbolType, uint8_t vxSymbolType, uint64_t address); + void DefineSymbolTableDataVariable(); void ProcessSymbolTable(BinaryReader *reader); bool FunctionAddressesAreValid(VxWorksVersion version); - bool ScanForVxWorks6SymbolTable(BinaryView* parentView, BinaryReader *reader); - bool ScanForVxWorks5SymbolTable(BinaryView* parentView, BinaryReader *reader); - bool ScanForVxWorksSymbolTable(BinaryView* parentView, BinaryReader *reader); + bool TryReadVxWorksSymbolEntry(BinaryReader *reader, uint64_t offset, + VxWorksSymbolEntry& entry, VxWorksVersion version); + bool ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion version, BNEndianness endianness); + bool FindSymbolTable(BinaryReader *reader); void DetermineImageBaseFromSymbols(); protected: From 22695f21ebed1cdd0367245009dc739de5d203f6 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Tue, 2 Jul 2024 16:09:19 -0400 Subject: [PATCH 07/14] VxWorks allow user to override base address --- view/vxworks/vxworksview.cpp | 64 +++++++++++++++++++++++------------- view/vxworks/vxworksview.h | 4 +-- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 4e147b2585..516b5274a4 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -10,10 +10,10 @@ using namespace std; #define VXWORKS6_SYMBOL_ENTRY_SIZE 0x14 #define MAX_SYMBOL_NAME_LENGTH 128 #define MIN_VALID_SYMBOL_ENTRIES 1000 -#define VXWORKS_SYMBOL_ENTRY_TYPE(flags) (((flags >> 8) & 0xff)) +#define VXWORKS_SYMBOL_ENTRY_TYPE(flags) ((flags >> 8) & 0xff) #define LOWEST_TEXT_SYMBOL_ADDRESS_START 0xffffffffffffffff -#define DEFAULT_VXWORKS_BASE_ADDRESS 0x10000 #define MAX_ADDRESSES_ENDIANNESS_CHECK 10 +#define ALIGN4(x) (x & 0xfffffffffffffffc) static const std::map VxWorks5SymbolTypeMap = { { VxWorks5UndefinedSymbolType, FunctionSymbol }, @@ -135,8 +135,7 @@ void VxWorksView::DetermineImageBaseFromSymbols() if (lowestTextAddress == LOWEST_TEXT_SYMBOL_ADDRESS_START) { - m_logger->LogWarn("Could not determine image base address, using default 0x%08x", DEFAULT_VXWORKS_BASE_ADDRESS); - m_imageBase = DEFAULT_VXWORKS_BASE_ADDRESS; + m_logger->LogWarn("Could not determine image base from VxWorks symbol table"); return; } @@ -168,7 +167,7 @@ bool VxWorksView::FunctionAddressesAreValid(VxWorksVersion version) } } - // Too few function symbols for check + // Too few symbols to check return false; } @@ -231,17 +230,24 @@ bool VxWorksView::ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion } VxWorksSymbolEntry entry; - ssize_t startOffset = m_parentView->GetLength() - entrySize; + ssize_t startOffset = ALIGN4(m_parentView->GetLength() - entrySize); ssize_t endOffset = 0; if (m_parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) - endOffset = m_parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE; + endOffset = ALIGN4(m_parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE); ssize_t searchPos = startOffset; + std::vector foundNames; + m_logger->LogDebug("Scanning backwards for VxWorks system table (0x%016x-0x%016x) (endianess=%s) (version=%d)...", startOffset, endOffset, m_endianness == BigEndian ? "big" : "little", version == VxWorksVersion5 ? 5 : 6); while (searchPos > endOffset) { - if (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version)) + if (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version) && + find(foundNames.begin(), foundNames.end(), entry.name) == foundNames.end()) { + if (version == VxWorksVersion5 && endianness == BigEndian) + m_logger->LogDebug("0x%016x: address=%016x name=%016x flags=%08x count=%d", searchPos, entry.address, entry.name, entry.flags, m_symbols.size()); + + foundNames.push_back(entry.address); m_symbols.push_back(entry); searchPos -= entrySize; continue; @@ -251,6 +257,7 @@ bool VxWorksView::ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion break; searchPos -= 4; + foundNames.clear(); m_symbols.clear(); } @@ -365,6 +372,7 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) if (m_parentView->IsOffsetBackedByFile(entry.address - m_imageBase)) { AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); + // TODO: make sure symbolName only contains ASCII DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address)); if (symbolName == "sysInit" || symbolName == "_sysInit") m_sysInit = entry.address; @@ -462,8 +470,8 @@ bool VxWorksView::Init() } BinaryReader reader(m_parentView, m_endianness); - bool isSymTable = FindSymbolTable(&reader); - if (isSymTable) + m_hasSymbolTable = FindSymbolTable(&reader); + if (m_hasSymbolTable) { DetermineImageBaseFromSymbols(); m_entryPoint = m_imageBase; // This will get updated later if the sysInit symbol is found @@ -471,12 +479,8 @@ bool VxWorksView::Init() else { m_logger->LogWarn("Could not find VxWorks symbol table"); - m_imageBase = DEFAULT_VXWORKS_BASE_ADDRESS; } - AddAutoSegment(m_imageBase, m_parentView->GetLength(), 0, m_parentView->GetLength(), - SegmentReadable | SegmentWritable | SegmentExecutable); - auto settings = GetLoadSettings(GetTypeName()); if (!settings || settings->IsEmpty()) { @@ -485,14 +489,20 @@ bool VxWorksView::Init() return true; } - auto platformName = settings->Get("loader.platform"); - m_platform = Platform::GetByName(platformName); - if (!m_platform) + if (settings->Contains("loader.platform")) { - m_logger->LogError("Failed to get platform"); - return false; + auto platformName = settings->Get("loader.platform", this); + m_platform = Platform::GetByName(platformName); + if (!m_platform) + { + m_logger->LogError("Failed to get platform"); + return false; + } } + if (settings->Contains("loader.imageBase")) + m_imageBase = settings->Get("loader.imageBase", this); + m_arch = m_platform->GetArchitecture(); m_addressSize = m_arch->GetAddressSize(); SetDefaultPlatform(m_platform); @@ -501,7 +511,10 @@ bool VxWorksView::Init() if (m_parseOnly) return true; - if (isSymTable) + AddAutoSegment(m_imageBase, m_parentView->GetLength(), 0, m_parentView->GetLength(), + SegmentReadable | SegmentWritable | SegmentExecutable); + + if (m_hasSymbolTable) { ProcessSymbolTable(&reader); DefineSymbolTableDataVariable(); @@ -613,8 +626,15 @@ Ref VxWorksViewType::GetLoadSettingsForData(BinaryView *data) settings->UpdateProperty(override, "readOnly", false); } - if (settings->Contains("loader.entryPointOffset")) - settings->UpdateProperty("loader.entryPointOffset", "default", viewRef->GetEntryPoint()); + if (!viewRef->IsRelocatable()) + { + settings->UpdateProperty("loader.imageBase", "default", viewRef->GetEntryPoint()); + settings->UpdateProperty("loader.imageBase", "message", "Note: base address determined from VxWorks symbol table."); + } + else + { + settings->UpdateProperty("loader.imageBase", "message", "VxWorks symbol table was not found. Base address must be set manually."); + } return settings; } diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index e105dcb857..ca1d133246 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -79,12 +79,12 @@ namespace BinaryNinja { Ref m_logger; bool m_parseOnly; - bool m_relocatable = false; Ref m_parentView = nullptr; BNEndianness m_endianness = BigEndian; Ref m_platform; Ref m_arch; size_t m_addressSize; + bool m_hasSymbolTable = false; uint64_t m_symbolTableOffset = 0; uint64_t m_entryPoint = 0; uint64_t m_imageBase = 0; @@ -112,7 +112,7 @@ namespace BinaryNinja virtual uint64_t PerformGetEntryPoint() const override; virtual bool PerformIsExecutable() const override { return true; } virtual BNEndianness PerformGetDefaultEndianness() const override { return m_endianness; } - virtual bool PerformIsRelocatable() const override { return m_relocatable; } + virtual bool PerformIsRelocatable() const override { return m_hasSymbolTable == false; } virtual size_t PerformGetAddressSize() const override; public: From 3071f0b60be227dbcf4a9562d6eedaf8e1778d77 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Wed, 3 Jul 2024 15:30:35 -0400 Subject: [PATCH 08/14] Adjusting base for VxWorks images w/ image header --- view/vxworks/vxworksview.cpp | 110 ++++++++++++++++++++++++----------- view/vxworks/vxworksview.h | 10 ++-- 2 files changed, 81 insertions(+), 39 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 516b5274a4..eb07753451 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -117,8 +117,52 @@ void VxWorksView::DefineSymbolTableDataVariable() DefineAutoSymbol(new Symbol(DataSymbol, "VxWorksSymbolTable", m_imageBase + m_symbolTableOffset)); } -void VxWorksView::DetermineImageBaseFromSymbols() + +uint64_t VxWorksView::FindSysInit(BinaryReader *reader, uint64_t imageBase) +{ + for (const auto& entry : m_symbols) + { + reader->Seek(entry.name - imageBase); + string symbolName = reader->ReadCString(MAX_SYMBOL_NAME_LENGTH); + if (symbolName == "sysInit" || symbolName == "_sysInit") + { + m_logger->LogDebug("Found %s function at 0x%016x", symbolName.c_str(), entry.address); + return entry.address; + } + } + + return 0; +} + + +// All VxWorks image headers I've seen are less than 256 bytes in size. 1k should be plenty. +#define MAX_VXWORKS_HEADER_SIZE 1024 +void VxWorksView::AdjustImageBaseForHeaderIfPresent(BinaryReader *reader) +{ + // Many VxWorks images contain a header and the first dword contains the size of the header. + reader->Seek(0); + uint32_t possibleHeaderSz = 0; + if (!reader->TryRead32(possibleHeaderSz)) + { + m_logger->LogWarn("Failed to read first 4 bytes of VxWorks image. Please, report this issue."); + return; + } + + if (!possibleHeaderSz || possibleHeaderSz > MAX_VXWORKS_HEADER_SIZE) + return; // Likely not a header + + // Meets size constraints, now verify that a symbol name address aligns with a known symbol name before adjusting + if (FindSysInit(reader, m_determinedImagebase - possibleHeaderSz)) + { + m_logger->LogDebug("sysInit found, adjusting base address by 0x%08x bytes", possibleHeaderSz); + m_determinedImagebase -= possibleHeaderSz; + } +} + + +void VxWorksView::DetermineImageBaseFromSymbols(BinaryReader* reader) { + // Get lowest address from symbol table text section entries uint64_t lowestTextAddress = LOWEST_TEXT_SYMBOL_ADDRESS_START; for (const auto& entry : m_symbols) { @@ -139,8 +183,10 @@ void VxWorksView::DetermineImageBaseFromSymbols() return; } + m_determinedImagebase = lowestTextAddress; + AdjustImageBaseForHeaderIfPresent(reader); m_logger->LogDebug("Determined image base address: 0x%016x", lowestTextAddress); - m_imageBase = lowestTextAddress; + m_imageBase = m_determinedImagebase; } @@ -244,9 +290,6 @@ bool VxWorksView::ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion if (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version) && find(foundNames.begin(), foundNames.end(), entry.name) == foundNames.end()) { - if (version == VxWorksVersion5 && endianness == BigEndian) - m_logger->LogDebug("0x%016x: address=%016x name=%016x flags=%08x count=%d", searchPos, entry.address, entry.name, entry.flags, m_symbols.size()); - foundNames.push_back(entry.address); m_symbols.push_back(entry); searchPos -= entrySize; @@ -374,8 +417,6 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); // TODO: make sure symbolName only contains ASCII DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address)); - if (symbolName == "sysInit" || symbolName == "_sysInit") - m_sysInit = entry.address; } } @@ -409,12 +450,14 @@ void VxWorksView::AddSections() { if (m_sections.empty()) { - m_logger->LogDebug("No sections found, creating default section"); + // User overrode the base address or we couldn't find the symbol table + m_logger->LogWarn("Creating default .text section over everything..."); AddAutoSection(".text", m_imageBase, m_parentView->GetLength(), ReadOnlyCodeSectionSemantics); return; } // Sort section information by start address (section w/ highest start address first) + m_logger->LogWarn("Creating sections from VxWorks symbol table entry ranges..."); std::sort(m_sections.begin(), m_sections.end(), [](const VxWorksSectionInfo& a, const VxWorksSectionInfo& b) { return a.AddressRange.first > b.AddressRange.first; @@ -439,25 +482,6 @@ void VxWorksView::AddSections() } -void VxWorksView::DetermineEntryPoint() -{ - m_entryPoint = m_imageBase; - if (m_sysInit) - { - // If we found the sysInit function in the symbol table, use it - m_entryPoint = m_sysInit; - return; - } - - for (const auto& section : m_sections) - { - // No symbol table, set the entry point to the start of .text, likely the sysInit function - if (section.Name == ".text") - m_entryPoint = section.AddressRange.first; - } -} - - bool VxWorksView::Init() { try @@ -473,8 +497,9 @@ bool VxWorksView::Init() m_hasSymbolTable = FindSymbolTable(&reader); if (m_hasSymbolTable) { - DetermineImageBaseFromSymbols(); - m_entryPoint = m_imageBase; // This will get updated later if the sysInit symbol is found + DetermineImageBaseFromSymbols(&reader); + uint64_t sysInit = FindSysInit(&reader, m_determinedImagebase); + m_entryPoint = sysInit ? sysInit : m_imageBase; } else { @@ -516,18 +541,21 @@ bool VxWorksView::Init() if (m_hasSymbolTable) { - ProcessSymbolTable(&reader); + if (m_determinedImagebase != m_imageBase) + m_logger->LogWarn("VxWorks image base overriden by user. Not applying symbols..."); + else + ProcessSymbolTable(&reader); + DefineSymbolTableDataVariable(); } AddSections(); - DetermineEntryPoint(); AddEntryPointForAnalysis(m_platform, m_entryPoint); return true; } catch (std::exception& e) { - m_logger->LogError("Failed to load VxWorks image: %s", e.what()); + m_logger->LogError("Failed to parse VxWorks image: %s", e.what()); return false; } @@ -535,6 +563,12 @@ bool VxWorksView::Init() } +uint64_t VxWorksView::PerformGetStart() const +{ + return m_imageBase; +} + + uint64_t VxWorksView::PerformGetEntryPoint() const { return m_entryPoint; @@ -628,12 +662,18 @@ Ref VxWorksViewType::GetLoadSettingsForData(BinaryView *data) if (!viewRef->IsRelocatable()) { - settings->UpdateProperty("loader.imageBase", "default", viewRef->GetEntryPoint()); - settings->UpdateProperty("loader.imageBase", "message", "Note: base address determined from VxWorks symbol table."); + settings->UpdateProperty( + "loader.imageBase", "message", + "Base address determined from discovered VxWorks symbol table. This image is not relocatable.\n" \ + " Overriding this value will degrade analysis and is NOT recommended." + ); } else { - settings->UpdateProperty("loader.imageBase", "message", "VxWorks symbol table was not found. Base address must be set manually."); + settings->UpdateProperty( + "loader.imageBase", "message", + "VxWorks symbol table was not found. Set the base address manually." + ); } return settings; diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index ca1d133246..4e608cb0d3 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -87,10 +87,9 @@ namespace BinaryNinja bool m_hasSymbolTable = false; uint64_t m_symbolTableOffset = 0; uint64_t m_entryPoint = 0; - uint64_t m_imageBase = 0; - uint64_t m_sysInit = 0; // Entrypoint, if we find it in the symbol table + uint64_t m_determinedImagebase = 0; // Determined from analysis of the symbol table + uint64_t m_imageBase = 0; // Selected image base that could be overriden by user std::vector m_sections; - VxWorksVersion m_version = VxWorksUnknownVersion; std::vector m_symbols; @@ -106,9 +105,12 @@ namespace BinaryNinja VxWorksSymbolEntry& entry, VxWorksVersion version); bool ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion version, BNEndianness endianness); bool FindSymbolTable(BinaryReader *reader); - void DetermineImageBaseFromSymbols(); + uint64_t FindSysInit(BinaryReader *reader, uint64_t imageBase); + void AdjustImageBaseForHeaderIfPresent(BinaryReader* reader); + void DetermineImageBaseFromSymbols(BinaryReader* reader); protected: + virtual uint64_t PerformGetStart() const override; virtual uint64_t PerformGetEntryPoint() const override; virtual bool PerformIsExecutable() const override { return true; } virtual BNEndianness PerformGetDefaultEndianness() const override { return m_endianness; } From ac362ddf8b89084208473045ddd715c68ac83428 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Wed, 3 Jul 2024 16:11:06 -0400 Subject: [PATCH 09/14] Verifying symbol names in VxWorks symtab --- view/vxworks/vxworksview.cpp | 43 ++++++++++++++++++++++++++++++------ view/vxworks/vxworksview.h | 18 +++++++-------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index eb07753451..2b76010da8 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -77,6 +77,15 @@ VxWorksView::VxWorksView(BinaryView* data, bool parseOnly): BinaryView("VxWorks" m_logger = CreateLogger("BinaryView.VxWorksView"); } + +bool VxWorksView::IsASCIIString(std::string &s) +{ + return !std::any_of(s.begin(), s.end(), [](char c) { + return static_cast(c) > 127; + }); +} + + void VxWorksView::DefineSymbolTableDataVariable() { StructureBuilder symbolTableEntry; @@ -152,10 +161,10 @@ void VxWorksView::AdjustImageBaseForHeaderIfPresent(BinaryReader *reader) return; // Likely not a header // Meets size constraints, now verify that a symbol name address aligns with a known symbol name before adjusting - if (FindSysInit(reader, m_determinedImagebase - possibleHeaderSz)) + if (FindSysInit(reader, m_determinedImageBase - possibleHeaderSz)) { m_logger->LogDebug("sysInit found, adjusting base address by 0x%08x bytes", possibleHeaderSz); - m_determinedImagebase -= possibleHeaderSz; + m_determinedImageBase -= possibleHeaderSz; } } @@ -183,10 +192,10 @@ void VxWorksView::DetermineImageBaseFromSymbols(BinaryReader* reader) return; } - m_determinedImagebase = lowestTextAddress; + m_determinedImageBase = lowestTextAddress; AdjustImageBaseForHeaderIfPresent(reader); m_logger->LogDebug("Determined image base address: 0x%016x", lowestTextAddress); - m_imageBase = m_determinedImagebase; + m_imageBase = m_determinedImageBase; } @@ -365,6 +374,7 @@ void VxWorksView::AssignSymbolToSection(std::map } +#define MAX_BAD_SYMBOLS_BEFORE_ABORT 10 void VxWorksView::ProcessSymbolTable(BinaryReader *reader) { std::map> sections = { @@ -374,6 +384,7 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) { ".symtab", {} }, }; + size_t badSymbols = 0; for (const auto& entry : m_symbols) { reader->Seek(entry.name - m_imageBase); @@ -412,10 +423,28 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) return; } + // While our scanning code for symbol table discovery has been tested, false positives are possible. + if (!IsASCIIString(symbolName) || symbolName.empty()) + { + if (badSymbols < MAX_BAD_SYMBOLS_BEFORE_ABORT) // Hush after reporting 10 bad symbols + m_logger->LogWarn("Symbol entry name for 0x%016x is invalid", entry.address); + + badSymbols++; + if (badSymbols == MAX_BAD_SYMBOLS_BEFORE_ABORT) + { + m_logger->LogWarn( + "%d or more symbols contain invalid names. VxWorks symbol table might not be a " \ + "symbol table at all! Please, report this issue.", MAX_BAD_SYMBOLS_BEFORE_ABORT + ); + return; + } + + continue; + } + if (m_parentView->IsOffsetBackedByFile(entry.address - m_imageBase)) { AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); - // TODO: make sure symbolName only contains ASCII DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address)); } } @@ -498,7 +527,7 @@ bool VxWorksView::Init() if (m_hasSymbolTable) { DetermineImageBaseFromSymbols(&reader); - uint64_t sysInit = FindSysInit(&reader, m_determinedImagebase); + uint64_t sysInit = FindSysInit(&reader, m_determinedImageBase); m_entryPoint = sysInit ? sysInit : m_imageBase; } else @@ -541,7 +570,7 @@ bool VxWorksView::Init() if (m_hasSymbolTable) { - if (m_determinedImagebase != m_imageBase) + if (m_determinedImageBase != m_imageBase) m_logger->LogWarn("VxWorks image base overriden by user. Not applying symbols..."); else ProcessSymbolTable(&reader); diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index 4e608cb0d3..946453e9be 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -87,27 +87,27 @@ namespace BinaryNinja bool m_hasSymbolTable = false; uint64_t m_symbolTableOffset = 0; uint64_t m_entryPoint = 0; - uint64_t m_determinedImagebase = 0; // Determined from analysis of the symbol table + uint64_t m_determinedImageBase = 0; // Determined from analysis of the symbol table uint64_t m_imageBase = 0; // Selected image base that could be overriden by user std::vector m_sections; VxWorksVersion m_version = VxWorksUnknownVersion; std::vector m_symbols; private: - void DetermineEntryPoint(); - void AddSections(); - void AssignSymbolToSection(std::map>& sections, - BNSymbolType bnSymbolType, uint8_t vxSymbolType, uint64_t address); + bool IsASCIIString(std::string &s); void DefineSymbolTableDataVariable(); - void ProcessSymbolTable(BinaryReader *reader); + uint64_t FindSysInit(BinaryReader *reader, uint64_t imageBase); + void AdjustImageBaseForHeaderIfPresent(BinaryReader* reader); + void DetermineImageBaseFromSymbols(BinaryReader* reader); bool FunctionAddressesAreValid(VxWorksVersion version); bool TryReadVxWorksSymbolEntry(BinaryReader *reader, uint64_t offset, VxWorksSymbolEntry& entry, VxWorksVersion version); bool ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion version, BNEndianness endianness); bool FindSymbolTable(BinaryReader *reader); - uint64_t FindSysInit(BinaryReader *reader, uint64_t imageBase); - void AdjustImageBaseForHeaderIfPresent(BinaryReader* reader); - void DetermineImageBaseFromSymbols(BinaryReader* reader); + void AssignSymbolToSection(std::map>& sections, + BNSymbolType bnSymbolType, uint8_t vxSymbolType, uint64_t address); + void ProcessSymbolTable(BinaryReader *reader); + void AddSections(); protected: virtual uint64_t PerformGetStart() const override; From 1ba43b266cde1685fc3292a4d80e4956d61d0aa3 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Mon, 8 Jul 2024 16:16:05 -0400 Subject: [PATCH 10/14] Added custom platforms for VxWorks --- platform/vxworks/CMakeLists.txt | 33 +++++ platform/vxworks/platform_vxworks.cpp | 183 ++++++++++++++++++++++++++ view/vxworks/vxworksview.cpp | 16 ++- 3 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 platform/vxworks/CMakeLists.txt create mode 100644 platform/vxworks/platform_vxworks.cpp diff --git a/platform/vxworks/CMakeLists.txt b/platform/vxworks/CMakeLists.txt new file mode 100644 index 0000000000..67acf2dcf9 --- /dev/null +++ b/platform/vxworks/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.9 FATAL_ERROR) + +project(platform_vxworks) + +if(NOT BN_INTERNAL_BUILD) + add_subdirectory(${PROJECT_SOURCE_DIR}/../.. ${PROJECT_BINARY_DIR}/api) +endif() + +file(GLOB SOURCES + *.cpp + *.h) + +if(DEMO) + add_library(platform_vxworks STATIC ${SOURCES}) +else() + add_library(platform_vxworks SHARED ${SOURCES}) +endif() + +target_link_libraries(platform_vxworks binaryninjaapi) + +set_target_properties(platform_vxworks PROPERTIES + CXX_STANDARD 17 + CXX_VISIBILITY_PRESET hidden + CXX_STANDARD_REQUIRED ON + VISIBILITY_INLINES_HIDDEN ON + POSITION_INDEPENDENT_CODE ON) + +if(BN_INTERNAL_BUILD) + plugin_rpath(platform_vxworks) + set_target_properties(platform_vxworks PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR} + RUNTIME_OUTPUT_DIRECTORY ${BN_CORE_PLUGIN_DIR}) +endif() diff --git a/platform/vxworks/platform_vxworks.cpp b/platform/vxworks/platform_vxworks.cpp new file mode 100644 index 0000000000..3156ef5666 --- /dev/null +++ b/platform/vxworks/platform_vxworks.cpp @@ -0,0 +1,183 @@ +#include "binaryninjaapi.h" + +using namespace BinaryNinja; +using namespace std; + +Ref g_vxWorksX86, g_vxWorksX64, g_vxWorksArm, g_vxWorksArm64, g_vxWorksThumb; +Ref g_vxWorksMips32, g_vxWorksMips64, g_vxWorksPpc32, g_vxWorksPpc64; +Ref g_vxWorksRiscV32, g_vxWorksRiscv64; + + +class VxWorksIntelPlatform : public Platform +{ +public: + VxWorksIntelPlatform(Architecture* arch, const std::string& name) : Platform(arch, name) + { + Ref cc; + cc = arch->GetCallingConventionByName("cdecl"); + if (cc) + { + RegisterDefaultCallingConvention(cc); + RegisterCdeclCallingConvention(cc); + RegisterFastcallCallingConvention(cc); + RegisterStdcallCallingConvention(cc); + } + } +}; + +class VxWorksArmPlatform : public Platform +{ +public: + VxWorksArmPlatform(Architecture* arch, const std::string& name) : Platform(arch, name) + { + Ref cc; + cc = arch->GetCallingConventionByName("cdecl"); + if (cc) + { + RegisterDefaultCallingConvention(cc); + RegisterCdeclCallingConvention(cc); + RegisterFastcallCallingConvention(cc); + RegisterStdcallCallingConvention(cc); + } + } +}; + +class VxWorksMipsPlatform : public Platform +{ +public: + VxWorksMipsPlatform(Architecture* arch, const std::string& name) : Platform(arch, name) + { + Ref cc; + cc = arch->GetCallingConventionByName("o32"); + if (cc) + { + RegisterDefaultCallingConvention(cc); + RegisterCdeclCallingConvention(cc); + RegisterFastcallCallingConvention(cc); + RegisterStdcallCallingConvention(cc); + } + } +}; + +class VxWorksPpcPlatform : public Platform +{ +public: + VxWorksPpcPlatform(Architecture* arch, const std::string& name): Platform(arch, name) + { + Ref cc; + cc = arch->GetCallingConventionByName("svr4"); + if (cc) + RegisterDefaultCallingConvention(cc); + } +}; + +class VxWorksRiscVPlatform : public Platform +{ +public: + VxWorksRiscVPlatform(Architecture* arch, const std::string& name): Platform(arch, name) + { + Ref cc; + cc = arch->GetCallingConventionByName("default"); + if (cc) + { + RegisterDefaultCallingConvention(cc); + RegisterCdeclCallingConvention(cc); + RegisterFastcallCallingConvention(cc); + RegisterStdcallCallingConvention(cc); + } + } +}; + +extern "C" +{ + BN_DECLARE_CORE_ABI_VERSION + +#ifndef DEMO_VERSION + BINARYNINJAPLUGIN void CorePluginDependencies() + { + AddOptionalPluginDependency("arch_x86"); + AddOptionalPluginDependency("arch_armv7"); + AddOptionalPluginDependency("arch_arm64"); + AddOptionalPluginDependency("arch_mips"); + AddOptionalPluginDependency("arch_ppc"); + AddOptionalPluginDependency("arch_riscv"); + } +#endif + +#ifdef DEMO_VERSION + bool VxWorksPluginInit() +#else + BINARYNINJAPLUGIN bool CorePluginInit() +#endif + { + Ref vx = BinaryViewType::GetByName("VxWorks"); + if (!vx) + return true; + + Ref x86 = Architecture::GetByName("x86"); + Ref x64 = Architecture::GetByName("x86_64"); + if (x86 && x64) + { + g_vxWorksX86 = new VxWorksIntelPlatform(x86, "vxworks-x86"); + Platform::Register("vxworks", g_vxWorksX86); + BinaryViewType::RegisterDefaultPlatform("VxWorks", x86, g_vxWorksX86); + g_vxWorksX64 = new VxWorksIntelPlatform(x64, "vxworks-x86_64"); + Platform::Register("vxworks", g_vxWorksX64); + BinaryViewType::RegisterDefaultPlatform("VxWorks", x64, g_vxWorksX64); + } + + Ref armv7 = Architecture::GetByName("armv7"); + Ref thumb2 = Architecture::GetByName("thumb2"); + Ref arm64 = Architecture::GetByName("aarch64"); + if (armv7 && thumb2) + { + g_vxWorksArm = new VxWorksArmPlatform(armv7, "vxworks-armv7"); + Platform::Register("vxworks", g_vxWorksArm); + BinaryViewType::RegisterDefaultPlatform("VxWorks", armv7, g_vxWorksArm); + g_vxWorksThumb = new VxWorksArmPlatform(thumb2, "vxworks-thumb2"); + Platform::Register("vxworks", g_vxWorksThumb); + BinaryViewType::RegisterDefaultPlatform("VxWorks", thumb2, g_vxWorksThumb); + g_vxWorksArm64 = new VxWorksArmPlatform(arm64, "vxworks-aarch64"); + Platform::Register("vxworks", g_vxWorksArm64); + BinaryViewType::RegisterDefaultPlatform("VxWorks", arm64, g_vxWorksArm64); + } + + Ref mips32 = Architecture::GetByName("mips32"); + Ref mips64 = Architecture::GetByName("mips64"); + if (mips64 && mips32) + { + g_vxWorksMips32 = new VxWorksMipsPlatform(mips32, "vxworks-mips32"); + Platform::Register("vxworks", g_vxWorksMips32); + BinaryViewType::RegisterDefaultPlatform("VxWorks", mips32, g_vxWorksMips32); + g_vxWorksMips64 = new VxWorksMipsPlatform(mips64, "vxworks-mips64"); + Platform::Register("vxworks", g_vxWorksMips64); + BinaryViewType::RegisterDefaultPlatform("VxWorks", mips64, g_vxWorksMips64); + } + + Ref ppc32 = Architecture::GetByName("ppc"); + Ref ppc64 = Architecture::GetByName("ppc64"); + if (ppc32 && ppc64) + { + g_vxWorksPpc32 = new VxWorksPpcPlatform(ppc32, "vxworks-ppc32"); + Platform::Register("vxworks", g_vxWorksPpc32); + BinaryViewType::RegisterDefaultPlatform("VxWorks", ppc32, g_vxWorksPpc32); + g_vxWorksPpc64 = new VxWorksPpcPlatform(ppc64, "vxworks-ppc64"); + Platform::Register("vxworks", g_vxWorksPpc64); + BinaryViewType::RegisterDefaultPlatform("VxWorks", ppc64, g_vxWorksPpc64); + } + + Ref riscv32 = Architecture::GetByName("rv32gc"); + Ref riscv64 = Architecture::GetByName("rv64gc"); + if (riscv32 && riscv64) + { + g_vxWorksRiscV32 = new VxWorksRiscVPlatform(riscv32, "vxworks-rv32gc"); + Platform::Register("vxworks", g_vxWorksRiscV32); + BinaryViewType::RegisterDefaultPlatform("VxWorks", riscv32, g_vxWorksRiscV32); + g_vxWorksRiscv64 = new VxWorksRiscVPlatform(riscv64, "vxworks-rv64gc"); + Platform::Register("vxworks", g_vxWorksRiscv64); + BinaryViewType::RegisterDefaultPlatform("VxWorks", riscv64, g_vxWorksRiscv64); + } + + return true; + } +} \ No newline at end of file diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 2b76010da8..c219faef3d 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -17,7 +17,7 @@ using namespace std; static const std::map VxWorks5SymbolTypeMap = { { VxWorks5UndefinedSymbolType, FunctionSymbol }, - { VxWorks5GlobalExternalSymbolType, ImportAddressSymbol }, + { VxWorks5GlobalExternalSymbolType, ExternalSymbol }, { VxWorks5LocalAbsoluteSymbolType, DataSymbol }, { VxWorks5GlobalAbsoluteSymbolType, DataSymbol }, { VxWorks5LocalTextSymbolType, FunctionSymbol }, @@ -36,7 +36,7 @@ static const std::map VxWorks5SymbolTypeMap = static const std::map VxWorks6SymbolTypeMap = { { VxWorks6UndefinedSymbolType, FunctionSymbol }, - { VxWorks6GlobalExternalSymbolType, ImportAddressSymbol }, + { VxWorks6GlobalExternalSymbolType, ExternalSymbol }, { VxWorks6LocalAbsoluteSymbolType, DataSymbol }, { VxWorks6GlobalAbsoluteSymbolType, DataSymbol }, { VxWorks6LocalTextSymbolType, FunctionSymbol }, @@ -359,7 +359,6 @@ void VxWorksView::AssignSymbolToSection(std::map { case FunctionSymbol: sections[".text"].insert(address); - AddFunctionForAnalysis(m_platform, address); break; case DataSymbol: sections[".data"].insert(address); @@ -385,6 +384,7 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) }; size_t badSymbols = 0; + NameSpace nameSpace = GetInternalNameSpace(); for (const auto& entry : m_symbols) { reader->Seek(entry.name - m_imageBase); @@ -445,7 +445,15 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) if (m_parentView->IsOffsetBackedByFile(entry.address - m_imageBase)) { AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); - DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address)); + auto symbol = new Symbol(bnSymbolType, symbolName, entry.address, GlobalBinding, nameSpace); + Ref type = nullptr; + if (bnSymbolType == FunctionSymbol) + type = m_platform->GetFunctionByName(symbolName); + else if (bnSymbolType == DataSymbol) + type = m_platform->GetTypeByName(symbolName); + + // TODO: not sure why the type is not being applied here + DefineAutoSymbolAndVariableOrFunction(m_platform, symbol, type); } } From f10d38faaa087d78379119b9f4bfcac48ced166e Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Wed, 10 Jul 2024 10:59:04 -0400 Subject: [PATCH 11/14] Applying VxWorks platform types to symbols --- view/vxworks/vxworksview.cpp | 42 +++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index c219faef3d..6bf52f822c 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -384,7 +384,6 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) }; size_t badSymbols = 0; - NameSpace nameSpace = GetInternalNameSpace(); for (const auto& entry : m_symbols) { reader->Seek(entry.name - m_imageBase); @@ -444,16 +443,29 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) if (m_parentView->IsOffsetBackedByFile(entry.address - m_imageBase)) { - AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); - auto symbol = new Symbol(bnSymbolType, symbolName, entry.address, GlobalBinding, nameSpace); - Ref type = nullptr; + NameSpace nameSpace = GetInternalNameSpace(); + if (bnSymbolType == ExternalSymbol) + nameSpace = GetExternalNameSpace(); + if (bnSymbolType == FunctionSymbol) - type = m_platform->GetFunctionByName(symbolName); - else if (bnSymbolType == DataSymbol) - type = m_platform->GetTypeByName(symbolName); + { + auto func = AddFunctionForAnalysis(GetDefaultPlatform(), entry.address); + auto typeRef = GetDefaultPlatform()->GetFunctionByName(symbolName); + if (func && typeRef) + func->ApplyAutoDiscoveredType(typeRef); + } + + if (bnSymbolType == DataSymbol) + { + auto typeRef = GetDefaultPlatform()->GetVariableByName(symbolName); + if (typeRef) + DefineDataVariable(entry.address, typeRef->WithConfidence(BN_FULL_CONFIDENCE)); + else + DefineDataVariable(entry.address, Type::VoidType()->WithConfidence(0)); + } - // TODO: not sure why the type is not being applied here - DefineAutoSymbolAndVariableOrFunction(m_platform, symbol, type); + DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address, LocalBinding, nameSpace)); + AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); } } @@ -575,19 +587,23 @@ bool VxWorksView::Init() AddAutoSegment(m_imageBase, m_parentView->GetLength(), 0, m_parentView->GetLength(), SegmentReadable | SegmentWritable | SegmentExecutable); + AddSections(); + AddEntryPointForAnalysis(m_platform, m_entryPoint); if (m_hasSymbolTable) { + DefineSymbolTableDataVariable(); if (m_determinedImageBase != m_imageBase) + { m_logger->LogWarn("VxWorks image base overriden by user. Not applying symbols..."); + } else + { ProcessSymbolTable(&reader); - - DefineSymbolTableDataVariable(); + EndBulkModifySymbols(); + } } - AddSections(); - AddEntryPointForAnalysis(m_platform, m_entryPoint); return true; } catch (std::exception& e) From c4626934c78a7af8f6a861f0cbfccddc547244a4 Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Wed, 10 Jul 2024 12:15:25 -0400 Subject: [PATCH 12/14] Demangling mangled VxWorks symbols Also added More checks for VxWorks IsTypeValidForData --- view/vxworks/vxworksview.cpp | 92 ++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 24 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 6bf52f822c..5dcf6bc499 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -441,32 +441,65 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) continue; } - if (m_parentView->IsOffsetBackedByFile(entry.address - m_imageBase)) + if (!m_parentView->IsOffsetBackedByFile(entry.address - m_imageBase)) + continue; + + NameSpace nameSpace = GetInternalNameSpace(); + if (bnSymbolType == ExternalSymbol) + nameSpace = GetExternalNameSpace(); + + Ref typeRef = nullptr; + if (bnSymbolType == FunctionSymbol) + { + auto func = AddFunctionForAnalysis(GetDefaultPlatform(), entry.address); + typeRef = GetDefaultPlatform()->GetFunctionByName(symbolName); + if (func && typeRef) + func->ApplyAutoDiscoveredType(typeRef); + } + + if (bnSymbolType == DataSymbol) { - NameSpace nameSpace = GetInternalNameSpace(); - if (bnSymbolType == ExternalSymbol) - nameSpace = GetExternalNameSpace(); + typeRef = GetDefaultPlatform()->GetVariableByName(symbolName); + if (typeRef) + DefineDataVariable(entry.address, typeRef->WithConfidence(BN_FULL_CONFIDENCE)); + else + DefineDataVariable(entry.address, Type::VoidType()->WithConfidence(0)); + } - if (bnSymbolType == FunctionSymbol) + // If name does not start with alphabetic char or symbol, prepend an underscore + string rawName = symbolName; + if (!(((symbolName[0] >= 'A') && (symbolName[0] <= 'Z')) || ((symbolName[0] >= 'a') && + (symbolName[0] <= 'z')) || (symbolName[0] == '_') || (symbolName[0] == '?') || (symbolName[0] == '$') || + (symbolName[0] == '@'))) + rawName = "_" + symbolName; + + string shortName = rawName; + string fullName = rawName; + QualifiedName varName; + if (IsGNU3MangledString(rawName)) + { + Ref demangledType; + if (DemangleGNU3(m_arch, rawName, demangledType, varName)) { - auto func = AddFunctionForAnalysis(GetDefaultPlatform(), entry.address); - auto typeRef = GetDefaultPlatform()->GetFunctionByName(symbolName); - if (func && typeRef) - func->ApplyAutoDiscoveredType(typeRef); + shortName = varName.GetString(); + fullName = shortName; + if (demangledType) + { + fullName += demangledType->GetStringAfterName(); + if (!typeRef) + typeRef = demangledType; + } } - - if (bnSymbolType == DataSymbol) + else if (DemangleLLVM(rawName, varName)) { - auto typeRef = GetDefaultPlatform()->GetVariableByName(symbolName); - if (typeRef) - DefineDataVariable(entry.address, typeRef->WithConfidence(BN_FULL_CONFIDENCE)); - else - DefineDataVariable(entry.address, Type::VoidType()->WithConfidence(0)); + shortName = varName.GetString(); + fullName = shortName; } - - DefineAutoSymbol(new Symbol(bnSymbolType, symbolName, entry.address, LocalBinding, nameSpace)); - AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); } + + DefineAutoSymbol(new Symbol(bnSymbolType, shortName, fullName, rawName, + entry.address, LocalBinding, nameSpace)); + AssignSymbolToSection(sections, bnSymbolType, vxSymbolType, entry.address); } // Build section info from address ranges of symbols and their types @@ -670,9 +703,10 @@ Ref VxWorksViewType::Parse(BinaryView* data) bool VxWorksViewType::IsTypeValidForData(BinaryView* data) { + // Every VxWorks image I've seen has "VxWorks" and "Wind River Systems, Inc." (in copyright strings) std::stringstream ss; ss << "{" - "\"pattern\":\"VxWorks\"," + "\"pattern\":\"VxWorks\\u0000|Wind River Systems, Inc.\"," "\"start\":0," "\"end\":" << data->GetLength()-1 << "," "\"raw\":false," @@ -681,17 +715,27 @@ bool VxWorksViewType::IsTypeValidForData(BinaryView* data) "\"align\":1" "}"; - bool isValid = false;; - auto StringSearchCallback = [&isValid](size_t index, const DataBuffer& dataBuffer) -> bool + bool hasVxWorksString = false; + bool hasWindRiverString = false; + auto StringSearchCallback = [&hasVxWorksString, &hasWindRiverString](size_t index, const DataBuffer& dataBuffer) -> bool { - isValid = true; + auto data = dataBuffer.GetData(); + if (!strcmp((const char *)data, "VxWorks")) + hasVxWorksString = true; + else if (!strcmp((const char *)data, "Wind River Systems, Inc.")) + hasWindRiverString = true; return true; }; if (!data->Search(string(ss.str()), StringSearchCallback)) m_logger->LogWarn("Error while searching for VxWorks signatures in raw view"); - return isValid; + // If we don't find VxWorks-related strings, bail before scanning + if (!hasVxWorksString || !hasWindRiverString) + return false; + + // TODO: scan for system table (requires rework of VxWorksView::FindSymbolTable) + return true; } From 404e144d4aee15ab1f69fb47a7d7abdfa67aff4b Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Tue, 23 Jul 2024 11:45:51 -0400 Subject: [PATCH 13/14] Scan for symtab in VxWorks view IsTypeValidForData Moved scanning code out of VxWorksView class so it can be used by both VxWorksView and VxWorksViewType classes --- view/vxworks/vxworksview.cpp | 344 +++++++++++++++++++---------------- view/vxworks/vxworksview.h | 5 - 2 files changed, 185 insertions(+), 164 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 5dcf6bc499..4ea3f03268 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -62,6 +62,179 @@ static const std::map VxWorksSectionSemanticsMa static VxWorksViewType* g_vxWorksViewType = nullptr; + +// Check least significant byte of the first 10 function symbol addresses to make sure they aren't all the same +static bool FunctionAddressesAreValid(VxWorksVersion version, std::vector& symbols) +{ + std::vector funcAddresses; + for (const auto& entry : symbols) + { + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + if (version == VxWorksVersion5 && type != VxWorks5GlobalTextSymbolType) + continue; + + if (version == VxWorksVersion6 && type != VxWorks6GlobalTextSymbolType) + continue; + + funcAddresses.push_back(entry.address); + if (funcAddresses.size() == MAX_ADDRESSES_ENDIANNESS_CHECK) + { + uint32_t val = 0; + for (const auto& addr : funcAddresses) + val ^= addr; + return (val & 0xff) != 0; + } + } + + // Too few symbols to check + return false; +} + + +static bool TryReadVxWorksSymbolEntry(BinaryReader *reader, uint64_t offset, + VxWorksSymbolEntry& entry, VxWorksVersion version, Logger* logger) +{ + reader->Seek(offset + 4); // Skip first unknown field + if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address)) + return false; + + if (version == VxWorksVersion6) + reader->Seek(offset + 16); // Skip second unknown field (VxWorks 6 only) + + if (!reader->TryReadBE32(entry.flags)) + return false; + + uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); + switch (version) + { + case VxWorksVersion5: + { + auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); + if (entry.name != 0 && entry.flags != 0 && it != VxWorks5SymbolTypeMap.end()) + return true; + + return false; + } + case VxWorksVersion6: + { + auto it = VxWorks6SymbolTypeMap.find((VxWorks6SymbolType)type); + if (entry.name != 0 && it != VxWorks6SymbolTypeMap.end()) + return true; + + return false; + } + default: + logger->LogError("VxWorks version is not set. Please report this issue."); + return false; + } +} + + +static bool ScanForVxWorksSymbolTable(BinaryReader* reader, size_t dataSize, VxWorksVersion version, + std::vector& symbols, uint64_t* symbolTableOffset, Logger* logger) +{ + size_t entrySize; + BNEndianness endianness = reader->GetEndianness(); + switch (version) + { + case VxWorksVersion5: + entrySize = VXWORKS5_SYMBOL_ENTRY_SIZE; + break; + case VxWorksVersion6: + entrySize = VXWORKS6_SYMBOL_ENTRY_SIZE; + break; + default: + logger->LogError("VxWorks version is not set. Please report this issue."); + return false; + } + + VxWorksSymbolEntry entry; + ssize_t startOffset = ALIGN4(dataSize - entrySize); + ssize_t endOffset = 0; + if (dataSize > MAX_SYMBOL_TABLE_REGION_SIZE) + endOffset = ALIGN4(dataSize - MAX_SYMBOL_TABLE_REGION_SIZE); + ssize_t searchPos = startOffset; + std::vector foundNames; + + logger->LogDebug("Scanning backwards for VxWorks symbol table (0x%016x-0x%016x) (endianess=%s) (version=%d)...", + startOffset, endOffset, endianness == BigEndian ? "big" : "little", version == VxWorksVersion5 ? 5 : 6); + while (searchPos > endOffset) + { + if (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version, logger) && + find(foundNames.begin(), foundNames.end(), entry.name) == foundNames.end()) + { + foundNames.push_back(entry.address); + symbols.push_back(entry); + searchPos -= entrySize; + continue; + } + + if (symbols.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(version, symbols)) + break; + + searchPos -= 4; + foundNames.clear(); + symbols.clear(); + } + + if (symbols.size() < MIN_VALID_SYMBOL_ENTRIES) + { + symbols.clear(); + return false; + } + + *symbolTableOffset = searchPos + entrySize; + + // Scan algorithm is prone to missing a few entries at the end of the table + searchPos = *symbolTableOffset + (entrySize * symbols.size()); + while (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version, logger)) + { + symbols.push_back(entry); + searchPos += entrySize; + } + + logger->LogDebug("Found %d VxWorks %d symbol table entries starting at offset 0x%016x", + symbols.size(), version == VxWorksVersion5 ? 5 : 6, *symbolTableOffset); + + return true; +} + + +static bool FindVxWorksSymbolTable(BinaryReader* reader, size_t dataSize, std::vector& symbols, + VxWorksVersion *version, uint64_t* symbolTableOffset, Logger *logger) +{ + reader->SetEndianness(BigEndian); + if (ScanForVxWorksSymbolTable(reader, dataSize, VxWorksVersion5, symbols, symbolTableOffset, logger)) + { + *version = VxWorksVersion5; + return true; + } + + reader->SetEndianness(LittleEndian); + if (ScanForVxWorksSymbolTable(reader, dataSize, VxWorksVersion5, symbols, symbolTableOffset, logger)) + { + *version = VxWorksVersion5; + return true; + } + + reader->SetEndianness(BigEndian); + if (ScanForVxWorksSymbolTable(reader, dataSize, VxWorksVersion6, symbols, symbolTableOffset, logger)) + { + *version = VxWorksVersion6; + return true; + } + + reader->SetEndianness(LittleEndian); + if (ScanForVxWorksSymbolTable(reader, dataSize, VxWorksVersion6, symbols, symbolTableOffset, logger)) + { + *version = VxWorksVersion6; + return true; + } + + return false; +} + + void BinaryNinja::InitVxWorksViewType() { static VxWorksViewType type; @@ -81,8 +254,8 @@ VxWorksView::VxWorksView(BinaryView* data, bool parseOnly): BinaryView("VxWorks" bool VxWorksView::IsASCIIString(std::string &s) { return !std::any_of(s.begin(), s.end(), [](char c) { - return static_cast(c) > 127; - }); + return static_cast(c) > 127; + }); } @@ -199,159 +372,6 @@ void VxWorksView::DetermineImageBaseFromSymbols(BinaryReader* reader) } -// Check least significant byte of the first 10 function symbol addresses to make sure they aren't all the same -bool VxWorksView::FunctionAddressesAreValid(VxWorksVersion version) -{ - std::vector funcAddresses; - for (const auto& entry : m_symbols) - { - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - if (version == VxWorksVersion5 && type != VxWorks5GlobalTextSymbolType) - continue; - - if (version == VxWorksVersion6 && type != VxWorks6GlobalTextSymbolType) - continue; - - funcAddresses.push_back(entry.address); - if (funcAddresses.size() == MAX_ADDRESSES_ENDIANNESS_CHECK) - { - uint32_t val = 0; - for (const auto& addr : funcAddresses) - val ^= addr; - return (val & 0xff) != 0; - } - } - - // Too few symbols to check - return false; -} - - -bool VxWorksView::TryReadVxWorksSymbolEntry(BinaryReader *reader, uint64_t offset, - VxWorksSymbolEntry& entry, VxWorksVersion version) -{ - reader->Seek(offset + 4); // Skip first unknown field - if (!reader->TryRead32(entry.name) || !reader->TryRead32(entry.address)) - return false; - - if (version == VxWorksVersion6) - reader->Seek(offset + 16); // Skip second unknown field (VxWorks 6 only) - - if (!reader->TryReadBE32(entry.flags)) - return false; - - uint8_t type = VXWORKS_SYMBOL_ENTRY_TYPE(entry.flags); - switch (version) - { - case VxWorksVersion5: - { - auto it = VxWorks5SymbolTypeMap.find((VxWorks5SymbolType)type); - if (entry.name != 0 && entry.flags != 0 && it != VxWorks5SymbolTypeMap.end()) - return true; - - return false; - } - case VxWorksVersion6: - { - auto it = VxWorks6SymbolTypeMap.find((VxWorks6SymbolType)type); - if (entry.name != 0 && it != VxWorks6SymbolTypeMap.end()) - return true; - - return false; - } - default: - m_logger->LogError("VxWorks version is not set. Please report this issue."); - return false; - } -} - - -bool VxWorksView::ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion version, BNEndianness endianness) -{ - size_t entrySize; - m_endianness = endianness; - reader->SetEndianness(m_endianness); - switch (version) - { - case VxWorksVersion5: - entrySize = VXWORKS5_SYMBOL_ENTRY_SIZE; - break; - case VxWorksVersion6: - entrySize = VXWORKS6_SYMBOL_ENTRY_SIZE; - break; - default: - m_logger->LogError("VxWorks version is not set. Please report this issue."); - return false; - } - - VxWorksSymbolEntry entry; - ssize_t startOffset = ALIGN4(m_parentView->GetLength() - entrySize); - ssize_t endOffset = 0; - if (m_parentView->GetLength() > MAX_SYMBOL_TABLE_REGION_SIZE) - endOffset = ALIGN4(m_parentView->GetLength() - MAX_SYMBOL_TABLE_REGION_SIZE); - ssize_t searchPos = startOffset; - std::vector foundNames; - - m_logger->LogDebug("Scanning backwards for VxWorks system table (0x%016x-0x%016x) (endianess=%s) (version=%d)...", - startOffset, endOffset, m_endianness == BigEndian ? "big" : "little", version == VxWorksVersion5 ? 5 : 6); - while (searchPos > endOffset) - { - if (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version) && - find(foundNames.begin(), foundNames.end(), entry.name) == foundNames.end()) - { - foundNames.push_back(entry.address); - m_symbols.push_back(entry); - searchPos -= entrySize; - continue; - } - - if (m_symbols.size() > MIN_VALID_SYMBOL_ENTRIES && FunctionAddressesAreValid(version)) - break; - - searchPos -= 4; - foundNames.clear(); - m_symbols.clear(); - } - - if (m_symbols.size() < MIN_VALID_SYMBOL_ENTRIES) - { - m_symbols.clear(); - return false; - } - - m_symbolTableOffset = searchPos + entrySize; - - // Scan algorithm is prone to missing a few entries at the end of the table - searchPos = m_symbolTableOffset + (entrySize * m_symbols.size()); - while (TryReadVxWorksSymbolEntry(reader, searchPos, entry, version)) - { - m_symbols.push_back(entry); - searchPos += entrySize; - } - - m_version = version; - m_logger->LogDebug("Found %d VxWorks %d symbol table entries starting at offset 0x%016x", - m_symbols.size(), version == VxWorksVersion5 ? 5 : 6, m_symbolTableOffset); - - return true; -} - - -bool VxWorksView::FindSymbolTable(BinaryReader *reader) -{ - if (ScanForVxWorksSystemTable(reader, VxWorksVersion5, BigEndian)) - return true; - - if (ScanForVxWorksSystemTable(reader, VxWorksVersion5, LittleEndian)) - return true; - - if (ScanForVxWorksSystemTable(reader, VxWorksVersion6, LittleEndian)) - return true; - - return ScanForVxWorksSystemTable(reader, VxWorksVersion6, BigEndian); -} - - void VxWorksView::AssignSymbolToSection(std::map>& sections, BNSymbolType bnSymbolType, uint8_t vxSymbolType, uint64_t address) { @@ -576,9 +596,11 @@ bool VxWorksView::Init() } BinaryReader reader(m_parentView, m_endianness); - m_hasSymbolTable = FindSymbolTable(&reader); + m_hasSymbolTable = FindVxWorksSymbolTable(&reader, m_parentView->GetLength(), m_symbols, + &m_version, &m_symbolTableOffset, m_logger); if (m_hasSymbolTable) { + m_endianness = reader.GetEndianness(); DetermineImageBaseFromSymbols(&reader); uint64_t sysInit = FindSysInit(&reader, m_determinedImageBase); m_entryPoint = sysInit ? sysInit : m_imageBase; @@ -717,7 +739,8 @@ bool VxWorksViewType::IsTypeValidForData(BinaryView* data) bool hasVxWorksString = false; bool hasWindRiverString = false; - auto StringSearchCallback = [&hasVxWorksString, &hasWindRiverString](size_t index, const DataBuffer& dataBuffer) -> bool + auto StringSearchCallback = [&hasVxWorksString, &hasWindRiverString]( + size_t index, const DataBuffer& dataBuffer) -> bool { auto data = dataBuffer.GetData(); if (!strcmp((const char *)data, "VxWorks")) @@ -734,8 +757,11 @@ bool VxWorksViewType::IsTypeValidForData(BinaryView* data) if (!hasVxWorksString || !hasWindRiverString) return false; - // TODO: scan for system table (requires rework of VxWorksView::FindSymbolTable) - return true; + uint64_t symbolTableOffset; + VxWorksVersion version; + std::vector symbols; + return FindVxWorksSymbolTable(new BinaryReader(data), data->GetLength(), symbols, + &version, &symbolTableOffset, m_logger); } diff --git a/view/vxworks/vxworksview.h b/view/vxworks/vxworksview.h index 946453e9be..b8baa4c8c9 100644 --- a/view/vxworks/vxworksview.h +++ b/view/vxworks/vxworksview.h @@ -99,11 +99,6 @@ namespace BinaryNinja uint64_t FindSysInit(BinaryReader *reader, uint64_t imageBase); void AdjustImageBaseForHeaderIfPresent(BinaryReader* reader); void DetermineImageBaseFromSymbols(BinaryReader* reader); - bool FunctionAddressesAreValid(VxWorksVersion version); - bool TryReadVxWorksSymbolEntry(BinaryReader *reader, uint64_t offset, - VxWorksSymbolEntry& entry, VxWorksVersion version); - bool ScanForVxWorksSystemTable(BinaryReader *reader, VxWorksVersion version, BNEndianness endianness); - bool FindSymbolTable(BinaryReader *reader); void AssignSymbolToSection(std::map>& sections, BNSymbolType bnSymbolType, uint8_t vxSymbolType, uint64_t address); void ProcessSymbolTable(BinaryReader *reader); From 0c317c53f6ae18189fd647ffeb68235306ac6c7f Mon Sep 17 00:00:00 2001 From: Brandon Miller Date: Tue, 13 Aug 2024 10:45:09 -0400 Subject: [PATCH 14/14] VxWorks create sections after processing symtab --- view/vxworks/vxworksview.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/view/vxworks/vxworksview.cpp b/view/vxworks/vxworksview.cpp index 4ea3f03268..279eb0bc52 100644 --- a/view/vxworks/vxworksview.cpp +++ b/view/vxworks/vxworksview.cpp @@ -148,12 +148,18 @@ static bool ScanForVxWorksSymbolTable(BinaryReader* reader, size_t dataSize, VxW return false; } + if (dataSize < entrySize) + { + logger->LogWarn("Data size is less than a single VxWorks symbol table entry size"); + return false; + } + VxWorksSymbolEntry entry; - ssize_t startOffset = ALIGN4(dataSize - entrySize); - ssize_t endOffset = 0; + int64_t startOffset = ALIGN4(dataSize - entrySize); + int64_t endOffset = 0; if (dataSize > MAX_SYMBOL_TABLE_REGION_SIZE) endOffset = ALIGN4(dataSize - MAX_SYMBOL_TABLE_REGION_SIZE); - ssize_t searchPos = startOffset; + int64_t searchPos = startOffset; std::vector foundNames; logger->LogDebug("Scanning backwards for VxWorks symbol table (0x%016x-0x%016x) (endianess=%s) (version=%d)...", @@ -539,6 +545,8 @@ void VxWorksView::ProcessSymbolTable(BinaryReader *reader) continue; } + m_logger->LogDebug("symbol section %s ranges from 0x%016x-0x%016x", section.first.c_str(), + *section.second.begin(), *section.second.rbegin()); m_sections.push_back({ { *section.second.begin(), *section.second.rbegin() }, section.first, @@ -642,9 +650,6 @@ bool VxWorksView::Init() AddAutoSegment(m_imageBase, m_parentView->GetLength(), 0, m_parentView->GetLength(), SegmentReadable | SegmentWritable | SegmentExecutable); - AddSections(); - AddEntryPointForAnalysis(m_platform, m_entryPoint); - if (m_hasSymbolTable) { DefineSymbolTableDataVariable(); @@ -659,6 +664,8 @@ bool VxWorksView::Init() } } + AddSections(); + AddEntryPointForAnalysis(m_platform, m_entryPoint); return true; } catch (std::exception& e)