summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrandon Miller <brandon@vector35.com>2025-05-08 15:08:10 -0400
committerBrandon Miller <brandon@vector35.com>2025-05-08 15:08:10 -0400
commit5147249a644f611a801aada7645b7a993fc8e314 (patch)
tree3a18e50df5ae9edcf31f3545a7f27774021c76a1
parentf7e831ab40a5031cec9186096a90d94735080ed7 (diff)
Implement EFI resolver as a module workflow
-rw-r--r--platform/efi/efi_resolver/LICENSE13
-rw-r--r--platform/efi/efi_resolver/src/Plugin.cpp65
-rw-r--r--platform/efi/platform_efi.cpp113
-rw-r--r--plugins/efi_resolver/CMakeLists.txt (renamed from platform/efi/efi_resolver/CMakeLists.txt)0
-rw-r--r--plugins/efi_resolver/README.md (renamed from platform/efi/efi_resolver/README.md)23
-rw-r--r--plugins/efi_resolver/include/DxeResolver.h (renamed from platform/efi/efi_resolver/include/DxeResolver.h)0
-rw-r--r--plugins/efi_resolver/include/GuidRenderer.h (renamed from platform/efi/efi_resolver/include/GuidRenderer.h)0
-rw-r--r--plugins/efi_resolver/include/ModuleType.h (renamed from platform/efi/efi_resolver/include/ModuleType.h)0
-rw-r--r--plugins/efi_resolver/include/PeiResolver.h (renamed from platform/efi/efi_resolver/include/PeiResolver.h)0
-rw-r--r--plugins/efi_resolver/include/Resolver.h (renamed from platform/efi/efi_resolver/include/Resolver.h)0
-rw-r--r--plugins/efi_resolver/include/TypePropagation.h (renamed from platform/efi/efi_resolver/include/TypePropagation.h)0
-rw-r--r--plugins/efi_resolver/include/Utils.h (renamed from platform/efi/efi_resolver/include/Utils.h)0
-rw-r--r--plugins/efi_resolver/src/DxeResolver.cpp (renamed from platform/efi/efi_resolver/src/DxeResolver.cpp)0
-rw-r--r--plugins/efi_resolver/src/GuidRenderer.cpp (renamed from platform/efi/efi_resolver/src/GuidRenderer.cpp)0
-rw-r--r--plugins/efi_resolver/src/PeiResolver.cpp (renamed from platform/efi/efi_resolver/src/PeiResolver.cpp)0
-rw-r--r--plugins/efi_resolver/src/Plugin.cpp81
-rw-r--r--plugins/efi_resolver/src/Resolver.cpp (renamed from platform/efi/efi_resolver/src/Resolver.cpp)0
-rw-r--r--plugins/efi_resolver/src/TypePropagation.cpp (renamed from platform/efi/efi_resolver/src/TypePropagation.cpp)0
18 files changed, 115 insertions, 180 deletions
diff --git a/platform/efi/efi_resolver/LICENSE b/platform/efi/efi_resolver/LICENSE
deleted file mode 100644
index 5cca4965..00000000
--- a/platform/efi/efi_resolver/LICENSE
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright 2023-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. \ No newline at end of file
diff --git a/platform/efi/efi_resolver/src/Plugin.cpp b/platform/efi/efi_resolver/src/Plugin.cpp
deleted file mode 100644
index b562975c..00000000
--- a/platform/efi/efi_resolver/src/Plugin.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-#include "DxeResolver.h"
-#include "PeiResolver.h"
-#include "binaryninjaapi.h"
-#include <thread>
-
-using namespace BinaryNinja;
-
-extern "C"
-{
-BN_DECLARE_CORE_ABI_VERSION
-
-BINARYNINJAPLUGIN void CorePluginDependencies()
-{
- BinaryNinja::AddOptionalPluginDependency("arch_x86");
- BinaryNinja::AddOptionalPluginDependency("arch_armv7");
- BinaryNinja::AddOptionalPluginDependency("arch_arm64");
- BinaryNinja::AddOptionalPluginDependency("platform_efi");
-}
-
-static Ref<BackgroundTask> efiBackgroundTask = nullptr;
-
-void Run(Ref<BinaryView> view)
-{
- efiBackgroundTask = new BackgroundTask("Loading EFI protocol mappings!", true);
- thread resolverThread([view]() {
- LogInfo("Entering new thread");
-
- LogInfo("Identifying module type");
- EFIModuleType moduleType = identifyModuleType(view);
-
-#ifndef DEBUG
- auto undo = view->BeginUndoActions();
-#endif
- if (moduleType == PEI)
- {
- efiBackgroundTask->SetProgressText("Resolving PEIM...");
- auto resolver = PeiResolver(view, efiBackgroundTask);
- resolver.resolvePei();
- }
- else if (moduleType == DXE)
- {
- efiBackgroundTask->SetProgressText("Resolving DXE protocols...");
- auto resolver = DxeResolver(view, efiBackgroundTask);
- resolver.resolveDxe();
- efiBackgroundTask->SetProgressText("Resolving MM related protocols...");
- resolver.resolveSmm();
- }
-
-#ifndef DEBUG
- view->CommitUndoActions(undo);
-#endif
- efiBackgroundTask->Finish();
- });
- resolverThread.detach();
-}
-
-BINARYNINJAPLUGIN bool CorePluginInit()
-{
- EfiGuidRenderer::Register();
-
- PluginCommand::Register("EFI Resolver\\Resolve EFI Types And Protocols", "Resolve EFI Protocols", &Run);
-
- return true;
-}
-}
diff --git a/platform/efi/platform_efi.cpp b/platform/efi/platform_efi.cpp
index 9f9840b2..d3ba74e2 100644
--- a/platform/efi/platform_efi.cpp
+++ b/platform/efi/platform_efi.cpp
@@ -20,7 +20,6 @@ public:
Ref<CallingConvention> cc;
m_idtr = arch->GetRegisterByName("idtr");
-
cc = arch->GetCallingConventionByName("cdecl");
if (cc)
{
@@ -58,19 +57,7 @@ public:
virtual void BinaryViewInit(BinaryView* view) override
{
- if (!m_idtrtype)
- m_idtrtype = Type::NamedType(QualifiedName("IDTR32"), GetTypeByName(QualifiedName("IDTR32")));
-
- auto ctx = PluginCommandContext();
- ctx.binaryView = view;
- auto commandList = PluginCommand::GetValidList(ctx);
- for (auto command : commandList)
- {
- if (command.GetName() == "EFI Resolver\\Resolve EFI Types And Protocols")
- {
- command.Execute(ctx);
- }
- }
+ m_idtrtype = Type::NamedType(QualifiedName("IDTR32"), GetTypeByName(QualifiedName("IDTR32")));
}
virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override
@@ -95,7 +82,6 @@ public:
Ref<CallingConvention> cc;
m_idtr = arch->GetRegisterByName("idtr");
-
cc = arch->GetCallingConventionByName("cdecl");
if (cc)
{
@@ -133,19 +119,7 @@ public:
virtual void BinaryViewInit(BinaryView* view) override
{
- if (!m_idtrtype)
- m_idtrtype = Type::NamedType(QualifiedName("IDTR32"), GetTypeByName(QualifiedName("IDTR32")));
-
- auto ctx = PluginCommandContext();
- ctx.binaryView = view;
- auto commandList = PluginCommand::GetValidList(ctx);
- for (auto command : commandList)
- {
- if (command.GetName() == "EFI Resolver\\Resolve EFI Types And Protocols")
- {
- command.Execute(ctx);
- }
- }
+ m_idtrtype = Type::NamedType(QualifiedName("IDTR32"), GetTypeByName(QualifiedName("IDTR32")));
}
virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override
@@ -191,19 +165,7 @@ public:
virtual void BinaryViewInit(BinaryView* view) override
{
- if (!m_idtrtype)
- m_idtrtype = Type::NamedType(QualifiedName("IDTR64"), GetTypeByName(QualifiedName("IDTR64")));
-
- auto ctx = PluginCommandContext();
- ctx.binaryView = view;
- auto commandList = PluginCommand::GetValidList(ctx);
- for (auto command : commandList)
- {
- if (command.GetName() == "EFI Resolver\\Resolve EFI Types And Protocols")
- {
- command.Execute(ctx);
- }
- }
+ m_idtrtype = Type::NamedType(QualifiedName("IDTR64"), GetTypeByName(QualifiedName("IDTR64")));
}
virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override
@@ -249,19 +211,7 @@ public:
virtual void BinaryViewInit(BinaryView* view) override
{
- if (!m_idtrtype)
- m_idtrtype = Type::NamedType(QualifiedName("IDTR64"), GetTypeByName(QualifiedName("IDTR64")));
-
- auto ctx = PluginCommandContext();
- ctx.binaryView = view;
- auto commandList = PluginCommand::GetValidList(ctx);
- for (auto command : commandList)
- {
- if (command.GetName() == "EFI Resolver\\Resolve EFI Types And Protocols")
- {
- command.Execute(ctx);
- }
- }
+ m_idtrtype = Type::NamedType(QualifiedName("IDTR64"), GetTypeByName(QualifiedName("IDTR64")));
}
virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override
@@ -324,26 +274,6 @@ public:
}
}
- virtual void BinaryViewInit(BinaryView* view) override
- {
- if (!m_tpidrel0type)
- m_tpidrel0type = Type::NamedType(QualifiedName("EFI_PEI_SERVICES"),
- Type::PointerType(view->GetDefaultArchitecture(),
- Type::PointerType(
- view->GetDefaultArchitecture(), GetTypeByName(QualifiedName("EFI_PEI_SERVICES")))));
-
- auto ctx = PluginCommandContext();
- ctx.binaryView = view;
- auto commandList = PluginCommand::GetValidList(ctx);
- for (auto command : commandList)
- {
- if (command.GetName() == "EFI Resolver\\Resolve EFI Types And Protocols")
- {
- command.Execute(ctx);
- }
- }
- }
-
static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata)
{
Ref<Metadata> subsystem = metadata->Get("Subsystem");
@@ -354,6 +284,13 @@ public:
return nullptr;
}
+ virtual void BinaryViewInit(BinaryView* view) override
+ {
+ m_tpidrel0type = Type::NamedType(QualifiedName("EFI_PEI_SERVICES"),
+ Type::PointerType(GetArchitecture(),
+ Type::PointerType(GetArchitecture(), GetTypeByName(QualifiedName("EFI_PEI_SERVICES")))));
+ }
+
virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override
{
if (reg == m_tpidrel0)
@@ -384,26 +321,6 @@ public:
}
}
- virtual void BinaryViewInit(BinaryView* view) override
- {
- if (!m_tpidrel0type)
- m_tpidrel0type = Type::NamedType(QualifiedName("EFI_PEI_SERVICES"),
- Type::PointerType(view->GetDefaultArchitecture(),
- Type::PointerType(
- view->GetDefaultArchitecture(), GetTypeByName(QualifiedName("EFI_PEI_SERVICES")))));
-
- auto ctx = PluginCommandContext();
- ctx.binaryView = view;
- auto commandList = PluginCommand::GetValidList(ctx);
- for (auto command : commandList)
- {
- if (command.GetName() == "EFI Resolver\\Resolve EFI Types And Protocols")
- {
- command.Execute(ctx);
- }
- }
- }
-
static Ref<Platform> Recognize(BinaryView* view, Metadata* metadata)
{
Ref<Metadata> subsystem = metadata->Get("Subsystem");
@@ -414,6 +331,14 @@ public:
return nullptr;
}
+ virtual void BinaryViewInit(BinaryView* view) override
+ {
+ m_tpidrel0type = Type::NamedType(QualifiedName("EFI_PEI_SERVICES"),
+ Type::PointerType(GetArchitecture(),
+ Type::PointerType(
+ GetArchitecture(), GetTypeByName(QualifiedName("EFI_PEI_SERVICES")))));
+ }
+
virtual Ref<Type> GetGlobalRegisterType(uint32_t reg) override
{
if (reg == m_tpidrel0)
diff --git a/platform/efi/efi_resolver/CMakeLists.txt b/plugins/efi_resolver/CMakeLists.txt
index 03fabbf6..03fabbf6 100644
--- a/platform/efi/efi_resolver/CMakeLists.txt
+++ b/plugins/efi_resolver/CMakeLists.txt
diff --git a/platform/efi/efi_resolver/README.md b/plugins/efi_resolver/README.md
index 93ba468b..5e81adf4 100644
--- a/platform/efi/efi_resolver/README.md
+++ b/plugins/efi_resolver/README.md
@@ -3,18 +3,25 @@ Author: **Vector 35 Inc**
_A Binary Ninja built-in plugin that automatically resolves type information for EFI protocol usage._
-This repository contains C++ version of EFI Resolver, which is bundled with Binary Ninja. For the original Python
-version, please refer to https://github.com/vector35/efi-resolver/tree/main
-
## Description:
-EFI Resolver is a Binary Ninja plugin that automates the task of resolving EFI protocol type information. It supports both DXE files and PEI files. It propagates parameter pointers from entry points to system table, MM system table, boot services, and runtime services to any global variables where they are stored. For PEI files, it also supports identifying [processor-specific mechanisms](https://uefi.org/specs/PI/1.8/V1_PEI_Foundation.html#pei-services-table-retrieval) for retrieving PEI services pointers. The plugin also identifies references to the boot services, MM protocol functions and PEI services, and applies type information according to the GUID passed to these functions. The plugin supports the core UEFI specification, and allows users to provide custom vendor protocols.
+EFI Resolver is a Binary Ninja plugin that automates the resolution of EFI protocol type information. It supports both
+DXE files and PEI modules. The plugin propagates parameter pointers from entry points to system tables, including the
+main system table, MM system table, boot services, and runtime services, assigning types to global variables.
+
+For PEI files, EFI Resolver can also detect
+[processor-specific patterns](https://uefi.org/specs/PI/1.8/V1_PEI_Foundation.html#pei-services-table-retrieval)
+used to retrieve PEI services pointers.
+
+Additionally, the plugin identifies references to boot services, MM protocol functions, and PEI services. It applies
+type information based on the GUIDs passed to these functions.
+
+EFI Resolver supports the core UEFI specification and allows users to define custom vendor protocols.
## Build Instructions
```bash
-git clone https://github.com/Vector35/binaryninja-api.git
-git clone https://github.com/Vector35/efi-resolver.git && cd efi-resolver
+git clone https://github.com/Vector35/binaryninja-api.git && cd binaryninja-api/plugins/efi_resolver
export BN_API_PATH=../binaryninja-api # Or specifying the path to api repo
cmake -S . -B build -GNinja
cmake --build build -t install
@@ -26,7 +33,7 @@ This plugin is released under an Apache-2.0 license.
## Supplying Custom UEFI Protocol GUIDs and Types
-By default, EFI Resolver propagates types and GUIDs using Binary Ninja's native platform types for EFI. Many UEFI
+EFI Resolver propagates types and GUIDs using Binary Ninja's native platform types for EFI. Many UEFI
firmware binaries include types (and GUIDs) for proprietary protocols. This section describes how users can supply
custom UEFI types and GUIDs for use with EFI Resolver type propagation.
@@ -125,4 +132,4 @@ struct EFI_EXAMPLE_CUSTOM_PROTOCOL
After a Binary Ninja restart, when a binary is loaded with the `efi-x86` platform, the `EFI_EXAMPLE_CUSTOM_PROTOCOL`
type will be imported. When EFI Resolver runs, it will detect uses of `EFI_EXAMPLE_CUSTOM_PROTOCOL_GUID` and propagate
-the `EFI_EXAMPLE_CUSTOM_PROTOCOL` type. \ No newline at end of file
+the `EFI_EXAMPLE_CUSTOM_PROTOCOL` type.
diff --git a/platform/efi/efi_resolver/include/DxeResolver.h b/plugins/efi_resolver/include/DxeResolver.h
index eef6e6c2..eef6e6c2 100644
--- a/platform/efi/efi_resolver/include/DxeResolver.h
+++ b/plugins/efi_resolver/include/DxeResolver.h
diff --git a/platform/efi/efi_resolver/include/GuidRenderer.h b/plugins/efi_resolver/include/GuidRenderer.h
index 9e5a43bc..9e5a43bc 100644
--- a/platform/efi/efi_resolver/include/GuidRenderer.h
+++ b/plugins/efi_resolver/include/GuidRenderer.h
diff --git a/platform/efi/efi_resolver/include/ModuleType.h b/plugins/efi_resolver/include/ModuleType.h
index 187dcc36..187dcc36 100644
--- a/platform/efi/efi_resolver/include/ModuleType.h
+++ b/plugins/efi_resolver/include/ModuleType.h
diff --git a/platform/efi/efi_resolver/include/PeiResolver.h b/plugins/efi_resolver/include/PeiResolver.h
index 2ecf8ace..2ecf8ace 100644
--- a/platform/efi/efi_resolver/include/PeiResolver.h
+++ b/plugins/efi_resolver/include/PeiResolver.h
diff --git a/platform/efi/efi_resolver/include/Resolver.h b/plugins/efi_resolver/include/Resolver.h
index 91bb1862..91bb1862 100644
--- a/platform/efi/efi_resolver/include/Resolver.h
+++ b/plugins/efi_resolver/include/Resolver.h
diff --git a/platform/efi/efi_resolver/include/TypePropagation.h b/plugins/efi_resolver/include/TypePropagation.h
index 1985e2ab..1985e2ab 100644
--- a/platform/efi/efi_resolver/include/TypePropagation.h
+++ b/plugins/efi_resolver/include/TypePropagation.h
diff --git a/platform/efi/efi_resolver/include/Utils.h b/plugins/efi_resolver/include/Utils.h
index 981908b2..981908b2 100644
--- a/platform/efi/efi_resolver/include/Utils.h
+++ b/plugins/efi_resolver/include/Utils.h
diff --git a/platform/efi/efi_resolver/src/DxeResolver.cpp b/plugins/efi_resolver/src/DxeResolver.cpp
index f31c42ae..f31c42ae 100644
--- a/platform/efi/efi_resolver/src/DxeResolver.cpp
+++ b/plugins/efi_resolver/src/DxeResolver.cpp
diff --git a/platform/efi/efi_resolver/src/GuidRenderer.cpp b/plugins/efi_resolver/src/GuidRenderer.cpp
index 2a220edc..2a220edc 100644
--- a/platform/efi/efi_resolver/src/GuidRenderer.cpp
+++ b/plugins/efi_resolver/src/GuidRenderer.cpp
diff --git a/platform/efi/efi_resolver/src/PeiResolver.cpp b/plugins/efi_resolver/src/PeiResolver.cpp
index c3f5d50a..c3f5d50a 100644
--- a/platform/efi/efi_resolver/src/PeiResolver.cpp
+++ b/plugins/efi_resolver/src/PeiResolver.cpp
diff --git a/plugins/efi_resolver/src/Plugin.cpp b/plugins/efi_resolver/src/Plugin.cpp
new file mode 100644
index 00000000..9d5a69ce
--- /dev/null
+++ b/plugins/efi_resolver/src/Plugin.cpp
@@ -0,0 +1,81 @@
+#include "DxeResolver.h"
+#include "PeiResolver.h"
+#include "binaryninjaapi.h"
+#include <thread>
+
+using namespace BinaryNinja;
+
+static Ref<BackgroundTask> m_efiBackgroundTask = nullptr;
+
+bool IsValid(BinaryView* view)
+{
+ if (!view)
+ return false;
+
+ auto platform = view->GetDefaultPlatform();
+ return (platform && platform->GetName().find("efi-") != std::string::npos);
+}
+
+
+void RunCommand(Ref<BinaryView> view)
+{
+ m_efiBackgroundTask = new BackgroundTask("Running EFI resolver...", true);
+ thread resolverThread([view]() {
+ LogInfo("Identifying EFI module type...");
+ EFIModuleType moduleType = identifyModuleType(view);
+
+ auto undo = view->BeginUndoActions();
+ if (moduleType == PEI)
+ {
+ m_efiBackgroundTask->SetProgressText("Resolving PEIM...");
+ auto resolver = PeiResolver(view, m_efiBackgroundTask);
+ resolver.resolvePei();
+ }
+ else if (moduleType == DXE)
+ {
+ m_efiBackgroundTask->SetProgressText("Resolving DXE protocols...");
+ auto resolver = DxeResolver(view, m_efiBackgroundTask);
+ resolver.resolveDxe();
+ m_efiBackgroundTask->SetProgressText("Resolving MM related protocols...");
+ resolver.resolveSmm();
+ }
+ view->CommitUndoActions(undo);
+ m_efiBackgroundTask->Finish();
+ });
+
+ resolverThread.detach();
+}
+
+
+void RunWorkflow(const Ref<AnalysisContext>& analysisContext)
+{
+ auto view = analysisContext->GetBinaryView();
+ if (IsValid(view))
+ RunCommand(view);
+}
+
+
+extern "C"
+{
+ BN_DECLARE_CORE_ABI_VERSION
+ BINARYNINJAPLUGIN bool CorePluginInit()
+ {
+ EfiGuidRenderer::Register();
+ auto workflow = Workflow::Instance("core.module.metaAnalysis")->Clone();
+ workflow->RegisterActivity(R"~({
+ "title": "EFI Resolver",
+ "name": "analysis.efi.efiResolver",
+ "role": "action",
+ "description": "This analysis step resolves EFI protocol interfaces and propagates type information.",
+ "eligibility": {
+ "runOnce": true,
+ "auto": {}
+ }
+ })~", &RunWorkflow);
+
+ workflow->InsertAfter("core.module.extendedAnalysis", "analysis.efi.efiResolver");
+ Workflow::RegisterWorkflow(workflow);
+ PluginCommand::Register("Run EFI Resolver", "Resolve EFI interfaces and types", &RunCommand, &IsValid);
+ return true;
+ }
+}
diff --git a/platform/efi/efi_resolver/src/Resolver.cpp b/plugins/efi_resolver/src/Resolver.cpp
index 36fa190b..36fa190b 100644
--- a/platform/efi/efi_resolver/src/Resolver.cpp
+++ b/plugins/efi_resolver/src/Resolver.cpp
diff --git a/platform/efi/efi_resolver/src/TypePropagation.cpp b/plugins/efi_resolver/src/TypePropagation.cpp
index ff0d43b9..ff0d43b9 100644
--- a/platform/efi/efi_resolver/src/TypePropagation.cpp
+++ b/plugins/efi_resolver/src/TypePropagation.cpp