#include "binaryninjaapi.h" #include "rapidjsonwrapper.h" #include #include using namespace BinaryNinja; using namespace std; AnalysisContext::AnalysisContext(BNAnalysisContext* analysisContext) { // LogError("API-Side AnalysisContext Constructed!"); m_object = analysisContext; } AnalysisContext::~AnalysisContext() { // LogError("API-Side AnalysisContext Destructed!"); } Ref AnalysisContext::GetBinaryView() { BNBinaryView* view = BNAnalysisContextGetBinaryView(m_object); if (!view) return nullptr; return new BinaryView(view); } Ref AnalysisContext::GetFunction() { BNFunction* func = BNAnalysisContextGetFunction(m_object); if (!func) return nullptr; return new Function(func); } Ref AnalysisContext::GetLiftedILFunction() { BNLowLevelILFunction* func = BNAnalysisContextGetLiftedILFunction(m_object); if (!func) return nullptr; return new LowLevelILFunction(func); } Ref AnalysisContext::GetLowLevelILFunction() { BNLowLevelILFunction* func = BNAnalysisContextGetLowLevelILFunction(m_object); if (!func) return nullptr; return new LowLevelILFunction(func); } Ref AnalysisContext::GetMediumLevelILFunction() { BNMediumLevelILFunction* func = BNAnalysisContextGetMediumLevelILFunction(m_object); if (!func) return nullptr; return new MediumLevelILFunction(func); } Ref AnalysisContext::GetHighLevelILFunction() { BNHighLevelILFunction* func = BNAnalysisContextGetHighLevelILFunction(m_object); if (!func) return nullptr; return new HighLevelILFunction(func); } void AnalysisContext::SetBasicBlockList(vector> basicBlocks) { BNBasicBlock** blocks = new BNBasicBlock*[basicBlocks.size()]; size_t i = 0; for (auto& j : basicBlocks) blocks[i++] = j->GetObject(); BNSetBasicBlockList(m_object, blocks, basicBlocks.size()); delete[] blocks; } void AnalysisContext::SetLiftedILFunction(Ref liftedIL) { BNSetLiftedILFunction(m_object, liftedIL->m_object); } void AnalysisContext::SetLowLevelILFunction(Ref lowLevelIL) { BNSetLowLevelILFunction(m_object, lowLevelIL->m_object); } void AnalysisContext::SetMediumLevelILFunction( Ref mediumLevelIL, std::unordered_map llilSsaToMlilInstrMap, std::vector llilSsaToMlilExprMap ) { if (llilSsaToMlilExprMap.empty() || llilSsaToMlilInstrMap.empty()) { // Build up maps from existing data in the function llilSsaToMlilExprMap = mediumLevelIL->GetLLILSSAToMLILExprMap(true); llilSsaToMlilInstrMap = mediumLevelIL->GetLLILSSAToMLILInstrMap(true); } std::vector instrMapVec; // Technically imprecise but doesn't matter this is just reserving instrMapVec.reserve(llilSsaToMlilInstrMap.size()); for (auto& [llilSSAIndex, mlilIndex]: llilSsaToMlilInstrMap) { if (instrMapVec.size() <= llilSSAIndex) { instrMapVec.resize(llilSSAIndex + 1, BN_INVALID_EXPR); } instrMapVec[llilSSAIndex] = mlilIndex; } BNSetMediumLevelILFunction( m_object, mediumLevelIL->m_object, instrMapVec.data(), instrMapVec.size(), llilSsaToMlilExprMap.data(), llilSsaToMlilExprMap.size() ); } void AnalysisContext::SetHighLevelILFunction(Ref highLevelIL) { BNSetHighLevelILFunction(m_object, highLevelIL->m_object); } bool AnalysisContext::Inform(const char* request) { return BNAnalysisContextInform(m_object, request); } bool AnalysisContext::Inform(const string& request) { return BNAnalysisContextInform(m_object, request.c_str()); } // Template specializations for GetSetting template<> bool AnalysisContext::GetSetting(const string& key) { return BNAnalysisContextGetSettingBool(m_object, key.c_str()); } template<> double AnalysisContext::GetSetting(const string& key) { return BNAnalysisContextGetSettingDouble(m_object, key.c_str()); } template<> int64_t AnalysisContext::GetSetting(const string& key) { return BNAnalysisContextGetSettingInt64(m_object, key.c_str()); } template<> uint64_t AnalysisContext::GetSetting(const string& key) { return BNAnalysisContextGetSettingUInt64(m_object, key.c_str()); } template<> string AnalysisContext::GetSetting(const string& key) { char* str = BNAnalysisContextGetSettingString(m_object, key.c_str()); string result = str; BNFreeString(str); return result; } template<> vector AnalysisContext::GetSetting>(const string& key) { size_t count = 0; char** list = BNAnalysisContextGetSettingStringList(m_object, key.c_str(), &count); vector result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(list[i]); BNFreeStringList(list, count); return result; } bool AnalysisContext::IsValidOffset(uint64_t offset) { return BNAnalysisContextIsValidOffset(m_object, offset); } bool AnalysisContext::IsOffsetReadable(uint64_t offset) { return BNAnalysisContextIsOffsetReadable(m_object, offset); } bool AnalysisContext::IsOffsetWritable(uint64_t offset) { return BNAnalysisContextIsOffsetWritable(m_object, offset); } bool AnalysisContext::IsOffsetExecutable(uint64_t offset) { return BNAnalysisContextIsOffsetExecutable(m_object, offset); } bool AnalysisContext::IsOffsetBackedByFile(uint64_t offset) { return BNAnalysisContextIsOffsetBackedByFile(m_object, offset); } bool AnalysisContext::IsOffsetCodeSemantics(uint64_t offset) { return BNAnalysisContextIsOffsetCodeSemantics(m_object, offset); } bool AnalysisContext::IsOffsetExternSemantics(uint64_t offset) { return BNAnalysisContextIsOffsetExternSemantics(m_object, offset); } bool AnalysisContext::IsOffsetWritableSemantics(uint64_t offset) { return BNAnalysisContextIsOffsetWritableSemantics(m_object, offset); } bool AnalysisContext::IsOffsetReadOnlySemantics(uint64_t offset) { return BNAnalysisContextIsOffsetReadOnlySemantics(m_object, offset); } vector> AnalysisContext::GetSections() { size_t count; BNSection** sections = BNAnalysisContextGetSections(m_object, &count); vector> result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(new Section(BNNewSectionReference(sections[i]))); BNFreeSectionList(sections, count); return result; } Ref
AnalysisContext::GetSectionByName(const string& name) { BNSection* section = BNAnalysisContextGetSectionByName(m_object, name.c_str()); if (!section) return nullptr; return new Section(section); } vector> AnalysisContext::GetSectionsAt(uint64_t addr) { size_t count; BNSection** sections = BNAnalysisContextGetSectionsAt(m_object, addr, &count); vector> result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(new Section(BNNewSectionReference(sections[i]))); BNFreeSectionList(sections, count); return result; } uint64_t AnalysisContext::GetStart() { return BNAnalysisContextGetStart(m_object); } uint64_t AnalysisContext::GetEnd() { return BNAnalysisContextGetEnd(m_object); } uint64_t AnalysisContext::GetLength() { return BNAnalysisContextGetLength(m_object); } uint64_t AnalysisContext::GetNextValidOffset(uint64_t offset) { return BNAnalysisContextGetNextValidOffset(m_object, offset); } uint64_t AnalysisContext::GetNextMappedAddress(uint64_t addr, uint32_t flags) { return BNAnalysisContextGetNextMappedAddress(m_object, addr, flags); } uint64_t AnalysisContext::GetNextBackedAddress(uint64_t addr, uint32_t flags) { return BNAnalysisContextGetNextBackedAddress(m_object, addr, flags); } Ref AnalysisContext::GetSegmentAt(uint64_t addr) { BNSegment* segment = BNAnalysisContextGetSegmentAt(m_object, addr); if (!segment) return nullptr; return new Segment(segment); } vector AnalysisContext::GetMappedAddressRanges() { size_t count = 0; BNAddressRange* ranges = BNAnalysisContextGetMappedAddressRanges(m_object, &count); vector result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(ranges[i]); BNFreeAddressRanges(ranges); return result; } vector AnalysisContext::GetBackedAddressRanges() { size_t count = 0; BNAddressRange* ranges = BNAnalysisContextGetBackedAddressRanges(m_object, &count); vector result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(ranges[i]); BNFreeAddressRanges(ranges); return result; } bool WorkflowMachine::PostRequest(const std::string& command) { rapidjson::Document request(rapidjson::kObjectType); rapidjson::Document::AllocatorType& allocator = request.GetAllocator(); rapidjson::Value commandValue(command.c_str(), command.size(), allocator); request.AddMember("command", commandValue, allocator); rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); request.Accept(writer); string jsonResult; if (m_function) jsonResult = BNPostWorkflowRequestForFunction(m_function->GetObject(), buffer.GetString()); else jsonResult = BNPostWorkflowRequestForBinaryView(m_view->GetObject(), buffer.GetString()); rapidjson::Document response(rapidjson::kObjectType); response.Parse(jsonResult.c_str()); if (response.HasMember("commandStatus") && response["commandStatus"].HasMember("accepted")) return response["commandStatus"]["accepted"].GetBool(); return false; } WorkflowMachine::WorkflowMachine(Ref view): m_view(view) { } WorkflowMachine::WorkflowMachine(Ref function): m_function(function) { } bool WorkflowMachine::PostJsonRequest(const std::string& request) { string jsonResult; if (m_function) jsonResult = BNPostWorkflowRequestForFunction(m_function->GetObject(), request.c_str()); else jsonResult = BNPostWorkflowRequestForBinaryView(m_view->GetObject(), request.c_str()); rapidjson::Document response(rapidjson::kObjectType); response.Parse(jsonResult.c_str()); if (response.HasMember("commandStatus") && response["commandStatus"].HasMember("accepted")) return response["commandStatus"]["accepted"].GetBool(); return false; } Ref WorkflowMachine::GetGraph(const std::string& activity, bool sequential) { BNFlowGraph* graph; if (m_function) graph = BNGetWorkflowGraphForFunction(m_function->GetObject(), activity.c_str(), sequential); else graph = BNGetWorkflowGraphForBinaryView(m_view->GetObject(), activity.c_str(), sequential); return new CoreFlowGraph(graph); } void WorkflowMachine::ShowTopology() { if (m_function) BNShowWorkflowReportForFunction(m_function->GetObject(), "topology"); else BNShowWorkflowReportForBinaryView(m_view->GetObject(), "topology"); } WorkflowMachine::Status WorkflowMachine::GetStatus() { WorkflowMachine::Status status; rapidjson::Document request(rapidjson::kObjectType); rapidjson::Document::AllocatorType& allocator = request.GetAllocator(); request.AddMember("command", "status", allocator); rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); request.Accept(writer); string jsonResult; if (m_function) jsonResult = BNPostWorkflowRequestForFunction(m_function->GetObject(), buffer.GetString()); else jsonResult = BNPostWorkflowRequestForBinaryView(m_view->GetObject(), buffer.GetString()); rapidjson::Document response(rapidjson::kObjectType); response.Parse(jsonResult.c_str()); if (response.HasMember("machineState") && response["machineState"].HasMember("state") && response["machineState"].HasMember("activity")) { status.state = response["machineState"]["state"].GetString(); status.activity = response["machineState"]["activity"].GetString(); } if (response.HasMember("logStatus") && response["logStatus"].HasMember("local") && response["logStatus"].HasMember("global")) { status.localLogEnabled = response["logStatus"]["local"].GetBool(); status.globalLogEnabled = response["logStatus"]["global"].GetBool(); } return status; } bool WorkflowMachine::Resume() { return PostRequest("resume"); } bool WorkflowMachine::Run() { return PostRequest("run"); } bool WorkflowMachine::Configure() { return PostRequest("configure"); } bool WorkflowMachine::Halt() { return PostRequest("halt"); } bool WorkflowMachine::Reset() { return PostRequest("reset"); } bool WorkflowMachine::Enable() { return PostRequest("enable"); } bool WorkflowMachine::Disable() { return PostRequest("disable"); } bool WorkflowMachine::Step() { return PostRequest("step"); } bool WorkflowMachine::SetLogEnabled(bool enable, bool global) { rapidjson::Document request(rapidjson::kObjectType); rapidjson::Document::AllocatorType& allocator = request.GetAllocator(); request.AddMember("command", "log", allocator); request.AddMember("enable", enable, allocator); request.AddMember("global", global, allocator); rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); request.Accept(writer); string jsonResult; if (m_function) jsonResult = BNPostWorkflowRequestForFunction(m_function->GetObject(), buffer.GetString()); else jsonResult = BNPostWorkflowRequestForBinaryView(m_view->GetObject(), buffer.GetString()); rapidjson::Document response(rapidjson::kObjectType); response.Parse(jsonResult.c_str()); if (response.HasMember("commandStatus") && response["commandStatus"].HasMember("accepted")) return response["commandStatus"]["accepted"].GetBool(); return false; } std::optional WorkflowMachine::QueryOverride(const string& activity) { rapidjson::Document request(rapidjson::kObjectType); rapidjson::Document::AllocatorType& allocator = request.GetAllocator(); request.AddMember("command", "override", allocator); request.AddMember("action", "query", allocator); request.AddMember("activity", activity, allocator); rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); request.Accept(writer); string jsonResult; if (m_function) jsonResult = BNPostWorkflowRequestForFunction(m_function->GetObject(), buffer.GetString()); else jsonResult = BNPostWorkflowRequestForBinaryView(m_view->GetObject(), buffer.GetString()); rapidjson::Document response(rapidjson::kObjectType); response.Parse(jsonResult.c_str()); if (response.HasMember("response") && response["response"].HasMember("activity") && response["response"]["activity"].HasMember("override")) return response["response"]["activity"]["override"].GetBool(); return std::nullopt; } bool WorkflowMachine::SetOverride(const string& activity, bool enable) { rapidjson::Document request(rapidjson::kObjectType); rapidjson::Document::AllocatorType& allocator = request.GetAllocator(); request.AddMember("command", "override", allocator); request.AddMember("action", "set", allocator); request.AddMember("activity", activity, allocator); request.AddMember("enable", enable, allocator); rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); request.Accept(writer); string jsonResult; if (m_function) jsonResult = BNPostWorkflowRequestForFunction(m_function->GetObject(), buffer.GetString()); else jsonResult = BNPostWorkflowRequestForBinaryView(m_view->GetObject(), buffer.GetString()); rapidjson::Document response(rapidjson::kObjectType); response.Parse(jsonResult.c_str()); if (response.HasMember("commandStatus") && response["commandStatus"].HasMember("accepted")) return response["commandStatus"]["accepted"].GetBool(); return false; } bool WorkflowMachine::ClearOverride(const string& activity) { rapidjson::Document request(rapidjson::kObjectType); rapidjson::Document::AllocatorType& allocator = request.GetAllocator(); request.AddMember("command", "override", allocator); request.AddMember("action", "clear", allocator); request.AddMember("activity", activity, allocator); rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); request.Accept(writer); string jsonResult; if (m_function) jsonResult = BNPostWorkflowRequestForFunction(m_function->GetObject(), buffer.GetString()); else jsonResult = BNPostWorkflowRequestForBinaryView(m_view->GetObject(), buffer.GetString()); rapidjson::Document response(rapidjson::kObjectType); response.Parse(jsonResult.c_str()); if (response.HasMember("commandStatus") && response["commandStatus"].HasMember("accepted")) return response["commandStatus"]["accepted"].GetBool(); return false; } Workflow::Workflow(const string& name) { m_object = BNCreateWorkflow(name.c_str()); } Workflow::Workflow(BNWorkflow* workflow) { m_object = workflow; } Workflow::Workflow(BNWorkflow* workflow, Ref view) { m_object = workflow; m_machine = make_unique(view); } Workflow::Workflow(BNWorkflow* workflow, Ref function) { m_object = workflow; m_machine = make_unique(function); } vector> Workflow::GetList() { size_t count; BNWorkflow** list = BNGetWorkflowList(&count); vector> result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(new Workflow(BNNewWorkflowReference(list[i]))); BNFreeWorkflowList(list, count); return result; } Ref Workflow::Get(const string& name) { auto result = BNWorkflowGet(name.c_str()); if (!result) return nullptr; return new Workflow(result); } Ref Workflow::GetOrCreate(const string& name) { return new Workflow(BNWorkflowGetOrCreate(name.c_str())); } bool Workflow::RegisterWorkflow(Ref workflow, const string& configuration) { return BNRegisterWorkflow(workflow->m_object, configuration.c_str()); } Ref Workflow::Clone(const string& name, const string& activity) { return new Workflow(BNWorkflowClone(m_object, name.c_str(), activity.c_str())); } Ref Workflow::RegisterActivity(const string& configuration, const function)>& action, const vector& subactivities) { return RegisterActivity(new Activity(configuration, action), subactivities); } Ref Workflow::RegisterActivity(Ref activity, const vector& subactivities) { char** buffer = new char*[subactivities.size()]; if (!buffer) return nullptr; activity->AddRefForRegistration(); // TODO for (size_t i = 0; i < subactivities.size(); i++) buffer[i] = BNAllocString(subactivities[i].c_str()); BNActivity* activityObject = BNWorkflowRegisterActivity(m_object, activity->GetObject(), (const char**)buffer, subactivities.size()); for (size_t i = 0; i < subactivities.size(); i++) BNFreeString(buffer[i]); delete[] buffer; if (!activityObject) return nullptr; return new Activity(BNNewActivityReference(activityObject)); } bool Workflow::Contains(const string& activity) { return BNWorkflowContains(m_object, activity.c_str()); } string Workflow::GetConfiguration(const string& activity) { char* tmpStr = BNWorkflowGetConfiguration(m_object, activity.c_str()); string result(tmpStr); BNFreeString(tmpStr); return result; } string Workflow::GetName() const { char* str = BNGetWorkflowName(m_object); string result = str; BNFreeString(str); return result; } bool Workflow::IsRegistered() const { return BNWorkflowIsRegistered(m_object); } size_t Workflow::Size() const { return BNWorkflowSize(m_object); } Ref Workflow::GetActivity(const string& activity) { BNActivity* activityObject = BNWorkflowGetActivity(m_object, activity.c_str()); return new Activity(BNNewActivityReference(activityObject)); } vector Workflow::GetActivityRoots(const string& activity) { size_t size = 0; char** outBuffer = (char**)BNWorkflowGetActivityRoots(m_object, activity.c_str(), &size); vector result; result.reserve(size); for (size_t i = 0; i < size; i++) result.emplace_back(outBuffer[i]); BNFreeStringList(outBuffer, size); return result; } vector Workflow::GetSubactivities(const string& activity, bool immediate) { size_t size = 0; char** outBuffer = (char**)BNWorkflowGetSubactivities(m_object, activity.c_str(), immediate, &size); vector result; result.reserve(size); for (size_t i = 0; i < size; i++) result.emplace_back(outBuffer[i]); BNFreeStringList(outBuffer, size); return result; } bool Workflow::AssignSubactivities(const string& activity, const vector& subactivities) { char** buffer = new char*[subactivities.size()]; if (!buffer) return false; for (size_t i = 0; i < subactivities.size(); i++) buffer[i] = BNAllocString(subactivities[i].c_str()); bool result = BNWorkflowAssignSubactivities(m_object, activity.c_str(), (const char**)buffer, subactivities.size()); for (size_t i = 0; i < subactivities.size(); i++) BNFreeString(buffer[i]); delete[] buffer; return result; } bool Workflow::Clear() { return BNWorkflowClear(m_object); } bool Workflow::Insert(const string& activity, const string& newActivity) { char* buffer[1]; buffer[0] = BNAllocString(newActivity.c_str()); bool result = BNWorkflowInsert(m_object, activity.c_str(), (const char**)buffer, 1); BNFreeString(buffer[0]); return result; } bool Workflow::Insert(const string& activity, const vector& activities) { char** buffer = new char*[activities.size()]; if (!buffer) return false; for (size_t i = 0; i < activities.size(); i++) buffer[i] = BNAllocString(activities[i].c_str()); bool result = BNWorkflowInsert(m_object, activity.c_str(), (const char**)buffer, activities.size()); for (size_t i = 0; i < activities.size(); i++) BNFreeString(buffer[i]); delete[] buffer; return result; } bool Workflow::InsertAfter(const string& activity, const string& newActivity) { char* buffer[1]; buffer[0] = BNAllocString(newActivity.c_str()); bool result = BNWorkflowInsertAfter(m_object, activity.c_str(), (const char**)buffer, 1); BNFreeString(buffer[0]); return result; } bool Workflow::InsertAfter(const string& activity, const vector& activities) { char** buffer = new char*[activities.size()]; if (!buffer) return false; for (size_t i = 0; i < activities.size(); i++) buffer[i] = BNAllocString(activities[i].c_str()); bool result = BNWorkflowInsertAfter(m_object, activity.c_str(), (const char**)buffer, activities.size()); for (size_t i = 0; i < activities.size(); i++) BNFreeString(buffer[i]); delete[] buffer; return result; } bool Workflow::Remove(const string& activity) { return BNWorkflowRemove(m_object, activity.c_str()); } bool Workflow::Replace(const string& activity, const string& newActivity) { return BNWorkflowReplace(m_object, activity.c_str(), newActivity.c_str()); } Ref Workflow::GetGraph(const string& activity, bool sequential) { BNFlowGraph* graph = BNWorkflowGetGraph(m_object, activity.c_str(), sequential); if (!graph) return nullptr; return new CoreFlowGraph(graph); } void Workflow::ShowReport(const string& name) { BNWorkflowShowReport(m_object, name.c_str()); } vector Workflow::GetEligibilitySettings() { size_t size = 0; char** outBuffer = (char**)BNWorkflowGetEligibilitySettings(m_object, &size); vector result; result.reserve(size); for (size_t i = 0; i < size; i++) result.emplace_back(outBuffer[i]); BNFreeStringList(outBuffer, size); return result; }