From 801b4138784a45643a7201b7e54105ea5eb3b6c4 Mon Sep 17 00:00:00 2001 From: Brian Potchik Date: Fri, 13 Aug 2021 18:48:51 -0400 Subject: Workflows early preview. --- examples/workflows/inliner/inliner.cpp | 159 +++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 examples/workflows/inliner/inliner.cpp (limited to 'examples/workflows/inliner/inliner.cpp') diff --git a/examples/workflows/inliner/inliner.cpp b/examples/workflows/inliner/inliner.cpp new file mode 100644 index 00000000..01eacbd2 --- /dev/null +++ b/examples/workflows/inliner/inliner.cpp @@ -0,0 +1,159 @@ +#define _CRT_SECURE_NO_WARNINGS +#define NOMINMAX + +#include +#include +#include +#include +#include +#include + +#include "binaryninjaapi.h" +#include "lowlevelilinstruction.h" +#include "mediumlevelilinstruction.h" + + +using namespace BinaryNinja; +using namespace std; + +#if defined(_MSC_VER) +#define snprintf _snprintf +#endif + + +extern "C" +{ + BN_DECLARE_CORE_ABI_VERSION + + unordered_map> g_callSiteInlines; + + void FunctionInliner(Ref analysisContext) + { + Ref function = analysisContext->GetFunction(); + Ref data = function->GetView(); + + set callSiteInlines; + if (const auto& itr = g_callSiteInlines.find(function->GetStart()); itr != g_callSiteInlines.end()) + callSiteInlines = itr->second; + + bool updated = false; + uint8_t opcode[BN_MAX_INSTRUCTION_LENGTH]; + InstructionInfo iInfo; + Ref llilFunc = analysisContext->GetLowLevelILFunction(); + for (const auto inlineAddr : callSiteInlines) + { + // if (m_owner->IsAborted()) + // return; + + for (auto& i : llilFunc->GetBasicBlocks()) + { + Ref arch = i->GetArchitecture(); + for (size_t instrIndex = i->GetStart(); instrIndex < i->GetEnd(); instrIndex++) + { + LowLevelILInstruction instr = llilFunc->GetInstruction(instrIndex); + + if (instr.address != inlineAddr) + continue; + + if (instr.operation != LLIL_CALL) + { + LogWarn("Failed to inline function at: 0x%" PRIx64 ". Mapping to LLIL_CALL Failed!", instr.address); + continue; + } + + uint64_t platformAddr; + LowLevelILInstruction destExpr = instr.GetDestExpr(); + RegisterValue target = destExpr.GetValue(); + if (target.IsConstant()) + platformAddr = target.value; + else + { + LogWarn("Failed to inline function at: 0x%" PRIx64 ". Destination not Constant!", instr.address); + continue; + } + + size_t opLen = data->Read(opcode, instr.address, arch->GetMaxInstructionLength()); + if (!opLen || !arch->GetInstructionInfo(opcode, instr.address, opLen, iInfo)) + continue; + Ref platform = iInfo.archTransitionByTargetAddr ? function->GetPlatform()->GetAssociatedPlatformByAddress(platformAddr) : function->GetPlatform(); + if (platform) + { + Ref targetFunc = data->GetAnalysisFunction(platform, platformAddr); + auto targetLlil = targetFunc->GetLowLevelIL(); + LowLevelILLabel inlineStartLabel; + llilFunc->MarkLabel(inlineStartLabel); + instr.Replace(llilFunc->Goto(inlineStartLabel)); + + llilFunc->PrepareToCopyFunction(targetLlil); + for (auto& ti : targetLlil->GetBasicBlocks()) + { + llilFunc->PrepareToCopyBlock(ti); + for (size_t tinstrIndex = ti->GetStart(); tinstrIndex < ti->GetEnd(); tinstrIndex++) + { + LowLevelILInstruction tinstr = targetLlil->GetInstruction(tinstrIndex); + if (tinstr.operation == LLIL_RET) + { + LowLevelILLabel label; + label.operand = instrIndex + 1; + llilFunc->AddInstruction(llilFunc->Pop(instr.size)); + llilFunc->AddInstruction(llilFunc->Goto(label)); + } + else + llilFunc->AddInstruction(tinstr.CopyTo(llilFunc)); + } + } + llilFunc->Finalize(); + } + + updated = true; + break; + } + } + } + + if (!updated) + return; + + // Updates found, regenerate SSA form + llilFunc->GenerateSSAForm(); + } + + + BINARYNINJAPLUGIN bool CorePluginInit() + { + auto inlinerIsValid = [](BinaryView* view, Function* func) { + if (auto workflow = func->GetWorkflow(); workflow) + return workflow->Contains("extension.functionInliner"); + return false; + }; + + // PluginCommand::RegisterForFunction( + // "Optimizer\\Inline All Calls to Current Function", + // "Inline all calls to the current function.", + // [](BinaryView* view, Function* func) { + // LogError("TODO Inline Current Function: %" PRIx64, func->GetStart()); + // }, inlinerIsValid); + + PluginCommand::RegisterForFunction( + "Optimizer\\Inline Function at Current Call Site", + "Inline function call at current call site.", + [](BinaryView* view, Function* func) { + // TODO func->Inform("inlinedCallSites") + // TODO resolve multiple embedded inlines + g_callSiteInlines[func->GetStart()].insert(view->GetCurrentOffset()); + func->Reanalyze(); + }, inlinerIsValid); + + Ref inlinerWorkflow = Workflow::Instance()->Clone("InlinerWorkflow"); + inlinerWorkflow->RegisterActivity(new Activity("extension.functionInliner", &FunctionInliner)); + inlinerWorkflow->Insert("core.function.translateTailCalls", "extension.functionInliner"); + Workflow::RegisterWorkflow(inlinerWorkflow, + R"#({ + "title" : "Function Inliner (Example)", + "description" : "This analysis stands in as an example to demonstrate Binary Ninja's extensible analysis APIs. ***Note** this feature is under active development and subject to change without notice.", + "capabilities" : [] + })#"); + + return true; + } +} -- cgit v1.3.1