summaryrefslogtreecommitdiff
path: root/platform/efi/efi_resolver/src/DxeResolver.cpp
diff options
context:
space:
mode:
authorZichuan Li <34680029+river-li@users.noreply.github.com>2024-08-15 11:53:05 -0400
committerBrandon Miller <brandon@vector35.com>2025-05-08 07:23:08 -0400
commit7f08117cfeb48a8f48d08e14cb498ee028efcef2 (patch)
tree345eab220c00cfa098e94fa261dce092fc8d5182 /platform/efi/efi_resolver/src/DxeResolver.cpp
parent64de95854f9ad4da90b9cf2ee69a80f5dddd7a18 (diff)
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
Diffstat (limited to 'platform/efi/efi_resolver/src/DxeResolver.cpp')
-rw-r--r--platform/efi/efi_resolver/src/DxeResolver.cpp255
1 files changed, 255 insertions, 0 deletions
diff --git a/platform/efi/efi_resolver/src/DxeResolver.cpp b/platform/efi/efi_resolver/src/DxeResolver.cpp
new file mode 100644
index 00000000..f801a8e5
--- /dev/null
+++ b/platform/efi/efi_resolver/src/DxeResolver.cpp
@@ -0,0 +1,255 @@
+#include "DxeResolver.h"
+
+bool DxeResolver::resolveBootServices()
+{
+ auto refs = m_view->GetCodeReferencesForType(QualifiedName("EFI_BOOT_SERVICES"));
+ // search reference of `EFI_BOOT_SERVICES` so that we can easily parse different services
+
+ for (auto& ref : refs) {
+ if (m_task->IsCancelled())
+ return false;
+
+ auto func = ref.func;
+ auto mlil = func->GetMediumLevelIL();
+ if (!mlil)
+ continue;
+
+ auto mlilSsa = mlil->GetSSAForm();
+ size_t mlilIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr);
+ auto instr = mlilSsa->GetInstruction(mlil->GetSSAInstructionIndex(mlilIdx));
+
+ if (instr.operation == MLIL_CALL_SSA || instr.operation == MLIL_TAILCALL_SSA) {
+ auto dest = instr.GetDestExpr();
+ if (dest.operation != MLIL_LOAD_STRUCT_SSA)
+ continue;
+ auto offset = dest.GetOffset();
+
+ if (offset == 0x18 + m_width * 16 || offset == 0x18 + m_width * 32) {
+ // HandleProtocol, OpenProtocol
+ // Guid:1, Interface:2
+ resolveGuidInterface(ref.func, ref.addr, 1, 2);
+ } else if (offset == 0x18 + m_width * 37) {
+ // LocateProtocol
+ resolveGuidInterface(ref.func, ref.addr, 0, 2);
+ }
+ }
+ }
+ return true;
+}
+
+bool DxeResolver::resolveRuntimeServices()
+{
+ auto refs = m_view->GetCodeReferencesForType(QualifiedName("EFI_RUNTIME_SERVICES"));
+
+ for (auto &ref : refs) {
+ if (m_task->IsCancelled())
+ return false;
+
+ auto func = ref.func;
+ auto mlil = func->GetMediumLevelIL();
+ if (!mlil)
+ continue;
+
+ auto mlilSsa = mlil->GetSSAForm();
+ size_t mlilIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr);
+ auto instr = mlilSsa->GetInstruction(mlil->GetSSAInstructionIndex(mlilIdx));
+
+ if (instr.operation == MLIL_CALL_SSA || instr.operation == MLIL_TAILCALL_SSA) {
+ auto dest = instr.GetDestExpr();
+ if (dest.operation != MLIL_LOAD_STRUCT_SSA)
+ continue;
+ auto offset = dest.GetOffset();
+ if (offset == 0x18 + m_width * 6 || offset == 0x18 + m_width * 8) {
+ // TODO implement this
+ // GetVariable and SetVariable
+ }
+ }
+ }
+ return true;
+}
+
+bool DxeResolver::resolveSmmTables(string serviceName, string tableName)
+{
+ auto refs = m_view->GetCodeReferencesForType(QualifiedName(serviceName));
+ // both versions use the same type, so we only need to search for this one
+ for (auto &ref : refs) {
+ if (m_task->IsCancelled())
+ return false;
+
+ auto func = ref.func;
+ auto mlil = func->GetMediumLevelIL();
+ if (!mlil)
+ continue;
+
+ auto mlilSsa = mlil->GetSSAForm();
+ size_t mlilIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr);
+ auto instr = mlilSsa->GetInstruction(mlil->GetSSAInstructionIndex(mlilIdx));
+
+ if (instr.operation != MLIL_CALL_SSA && instr.operation != MLIL_TAILCALL_SSA)
+ continue;
+
+ auto destExpr = instr.GetDestExpr();
+ if (destExpr.operation != MLIL_LOAD_STRUCT_SSA)
+ continue;
+
+ if (destExpr.GetOffset() != 8)
+ continue;
+
+ auto params = instr.GetParameterExprs();
+ if (params.size() < 2)
+ continue;
+
+ auto smstAddr = params[1];
+ if (smstAddr.operation != MLIL_CONST_PTR)
+ continue;
+
+ QualifiedNameAndType result;
+ string errors;
+ bool ok = m_view->ParseTypeString(tableName, result, errors);
+ if (!ok)
+ return false;
+ m_view->DefineDataVariable(smstAddr.GetValue().value, result.type);
+ m_view->DefineUserSymbol(new Symbol(DataSymbol, "gMmst", smstAddr.GetValue().value));
+ m_view->UpdateAnalysisAndWait();
+ }
+ return true;
+}
+
+bool DxeResolver::resolveSmmServices()
+{
+ auto refs = m_view->GetCodeReferencesForType(QualifiedName("EFI_MM_SYSTEM_TABLE"));
+ auto refs_smm = m_view->GetCodeReferencesForType(QualifiedName("EFI_SMM_SYSTEM_TABLE2"));
+ // These tables have same type information, we can just iterate once
+ refs.insert(refs.end(), refs_smm.begin(), refs_smm.end());
+
+ for (auto &ref : refs) {
+ if (m_task->IsCancelled())
+ return false;
+
+ auto func = ref.func;
+ auto mlil = func->GetMediumLevelIL();
+ if (!mlil)
+ continue;
+
+ auto mlilSsa = mlil->GetSSAForm();
+ size_t mlilIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr);
+ auto instr = mlilSsa->GetInstruction(mlil->GetSSAInstructionIndex(mlilIdx));
+
+ if (instr.operation == MLIL_CALL_SSA || instr.operation == MLIL_TAILCALL_SSA) {
+ auto dest = instr.GetDestExpr();
+ if (dest.operation != MLIL_LOAD_STRUCT_SSA)
+ continue;
+ auto offset = dest.GetOffset();
+
+ if (offset == 0x18 + m_width * 0x14) {
+ // SmmHandleProtocol
+ resolveGuidInterface(ref.func, ref.addr, 1, 2);
+ } else if (offset == 0x18 + m_width * 0x17) {
+ // SmmLocateProtocol
+ resolveGuidInterface(ref.func, ref.addr, 0, 2);
+ }
+ }
+ }
+ return true;
+}
+
+bool DxeResolver::resolveSmiHandlers()
+{
+ auto refs = m_view->GetCodeReferencesForType(QualifiedName("EFI_MM_SW_REGISTER"));
+ for (auto &ref : refs)
+ {
+ if (m_task->IsCancelled())
+ return false;
+
+ auto func = ref.func;
+ auto mlil = func->GetMediumLevelIL();
+ if (!mlil)
+ continue;
+
+ auto mlilSsa = mlil->GetSSAForm();
+ size_t mlilIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr);
+ auto instr = mlilSsa->GetInstruction(mlil->GetSSAInstructionIndex(mlilIdx));
+
+ if (instr.operation == MLIL_CALL_SSA || instr.operation == MLIL_TAILCALL_SSA)
+ {
+ auto dest = instr.GetDestExpr();
+ if (dest.operation != MLIL_LOAD_STRUCT_SSA)
+ continue;
+
+ auto offset = dest.GetOffset();
+ if (offset == 0) {
+ /* EFI_MM_SW_REGISTER, we want to rename the second parameter according to the third parameter
+ typedef enum EFI_STATUS (* EFI_MM_SW_REGISTER)(
+ struct EFI_MM_SW_DISPATCH_PROTOCOL* This,
+ EFI_MM_HANDLER_ENTRY_POINT DispatchFunction,
+ struct EFI_MM_SW_REGISTER_CONTEXT*
+ RegisterContext, EFI_HANDLE* DispatchHandle); */
+
+ auto parameters = instr.GetParameterExprs();
+ if (parameters.size() < 3)
+ continue;
+
+ auto dispatchFunction = parameters[1];
+ auto registerContext = parameters[2];
+
+ // Determine the function name according to the registerContext
+ /* struct EFI_MM_SW_REGISTER_CONTEXT
+ * {
+ * UINTN SwMmiInputValue;
+ * };
+ */
+ string funcName = "SmiHandler";
+
+ if (dispatchFunction.operation != MLIL_CONST_PTR)
+ continue;
+ auto funcAddr = static_cast<uint64_t> (dispatchFunction.GetConstant());
+ auto targetFunc = m_view->GetAnalysisFunction(m_view->GetDefaultPlatform(), funcAddr);
+ auto funcType = targetFunc->GetType();
+ // typedef enum
+ string handleTypeStr = "EFI_STATUS SmiHandler(EFI_HANDLE DispatchHandle, VOID* Context, VOID* CommBuffer, UINTN* CommBufferSize);";
+ QualifiedNameAndType result;
+ string errors;
+ bool ok = m_view->ParseTypeString(handleTypeStr, result, errors);
+ if (!ok)
+ return false;
+ targetFunc->SetUserType(result.type);
+ m_view->DefineUserSymbol(new Symbol(FunctionSymbol, funcName, funcAddr));
+ m_view->UpdateAnalysisAndWait();
+
+ // After setting the type, we want to propagate the parameters' type
+ TypePropagation propagator(m_view);
+ propagator.propagateFuncParamTypes(targetFunc);
+ }
+ }
+ }
+ return true;
+}
+
+bool DxeResolver::resolveDxe()
+{
+ if (!resolveBootServices())
+ return false;
+ if (!resolveRuntimeServices())
+ return false;
+ return true;
+}
+
+bool DxeResolver::resolveSmm()
+{
+ if (!resolveSmmTables("EFI_SMM_GET_SMST_LOCATION2", "EFI_SMM_SYSTEM_TABLE2*"))
+ return false;
+ if (!resolveSmmTables("EFI_MM_GET_MMST_LOCATION", "EFI_MM_SYSTEM_TABLE*"))
+ return false;
+ if (!resolveSmmServices())
+ return false;
+ if (!resolveSmiHandlers())
+ return false;
+ return true;
+}
+
+DxeResolver::DxeResolver(Ref<BinaryView> view, Ref<BackgroundTask> task)
+ : Resolver(view, task)
+{
+ initProtocolMapping();
+ setModuleEntry(DXE);
+}