From 6266ff041265d31d3f212fe2233c6108f443be4c Mon Sep 17 00:00:00 2001 From: Glenn Smith Date: Fri, 4 Feb 2022 16:52:13 -0500 Subject: BinaryNinja::OpenView() c++ port of python open_view() Why has this never existed --- binaryview.cpp | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) (limited to 'binaryview.cpp') diff --git a/binaryview.cpp b/binaryview.cpp index 62bb6f2b..853e201a 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -3817,3 +3817,209 @@ BinaryData::BinaryData(FileMetadata* file, const string& path) : BinaryData::BinaryData(FileMetadata* file, FileAccessor* accessor) : BinaryView(BNCreateBinaryDataViewFromFile(file->GetObject(), accessor->GetCallbacks())) {} + + +Ref BinaryNinja::OpenView(const std::string& filename, bool updateAnalysis, std::function progress, Json::Value options) +{ + if (!progress) + progress = [](size_t, size_t) { return true; }; + + // Detect bndb + bool isDatabase = false; + Ref view = nullptr; + + if (filename.size() > 6 && filename.substr(filename.size() - 5) == ".bndb") + { + // Open database, read raw view contents from it + static const std::string sqlite_header = "SQLite format 3"; + + FILE* f = fopen(filename.c_str(), "rb"); + if (f == nullptr) + return nullptr; + char header[0x20]; + fread(header, 1, sqlite_header.size(), f); + fclose(f); + header[sqlite_header.size()] = 0; + + if (sqlite_header != header) + return nullptr; + + Ref file = new FileMetadata(filename); + view = file->OpenDatabaseForConfiguration(filename); + isDatabase = true; + } + else + { + // Open file, read raw contents + Ref file = new FileMetadata(filename); + view = new BinaryData(file, filename); + } + + if (!view) + return nullptr; + + Ref bvt; + Ref universalBvt; + for (auto available : BinaryViewType::GetViewTypesForData(view)) + { + if (available->GetName() == "Universal") + { + universalBvt = available; + continue; + } + if (!bvt && available->GetName() != "Raw") + { + bvt = available; + } + } + + // No available views: Load as Mapped + if (!bvt) + bvt = BinaryViewType::GetByName("Mapped"); + + Ref defaultSettings = Settings::Instance(bvt->GetName() + "_settings"); + defaultSettings->DeserializeSchema(Settings::Instance()->SerializeSchema()); + defaultSettings->SetResourceId(bvt->GetName()); + + Ref loadSettings; + if (isDatabase) + { + loadSettings = view->GetLoadSettings(bvt->GetName()); + } + if (!loadSettings) + { + if (universalBvt && options.isMember("files.universal.architecturePreference")) + { + // Load universal architecture + loadSettings = universalBvt->GetLoadSettingsForData(view); + if (!loadSettings) + { + LogError("Could not load entry from Universal image. No load settings!"); + return nullptr; + } + std::string architectures = loadSettings->Get("loader.universal.architectures"); + + std::unique_ptr reader(Json::CharReaderBuilder().newCharReader()); + Json::Value archList; + std::string errors; + if (!reader->parse((const char*)architectures.data(), (const char*)architectures.data() + architectures.size(), &archList, &errors)) + { + BinaryNinja::LogError("Error parsing architecture list: %s", errors.data()); + return nullptr; + } + + Json::Value archEntry; + for (auto archPref : options["files.universal.architecturePreference"]) + { + for (auto entry : archList) + { + if (entry["architecture"].asString() == archPref.asString()) + { + archEntry = entry; + break; + } + } + if (!archEntry.isNull()) + break; + } + if (archEntry.isNull()) + { + std::string error = "Could not load any of:"; + for (auto archPref : options["files.universal.architecturePreference"]) + { + error += string(" ") + archPref.asString(); + } + error += " from Universal image. Entry not found! Available entries:"; + for (auto entry : archList) + { + error += string(" ") + entry["architecture"].asString(); + } + LogError("%s", error.c_str()); + return nullptr; + } + + loadSettings = Settings::Instance(GetUniqueIdentifierString()); + + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + string json = Json::writeString(builder, archEntry["loadSchema"]); + + loadSettings->DeserializeSchema(json); + } + else + { + // Load non-universal architecture + loadSettings = bvt->GetLoadSettingsForData(view); + } + } + + if (!loadSettings) + { + LogError("Could not get load settings for binary view of type '%s'", bvt->GetName().c_str()); + return nullptr; + } + + loadSettings->SetResourceId(bvt->GetName()); + view->SetLoadSettings(bvt->GetName(), loadSettings); + + for (auto key : options.getMemberNames()) + { + auto value = options[key]; + if (loadSettings->Contains(key)) + { + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + string json = Json::writeString(builder, value); + + if (!loadSettings->SetJson(key, json, view)) + { + LogError("Setting: %s set operation failed!", key.c_str()); + return nullptr; + } + } + else if (defaultSettings->Contains(key)) + { + Json::StreamWriterBuilder builder; + builder["indentation"] = ""; + string json = Json::writeString(builder, value); + + if (!defaultSettings->SetJson(key, json, view)) + { + LogError("Setting: %s set operation failed!", key.c_str()); + return nullptr; + } + } + else + { + LogError("Setting: %s not available!", key.c_str()); + return nullptr; + } + } + + Ref bv; + if (isDatabase) + { + view = view->GetFile()->OpenExistingDatabase(filename, progress); + if (!view) + { + LogError("Unable to open existing database with filename %s", filename.c_str()); + return nullptr; + } + bv = view->GetFile()->GetViewOfType(bvt->GetName()); + } + else + { + bv = bvt->Create(view); + } + + if (!bv) + { + return view; + } + if (updateAnalysis) + { + bv->UpdateAnalysisAndWait(); + } + return bv; +} + -- cgit v1.3.1