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 /platform/efi/efi_resolver/src | |
| parent | f7e831ab40a5031cec9186096a90d94735080ed7 (diff) | |
Implement EFI resolver as a module workflow
Diffstat (limited to 'platform/efi/efi_resolver/src')
| -rw-r--r-- | platform/efi/efi_resolver/src/DxeResolver.cpp | 274 | ||||
| -rw-r--r-- | platform/efi/efi_resolver/src/GuidRenderer.cpp | 52 | ||||
| -rw-r--r-- | platform/efi/efi_resolver/src/PeiResolver.cpp | 304 | ||||
| -rw-r--r-- | platform/efi/efi_resolver/src/Plugin.cpp | 65 | ||||
| -rw-r--r-- | platform/efi/efi_resolver/src/Resolver.cpp | 753 | ||||
| -rw-r--r-- | platform/efi/efi_resolver/src/TypePropagation.cpp | 198 |
6 files changed, 0 insertions, 1646 deletions
diff --git a/platform/efi/efi_resolver/src/DxeResolver.cpp b/platform/efi/efi_resolver/src/DxeResolver.cpp deleted file mode 100644 index f31c42ae..00000000 --- a/platform/efi/efi_resolver/src/DxeResolver.cpp +++ /dev/null @@ -1,274 +0,0 @@ -#include "DxeResolver.h" - -bool DxeResolver::resolveBootServices() -{ - m_task->SetProgressText("Resolving Boot Services..."); - 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() -{ - m_task->SetProgressText("Resolving Runtime Services..."); - 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) -{ - m_task->SetProgressText("Defining MM tables..."); - 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() -{ - m_task->SetProgressText("Resolving MM services..."); - 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() -{ - m_task->SetProgressText("Resolving SMI Handlers..."); - auto refs = m_view->GetCodeReferencesForType(QualifiedName("EFI_MM_SW_REGISTER")); - auto refs_smm_sw = m_view->GetCodeReferencesForType(QualifiedName("EFI_SMM_SW_REGISTER2")); - auto refs_mm_sx = m_view->GetCodeReferencesForType(QualifiedName("EFI_MM_SX_REGISTER")); - auto refs_smm_sx = m_view->GetCodeReferencesForType(QualifiedName("EFI_SMM_SX_REGISTER2")); - // Define them together - - refs.insert(refs.end(), refs_smm_sw.begin(), refs_smm_sw.end()); - refs.insert(refs.end(), refs_smm_sx.begin(), refs_smm_sw.end()); - refs.insert(refs.end(), refs_mm_sx.begin(), refs_mm_sx.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 == 0) - { - auto parameters = instr.GetParameterExprs(); - if (parameters.size() < 4) - continue; - - // TODO we should be able to parse registerContext, but it's normally an aliased variable - // and we have some issues relate to that - auto dispatchFunction = parameters[1]; - 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(); - std::ostringstream ss; - ss << "SmiHandler_" << std::hex << funcAddr; - string funcName = ss.str(); - - // 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); -} diff --git a/platform/efi/efi_resolver/src/GuidRenderer.cpp b/platform/efi/efi_resolver/src/GuidRenderer.cpp deleted file mode 100644 index 2a220edc..00000000 --- a/platform/efi/efi_resolver/src/GuidRenderer.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "GuidRenderer.h" - -bool isType(const vector<pair<Type*, size_t>>& context, const string& name) -{ - if (context.empty()) - return false; - - auto [deepestType, size] = context.back(); - if (!deepestType->IsNamedTypeRefer()) - return false; - - return deepestType->GetTypeName().GetString() == name; -} - -bool EfiGuidRenderer::IsValidForData(BinaryView* bv, uint64_t address, Type* type, vector<pair<Type*, size_t>>& context) -{ - return isType(context, "EFI_GUID"); -} - -static string formatGuid(uint32_t data1, uint16_t data2, uint16_t data3, uint64_t data4) -{ - std::ostringstream oss; - oss << std::hex << std::uppercase << std::setfill('0') << std::setw(8) << data1 << "-" << std::setw(4) << data2 - << "-" << std::setw(4) << data3 << "-" << std::setw(16) << data4; - return oss.str(); -} - -vector<DisassemblyTextLine> EfiGuidRenderer::GetLinesForData( - BinaryView* bv, uint64_t address, Type*, const vector<InstructionTextToken>& prefix, size_t width, - vector<pair<Type*, size_t>>& context, const std::string& language) -{ - BinaryReader reader(bv); - reader.Seek(address); - auto data1 = reader.Read32(); - auto data2 = reader.Read16(); - auto data3 = reader.Read16(); - auto data4 = reader.ReadBE64(); - string guidStr = formatGuid(data1, data2, data3, data4); - - DisassemblyTextLine line; - line.addr = address; - line.tokens = prefix; - line.tokens.emplace_back(TextToken, "[EFI_GUID(\""); - line.tokens.emplace_back(StringToken, guidStr); - line.tokens.emplace_back(TextToken, "\")]"); - return {line}; -} - -void EfiGuidRenderer::Register() -{ - DataRendererContainer::RegisterTypeSpecificDataRenderer(new EfiGuidRenderer()); -} diff --git a/platform/efi/efi_resolver/src/PeiResolver.cpp b/platform/efi/efi_resolver/src/PeiResolver.cpp deleted file mode 100644 index c3f5d50a..00000000 --- a/platform/efi/efi_resolver/src/PeiResolver.cpp +++ /dev/null @@ -1,304 +0,0 @@ -#include "PeiResolver.h" - -bool PeiResolver::resolvePeiIdt() -{ - string archName = m_view->GetDefaultArchitecture()->GetName(); - string intrinsicName; - if (archName == "x86") - intrinsicName = "IDTR32"; - else - intrinsicName = "IDTR64"; - - auto refs = m_view->GetCodeReferencesForType(QualifiedName(intrinsicName)); - for (auto ref : refs) - { - if (m_task->IsCancelled()) - return false; - - auto mlil = ref.func->GetMediumLevelIL(); - auto instrIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr); - auto instr = mlil->GetInstruction(instrIdx); - - auto hlil = ref.func->GetHighLevelIL(); - auto hlils = HighLevelILExprsAt(ref.func, m_view->GetDefaultArchitecture(), ref.addr); - - for (auto expr : hlils) - { - if (expr.operation != HLIL_INTRINSIC || expr.GetParent().operation != HLIL_ASSIGN - || expr.GetParent().GetDestExpr<HLIL_ASSIGN>().operation != HLIL_STRUCT_FIELD - || expr.GetParent().GetDestExpr<HLIL_ASSIGN>().GetSourceExpr<HLIL_STRUCT_FIELD>().operation != HLIL_VAR) - continue; - - auto var = expr.GetParent().GetDestExpr<HLIL_ASSIGN>().GetSourceExpr<HLIL_STRUCT_FIELD>().GetVariable(); - ref.func->CreateUserVariable(var, m_view->GetTypeByName(QualifiedName(intrinsicName)), intrinsicName); - } - - if (instr.operation == MLIL_INTRINSIC) - { - // binja doesn't do type propagation on intrinsic instructions - auto output_params = instr.GetOutputVariables<MLIL_INTRINSIC>(); - if (output_params.size() < 1) - continue; - ref.func->CreateUserVariable( - output_params[0], m_view->GetTypeByName(QualifiedName(intrinsicName)), intrinsicName); - } - m_view->UpdateAnalysisAndWait(); - } - - // TODO There is an issue related to structure's type propagation, binja doesn't propagate indirect structure access - // properly - // here is a temporary fix, should be removed after vector35/binaryninja/#749 got fixed - refs = m_view->GetCodeReferencesForType(QualifiedName("EFI_PEI_SERVICES")); - for (auto ref : refs) - { - if (m_task->IsCancelled()) - return false; - - auto mlil = ref.func->GetMediumLevelIL(); - auto instrIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr); - auto instr = mlil->GetInstruction(instrIdx); - - if (instr.operation != MLIL_SET_VAR) - continue; - - if (instr.GetSourceExpr<MLIL_SET_VAR>().operation != MLIL_LOAD_STRUCT) - continue; - - ref.func->CreateUserVariable(instr.GetDestVariable<MLIL_SET_VAR>(), - mlil->GetExprType(instr.GetSourceExpr<MLIL_SET_VAR>()).GetValue(), - nonConflictingLocalName(ref.func, "EfiPeiServices")); - m_view->UpdateAnalysisAndWait(); - } - - return true; -} - -bool PeiResolver::resolvePeiMrc() -{ - auto funcs = m_view->GetAnalysisFunctionList(); - for (auto func : funcs) - { - if (m_task->IsCancelled()) - return false; - - auto mlil = func->GetMediumLevelIL(); - auto blocks = mlil->GetBasicBlocks(); - for (auto block : blocks) - { - for (size_t i = block->GetStart(); i < block->GetEnd(); i++) - { - auto instr = mlil->GetInstruction(i); - if (instr.operation != MLIL_INTRINSIC) - continue; - uint32_t intrinsicIdx = instr.GetIntrinsic<MLIL_INTRINSIC>(); - - if (m_view->GetDefaultArchitecture()->GetIntrinsicName(intrinsicIdx) != "Coproc_GetOneWord") - continue; - auto intrinsicParams = instr.GetParameterExprs<MLIL_INTRINSIC>(); - if (intrinsicParams.size() != 5) - continue; - - bool found = true; - - const int value[5] = {0xf, 0x0, 0xd, 0x0, 0x2}; - for (int j = 0; j < 5; j++) - { - auto param = intrinsicParams[j]; - if (param.operation != MLIL_CONST) - { - found = false; - break; - } - - if (param.GetConstant<MLIL_CONST>() != value[j]) - { - found = false; - break; - } - } - - if (!found) - continue; - - // At this point, we can make sure this instruction fetches EFI_PEI_SERVICES - auto output = instr.GetOutputVariables(); - if (output.size() > 0) - { - auto pointerType = Type::PointerType(m_view->GetDefaultArchitecture(), - Type::PointerType(m_view->GetDefaultArchitecture(), - m_view->GetTypeByName(QualifiedName("EFI_PEI_SERVICES")))); - func->CreateUserVariable(output[0], pointerType, nonConflictingLocalName(func, "PeiServices")); - m_view->UpdateAnalysisAndWait(); - } - } - } - } - return true; -} - -bool PeiResolver::resolvePeiMrs() -{ - // ideally we don't need this function, but since we don't support type propagation on intrinsic instructions - // we have to manually propagate it - auto refs = m_view->GetCodeReferencesForType(QualifiedName("EFI_PEI_SERVICES")); - for (auto ref : refs) - { - if (m_task->IsCancelled()) - return false; - - auto mlil = ref.func->GetMediumLevelIL(); - auto instrIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr); - auto instr = mlil->GetInstruction(instrIdx); - if (instr.operation == MLIL_INTRINSIC) - { - auto params = instr.GetOutputVariables(); - if (params.size() < 1) - continue; - - auto pointerType = Type::PointerType(m_view->GetDefaultArchitecture(), - Type::PointerType( - m_view->GetDefaultArchitecture(), m_view->GetTypeByName(QualifiedName("EFI_PEI_SERVICES")))); - ref.func->CreateUserVariable(params[0], pointerType, nonConflictingLocalName(ref.func, "EfiPeiServices")); - m_view->UpdateAnalysisAndWait(); - } - } - return true; -} - -bool PeiResolver::resolvePlatformPointers() -{ - m_task->SetProgressText("Resolving PEI Services Pointers..."); - string archName = m_view->GetDefaultArchitecture()->GetName(); - string intrinsicTypeName; - - if (archName == "x86" || archName == "x86-64") - { - return resolvePeiIdt(); - } - else if (archName == "arm" || archName == "thumb2") - { - return resolvePeiMrc(); - } - else if (archName == "aarch64") - { - return resolvePeiMrs(); - } - LogError("Not supported arch: %s", archName.c_str()); - return false; -} - -bool PeiResolver::resolvePeiDescriptors() -{ - m_task->SetProgressText("Defining PEI Descriptors..."); - const string descriptorNames[2] = {"EFI_PEI_NOTIFY_DESCRIPTOR", "EFI_PEI_PPI_DESCRIPTOR"}; - for (auto descriptor : descriptorNames) - { - auto refs = m_view->GetCodeReferencesForType(QualifiedName(descriptor)); - for (auto ref : refs) - { - if (m_task->IsCancelled()) - return false; - - auto mlil = ref.func->GetMediumLevelIL(); - auto instrIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), ref.addr); - auto instr = mlil->GetInstruction(instrIdx); - - if (instr.operation != MLIL_CALL && instr.operation != MLIL_TAILCALL) - continue; - - auto destExpr = instr.GetDestExpr(); - if (destExpr.operation != MLIL_LOAD_STRUCT) - continue; - - // at this point this instruction is probably a call to LocatPpi, InstallPpi or NotifyPpi - if (!mlil->GetExprType(destExpr).GetValue()->IsPointer()) - continue; - - auto funcType = mlil->GetExprType(destExpr).GetValue()->GetChildType().GetValue(); - auto params = funcType->GetParameters(); - int targetParamIdx = -1; - for (int i = 0; i < params.size(); i++) - { - auto param = params[i]; - if (!param.type.GetValue()->IsPointer()) - continue; - auto paramTypeName = param.type.GetValue()->GetChildType().GetValue()->GetTypeName().GetString(); - if (paramTypeName.find(descriptor) != paramTypeName.npos) - { - // this is the param - targetParamIdx = i; - break; - } - } - if (targetParamIdx < 0) - continue; - - // Now we are confident that this position is a call that pass Descriptor as a parameter - defineTypeAtCallsite(ref.func, ref.addr, descriptor, targetParamIdx, true); - } - } - return true; -} - -bool PeiResolver::resolvePeiServices() -{ - m_task->SetProgressText("Resolving PPIs..."); - auto refs = m_view->GetCodeReferencesForType(QualifiedName("EFI_PEI_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 * 2) - { - // LocatePpi - resolveGuidInterface(ref.func, ref.addr, 1, 4); - } - else if (offset == 0x18 || offset == 0x18 + m_width || offset == 0x18 + m_width * 3) - { - // InstallPpi, ReinstallPpi, NotifyPpi - } - } - } - return true; -} - -bool PeiResolver::resolvePei() -{ - if (!setModuleEntry(PEI)) - return false; - - if (!resolvePlatformPointers()) - return false; - - if (!resolvePeiDescriptors()) - return false; - - if (!resolvePeiServices()) - return false; - - return true; -} - -PeiResolver::PeiResolver(Ref<BinaryView> view, Ref<BackgroundTask> task) : Resolver(view, task) -{ - initProtocolMapping(); - setModuleEntry(PEI); -} 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/efi_resolver/src/Resolver.cpp b/platform/efi/efi_resolver/src/Resolver.cpp deleted file mode 100644 index 36fa190b..00000000 --- a/platform/efi/efi_resolver/src/Resolver.cpp +++ /dev/null @@ -1,753 +0,0 @@ -#include "Resolver.h" - -string Resolver::nonConflictingName(const string& basename) -{ - int idx = 0; - string name = basename; - do - { - auto sym = m_view->GetSymbolByRawName(name); - if (!sym) - return name; - else - { - name = basename + to_string(idx); - idx += 1; - } - } while (true); -} - -string Resolver::nonConflictingLocalName(Ref<Function> func, const string& basename) -{ - string name = basename; - int idx = 0; - while (true) - { - bool ok = true; - for (const auto& varPair : func->GetVariables()) - { - if (varPair.second.name == name) - { - ok = false; - break; - } - } - if (ok) - break; - name = basename + to_string(idx); - idx += 1; - } - return name; -} - -static string GetBundledEfiPath() -{ - string path = GetBundledPluginDirectory(); -#if defined(_WIN32) - return path + "..\\types\\efi.c"; -#elif defined(__APPLE__) - return path + "/../../Resources/types/efi.c"; -#else - return path + "../types/efi.c"; -#endif -} - -static string GetUserGuidPath() -{ - string path = GetUserDirectory(); -#if defined(_WIN32) - return path + "\\types\\efi-guids.json"; -#elif defined(__APPLE__) - return path + "/types/efi-guids.json"; -#else - return path + "/types/efi-guids.json"; -#endif -} - -static EFI_GUID parseGuid(const string& guidStr) -{ - EFI_GUID guid; - istringstream iss(guidStr); - string token; - unsigned long value; - - getline(iss, token, ','); - value = stoul(token, nullptr, 16); - guid[0] = static_cast<uint8_t>(value); - guid[1] = static_cast<uint8_t>(value >> 8); - guid[2] = static_cast<uint8_t>(value >> 16); - guid[3] = static_cast<uint8_t>(value >> 24); - - getline(iss, token, ','); - value = stoul(token, nullptr, 16); - guid[4] = static_cast<uint8_t>(value); - guid[5] = static_cast<uint8_t>(value >> 8); - - getline(iss, token, ','); - value = stoul(token, nullptr, 16); - guid[6] = static_cast<uint8_t>(value); - guid[7] = static_cast<uint8_t>(value >> 8); - - for (int i = 8; i < 16; i++) - { - getline(iss, token, ','); - value = stoul(token, nullptr, 16); - guid[i] = static_cast<uint8_t>(value); - } - return guid; -} - -bool Resolver::parseProtocolMapping(const string& filePath) -{ - vector<pair<EFI_GUID, string>> guids; - ifstream efiDefs; - string line; - - m_protocol.clear(); - - efiDefs.open(filePath.c_str()); - if (!efiDefs.is_open()) - return false; - - while (getline(efiDefs, line)) - { - if (m_task->IsCancelled()) - return false; - - if (line.substr(0, 12) == "///@protocol") - { - string guid = line.substr(12); - guid.erase(remove_if(guid.begin(), guid.end(), [](char c) { return c == '{' || c == '}' || c == ' '; }), - guid.end()); - guids.emplace_back(parseGuid(guid), ""); - } - else if (line.substr(0, 11) == "///@binding") - { - istringstream iss(line.substr(11)); - string guidName, guid; - iss >> guidName >> guid; - guid.erase(remove_if(guid.begin(), guid.end(), [](char c) { return c == '{' || c == '}' || c == ' '; }), - guid.end()); - guids.emplace_back(parseGuid(guid), guidName); - } - else if (line.substr(0, 6) == "struct") - { - if (guids.empty()) - continue; - istringstream iss(line.substr(6)); - string name; - iss >> name; - for (const auto& guidInfo : guids) - { - if (guidInfo.second.empty()) - { - m_protocol[guidInfo.first] = make_pair(name, name + "_GUID"); - } - else - { - m_protocol[guidInfo.first] = make_pair(name, guidInfo.second); - } - } - } - else - { - guids.clear(); - } - } - efiDefs.close(); - - return true; -} - -bool Resolver::parseUserGuidIfExists(const string& filePath) -{ - ifstream userJson(filePath); - if (!userJson.is_open()) - return false; - - nlohmann::json jsonContent; - userJson >> jsonContent; - - for (const auto& element : jsonContent.items()) - { - if (m_task->IsCancelled()) - return false; - - const auto& guidName = element.key(); - auto guidBytes = element.value(); - if (guidBytes.size() != 11) - { - LogError("Error: GUID array size is incorrect for %s", guidName.c_str()); - return false; - } - EFI_GUID guid; - guid[0] = static_cast<uint8_t>(int(guidBytes[0])); - guid[1] = static_cast<uint8_t>(int(guidBytes[0]) >> 8); - guid[2] = static_cast<uint8_t>(int(guidBytes[0]) >> 16); - guid[3] = static_cast<uint8_t>(int(guidBytes[0]) >> 24); - - guid[4] = static_cast<uint8_t>(int(guidBytes[1])); - guid[5] = static_cast<uint8_t>(int(guidBytes[1]) >> 8); - - guid[6] = static_cast<uint8_t>(int(guidBytes[2])); - guid[7] = static_cast<uint8_t>(int(guidBytes[2]) >> 8); - - for (int i = 8; i < 16; i++) - guid[i] = static_cast<uint8_t>(int(guidBytes[i - 5])); - - // Insert the GUID and its name into the map - m_user_guids[guid] = guidName; - } - - return true; -} - -void Resolver::initProtocolMapping() -{ - if (!m_protocol.empty()) - return; - auto fileName = GetBundledEfiPath(); - if (!parseProtocolMapping(fileName)) - LogAlert("Binary Ninja Version Too Low. Please upgrade to a new version."); - - fileName = GetUserGuidPath(); - parseUserGuidIfExists(fileName); -} - -bool Resolver::setModuleEntry(EFIModuleType fileType) -{ - // Wait until initial analysis is finished - m_view->UpdateAnalysisAndWait(); - - uint64_t entry = m_view->GetEntryPoint(); - auto entryFunc = m_view->GetAnalysisFunction(m_view->GetDefaultPlatform(), entry); - if (!entryFunc) - { - LogDebug("Entry func Not found... "); - return false; - } - - // TODO sometimes the parameter at callsite cannot be correctly recognized, #Vector35/binaryninja-api/4529 - // temporary workaround for this issue, adjust callsite types in entry function if it doesn't has parameters - - // Note: we only adjust the callsite in entry function, this is just a temp fix and it cannot cover all cases - auto callsites = entryFunc->GetCallSites(); - LogDebug("Checking callsites at 0x%llx", entryFunc->GetStart()); - LogDebug("callsite count : %zu", callsites.size()); - for (auto callsite : entryFunc->GetCallSites()) - { - auto mlil = entryFunc->GetMediumLevelIL(); - size_t mlilIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), callsite.addr); - auto instr = mlil->GetInstruction(mlilIdx); - LogDebug("Checking Callsite at 0x%llx", callsite.addr); - if (instr.operation == MLIL_CALL || instr.operation == MLIL_TAILCALL) - { - auto params = instr.GetParameterExprs(); - if (params.size() == 0) - { - // no parameter at call site, check whether it's correctly recognized - auto constantPtr = instr.GetDestExpr(); - if (constantPtr.operation == MLIL_CONST_PTR) - { - auto addr = constantPtr.GetConstant(); - auto funcType = m_view->GetAnalysisFunction(m_view->GetDefaultPlatform(), addr)->GetType(); - entryFunc->SetUserCallTypeAdjustment(m_view->GetDefaultArchitecture(), callsite.addr, funcType); - m_view->UpdateAnalysisAndWait(); - } - else - LogDebug("Operation not ConstPtr: %d", constantPtr.operation); - } - else - LogDebug("param size not zero"); - } - } - - string errors; - QualifiedNameAndType result; - bool ok; - - string typeString; - switch (fileType) - { - case PEI: - { - typeString = "EFI_STATUS _ModuleEntry(EFI_PEI_FILE_HANDLE FileHandle, EFI_PEI_SERVICES **PeiServices)"; - ok = m_view->ParseTypeString(typeString, result, errors, {}, true); - break; - } - - case DXE: - { - typeString = "EFI_STATUS _ModuleEntry(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable)"; - ok = m_view->ParseTypeString(typeString, result, errors, {}, true); - break; - } - - case UNKNOWN: - { - LogAlert("Could not identify EFI module type"); - return false; - } - } - - if (!ok) - return false; - - // use UserType so that it would not be overwritten - entryFunc->SetUserType(result.type); - m_view->DefineUserSymbol(new Symbol(FunctionSymbol, "_ModuleEntry", entry)); - m_view->UpdateAnalysisAndWait(); - - TypePropagation propagation = TypePropagation(m_view); - return propagation.propagateFuncParamTypes(entryFunc); -} - -vector<HighLevelILInstruction> Resolver::HighLevelILExprsAt(Ref<Function> func, Ref<Architecture> arch, uint64_t addr) -{ - auto llil = func->GetLowLevelIL(); - auto mlil = func->GetMediumLevelIL(); - auto hlil = func->GetHighLevelIL(); - - size_t llilIdx = func->GetLowLevelILForInstruction(arch, addr); - size_t llilExprIdx = llil->GetIndexForInstruction(llilIdx); - auto mlilIdxes = llil->GetMediumLevelILExprIndexes(llilExprIdx); - - vector<HighLevelILInstruction> hlils; - - for (size_t mlilIdx : mlilIdxes) - { - auto hlilIdxes = mlil->GetHighLevelILExprIndexes(mlilIdx); - for (auto hlilIdx : hlilIdxes) - { - auto hlilExpr = hlil->GetExpr(hlilIdx); - hlils.push_back(hlilExpr); - } - } - return hlils; -} - -Ref<Type> Resolver::GetTypeFromViewAndPlatform(string typeName) -{ - QualifiedNameAndType result; - string errors; - bool ok = m_view->ParseTypeString(typeName, result, errors); - if (!ok) - { - // TODO how to retrieve platform types? - return nullptr; - } - return result.type; -} - -bool Resolver::resolveGuidInterface(Ref<Function> func, uint64_t addr, int guidPos, int interfacePos) -{ - auto hlils = HighLevelILExprsAt(func, m_view->GetDefaultArchitecture(), addr); - for (auto hlil : hlils) - { - if (hlil.operation != HLIL_CALL) - continue; - - HighLevelILInstruction instr; - if (hlil.GetParameterExprs().size() == 1 && hlil.GetParameterExprs()[0].operation == HLIL_CALL) - instr = hlil.GetParameterExprs()[0]; - else - instr = hlil; - - auto params = instr.GetParameterExprs(); - if (params.size() <= max(guidPos, interfacePos)) - continue; - - auto guidAddr = params[guidPos].GetValue(); - EFI_GUID guid; - if (guidAddr.state == ConstantValue || guidAddr.state == ConstantPointerValue) - { - if (m_view->Read(&guid, guidAddr.value, 16) < 16) - continue; - } - else if (guidAddr.state == StackFrameOffset) - { - auto mlil = instr.GetMediumLevelIL(); - int64_t offset = 0; - vector<uint8_t> contentBytes; - while (offset < 16) - { - auto var = mlil.GetVariableForStackLocation(guidAddr.value + offset); - if (!func->GetVariableType(var)) - break; - - auto width = func->GetVariableType(var)->GetWidth(); - if (width == 0 || width > 8) - break; - - auto value = mlil.GetStackContents(guidAddr.value + offset, width); - int64_t content; - if (value.state == ConstantValue || value.state == ConstantPointerValue) - content = value.value; - else - break; - - for (auto i = 0; i < width; i++) - { - contentBytes.push_back(static_cast<uint8_t>(content >> (i * 8))); - } - } - if (contentBytes.size() != 16) - continue; - - memcpy(guid.data(), contentBytes.data(), 16); - } - else if (params[guidPos].operation == HLIL_VAR) - { - // want to check whether is a protocol wrapper - auto ssa = params[guidPos].GetSSAForm(); - HighLevelILInstruction ssaExpr; - if (ssa.operation != HLIL_VAR_SSA) - continue; - if (ssa.GetSSAVariable().version != 0) - { - auto incomming_def = func->GetHighLevelIL()->GetSSAVarDefinition(ssa.GetSSAVariable()); - if (!incomming_def) - continue; - auto incomming_def_ssa = func->GetHighLevelIL()->GetSSAForm()->GetExpr(incomming_def); - if (incomming_def_ssa.operation != HLIL_VAR_INIT_SSA) - continue; - if (incomming_def_ssa.GetSourceExpr().operation != HLIL_VAR_SSA) - continue; - if (incomming_def_ssa.GetSourceExpr().GetSSAVariable().version != 0) - continue; - ssaExpr = incomming_def_ssa.GetSourceExpr(); - } - else - ssaExpr = ssa; - - auto funcParams = func->GetParameterVariables().GetValue(); - bool found = false; - int incomingGuidIdx; - for (int i = 0; i < funcParams.size(); i++) - { - if (funcParams[i] == ssaExpr.GetSSAVariable().var) - { - incomingGuidIdx = i; - found = true; - break; - } - } - if (!found) - continue; - - // see if output interface varible is an incoming parameter - auto interfaceInstrSsa = params[interfacePos].GetSSAForm(); - if (interfaceInstrSsa.operation != HLIL_VAR_SSA) - continue; - - if (interfaceInstrSsa.GetSSAVariable().version != 0) - { - auto incomingDef = - func->GetHighLevelIL()->GetSSAForm()->GetSSAVarDefinition(interfaceInstrSsa.GetSSAVariable()); - auto defExpr = func->GetHighLevelIL()->GetSSAForm()->GetExpr(incomingDef); - if (defExpr.operation != HLIL_VAR_INIT_SSA) - continue; - if (defExpr.GetSourceExpr().operation != HLIL_VAR_SSA) - continue; - if (defExpr.GetSourceExpr().GetSSAVariable().version != 0) - continue; - interfaceInstrSsa = defExpr.GetSourceExpr(); - } - found = false; - int incomingInstrIdx; - for (int i = 0; i < funcParams.size(); i++) - { - if (funcParams[i] == interfaceInstrSsa.GetSSAVariable().var) - { - incomingInstrIdx = i; - found = true; - break; - } - } - if (!found) - continue; - - LogInfo("Found EFI Protocol wrapper at 0x%llx, checking reference to this function", addr); - - auto refs = m_view->GetCodeReferences(func->GetStart()); - for (auto& ref : refs) - resolveGuidInterface(ref.func, ref.addr, incomingGuidIdx, incomingInstrIdx); - continue; - } - - if (guid.empty()) - continue; - - auto names = lookupGuid(guid); - string protocol_name = names.first; - string guidName = names.second; - - if (protocol_name.empty()) - { - // protocol name is empty - if (!guidName.empty()) - { - // user added guid, check whether the user has added the protocol type - string possible_protocol_type = guidName; - size_t pos = possible_protocol_type.rfind("_GUID"); - if (pos != string::npos) - possible_protocol_type.erase(pos, 5); - - // check whether `possible_protocol_type` is in bv.types - QualifiedNameAndType result; - string errors; - bool ok = m_view->ParseTypeString(possible_protocol_type, result, errors); - if (ok) - protocol_name = possible_protocol_type; - } - else - { - // use UnknownProtocol as defult - LogWarn("Unknown EFI Protocol referenced at 0x%llx", addr); - guidName = nonConflictingName("UnknownProtocolGuid"); - } - } - - // now we just need to rename the GUID and apply the protocol type - auto sym = m_view->GetSymbolByAddress(guidAddr.value); - auto guidVarName = guidName; - if (sym) - guidVarName = sym->GetRawName(); - - QualifiedNameAndType result; - string errors; - bool ok = m_view->ParseTypeString("EFI_GUID", result, errors); - if (!ok) - return false; - m_view->DefineDataVariable(guidAddr.value, result.type); - m_view->DefineUserSymbol(new Symbol(DataSymbol, guidVarName, guidAddr.value)); - - if (protocol_name.empty()) - { - LogWarn("Found unknown protocol at 0x%llx", addr); - protocol_name = "VOID*"; - } - - auto protocolType = GetTypeFromViewAndPlatform(protocol_name); - if (!protocolType) - continue; - protocolType = Type::PointerType(m_view->GetDefaultArchitecture(), protocolType); - auto interfaceParam = params[interfacePos]; - - // TODO we need to check whether it is an aliased var, or it can probably overwrite the other interfaces - - if (interfaceParam.operation == HLIL_ADDRESS_OF) - { - interfaceParam = interfaceParam.GetSourceExpr(); - if (interfaceParam.operation == HLIL_VAR) - { - string interfaceName = guidName; - if (guidName.substr(0, 19) == "UnknownProtocolGuid") - { - interfaceName.replace(0, 19, "UnknownProtocolInterface"); - interfaceName = nonConflictingLocalName(func, interfaceName); - } - else - { - interfaceName = nonConflictingLocalName(func, GetVarNameForTypeStr(guidName)); - } - func->CreateUserVariable(interfaceParam.GetVariable(), protocolType, interfaceName); - } - } - else if (interfaceParam.operation == HLIL_CONST_PTR) - { - auto dataVarAddr = interfaceParam.GetValue().value; - m_view->DefineDataVariable(dataVarAddr, protocolType); - string interfaceName = guidName; - if (interfaceName.find("GUID") != interfaceName.npos) - { - interfaceName = interfaceName.replace(interfaceName.find("GUID"), 4, "INTERFACE"); - interfaceName = GetVarNameForTypeStr(interfaceName); - } - else if (guidName.substr(0, 19) == "UnknownProtocolGuid") - { - interfaceName.replace(15, 4, "Interface"); - } - m_view->DefineUserSymbol(new Symbol(DataSymbol, interfaceName, dataVarAddr)); - } - m_view->UpdateAnalysisAndWait(); - } - - return true; -} - -bool Resolver::defineTypeAtCallsite( - Ref<Function> func, uint64_t addr, const string typeName, int paramIdx, bool followFields) -{ - auto mlil = func->GetMediumLevelIL(); - size_t mlilIdx = mlil->GetInstructionStart(m_view->GetDefaultArchitecture(), addr); - auto instr = mlil->GetInstruction(mlilIdx); - - auto params = instr.GetParameterExprs(); - if (params.size() < paramIdx + 1) - return false; - - auto param = params[paramIdx]; - if (param.operation != MLIL_CONST_PTR) - return false; - - uint64_t varAddr = param.GetConstant(); - DataVariable datavar; - auto ok = m_view->GetDataVariableAtAddress(varAddr, datavar); - if (ok) - { - string datavarTypeName = datavar.type.GetValue()->GetTypeName().GetString(); - if (datavarTypeName.find(typeName) != datavarTypeName.npos) - // the variable already has this type, return - return false; - } - - // Now we want to define the type at varAddr - - if (typeName == "EFI_GUID") - { - // If it's GUID, we want to define it with name - defineAndLookupGuid(varAddr); - // defining a GUID should never fail. Also it can not have fields - return true; - } - - QualifiedNameAndType result; - string errors; - ok = m_view->ParseTypeString(typeName, result, errors); - if (!ok) - { - LogError("Cannot parse type %s when trying to define type at 0x%llx", typeName.c_str(), addr); - return false; - } - - m_view->DefineDataVariable(varAddr, result.type); - - if (!followFields) - return true; - - // We want to define the Guid field and the Notify field, which are both pointers - DataVariable structVar; - ok = m_view->GetDataVariableAtAddress(varAddr, structVar); - if (!ok) - return false; - - if (!structVar.type.GetValue()->IsNamedTypeRefer()) - return false; - - auto structTypeId = structVar.type.GetValue()->GetNamedTypeReference()->GetTypeId(); - auto structStructureType = m_view->GetTypeById(structTypeId)->GetStructure(); - - if (!structStructureType) - return false; - auto members = structStructureType->GetMembers(); - - // we want to keep this name for renaming NotifyFunction - string guidName; - for (auto member : members) - { - auto memberOffset = member.offset; - auto memberType = member.type.GetValue(); - auto memberName = member.name; - - // we only want to define pointers - if (!memberType->IsPointer() && !(memberType->IsNamedTypeRefer() && memberName == "Notify")) - continue; - - if (memberName == "Guid") - { - uint64_t guidAddr = 0; - m_view->Read(&guidAddr, varAddr + memberOffset, m_view->GetAddressSize()); - auto name = defineAndLookupGuid(guidAddr); - guidName = name.second; - } - else if (memberName == "Notify") - { - // Notify has the type EFI_NOTIFY_ENTRY_POINT - // which is a NamedTypeRefer - uint64_t funcAddr; - m_view->Read(&funcAddr, varAddr + memberOffset, m_view->GetAddressSize()); - auto notifyFunc = m_view->GetAnalysisFunction(m_view->GetDefaultPlatform(), funcAddr); - if (!notifyFunc) - continue; - - string funcName = guidName; - if (guidName.empty()) - funcName = nonConflictingName("UnknownNotify"); - else - funcName = "Notify" + funcName.replace(funcName.find("GUID"), 4, ""); - - string notifyTypeStr = - "EFI_STATUS Notify(EFI_PEI_SERVICES **PeiServices, EFI_PEI_NOTIFY_DESCRIPTOR* NotifyDescriptor, VOID* " - "Ppi)"; - ok = m_view->ParseTypeString(notifyTypeStr, result, errors); - notifyFunc->SetUserType(result.type); - m_view->DefineUserSymbol(new Symbol(FunctionSymbol, funcName, funcAddr)); - m_view->UpdateAnalysisAndWait(); - - TypePropagation propagator(m_view); - propagator.propagateFuncParamTypes(notifyFunc); - } - } - return true; -} - -Resolver::Resolver(Ref<BinaryView> view, Ref<BackgroundTask> task) -{ - m_view = view; - m_task = task; - m_width = m_view->GetAddressSize(); -} - -pair<string, string> Resolver::lookupGuid(EFI_GUID guidBytes) -{ - auto it = m_protocol.find(guidBytes); - if (it != m_protocol.end()) - return it->second; - - auto user_it = m_user_guids.find(guidBytes); - if (user_it != m_user_guids.end()) - return make_pair(string(), user_it->second); - - return {}; -} - -pair<string, string> Resolver::defineAndLookupGuid(uint64_t addr) -{ - EFI_GUID guidBytes; - try - { - auto readSize = m_view->Read(&guidBytes, addr, 16); - if (readSize != 16) - return make_pair(string(), string()); - } - catch (ReadException) - { - LogError("Read GUID failed at 0x%llx", addr); - return make_pair(string(), string()); - } - auto namePair = lookupGuid(guidBytes); - string protocolName = namePair.first; - string guidName = namePair.second; - - QualifiedNameAndType result; - string errors; - // must use ParseTypeString, - // m_view->GetTypeByName() doesn't return a NamedTypeReference and the DataRenderer doesn't applied - bool ok = m_view->ParseTypeString("EFI_GUID", result, errors); - if (!ok) - return make_pair(string(""), string("")); - m_view->DefineDataVariable(addr, result.type); - if (guidName.empty()) - { - m_view->DefineUserSymbol(new Symbol(DataSymbol, nonConflictingName("UnknownGuid"), addr)); - LogDebug("Found UnknownGuid at 0x%llx", addr); - } - else - { - m_view->DefineUserSymbol(new Symbol(DataSymbol, guidName, addr)); - LogDebug("Define %s at 0x%llx", guidName.c_str(), addr); - } - - return namePair; -} diff --git a/platform/efi/efi_resolver/src/TypePropagation.cpp b/platform/efi/efi_resolver/src/TypePropagation.cpp deleted file mode 100644 index ff0d43b9..00000000 --- a/platform/efi/efi_resolver/src/TypePropagation.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#include "TypePropagation.h" -#include "highlevelilinstruction.h" - -TypePropagation::TypePropagation(BinaryView* view) -{ - m_view = view; - m_queue.clear(); - m_platform = view->GetDefaultPlatform(); -} - -const std::map<std::string, std::string> defaultName = {{"EFI_SYSTEM_TABLE", "gST"}, {"EFI_BOOT_SERVICES", "gBS"}, - {"EFI_RUNTIME_SERVICES", "gRT"}, {"EFI_MM_SYSTEM_TABLE", "gMmst"}, {"EFI_SMM_SYSTEM_TABLE2", "gSmmst"}, - {"EFI_HANDLE", "gHandle"}}; - -bool TypePropagation::propagateFuncParamTypes(Function* func) -{ - m_queue.push_back(func->GetStart()); - - LogDebug("Start Type propagation from 0x%llx", func->GetStart()); - - while (!m_queue.empty()) - { - uint64_t addr = m_queue.front(); - m_queue.pop_front(); - - Ref<Function> target_func = m_view->GetAnalysisFunction(m_platform, addr); - auto params = target_func->GetType()->GetParameters(); - bool update = false; - - auto param_vars = target_func->GetParameterVariables().GetValue(); - for (auto var : param_vars) - { - bool propagate = false; - auto var_type = target_func->GetVariableType(var).GetValue(); - - if (var_type->IsPointer()) - { - Ref<Type> target_type = var_type->GetChildType().GetValue(); - if (target_type->IsPointer() || target_type->IsNamedTypeRefer()) - propagate = true; - } - else if (var_type->IsNamedTypeRefer()) - { - Ref<Type> target_type = m_view->GetTypeById(var_type->GetNamedTypeReference()->GetTypeId()); - if (target_type->IsPointer()) - propagate = true; - } - if (!propagate) - continue; - - // Check whether the param is an aliased var. If it's an aliased var, it may not be directly used in the - // function - Ref<HighLevelILFunction> hlil_func_ssa = target_func->GetHighLevelIL()->GetSSAForm(); - std::set<Variable> aliased_vars = target_func->GetHighLevelILAliasedVariables(); - - auto it = aliased_vars.find(var); - if (it == aliased_vars.end()) - { - // not an aliaed var, use version 0 - update |= propagateFuncParamTypes(target_func, SSAVariable(var, 0)); - } - else - { - // this param is an aliased var, get the ssa_var - auto uses = target_func->GetHighLevelIL()->GetVariableUses(var); - for (auto use : uses) - { - auto hlil_instr = target_func->GetHighLevelIL()->GetExpr(use); - hlil_instr = hlil_instr.GetParent(); - if (hlil_instr.operation != HLIL_VAR_INIT) - continue; - SSAVariable ssa_var = hlil_instr.GetSSAForm().GetDestSSAVariable(); - update |= propagateFuncParamTypes(target_func, ssa_var); - } - } - } - - if (update) - m_view->UpdateAnalysisAndWait(); - } - return true; -} - -bool TypePropagation::propagateFuncParamTypes(Function* func, SSAVariable ssa_var) -{ - bool update = false; - auto mlil_func_ssa = func->GetMediumLevelIL()->GetSSAForm(); - auto uses = mlil_func_ssa->GetSSAVarUses(ssa_var); - for (auto use : uses) - { - auto instr = mlil_func_ssa->GetInstruction(use); - switch (instr.operation) - { - case MLIL_CALL_SSA: - case MLIL_TAILCALL_SSA: - { - // propagate variable type to sub function - auto dest = instr.GetDestExpr(); - if (!dest.GetValue().IsConstant()) - continue; - Ref<Function> subfunc = m_view->GetAnalysisFunction(m_platform, dest.GetValue().value); - - if (!subfunc) - continue; - - auto subfunc_type = subfunc->GetType(); - auto subfunc_params = subfunc->GetType()->GetParameters(); - - auto instr_params = instr.GetParameterExprs(); - for (int i = 0; i < instr_params.size(); i++) - { - if (instr_params[i].operation != MLIL_VAR_SSA) - continue; - if (instr_params[i].GetSourceSSAVariable() != ssa_var) - continue; - if (i >= subfunc_params.size()) - break; - auto ssa_var_type = func->GetVariableType(ssa_var.var).GetValue(); - auto typeName = GetOriginalTypeName(ssa_var_type); - - auto changeFuncType = - [](BinaryView* bv, Ref<Type> funcType, std::string paramName, Ref<Type> paramType, int paramIdx) { - auto newFuncType = TypeBuilder(funcType); - auto adjustedParams = newFuncType.GetParameters(); - adjustedParams.at(paramIdx) = FunctionParameter(paramName, paramType); - newFuncType.SetParameters(adjustedParams); - return newFuncType.Finalize(); - }; - - subfunc->SetUserType( - changeFuncType(m_view, subfunc_type, GetVarNameForTypeStr(typeName), ssa_var_type, i)); - m_view->UpdateAnalysisAndWait(); - - if (std::find(m_queue.begin(), m_queue.end(), subfunc->GetStart()) == m_queue.end()) - m_queue.push_back(subfunc->GetStart()); - update = true; - break; - } - break; - } - - case MLIL_STORE_SSA: - { - auto target = instr.GetDestExpr<MLIL_STORE_SSA>(); - if (!target.GetValue().IsConstant()) - continue; - auto constant = target.GetValue().value; - auto ssa_var_type = func->GetVariableType(ssa_var.var).GetValue(); - auto typeName = GetOriginalTypeName(ssa_var_type); - - auto it = defaultName.find(typeName); - if (it != defaultName.end()) - typeName = it->second; - - m_view->DefineDataVariable(constant, ssa_var_type); - m_view->DefineUserSymbol(new Symbol(DataSymbol, typeName, constant)); - - update = true; - break; - } - - case MLIL_SET_VAR_SSA: - { - auto src = instr.GetSourceExpr<MLIL_SET_VAR_SSA>(); - auto dest = instr.GetDestSSAVariable<MLIL_SET_VAR_SSA>(); - - auto dest_type = func->GetVariableType(dest.var); - Confidence<Ref<Type>> src_type; - switch (src.operation) - { - case MLIL_VAR_SSA: - src_type = func->GetVariableType(src.GetSourceSSAVariable().var); - break; - - case MLIL_LOAD_SSA: - case MLIL_LOAD_STRUCT_SSA: - src_type = src.GetType(); - break; - - default: - continue; - } - - if (src_type.GetValue() && src_type.GetValue() != dest_type.GetValue()) - { - func->CreateUserVariable(dest.var, src_type, func->GetVariableName(dest.var)); - update |= propagateFuncParamTypes(func, SSAVariable(dest.var, dest.version)); - } - break; - } - - default: - LogInfo("Not handled case during type propagation. At %llx: %d", instr.address, instr.operation); - break; - } - } - return update; -} |
