mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +02:00
GP-4732: from the demo (lol)
GP-4732: frome review GP-4732: working until we step GP-4732: manifestGP-4732: works, except for resumeGP-4732: successGP-4732: frome review
This commit is contained in:
parent
e0fd708d30
commit
05ed589fa0
10 changed files with 272 additions and 67 deletions
|
@ -9,6 +9,7 @@ data/debugger-launchers/local-dbgeng-ext.bat||GHIDRA||||END|
|
|||
data/debugger-launchers/local-dbgeng.bat||GHIDRA||||END|
|
||||
data/debugger-launchers/local-ttd.bat||GHIDRA||||END|
|
||||
data/debugger-launchers/remote-dbgeng.bat||GHIDRA||||END|
|
||||
data/debugger-launchers/svrcx-dbgeng.bat||GHIDRA||||END|
|
||||
src/main/py/LICENSE||GHIDRA||||END|
|
||||
src/main/py/MANIFEST.in||GHIDRA||||END|
|
||||
src/main/py/README.md||GHIDRA||||END|
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
::@enum Connection:str Remote Local EXDI
|
||||
::@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."
|
||||
:: Use env instead of args, because "all args except first" is terrible to implement in batch
|
||||
::@env OPT_TARGET_ARGS:str="" "Arguments" "Connection-string arguments (a la .server)"
|
||||
::@env OPT_KCONNECT_STRING:str="" "Arguments" "Connection-string arguments (a la .server)"
|
||||
::@env OPT_TARGET_FLAGS:Connection="Remote" "Type" "Type/flags for connection (Remote/Local/EXDI)."
|
||||
::@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)."
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
::@title dbgeng-remote
|
||||
::@image-opt env:OPT_TARGET_IMG
|
||||
::@desc <html><body width="300px">
|
||||
::@desc <h3>Launch with <tt>dbgeng</tt> remotely (in a Python interpreter)</h3>
|
||||
::@desc <h3>Connect to a remote debugger (via the .server interface)</h3>
|
||||
::@desc <p>
|
||||
::@desc This will launch the target on a remote machine using <tt>dbgeng.dll</tt>.
|
||||
::@desc This will connect to a remote machine using the .server interface.
|
||||
::@desc For setup instructions, press <b>F1</b>.
|
||||
::@desc </p>
|
||||
::@desc </body></html>
|
||||
|
@ -11,11 +10,7 @@
|
|||
::@icon icon.debugger
|
||||
::@help TraceRmiLauncherServicePlugin#dbgeng_remote
|
||||
::@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."
|
||||
:: Use env instead of args, because "all args except first" is terrible to implement in batch
|
||||
::@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_CONNECT_STRING:str="" "Connection" "Connection-string arguments (a la dbgsrv args)"
|
||||
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
|
||||
::@env OPT_CONNECT_STRING:str="" "Connection" "Connection-string arguments (a la .server)"
|
||||
::@env WINDBG_DIR:dir="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
|
||||
|
||||
@echo off
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
::@title dbgeng-svrcx
|
||||
::@image-opt env:OPT_TARGET_IMG
|
||||
::@desc <html><body width="300px">
|
||||
::@desc <h3>Connect to a remote <tt>dbgeng</tt> connection server and launch the target (in a Python interpreter)</h3>
|
||||
::@desc <p>
|
||||
::@desc This will launch the target via a connection server on a remote machine.
|
||||
::@desc For setup instructions, press <b>F1</b>.
|
||||
::@desc </p>
|
||||
::@desc </body></html>
|
||||
::@menu-group local
|
||||
::@icon icon.debugger
|
||||
::@help TraceRmiLauncherServicePlugin#dbgeng_svrcx
|
||||
::@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."
|
||||
:: Use env instead of args, because "all args except first" is terrible to implement in batch
|
||||
::@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_CONNECT_STRING:str="" "Connection" "Connection-string arguments (a la dbgsrv args)"
|
||||
::@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)."
|
||||
|
||||
@echo off
|
||||
|
||||
"%OPT_PYTHON_EXE%" -i ..\support\svrcx-dbgeng.py
|
|
@ -57,7 +57,7 @@ def main():
|
|||
print(f"RegMapFile: {os.getenv('EXDI_SYSTEM_REGISTERS_MAP_XML_FILE')}")
|
||||
util.set_convenience_variable('output-radix', 16)
|
||||
flags = 2
|
||||
args = os.getenv('OPT_TARGET_ARGS')
|
||||
args = os.getenv('OPT_KCONNECT_STRING')
|
||||
cmd.ghidra_trace_attach_kernel(args, flags, start_trace=False)
|
||||
|
||||
# TODO: HACK
|
||||
|
|
|
@ -48,22 +48,11 @@ def main():
|
|||
repl = cmd.repl
|
||||
|
||||
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
|
||||
args = os.getenv('OPT_TARGET_ARGS')
|
||||
if args:
|
||||
args = ' ' + args
|
||||
cmd.ghidra_trace_connect_server(os.getenv('OPT_CONNECT_STRING'))
|
||||
img = os.getenv('OPT_TARGET_IMG')
|
||||
if img is not None and img != "":
|
||||
cmd.ghidra_trace_create(img + args, start_trace=False)
|
||||
|
||||
# TODO: HACK
|
||||
try:
|
||||
dbg.wait()
|
||||
except KeyboardInterrupt as ki:
|
||||
dbg.interrupt()
|
||||
|
||||
cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
|
||||
os.environ['OPT_USE_DBGMODEL'] = "false"
|
||||
cmd.ghidra_trace_start("Remote")
|
||||
cmd.ghidra_trace_sync_enable()
|
||||
dbg.interrupt()
|
||||
|
||||
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
|
||||
cmd.repl()
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
## ###
|
||||
# IP: GHIDRA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
##
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
home = os.getenv('GHIDRA_HOME')
|
||||
|
||||
if os.path.isdir(f'{home}\\ghidra\\.git'):
|
||||
sys.path.append(
|
||||
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
|
||||
sys.path.append(
|
||||
f'{home}\\ghidra\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
|
||||
elif os.path.isdir(f'{home}\\.git'):
|
||||
sys.path.append(
|
||||
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\build\\pypkg\\src')
|
||||
sys.path.append(
|
||||
f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\build\\pypkg\\src')
|
||||
else:
|
||||
sys.path.append(
|
||||
f'{home}\\Ghidra\\Debug\\Debugger-agent-dbgeng\\pypkg\\src')
|
||||
sys.path.append(f'{home}\\Ghidra\\Debug\\Debugger-rmi-trace\\pypkg\\src')
|
||||
|
||||
|
||||
def main():
|
||||
# Delay these imports until sys.path is patched
|
||||
from ghidradbg import commands as cmd
|
||||
from pybag.dbgeng import core as DbgEng
|
||||
from ghidradbg.hooks import on_state_changed
|
||||
from ghidradbg.util import dbg
|
||||
|
||||
# So that the user can re-enter by typing repl()
|
||||
global repl
|
||||
repl = cmd.repl
|
||||
|
||||
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
|
||||
args = os.getenv('OPT_TARGET_ARGS')
|
||||
if args:
|
||||
args = ' ' + args
|
||||
cmd.ghidra_trace_connect_server(os.getenv('OPT_CONNECT_STRING'))
|
||||
img = os.getenv('OPT_TARGET_IMG')
|
||||
if img is not None and img != "":
|
||||
cmd.ghidra_trace_create(img + args, start_trace=False)
|
||||
|
||||
# TODO: HACK
|
||||
try:
|
||||
dbg.wait()
|
||||
except KeyboardInterrupt as ki:
|
||||
dbg.interrupt()
|
||||
|
||||
cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
|
||||
cmd.ghidra_trace_sync_enable()
|
||||
|
||||
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
|
||||
cmd.repl()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -489,6 +489,23 @@ def install_hooks():
|
|||
|
||||
events = util.dbg._base.events
|
||||
|
||||
if util.is_remote():
|
||||
events.engine_state(handler=on_state_changed_async)
|
||||
events.debuggee_state(handler=on_debuggee_changed_async)
|
||||
events.session_status(handler=on_session_status_changed_async)
|
||||
events.symbol_state(handler=on_symbol_state_changed_async)
|
||||
events.system_error(handler=on_system_error_async)
|
||||
|
||||
events.create_process(handler=on_new_process_async)
|
||||
events.exit_process(handler=on_process_deleted_async)
|
||||
events.create_thread(handler=on_threads_changed_async)
|
||||
events.exit_thread(handler=on_threads_changed_async)
|
||||
events.module_load(handler=on_modules_changed_async)
|
||||
events.unload_module(handler=on_modules_changed_async)
|
||||
|
||||
events.breakpoint(handler=on_breakpoint_hit_async)
|
||||
events.exception(handler=on_exception_async)
|
||||
else:
|
||||
events.engine_state(handler=on_state_changed)
|
||||
events.debuggee_state(handler=on_debuggee_changed)
|
||||
events.session_status(handler=on_session_status_changed)
|
||||
|
@ -527,3 +544,59 @@ def disable_current_process():
|
|||
if proc in PROC_STATE:
|
||||
# Silently ignore already disabled
|
||||
del PROC_STATE[proc]
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_state_changed_async(*args):
|
||||
util.dbg.run_async(on_state_changed, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_debuggee_changed_async(*args):
|
||||
util.dbg.run_async(on_debuggee_changed, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_session_status_changed_async(*args):
|
||||
util.dbg.run_async(on_session_status_changed, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_symbol_state_changed_async(*args):
|
||||
util.dbg.run_async(on_symbol_state_changed, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_system_error_async(*args):
|
||||
util.dbg.run_async(on_system_error, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_new_process_async(*args):
|
||||
util.dbg.run_async(on_new_process, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_process_deleted_async(*args):
|
||||
util.dbg.run_async(on_process_deleted, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_threads_changed_async(*args):
|
||||
util.dbg.run_async(on_threads_changed, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_modules_changed_async(*args):
|
||||
util.dbg.run_async(on_modules_changed, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_breakpoint_hit_async(*args):
|
||||
util.dbg.run_async(on_breakpoint_hit, *args)
|
||||
|
||||
|
||||
@log_errors
|
||||
def on_exception_async(*args):
|
||||
util.dbg.run_async(on_exception, *args)
|
||||
|
||||
|
|
|
@ -29,12 +29,13 @@ import traceback
|
|||
from comtypes import CoClass, GUID
|
||||
import comtypes
|
||||
from comtypes.gen import DbgMod
|
||||
from comtypes.hresult import S_OK
|
||||
from comtypes.hresult import S_OK, S_FALSE
|
||||
from pybag import pydbg, userdbg, kerneldbg, crashdbg
|
||||
from pybag.dbgeng import core as DbgEng
|
||||
from pybag.dbgeng import exception
|
||||
from pybag.dbgeng import util as DbgUtil
|
||||
from pybag.dbgeng.callbacks import DbgEngCallbacks
|
||||
from pybag.dbgeng.idebugclient import DebugClient
|
||||
|
||||
from ghidradbg.dbgmodel.ihostdatamodelaccess import HostDataModelAccess
|
||||
from _winapi import STILL_ACTIVE
|
||||
|
@ -145,7 +146,7 @@ class DbgExecutor(object):
|
|||
|
||||
def _submit_no_exit(self, fn, /, *args, **kwargs):
|
||||
f = Future()
|
||||
if self._executing:
|
||||
if self._executing and self._ghidra_dbg.IS_REMOTE == False:
|
||||
f.set_exception(DebuggeeRunningException("Debuggee is Running"))
|
||||
return f
|
||||
w = _WorkItem(f, fn, args, kwargs)
|
||||
|
@ -163,6 +164,7 @@ class DbgExecutor(object):
|
|||
|
||||
def _state_execute(self):
|
||||
self._executing = True
|
||||
if self._ghidra_dbg.IS_REMOTE == False:
|
||||
self._clear_queue()
|
||||
|
||||
def _state_break(self):
|
||||
|
@ -239,10 +241,26 @@ class GhidraDbg(object):
|
|||
setattr(self, name, self.eng_thread(getattr(base, name)))
|
||||
self.IS_KERNEL = False
|
||||
self.IS_EXDI = False
|
||||
self.IS_REMOTE = os.getenv('OPT_CONNECT_STRING') is not None
|
||||
|
||||
def _new_base(self):
|
||||
remote = os.getenv('OPT_CONNECT_STRING')
|
||||
if remote is not None:
|
||||
remote_client = DbgEng.DebugConnect(remote)
|
||||
debug_client = self._generate_client(remote_client)
|
||||
self._protected_base = AllDbg(client=debug_client)
|
||||
else:
|
||||
self._protected_base = AllDbg()
|
||||
|
||||
|
||||
def _generate_client(self, original):
|
||||
cli = POINTER(DbgEng.IDebugClient)()
|
||||
cliptr = POINTER(POINTER(DbgEng.IDebugClient))(cli)
|
||||
hr = original.CreateClient(cliptr)
|
||||
exception.check_err(hr)
|
||||
return DebugClient(client=cli)
|
||||
|
||||
|
||||
@property
|
||||
def _base(self):
|
||||
if threading.current_thread() is not self._thread:
|
||||
|
@ -655,6 +673,9 @@ def GetExitCode():
|
|||
return STILL_ACTIVE
|
||||
exit_code = c_ulong()
|
||||
hr = dbg._base._client._cli.GetExitCode(byref(exit_code))
|
||||
# DebugConnect targets return E_UNEXPECTED but the target is STILL_ACTIVE
|
||||
if hr != S_OK and hr != S_FALSE:
|
||||
return STILL_ACTIVE
|
||||
return exit_code.value
|
||||
|
||||
|
||||
|
@ -915,8 +936,20 @@ def set_kernel(value):
|
|||
def is_kernel():
|
||||
return dbg.IS_KERNEL
|
||||
|
||||
|
||||
def set_exdi(value):
|
||||
dbg.IS_EXDI = value
|
||||
|
||||
|
||||
def is_exdi():
|
||||
return dbg.IS_EXDI
|
||||
|
||||
|
||||
def set_remote(value):
|
||||
dbg.IS_REMOTE = value
|
||||
|
||||
|
||||
def is_remote():
|
||||
return dbg.IS_REMOTE
|
||||
|
||||
|
||||
|
|
|
@ -843,6 +843,24 @@ python3 -m pip install --no-index -f Debugger-rmi-trace\pypkg\dist -f Debugger-a
|
|||
|
||||
<H3><A name="dbgeng_remote"></A>dbgeng-remote</H3>
|
||||
|
||||
<P>This launcher connects to a remote debugger that has opened a port for remote control.
|
||||
</P>
|
||||
|
||||
<H4>Options</H4>
|
||||
|
||||
<UL>
|
||||
<LI>
|
||||
<B>Connection</B>: 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
|
||||
<PRE>
|
||||
.server tcp:port=12345
|
||||
</PRE>
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
<H3><A name="dbgeng_svrcx"></A>dbgeng-svrcx</H3>
|
||||
|
||||
<P>This launcher extends the base dbgeng launcher adding an option for connecting through a
|
||||
remote process server.</P>
|
||||
|
||||
|
@ -852,7 +870,7 @@ python3 -m pip install --no-index -f Debugger-rmi-trace\pypkg\dist -f Debugger-a
|
|||
<LI>
|
||||
<B>Connection</B>: 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
|
||||
'tcp:port=12345,server=192.168.0.2' for a process server launched on the machine at
|
||||
192.168.0.2 using:
|
||||
<PRE>
|
||||
dbgsrv -t tcp:port=12345
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue