From 7f08117cfeb48a8f48d08e14cb498ee028efcef2 Mon Sep 17 00:00:00 2001 From: Zichuan Li <34680029+river-li@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:53:05 -0400 Subject: Move EFI Resolver to API Support all existing features in EFI Resolver, 1. Doesn't support running on existing BNDBs (though we tried to support this in python plugins, it doesn't work well) 2. Perform analysis on MLIL rather than HLIL, previous pattern matching on HLIL constains many false negatives --- platform/efi/efi_resolver/include/DxeResolver.h | 25 +++++++ platform/efi/efi_resolver/include/GuidRenderer.h | 21 ++++++ platform/efi/efi_resolver/include/ModuleType.h | 22 +++++++ platform/efi/efi_resolver/include/PeiResolver.h | 20 ++++++ platform/efi/efi_resolver/include/Resolver.h | 76 ++++++++++++++++++++++ .../efi/efi_resolver/include/TypePropagation.h | 17 +++++ platform/efi/efi_resolver/include/Utils.h | 36 ++++++++++ 7 files changed, 217 insertions(+) create mode 100644 platform/efi/efi_resolver/include/DxeResolver.h create mode 100644 platform/efi/efi_resolver/include/GuidRenderer.h create mode 100644 platform/efi/efi_resolver/include/ModuleType.h create mode 100644 platform/efi/efi_resolver/include/PeiResolver.h create mode 100644 platform/efi/efi_resolver/include/Resolver.h create mode 100644 platform/efi/efi_resolver/include/TypePropagation.h create mode 100644 platform/efi/efi_resolver/include/Utils.h (limited to 'platform/efi/efi_resolver/include') diff --git a/platform/efi/efi_resolver/include/DxeResolver.h b/platform/efi/efi_resolver/include/DxeResolver.h new file mode 100644 index 00000000..3515b94a --- /dev/null +++ b/platform/efi/efi_resolver/include/DxeResolver.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Resolver.h" + +class DxeResolver : Resolver { + bool resolveBootServices(); + bool resolveRuntimeServices(); + + bool resolveSmmTables(string serviceName, string tableName); + bool resolveSmmServices(); + bool resolveSmiHandlers(); + +public: + /*! + resolve BootServices and RuntimeServices, define protocol types that loaded by BootServices + */ + bool resolveDxe(); + + /*! + Define MMST/SMMST and resolve SMM related protocols + */ + bool resolveSmm(); + + DxeResolver(Ref view, Ref task); +}; \ No newline at end of file diff --git a/platform/efi/efi_resolver/include/GuidRenderer.h b/platform/efi/efi_resolver/include/GuidRenderer.h new file mode 100644 index 00000000..30bd9126 --- /dev/null +++ b/platform/efi/efi_resolver/include/GuidRenderer.h @@ -0,0 +1,21 @@ +#pragma once + +#include "binaryninjaapi.h" +#include + +using namespace BinaryNinja; +using namespace std; + +class EfiGuidRenderer : public BinaryNinja::DataRenderer { + EfiGuidRenderer() = default; + +public: + bool IsValidForData(BinaryView*, uint64_t address, Type*, + vector>&) override; + + vector GetLinesForData( + BinaryView*, uint64_t address, Type*, const vector& prefix, + size_t width, vector>&) override; + + static void Register(); +}; \ No newline at end of file diff --git a/platform/efi/efi_resolver/include/ModuleType.h b/platform/efi/efi_resolver/include/ModuleType.h new file mode 100644 index 00000000..81b579b9 --- /dev/null +++ b/platform/efi/efi_resolver/include/ModuleType.h @@ -0,0 +1,22 @@ +#pragma once + +#include "binaryninjaapi.h" + +using namespace BinaryNinja; + +enum EFIModuleType { + UNKNOWN, + PEI, + DXE, +}; + +static inline EFIModuleType identifyModuleType(BinaryView* bv) +{ + std::string viewType = bv->GetCurrentView(); + if (viewType == "Linear:PE") + return DXE; + else if (viewType == "Linear:TE") + return PEI; + else + return UNKNOWN; +} \ No newline at end of file diff --git a/platform/efi/efi_resolver/include/PeiResolver.h b/platform/efi/efi_resolver/include/PeiResolver.h new file mode 100644 index 00000000..76827a1a --- /dev/null +++ b/platform/efi/efi_resolver/include/PeiResolver.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Resolver.h" + +class PeiResolver : Resolver { + bool resolvePeiIdt(); + bool resolvePeiMrc(); + bool resolvePeiMrs(); + bool resolvePlatformPointers(); + bool resolvePeiDescriptors(); + bool resolvePeiServices(); + +public: + /*! + resolve Pei related types and PPIs, this function will also resolve processor-specific pointers + and tried to define the EFI_PEI_DESCRIPTORS + */ + bool resolvePei(); + PeiResolver(Ref view, Ref task); +}; \ No newline at end of file diff --git a/platform/efi/efi_resolver/include/Resolver.h b/platform/efi/efi_resolver/include/Resolver.h new file mode 100644 index 00000000..7bbd3b99 --- /dev/null +++ b/platform/efi/efi_resolver/include/Resolver.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +#include "GuidRenderer.h" +#include "ModuleType.h" +#include "TypePropagation.h" +#include "binaryninjaapi.h" +#include "highlevelilinstruction.h" +#include "lowlevelilinstruction.h" +#include "mediumlevelilinstruction.h" + +using namespace BinaryNinja; +using namespace std; + +typedef array EFI_GUID; + +class Resolver { +protected: + Ref m_view; + Ref m_task; + size_t m_width; + map> m_protocol; + map m_user_guids; + + vector> m_service_usages; + vector> m_protocol_usages; + vector> m_guid_usages; + vector> m_variable_usages; + + bool parseUserGuidIfExists(const string& filePath); + bool parseProtocolMapping(const string& filePath); + + /*! + For backward compatibility, if a user saved a bndb with older version Binary Ninja + this function will try to retrieve types from Platform Types if it doesn't find one + in BinaryView + */ + Ref GetTypeFromViewAndPlatform(string type_name); + void initProtocolMapping(); + +public: + bool setModuleEntry(EFIModuleType fileType); + bool resolveGuidInterface(Ref func, uint64_t addr, int guid_pos, int interface_pos); + Resolver(Ref view, Ref task); + + pair lookupGuid(EFI_GUID guidBytes); + pair defineAndLookupGuid(uint64_t addr); + + string nonConflictingName(const string& basename); + static string nonConflictingLocalName(Ref func, const string& basename); + + /*! + Define the structure used at the callsite with type `typeName`, propagate it to the data section. If it's a structure type, define it fields + according to the `followFields` parameter. The input `addr` should be a call instruction + \param func the function that contains the callsite (it's parent function) + \param addr address of the callsite + \param typeName the type that need to define + \param paramIdx the parameter index that want to define + \param followFields whether to define the structure's fields if they are pointers + \return False if failed + + \b Example: + \code{.cpp} + refs = bv->GetCodeReferencesForType(QualifiedName("EFI_GET_VARIABLE")); + for (auto ref : refs) + { + // ... some checking, need to make sure is a call instruction + bool ok = defineTypeAtCallsite(ref.func, ref.addr, "EFI_GUID", 2, false); + } + \endcode + */ + bool defineTypeAtCallsite(Ref func, uint64_t addr, string typeName, int paramIdx, bool followFields = false); + vector HighLevelILExprsAt(Ref func, Ref arch, uint64_t addr); +}; \ No newline at end of file diff --git a/platform/efi/efi_resolver/include/TypePropagation.h b/platform/efi/efi_resolver/include/TypePropagation.h new file mode 100644 index 00000000..2ba131ba --- /dev/null +++ b/platform/efi/efi_resolver/include/TypePropagation.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Utils.h" +#include "binaryninjaapi.h" + +using namespace BinaryNinja; + +class TypePropagation { + Ref m_view; + std::deque m_queue; + Ref m_platform; + +public: + TypePropagation(BinaryView* view); + bool propagateFuncParamTypes(Function* func); + bool propagateFuncParamTypes(Function* func, SSAVariable ssa_var); +}; \ No newline at end of file diff --git a/platform/efi/efi_resolver/include/Utils.h b/platform/efi/efi_resolver/include/Utils.h new file mode 100644 index 00000000..f2c371a8 --- /dev/null +++ b/platform/efi/efi_resolver/include/Utils.h @@ -0,0 +1,36 @@ +#pragma once + +#include "binaryninjaapi.h" + +using namespace BinaryNinja; + +static inline std::string GetOriginalTypeName(Ref type) +{ + std::string result; + if (type->IsPointer()) { + if (type->GetChildType().GetValue()->IsNamedTypeRefer()) { + return type->GetChildType().GetValue()->GetNamedTypeReference()->GetName().GetString(); + } + return type->GetTypeName().GetString(); + } + if (type->IsNamedTypeRefer()) + return type->GetNamedTypeReference()->GetName().GetString(); + + return type->GetTypeName().GetString(); +} + +static inline std::string GetVarNameForTypeStr(const std::string typeStr) +{ + std::istringstream iss(typeStr); + std::string word; + std::string result; + + while (std::getline(iss, word, '_')) { + if (!word.empty()) { + word[0] = std::toupper(word[0]); + std::transform(word.begin() + 1, word.end(), word.begin() + 1, ::tolower); + result += word; + } + } + return result; +} -- cgit v1.3.1