diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.ps1 b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.ps1 index c06d0bc0f5..6a58a6e93f 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.ps1 +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.ps1 @@ -31,7 +31,7 @@ #@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." #@env OPT_PYTHON_ARGS:str="" "python cmd args" "Arguments passed to python (versus the target)" #@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." -#@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." +#@env WINDBG_DIR:dir="C:\Windows\System32" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." . ..\support\dbgsetuputils.ps1 @@ -47,6 +47,7 @@ function Compute-Python-Args { $arglist+=($Env:GHIDRA_TRACE_RMI_ADDR) $arglist+=($Env:OPT_USE_DBGMODEL) + $arglist+=($Env:WINDBG_DIR) $arglist+=($Env:OPT_TARGET_IMG) if ("$Env:OPT_TARGET_ARGS" -ne "") { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng-attach.ps1 b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng-attach.ps1 index 8f16c6aa0a..989005eec3 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng-attach.ps1 +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng-attach.ps1 @@ -34,6 +34,7 @@ #@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." #@env OPT_PYTHON_ARGS:str="" "python cmd args" "Arguments passed to python (versus the target)" #@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." +#@env WINDBG_DIR:dir="C:\Windows\System32" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." . ..\support\dbgsetuputils.ps1 @@ -49,6 +50,7 @@ function Compute-Python-Args { $arglist+=("localhost:$Env:OPT_REMOTE_PORT") $arglist+=($Env:OPT_USE_DBGMODEL) + $arglist+=($Env:WINDBG_DIR) $arglist+=($Env:OPT_TARGET_PID) $arglist+=($Env:OPT_ATTACH_FLAGS) diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng-attach.sh b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng-attach.sh index 245bc51e58..1724e960cf 100755 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng-attach.sh +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng-attach.sh @@ -15,7 +15,6 @@ # limitations under the License. ## #@title dbgeng attach via ssh (shell) -#@image-opt arg:1 #@desc #@desc

Launch with dbgeng via ssh

#@desc

@@ -36,11 +35,10 @@ #@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." #@env OPT_PYTHON_ARGS:str="" "python cmd args" "Arguments passed to python (versus the target)" #@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." +#@env WINDBG_DIR:dir="C:\\Windows\\System32" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." . ../support/dbgsetuputils.sh -target_image=$(echo $OPT_TARGET_IMG | sed 's/\\/\\\\/g') - OPT_OS_WINDOWS=true function launch-dbg-scp() { @@ -52,7 +50,7 @@ function launch-dbg-scp() { function launch-dbg-ssh() { local -a sshargs - compute-ssh-args true "$OPT_PYTHON_EXE -i $OPT_PYTHON_ARGS .\\local-dbgeng-attach.py localhost:$OPT_REMOTE_PORT $OPT_USE_DBGMODEL $OPT_TARGET_PID $OPT_ATTACH_FLAGS" + compute-ssh-args true "$OPT_PYTHON_EXE -i $OPT_PYTHON_ARGS .\\local-dbgeng-attach.py localhost:$OPT_REMOTE_PORT $OPT_USE_DBGMODEL $WINDBG_DIR $OPT_TARGET_PID $OPT_ATTACH_FLAGS" "${sshargs[@]}" } @@ -98,7 +96,9 @@ finished, try launching again. " "Would you like to install 'ghidradbg>=$version'?"; then echo "Copying Wheels to $OPT_HOST" - mitigate-scp-pymodules "Debugger-rmi-trace" "" + if ! mitigate-scp-pymodules "Debugger-rmi-trace" ""; then + exit 1 + fi echo "Installing Wheels into Python" do-installation diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng.ps1 b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng.ps1 index e1eca494ce..e49a0b0da4 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng.ps1 +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng.ps1 @@ -26,7 +26,7 @@ #@icon icon.debugger #@help dbgeng#ssh #@depends Debugger-rmi-trace -#@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image" +#@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image" #@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" #@env OPT_SSH_PATH:file="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." #@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" @@ -35,6 +35,7 @@ #@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." #@env OPT_PYTHON_ARGS:str="" "python cmd args" "Arguments passed to python (versus the target)" #@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." +#@env WINDBG_DIR:dir="C:\Windows\System32" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." . ..\support\dbgsetuputils.ps1 @@ -50,6 +51,7 @@ function Compute-Python-Args { $arglist+=("localhost:$Env:OPT_REMOTE_PORT") $arglist+=($Env:OPT_USE_DBGMODEL) + $arglist+=($Env:WINDBG_DIR) $arglist+=($Env:OPT_TARGET_IMG) if ("$Env:OPT_TARGET_ARGS" -ne "") { diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng.sh b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng.sh index a5bc2814c6..cad4770fb8 100755 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng.sh +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/ssh-dbgeng.sh @@ -15,7 +15,7 @@ # limitations under the License. ## #@title dbgeng via ssh (shell) -#@image-opt arg:1 +#@image-opt env:OPT_TARGET_IMG #@desc #@desc

Launch with dbgeng via ssh

#@desc

@@ -27,7 +27,7 @@ #@icon icon.debugger #@help dbgeng#ssh #@depends Debugger-rmi-trace -#@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image" +#@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image" #@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" #@env OPT_SSH_PATH:file="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." #@env OPT_HOST:str="localhost" "[User@]Host" "The hostname or user@host" @@ -36,6 +36,7 @@ #@env OPT_PYTHON_EXE:file!="python" "Python command" "The path to the Python 3 interpreter. Omit the full path to resolve using the system PATH." #@env OPT_PYTHON_ARGS:str="" "python cmd args" "Arguments passed to python (versus the target)" #@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available." +#@env WINDBG_DIR:dir="C:\\Windows\\System32" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)." . ../support/dbgsetuputils.sh @@ -52,7 +53,7 @@ function launch-dbg-scp() { function launch-dbg-ssh() { local -a sshargs - compute-ssh-args true "$OPT_PYTHON_EXE -i $OPT_PYTHON_ARGS .\\local-dbgeng.py localhost:$OPT_REMOTE_PORT $OPT_USE_DBGMODEL $target_image $OPT_TARGET_ARGS" + compute-ssh-args true "$OPT_PYTHON_EXE -i $OPT_PYTHON_ARGS .\\local-dbgeng.py localhost:$OPT_REMOTE_PORT $OPT_USE_DBGMODEL $WINDBG_DIR $target_image $OPT_TARGET_ARGS" "${sshargs[@]}" } @@ -98,7 +99,9 @@ finished, try launching again. " "Would you like to install 'ghidradbg>=$version'?"; then echo "Copying Wheels to $OPT_HOST" - mitigate-scp-pymodules "Debugger-rmi-trace" "" + if ! mitigate-scp-pymodules "Debugger-rmi-trace" ""; then + exit 1 + fi echo "Installing Wheels into Python" do-installation diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/dbgsetuputils.sh b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/dbgsetuputils.sh index 6b6a4f1aae..d26299b3a6 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/dbgsetuputils.sh +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/dbgsetuputils.sh @@ -20,5 +20,5 @@ compute-dbg-pipinstall-args() { printf -v argvpart ", %s" "$@" pipargs=("$OPT_PYTHON_EXE") pipargs+=(-c) - pipargs+=("import os, sys, runpy; sys.argv=['pip', 'install', '--force-reinstall'$argvpart]; os.environ['PIP_BREAK_SYSTEM_PACKAGE']='1'; runpy.run_module('pip', run_name='__main__')") + pipargs+=("\"import os, sys, runpy; sys.argv=['pip', 'install', '--force-reinstall'$argvpart]; os.environ['PIP_BREAK_SYSTEM_PACKAGE']='1'; runpy.run_module('pip', run_name='__main__')\"") } diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/kernel-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/kernel-dbgeng.py index 5e19000364..fe460efa9a 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/kernel-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/kernel-dbgeng.py @@ -28,7 +28,13 @@ def append_paths(): def main(): append_paths() + # Delay these imports until sys.path is patched + try: + import ghidradbg + except ModuleNotFoundError: + os._exit(253) + from ghidradbg import commands as cmd from ghidradbg import util from pybag.dbgeng import core as DbgEng diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-attach.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-attach.py index bb0aca17eb..9e8b89c1b9 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-attach.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-attach.py @@ -27,14 +27,17 @@ def parse_parameters(): global cxn, target, args os.environ['OPT_OS_WINDOWS'] = "true" argc = len(sys.argv) + # This is the .bat case: if argc == 1: return True - if argc >= 4: + # Local and remote .ps1 cases + if argc >= 5: cxn = sys.argv[1] os.environ['OPT_USE_DBGMODEL'] = sys.argv[2] - target = sys.argv[3] - if argc > 4: - args = sys.argv[4] + os.environ['WINDBG_DIR'] = sys.argv[3] + target = sys.argv[4] + if argc > 5: + args = sys.argv[5] return True print("Error: expected (cxn, use_dbgmodel, target, ...)") return False @@ -59,8 +62,9 @@ def main(): # Delay these imports until sys.path is patched try: import ghidradbg - except Exception as e: - exit(253) + except ModuleNotFoundError: + os._exit(253) + from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng from ghidradbg.hooks import on_state_changed @@ -91,7 +95,5 @@ if __name__ == '__main__': try: main() except SystemExit as x: - if x.code == 253: - exit(253) if x.code != 0: print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-ext.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-ext.py index 61d43273cf..11ea78538c 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-ext.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-ext.py @@ -28,7 +28,13 @@ def append_paths(): def main(): append_paths() + # Delay these imports until sys.path is patched + try: + import ghidradbg + except ModuleNotFoundError: + os._exit(253) + from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng from ghidradbg.hooks import on_state_changed diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-trace.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-trace.py index 412522001d..a1c6ce787d 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-trace.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng-trace.py @@ -28,7 +28,13 @@ def append_paths(): def main(): append_paths() + # Delay these imports until sys.path is patched + try: + import ghidradbg + except ModuleNotFoundError: + os._exit(253) + from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng from ghidradbg.hooks import on_state_changed diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py index e8e4671b56..3b75e33446 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py @@ -26,16 +26,19 @@ args = os.getenv('OPT_TARGET_ARGS') def parse_parameters(): global cxn, target, args argc = len(sys.argv) + # This is the .bat case: if argc == 1: return True - if argc >= 4: + # Local and remote .ps1 cases + if argc >= 5: cxn = sys.argv[1] os.environ['OPT_USE_DBGMODEL'] = sys.argv[2] - target = sys.argv[3] - if argc > 4: - args = sys.argv[4] + os.environ['WINDBG_DIR'] = sys.argv[3] + target = sys.argv[4] + if argc > 5: + args = sys.argv[5] return True - print("Error: expected (cxn, use_dbgmodel, target, ...)") + print("Error: expected (cxn, use_dbgmodel, windbg_dir, target, ...)") return False def append_paths(): @@ -52,14 +55,16 @@ def append_paths(): def main(): global cxn, target, args append_paths() + if parse_parameters() is False: return # Delay these imports until sys.path is patched try: import ghidradbg - except: - exit(253) + except ModuleNotFoundError: + os._exit(253) + from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng from ghidradbg.hooks import on_state_changed @@ -97,7 +102,5 @@ if __name__ == '__main__': try: main() except SystemExit as x: - if x.code == 253: - exit(253) if x.code != 0: print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/remote-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/remote-dbgeng.py index 657883c4de..24ad78f7e7 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/remote-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/remote-dbgeng.py @@ -28,7 +28,13 @@ def append_paths(): def main(): append_paths() + # Delay these imports until sys.path is patched + try: + import ghidradbg + except ModuleNotFoundError: + os._exit(253) + from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng from ghidradbg.hooks import on_state_changed diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/svrcx-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/svrcx-dbgeng.py index f99f94654b..11227a30a2 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/svrcx-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/svrcx-dbgeng.py @@ -28,7 +28,13 @@ def append_paths(): def main(): append_paths() + # Delay these imports until sys.path is patched + try: + import ghidradbg + except ModuleNotFoundError: + os._exit(253) + from ghidradbg import commands as cmd from pybag.dbgeng import core as DbgEng from ghidradbg.hooks import on_state_changed diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/help/help/topics/dbgeng/dbgeng.html b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/help/help/topics/dbgeng/dbgeng.html index c13e013a87..93de4d0ef1 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/help/help/topics/dbgeng/dbgeng.html +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/help/help/topics/dbgeng/dbgeng.html @@ -35,6 +35,26 @@ might work around this by copying the affected DLLs from your WinDbg installation into your Python installation.

+

Also worth noting, there are now two local launchers, the original .bat-based launcher and a + newer .ps1-based launcher. The powershell launcher is not signed. You must therefore set the + current user's execution policy or permissions on the script:

+ + +

Setup

Installing WinDbg is highly recommended. If you wish to forego installing WinDbg, you can @@ -48,7 +68,7 @@

@@ -123,7 +143,7 @@ python3 -m pip install --no-index -f Debugger-rmi-trace\pypkg\dist -f Debugger-a
  • Env: This is a composite string containg Environment Variable entries delineated by '/0' separators. For example, you could redefine USERNAME and USERPROFILE with the entry - 'USERNAME=SomeUser/0USERPROFILE=C:\Users\SomeUser'.
  • + "USERNAME=SomeUser/0USERPROFILE=C:\Users\SomeUser".
  • CreateFlags: Flags used when creating the process, typically either DEBUG_PROCESS(1) or DEBUG_ONLY_THIS_PROCESS(2) if you do not wish to follow spawned @@ -163,42 +183,45 @@ python3 -m pip install --no-index -f Debugger-rmi-trace\pypkg\dist -f Debugger-a
  • Connection: This is the connection string specifying the transport options for communicating with the remote debugger. A typical example might be - 'tcp:port=12345,server=192.168.0.2' for a debugger that has issued the command + "tcp:port=12345,server=192.168.0.2" for a debugger that has issued the command
     .server tcp:port=12345
     
  • -

    Remote via SSH

    +

    Remote via SSH

    -

    "ssh-dbgeng" is the remote equivalent to "dbgeng"; - "ssh-dbgeng-attach" is the remote equivalent to "dbgeng-attach". -

    +

    "ssh-dbgeng" is the remote equivalent to "dbgeng"; + "ssh-dbgeng-attach" is the remote equivalent to "dbgeng-attach".

    -

    Setup

    +

    Setup

    -

    Instructions are indentical to those above but executed on the remote machine.

    +

    Instructions are identical to those above but executed on the remote machine. Both of these + commands are now implemented via powershell, so the same caveats listed above for the local + .ps1 launcher apply here, i.e. you will need to set the current user's execution policy or + permissions on the script. Separate launchers have also been added for starting the debugger on + a remote Windows box from a local Linux machine.

    -

    Additional Options

    +

    Additional Options

    - + +

    Process Server

    The "dbgeng-svrcx" launcher extends the base dbgeng launcher adding an option for connecting through a remote process server.

    @@ -209,11 +232,10 @@ python3 -m pip install --no-index -f Debugger-rmi-trace\pypkg\dist -f Debugger-a
  • Connection: This is the connection string specifying the transport options for communicating with the remote server. A typical example might be - 'tcp:port=12345,server=192.168.0.2' for a process server launched on the machine at - 192.168.0.2 using: + "tcp:port=12345,server=192.168.0.2" for a process server launched on the machine + at 192.168.0.2 using:
    -        dbgsrv -t tcp:port=12345
    -       
    +dbgsrv -t tcp:port=12345
     
  • diff --git a/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh b/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh index ae9ca68063..ddbb042b10 100755 --- a/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh +++ b/Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh @@ -15,6 +15,7 @@ # limitations under the License. ## #@title drgn core +#@image-opt env:OPT_TARGET_IMG #@desc #@desc

    Launch with drgn-core

    #@desc

    diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb-win.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb-win.sh index f0b0cab724..fa5f10d55b 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb-win.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb-win.sh @@ -118,7 +118,9 @@ finished, try launching again. " "Would you like to install 'ghidragdb>=$version'?"; then echo "Copying Wheels to $OPT_HOST" - mitigate-scp-pymodules "Debugger-rmi-trace" "" + if ! mitigate-scp-pymodules "Debugger-rmi-trace" ""; then + exit 1 + fi echo "Installing Wheels into GDB's embedded Python" do-installation diff --git a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh index fc24b26ffe..17699e4247 100755 --- a/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh +++ b/Ghidra/Debug/Debugger-agent-gdb/data/debugger-launchers/ssh-gdb.sh @@ -94,7 +94,9 @@ finished, try launching again. " "Would you like to install 'ghidragdb>=$version'?"; then echo "Copying Wheels to $OPT_HOST" - mitigate-scp-pymodules "Debugger-rmi-trace" "" + if ! mitigate-scp-pymodules "Debugger-rmi-trace" ""; then + exit 1 + fi echo "Installing Wheels into GDB's embedded Python" do-installation diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb-win.sh b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb-win.sh index 4512ec16bb..ebe3cd1247 100755 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb-win.sh +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb-win.sh @@ -116,7 +116,9 @@ finished, try launching again. " "Would you like to install 'ghidralldb>=$version'?"; then echo "Copying Wheels to $OPT_HOST" - mitigate-scp-pymodules "Debugger-rmi-trace" "" + if ! mitigate-scp-pymodules "Debugger-rmi-trace" ""; then + exit 1 + fi echo "Installing Wheels into LLDB's embedded Python" do-installation diff --git a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh index d70580f336..12148796ac 100755 --- a/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh +++ b/Ghidra/Debug/Debugger-agent-lldb/data/debugger-launchers/ssh-lldb.sh @@ -93,7 +93,9 @@ finished, try launching again. " "Would you like to install 'ghidralldb>=$version'?"; then echo "Copying Wheels to $OPT_HOST" - mitigate-scp-pymodules "Debugger-rmi-trace" "" + if ! mitigate-scp-pymodules "Debugger-rmi-trace" ""; then + exit 1 + fi echo "Installing Wheels into LLDB's embedded Python" do-installation diff --git a/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg-attach.sh b/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg-attach.sh index 440f1a4cb7..f0bc543db4 100755 --- a/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg-attach.sh +++ b/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg-attach.sh @@ -15,7 +15,6 @@ # limitations under the License. ## #@title x64dbg attach via ssh (shell) -#@image-opt arg:1 #@desc #@desc

    Launch with x64dbg via ssh

    #@desc

    @@ -39,7 +38,6 @@ . ../support/x64dbgsetuputils.sh -target_image=$(echo $OPT_TARGET_IMG | sed 's/\\/\\\\/g') x64dbg_exe=$(echo $OPT_X64DBG_EXE | sed 's/\\/\\\\/g') OPT_OS_WINDOWS=true @@ -62,7 +60,7 @@ version=$(get-ghidra-version) function do-installation() { local -a pipargs - compute-dbg-pipinstall-args "'-f'" "os.environ['HOME']" "'ghidraxdbg>=$version'" + compute-x64dbg-pipinstall-args "'-f'" "os.environ['HOME']" "'ghidraxdbg>=$version'" local -a sshargs compute-ssh-args false "${pipargs[@]}" @@ -96,10 +94,12 @@ are copied and installed. NOTE: Automatic resolution will cause this session to terminate. When it has finished, try launching again. -" "Would you like to install 'ghidradbg>=$version'?"; then +" "Would you like to install 'ghidraxdbg>=$version'?"; then echo "Copying Wheels to $OPT_HOST" - mitigate-scp-pymodules "Debugger-rmi-trace" "" + if ! mitigate-scp-pymodules "Debugger-rmi-trace" ""; then + exit 1 + fi echo "Installing Wheels into python" do-installation diff --git a/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg.ps1 b/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg.ps1 index 075668c2d5..f5e15b82f3 100644 --- a/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg.ps1 +++ b/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg.ps1 @@ -26,7 +26,7 @@ #@icon icon.debugger #@help x64dbg#ssh #@depends Debugger-rmi-trace -#@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image" +#@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image" #@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" #@env OPT_TARGET_DIR:str="" "Dir" "Initial directory" #@env OPT_SSH_PATH:file="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." diff --git a/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg.sh b/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg.sh index 045bdc06fd..aab164e86a 100755 --- a/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg.sh +++ b/Ghidra/Debug/Debugger-agent-x64dbg/data/debugger-launchers/ssh-x64dbg.sh @@ -15,7 +15,7 @@ # limitations under the License. ## #@title x64dbg via ssh (shell) -#@image-opt arg:1 +#@image-opt env:OPT_TARGET_IMG #@desc #@desc

    Launch with x64dbg via ssh

    #@desc

    @@ -27,7 +27,7 @@ #@icon icon.debugger #@help x64dbg#ssh #@depends Debugger-rmi-trace -#@env OPT_TARGET_IMG:file="" "Image" "The target binary executable image" +#@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image" #@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target" #@env OPT_TARGET_DIR:str="" "Dir" "Initial directory" #@env OPT_SSH_PATH:file="ssh" "ssh command" "The path to ssh on the local system. Omit the full path to resolve using the system PATH." @@ -97,10 +97,12 @@ are copied and installed. NOTE: Automatic resolution will cause this session to terminate. When it has finished, try launching again. -" "Would you like to install 'ghidradbg>=$version'?"; then +" "Would you like to install 'ghidraxdbg>=$version'?"; then echo "Copying Wheels to $OPT_HOST" - mitigate-scp-pymodules "Debugger-rmi-trace" "" + if ! mitigate-scp-pymodules "Debugger-rmi-trace" ""; then + exit 1 + fi echo "Installing Wheels into python" do-installation diff --git a/Ghidra/Debug/Debugger-agent-x64dbg/data/support/local-x64dbg-attach.py b/Ghidra/Debug/Debugger-agent-x64dbg/data/support/local-x64dbg-attach.py index 69a1570bee..2f35f98d80 100644 --- a/Ghidra/Debug/Debugger-agent-x64dbg/data/support/local-x64dbg-attach.py +++ b/Ghidra/Debug/Debugger-agent-x64dbg/data/support/local-x64dbg-attach.py @@ -55,8 +55,9 @@ def main(): # Delay these imports until sys.path is patched try: import ghidraxdbg - except: - exit(253) + except ModuleNotFoundError: + os._exit(253) + from ghidraxdbg import commands as cmd from ghidraxdbg.hooks import on_state_changed from ghidraxdbg.util import dbg @@ -86,7 +87,5 @@ if __name__ == '__main__': try: main() except SystemExit as x: - if x.code == 253: - exit(253) if x.code != 0: print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-x64dbg/data/support/local-x64dbg.py b/Ghidra/Debug/Debugger-agent-x64dbg/data/support/local-x64dbg.py index d5aacc64e0..d763be24ae 100644 --- a/Ghidra/Debug/Debugger-agent-x64dbg/data/support/local-x64dbg.py +++ b/Ghidra/Debug/Debugger-agent-x64dbg/data/support/local-x64dbg.py @@ -65,8 +65,9 @@ def main(): # Delay these imports until sys.path is patched try: import ghidraxdbg - except Exception as e: - exit(253) + except ModuleNotFoundError: + os._exit(253) + from ghidraxdbg import commands as cmd from ghidraxdbg.hooks import on_state_changed from ghidraxdbg.util import dbg @@ -100,7 +101,5 @@ if __name__ == '__main__': try: main() except SystemExit as x: - if x.code == 253: - exit(253) if x.code != 0: print(f"Exited with code {x.code}") diff --git a/Ghidra/Debug/Debugger-agent-x64dbg/data/support/x64dbgsetuputils.sh b/Ghidra/Debug/Debugger-agent-x64dbg/data/support/x64dbgsetuputils.sh index a25de6975e..d7520001f5 100644 --- a/Ghidra/Debug/Debugger-agent-x64dbg/data/support/x64dbgsetuputils.sh +++ b/Ghidra/Debug/Debugger-agent-x64dbg/data/support/x64dbgsetuputils.sh @@ -20,5 +20,5 @@ compute-x64dbg-pipinstall-args() { printf -v argvpart ", %s" "$@" pipargs=("$OPT_PYTHON_EXE") pipargs+=(-c) - pipargs+=("import os, sys, runpy; sys.argv=['pip', 'install', '--force-reinstall'$argvpart]; os.environ['PIP_BREAK_SYSTEM_PACKAGE']='1'; runpy.run_module('pip', run_name='__main__')") + pipargs+=("\"import os, sys, runpy; sys.argv=['pip', 'install', '--force-reinstall'$argvpart]; os.environ['PIP_BREAK_SYSTEM_PACKAGE']='1'; runpy.run_module('pip', run_name='__main__')\"") } diff --git a/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.sh b/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.sh index ed927a2223..5094f14f5f 100644 --- a/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.sh +++ b/Ghidra/Debug/Debugger-rmi-trace/data/support/setuputils.sh @@ -90,9 +90,6 @@ compute-ssh-args() { printf -v qargs '%q ' "$@" sshargs+=("$OPT_SSH_PATH") - if [ -n "$OPT_OS_WINDOWS" ]; then - sshargs+=(-t) - fi if [ "$forward" == "true" ]; then sshargs+=("-R$OPT_REMOTE_PORT:$GHIDRA_TRACE_RMI_ADDR") fi @@ -142,6 +139,9 @@ mitigate-scp-pymodules() { local -a scpargs for mod in "$@"; do dist=$(ghidra-module-pydist "$mod") + if [ "$?" -ne "0" ]; then + return 1 + fi scpargs+=("$dist"/*) done scp "${scpargs[@]}" "$OPT_HOST:~/" diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/AbstractRmiConnectorsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/AbstractRmiConnectorsTest.java index ab5b0d04b7..b645dc303c 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/AbstractRmiConnectorsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/AbstractRmiConnectorsTest.java @@ -15,11 +15,14 @@ */ package agent; -import static org.junit.Assert.*; -import static org.junit.Assume.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; -import java.io.FileOutputStream; -import java.io.OutputStream; +import java.io.*; +import java.lang.annotation.*; +import java.lang.reflect.Method; +import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -33,14 +36,14 @@ import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesPlugin; import ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.NoStaticMappingException; import ghidra.app.plugin.core.debug.gui.tracermi.launcher.TraceRmiLauncherServicePlugin; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin; -import ghidra.app.services.DebuggerAutoMappingService; -import ghidra.app.services.TraceRmiLauncherService; +import ghidra.app.services.*; import ghidra.debug.api.ValStr; import ghidra.debug.api.tracermi.TraceRmiLaunchOffer; import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.*; import ghidra.framework.Application; import ghidra.framework.OperatingSystem; import ghidra.framework.plugintool.AutoConfigState.PathIsFile; +import ghidra.pty.*; import ghidra.util.SystemUtilities; public abstract class AbstractRmiConnectorsTest @@ -52,9 +55,29 @@ public abstract class AbstractRmiConnectorsTest return "python"; } + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface NoLocalSetup { + } + + boolean localSetup() throws Exception { + Method method = null; + try { + method = getClass().getMethod(name.getMethodName()); + } + catch (NoSuchMethodException e) { + return true; + } + NoLocalSetup annotation = method.getAnnotation(NoLocalSetup.class); + return annotation == null; + } + protected abstract List getPipLinkModules(); protected void unpip(String... specs) throws Exception { + if (!localSetup()) { + return; + } List args = new ArrayList<>(); args.addAll(List.of(getPythonCmd(), "-m", "pip", "uninstall", "-y")); args.addAll(List.of(specs)); @@ -63,6 +86,9 @@ public abstract class AbstractRmiConnectorsTest } protected void pipOob(String... specs) throws Exception { + if (!localSetup()) { + return; + } List args = new ArrayList<>(); args.addAll(List.of(getPythonCmd(), "-m", "pip", "install")); args.addAll(List.of(specs)); @@ -71,6 +97,9 @@ public abstract class AbstractRmiConnectorsTest } protected void pip(String... specs) throws Exception { + if (!localSetup()) { + return; + } List args = new ArrayList<>(); args.addAll(List.of(getPythonCmd(), "-m", "pip", "install", "--no-index")); for (ResourceFile root : Application.getApplicationRootDirectories()) { @@ -90,6 +119,20 @@ public abstract class AbstractRmiConnectorsTest assertEquals("pip failed", 0, result); } + protected int runInTerminal(List command, Map env) + throws IOException, InterruptedException { + TerminalService terminalService = tool.getService(TerminalService.class); + if (terminalService == null) { + throw new NullPointerException("Terminal Service is not installed in test tool"); + } + try (Pty pty = PtyFactory.local().openpty(); + Terminal term = terminalService.createWithStreams(Charset.forName("utf8"), + pty.getParent().getInputStream(), pty.getParent().getOutputStream())) { + PtySession session = pty.getChild().session(command.toArray(String[]::new), env); + return session.waitExited(); + } + } + protected boolean isWindows() { return OperatingSystem.CURRENT_OPERATING_SYSTEM == OperatingSystem.WINDOWS; } diff --git a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngConnectorsTest.java b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngConnectorsTest.java index c7229cc2a2..86c4ba09f2 100644 --- a/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngConnectorsTest.java +++ b/Ghidra/Test/DebuggerIntegrationTest/src/test.slow/java/agent/dbgeng/rmi/DbgEngConnectorsTest.java @@ -18,11 +18,14 @@ package agent.dbgeng.rmi; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; +import static org.junit.Assume.*; import java.nio.file.Path; import java.util.List; import java.util.Map; +import javax.swing.JOptionPane; + import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; @@ -30,9 +33,11 @@ import org.junit.Test; import agent.AbstractRmiConnectorsTest; import generic.jar.ResourceFile; import ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.EarlyTerminationException; +import ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.NoStaticMappingException; import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.LaunchResult; import ghidra.framework.Application; import ghidra.framework.plugintool.AutoConfigState.PathIsFile; +import ghidra.pty.testutil.DummyProc; public class DbgEngConnectorsTest extends AbstractRmiConnectorsTest { @@ -122,8 +127,8 @@ public class DbgEngConnectorsTest extends AbstractRmiConnectorsTest { public void testDbgViaSsh() throws Exception { pip("ghidradbg==%s".formatted(Application.getApplicationVersion())); try (LaunchResult result = doLaunch("dbgeng via ssh", Map.ofEntries( - Map.entry("env:OPT_TARGET_IMG", chooseImage()), - Map.entry("OPT_HOST", "localhost")))) { + Map.entry("env:OPT_TARGET_IMG", chooseImage().toString()), + Map.entry("env:OPT_HOST", "localhost")))) { checkResult(result); } } @@ -136,15 +141,16 @@ public class DbgEngConnectorsTest extends AbstractRmiConnectorsTest { // Overwrite with an incompatible version we don't include pipOob("protobuf==3.19.0"); try (LaunchResult result = doLaunch("dbgeng via ssh", Map.ofEntries( - Map.entry("env:OPT_TARGET_IMG", chooseImage()), - Map.entry("OPT_HOST", "localhost")))) { + Map.entry("env:OPT_TARGET_IMG", chooseImage().toString()), + Map.entry("env:OPT_HOST", "localhost")))) { + // If the next line fails, make sure "python" on your box is 3.13 assertTrue(result.exception() instanceof EarlyTerminationException); assertThat(result.sessions().get("Shell").content(), Matchers.containsString("Would you like to install")); } try (LaunchResult result = doLaunch("dbgeng via ssh", Map.ofEntries( - Map.entry("env:OPT_TARGET_IMG", chooseImage()), - Map.entry("OPT_HOST", "localhost")))) { + Map.entry("env:OPT_TARGET_IMG", chooseImage().toString()), + Map.entry("env:OPT_HOST", "localhost")))) { checkResult(result); } } @@ -152,19 +158,53 @@ public class DbgEngConnectorsTest extends AbstractRmiConnectorsTest { @Test public void testDbgViaSshSetupGhidraDbg() throws Exception { try (LaunchResult result = doLaunch("dbgeng via ssh", Map.ofEntries( - Map.entry("env:OPT_TARGET_IMG", chooseImage()), - Map.entry("OPT_HOST", "localhost")))) { + Map.entry("env:OPT_TARGET_IMG", chooseImage().toString()), + Map.entry("env:OPT_HOST", "localhost")))) { + // If the next line fails, make sure "python" on your box is 3.13 assertTrue(result.exception() instanceof EarlyTerminationException); assertThat(result.sessions().get("Shell").content(), Matchers.containsString("Would you like to install")); } try (LaunchResult result = doLaunch("dbgeng via ssh", Map.ofEntries( - Map.entry("env:OPT_TARGET_IMG", chooseImage()), - Map.entry("OPT_HOST", "localhost")))) { + Map.entry("env:OPT_TARGET_IMG", chooseImage().toString()), + Map.entry("env:OPT_HOST", "localhost")))) { checkResult(result); } } + @Test + @NoLocalSetup + public void testLinuxToDbgViaSshSetupGhidraDbg() throws Exception { + assumeFalse(isWindows()); + + String hostname = JOptionPane.showInputDialog("Windows Hostname"); + + assertEquals(0, runInTerminal( + List.of(DummyProc.which("ssh"), hostname, "pip uninstall ghidradbg"), null)); + + try (LaunchResult result = doLaunch("dbgeng via ssh (shell)", Map.ofEntries( + Map.entry("env:OPT_TARGET_IMG", chooseImage().toString()), + Map.entry("env:OPT_HOST", hostname)))) { + assertTrue(result.exception() instanceof EarlyTerminationException); + assertThat(result.sessions().get("Shell").content(), + Matchers.containsString("Would you like to install")); + } + try (LaunchResult result = doLaunch("dbgeng via ssh (shell)", Map.ofEntries( + Map.entry("env:OPT_TARGET_IMG", chooseImage().toString()), + Map.entry("env:OPT_HOST", hostname)))) { + checkResult(result); + } + } + + @Override + protected void checkResult(LaunchResult result) { + // Exits to python shell, requires quit which generates early term exc. + if (result.exception() != null && + !(result.exception() instanceof EarlyTerminationException) && + !(result.exception() instanceof NoStaticMappingException)) { + throw new AssertionError(result); + } + } // LATER?: kernel // LATER?: attach (usermode by PID) // LATER?: ext