diff options
| author | Brandon Miller <brandon@vector35.com> | 2025-05-08 15:08:10 -0400 |
|---|---|---|
| committer | Brandon Miller <brandon@vector35.com> | 2025-05-08 15:08:10 -0400 |
| commit | 5147249a644f611a801aada7645b7a993fc8e314 (patch) | |
| tree | 3a18e50df5ae9edcf31f3545a7f27774021c76a1 /plugins/efi_resolver/include | |
| parent | f7e831ab40a5031cec9186096a90d94735080ed7 (diff) | |
Implement EFI resolver as a module workflow
Diffstat (limited to 'plugins/efi_resolver/include')
| -rw-r--r-- | plugins/efi_resolver/include/DxeResolver.h | 26 | ||||
| -rw-r--r-- | plugins/efi_resolver/include/GuidRenderer.h | 21 | ||||
| -rw-r--r-- | plugins/efi_resolver/include/ModuleType.h | 23 | ||||
| -rw-r--r-- | plugins/efi_resolver/include/PeiResolver.h | 21 | ||||
| -rw-r--r-- | plugins/efi_resolver/include/Resolver.h | 75 | ||||
| -rw-r--r-- | plugins/efi_resolver/include/TypePropagation.h | 18 | ||||
| -rw-r--r-- | plugins/efi_resolver/include/Utils.h | 40 |
7 files changed, 224 insertions, 0 deletions
diff --git a/plugins/efi_resolver/include/DxeResolver.h b/plugins/efi_resolver/include/DxeResolver.h new file mode 100644 index 00000000..eef6e6c2 --- /dev/null +++ b/plugins/efi_resolver/include/DxeResolver.h @@ -0,0 +1,26 @@ +#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<BinaryView> view, Ref<BackgroundTask> task); +};
\ No newline at end of file diff --git a/plugins/efi_resolver/include/GuidRenderer.h b/plugins/efi_resolver/include/GuidRenderer.h new file mode 100644 index 00000000..9e5a43bc --- /dev/null +++ b/plugins/efi_resolver/include/GuidRenderer.h @@ -0,0 +1,21 @@ +#pragma once + +#include "binaryninjaapi.h" +#include <iomanip> + +using namespace BinaryNinja; +using namespace std; + +class EfiGuidRenderer : public BinaryNinja::DataRenderer +{ + EfiGuidRenderer() = default; + +public: + bool IsValidForData(BinaryView*, uint64_t address, Type*, vector<pair<Type*, size_t>>&) override; + + vector<DisassemblyTextLine> GetLinesForData( + BinaryView*, uint64_t address, Type*, const vector<InstructionTextToken>& prefix, size_t width, + std::vector<std::pair<Type*, size_t>>& context, const std::string& language = std::string()) override; + + static void Register(); +}; diff --git a/plugins/efi_resolver/include/ModuleType.h b/plugins/efi_resolver/include/ModuleType.h new file mode 100644 index 00000000..187dcc36 --- /dev/null +++ b/plugins/efi_resolver/include/ModuleType.h @@ -0,0 +1,23 @@ +#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/plugins/efi_resolver/include/PeiResolver.h b/plugins/efi_resolver/include/PeiResolver.h new file mode 100644 index 00000000..2ecf8ace --- /dev/null +++ b/plugins/efi_resolver/include/PeiResolver.h @@ -0,0 +1,21 @@ +#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<BinaryView> view, Ref<BackgroundTask> task); +};
\ No newline at end of file diff --git a/plugins/efi_resolver/include/Resolver.h b/plugins/efi_resolver/include/Resolver.h new file mode 100644 index 00000000..91bb1862 --- /dev/null +++ b/plugins/efi_resolver/include/Resolver.h @@ -0,0 +1,75 @@ +#pragma once + +#include <fstream> +#include <thread> + +#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<uint8_t, 16> EFI_GUID; + +class Resolver +{ +protected: + Ref<BinaryView> m_view; + Ref<BackgroundTask> m_task; + size_t m_width; + map<EFI_GUID, pair<string, string>> m_protocol; + map<EFI_GUID, string> m_user_guids; + + vector<pair<uint64_t, string>> m_service_usages; + vector<pair<uint64_t, string>> m_protocol_usages; + vector<pair<uint64_t, EFI_GUID>> m_guid_usages; + vector<pair<uint64_t, string>> 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<Type> GetTypeFromViewAndPlatform(string type_name); + void initProtocolMapping(); + +public: + bool setModuleEntry(EFIModuleType fileType); + bool resolveGuidInterface(Ref<Function> func, uint64_t addr, int guid_pos, int interface_pos); + Resolver(Ref<BinaryView> view, Ref<BackgroundTask> task); + + pair<string, string> lookupGuid(EFI_GUID guidBytes); + pair<string, string> defineAndLookupGuid(uint64_t addr); + + string nonConflictingName(const string& basename); + static string nonConflictingLocalName(Ref<Function> 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<Function> func, uint64_t addr, string typeName, int paramIdx, bool followFields = false); + vector<HighLevelILInstruction> HighLevelILExprsAt(Ref<Function> func, Ref<Architecture> arch, uint64_t addr); +};
\ No newline at end of file diff --git a/plugins/efi_resolver/include/TypePropagation.h b/plugins/efi_resolver/include/TypePropagation.h new file mode 100644 index 00000000..1985e2ab --- /dev/null +++ b/plugins/efi_resolver/include/TypePropagation.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Utils.h" +#include "binaryninjaapi.h" + +using namespace BinaryNinja; + +class TypePropagation +{ + Ref<BinaryView> m_view; + std::deque<uint64_t> m_queue; + Ref<Platform> 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/plugins/efi_resolver/include/Utils.h b/plugins/efi_resolver/include/Utils.h new file mode 100644 index 00000000..981908b2 --- /dev/null +++ b/plugins/efi_resolver/include/Utils.h @@ -0,0 +1,40 @@ +#pragma once + +#include "binaryninjaapi.h" + +using namespace BinaryNinja; + +static inline std::string GetOriginalTypeName(Ref<Type> 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; +} |
