From dfbcc29371820820e49737bf5a0fb331b9eaee28 Mon Sep 17 00:00:00 2001 From: Xusheng Date: Fri, 31 Mar 2023 16:55:42 +0800 Subject: [PATCH] Show a warning dialog when the user tries to launch a file for the first time. Fix https://github.com/Vector35/debugger/issues/452 --- api/debuggerapi.h | 1 + api/debuggercontroller.cpp | 6 ++++++ api/ffi.h | 1 + api/python/debuggercontroller.py | 4 ++++ core/debugger.cpp | 9 ++++++++ core/debuggercontroller.cpp | 9 ++++++++ core/debuggercontroller.h | 4 ++++ core/ffi.cpp | 6 ++++++ ui/controlswidget.cpp | 36 +++++++++++++++++++------------- ui/ui.cpp | 8 +++++++ 10 files changed, 70 insertions(+), 14 deletions(-) diff --git a/api/debuggerapi.h b/api/debuggerapi.h index cd3fe06b..b23a39e2 100644 --- a/api/debuggerapi.h +++ b/api/debuggerapi.h @@ -576,6 +576,7 @@ namespace BinaryNinjaDebuggerAPI { bool ActivateDebugAdapter(); std::string GetAddressInformation(uint64_t address); + bool IsFirstLaunch(); void PostDebuggerEvent(const DebuggerEvent& event); }; diff --git a/api/debuggercontroller.cpp b/api/debuggercontroller.cpp index 3f431994..3fdc76cc 100644 --- a/api/debuggercontroller.cpp +++ b/api/debuggercontroller.cpp @@ -795,6 +795,12 @@ std::string DebuggerController::GetAddressInformation(uint64_t address) } +bool DebuggerController::IsFirstLaunch() +{ + return BNDebuggerIsFirstLaunch(m_object); +} + + void DebuggerController::PostDebuggerEvent(const DebuggerEvent &event) { BNDebuggerEvent* evt = new BNDebuggerEvent; diff --git a/api/ffi.h b/api/ffi.h index d5d55dd6..d30942ce 100644 --- a/api/ffi.h +++ b/api/ffi.h @@ -445,6 +445,7 @@ extern "C" DEBUGGER_FFI_API bool BNDebuggerActivateDebugAdapter(BNDebuggerController* controller); DEBUGGER_FFI_API char* BNDebuggerGetAddressInformation(BNDebuggerController* controller, uint64_t address); + DEBUGGER_FFI_API bool BNDebuggerIsFirstLaunch(BNDebuggerController* controller); DEBUGGER_FFI_API void BNDebuggerPostDebuggerEvent(BNDebuggerController* controller, BNDebuggerEvent* event); diff --git a/api/python/debuggercontroller.py b/api/python/debuggercontroller.py index e3226c9f..40571945 100644 --- a/api/python/debuggercontroller.py +++ b/api/python/debuggercontroller.py @@ -1371,6 +1371,10 @@ def set_adapter_property(self, name: str, value: binaryninja.metadata.MetadataVa def get_addr_info(self, addr: int): return dbgcore.BNDebuggerGetAddressInformation(self.handle, addr) + @property + def is_first_launch(self): + return dbgcore.BNDebuggerIsFirstLaunch(self.handle) + def __del__(self): if dbgcore is not None: dbgcore.BNDebuggerFreeController(self.handle) diff --git a/core/debugger.cpp b/core/debugger.cpp index f24f3acb..d7c20e96 100644 --- a/core/debugger.cpp +++ b/core/debugger.cpp @@ -113,6 +113,15 @@ static void RegisterSettings() "description" : "When enabled, this prevents the debugger from launching any file.", "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] })"); + + settings->RegisterSetting("debugger.confirmFirstLaunch", + R"({ + "title" : "Confirm on first launch", + "type" : "boolean", + "default" : true, + "description" : "Asks the user to confirm the operation when the target is launched for the first time.", + "ignore" : ["SettingsProjectScope", "SettingsResourceScope"] + })"); } extern "C" diff --git a/core/debuggercontroller.cpp b/core/debuggercontroller.cpp index 3c9cb5ed..9355520c 100644 --- a/core/debuggercontroller.cpp +++ b/core/debuggercontroller.cpp @@ -127,6 +127,9 @@ DebugStopReason DebuggerController::LaunchAndWaitInternal() return InternalError; } + if (m_firstLaunch) + m_firstLaunch = false; + DebuggerEvent event; event.type = LaunchEventType; PostDebuggerEvent(event); @@ -2090,3 +2093,9 @@ std::string DebuggerController::GetAddressInformation(uint64_t address) return ""; } + + +bool DebuggerController::IsFirstLaunch() +{ + return m_firstLaunch; +} diff --git a/core/debuggercontroller.h b/core/debuggercontroller.h index 0191ee4b..d4c5526c 100644 --- a/core/debuggercontroller.h +++ b/core/debuggercontroller.h @@ -93,6 +93,8 @@ namespace BinaryNinjaDebugger { bool m_inputFileLoaded = false; bool m_initialBreakpointSeen = false; + bool m_firstLaunch = true; + void EventHandler(const DebuggerEvent& event); void UpdateStackVariables(); void AddRegisterValuesToExpressionParser(); @@ -268,5 +270,7 @@ namespace BinaryNinjaDebugger { // Dereference an address and check for printable strings, functions, symbols, etc std::string GetAddressInformation(uint64_t address); + + bool IsFirstLaunch(); }; }; // namespace BinaryNinjaDebugger diff --git a/core/ffi.cpp b/core/ffi.cpp index 44e0c6a9..effbcf4f 100644 --- a/core/ffi.cpp +++ b/core/ffi.cpp @@ -977,6 +977,12 @@ char* BNDebuggerGetAddressInformation(BNDebuggerController* controller, uint64_t } +bool BNDebuggerIsFirstLaunch(BNDebuggerController* controller) +{ + return controller->object->IsFirstLaunch(); +} + + void BNDebuggerPostDebuggerEvent(BNDebuggerController* controller, BNDebuggerEvent* event) { DebuggerEvent evt; diff --git a/ui/controlswidget.cpp b/ui/controlswidget.cpp index c6ab9fc0..f7030372 100644 --- a/ui/controlswidget.cpp +++ b/ui/controlswidget.cpp @@ -18,6 +18,7 @@ limitations under the License. #include "adaptersettings.h" #include #include +#include #include "binaryninjaapi.h" #include "disassemblyview.h" #include "theme.h" @@ -128,20 +129,27 @@ QString DebugControlsWidget::getToolTip(const QString& name) void DebugControlsWidget::performLaunch() { -// QString text = QString( -// "The debugger is %1 the target and preparing the debugger binary view. \n" -// "This might take a while.").arg("launching"); -// ProgressTask* task = -// new ProgressTask(this, "Launching", text, "", [=](std::function progress) { -// m_controller->Launch(); -// -// // For now, this cant be canceled, as the Debugger model wasn't -// // designed with that in mind. This function below can return false if canceling is enabled -// progress(1, 1); -// return; -// }); -// task->wait(); - std::thread([&]() { m_controller->Launch(); }).detach(); + if (m_controller->IsFirstLaunch() && Settings::Instance()->Get("debugger.confirmFirstLaunch")) + { + auto prompt = QString("You are about to launch \n\n%1\n\non your machine. " + "This may harm your machine. Are you sure to continue?").arg(QString::fromStdString(m_controller->GetExecutablePath())); + if (QMessageBox::question(this, "Launch Target", prompt) != QMessageBox::Yes) + return; + } + + QString text = QString( + "The debugger is %1 the target and preparing the debugger binary view. \n" + "This might take a while.").arg("launching"); + ProgressTask* task = + new ProgressTask(this, "Launching", text, "", [=](std::function progress) { + m_controller->Launch(); + + // For now, this cant be canceled, as the Debugger model wasn't + // designed with that in mind. This function below can return false if canceling is enabled + progress(1, 1); + return; + }); + task->wait(); } diff --git a/ui/ui.cpp b/ui/ui.cpp index a45892b5..2d146821 100644 --- a/ui/ui.cpp +++ b/ui/ui.cpp @@ -322,6 +322,14 @@ void GlobalDebuggerUI::SetupMenu(UIContext* context) auto controller = DebuggerController::GetController(ctxt.binaryView); if (!controller) return; + if (controller->IsFirstLaunch() && Settings::Instance()->Get("debugger.confirmFirstLaunch")) + { + auto prompt = QString("You are about to launch \n\n%1\n\non your machine. " + "This may harm your machine. Are you sure to continue?"). + arg(QString::fromStdString(controller->GetExecutablePath())); + if (QMessageBox::question(ctxt.context->mainWindow(), "Launch Target", prompt) != QMessageBox::Yes) + return; + } QString text = QString( "The debugger is launching the target and preparing the debugger binary view. \n" "This might take a while.");