mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/GP-5185_d-millar_exdi--SQUASHED'
This commit is contained in:
commit
f0641fd72a
16 changed files with 855 additions and 37 deletions
|
@ -15,4 +15,5 @@ src/main/py/README.md||GHIDRA||||END|
|
||||||
src/main/py/pyproject.toml||GHIDRA||||END|
|
src/main/py/pyproject.toml||GHIDRA||||END|
|
||||||
src/main/py/src/ghidradbg/dbgmodel/DbgModel.idl||GHIDRA||||END|
|
src/main/py/src/ghidradbg/dbgmodel/DbgModel.idl||GHIDRA||||END|
|
||||||
src/main/py/src/ghidradbg/schema.xml||GHIDRA||||END|
|
src/main/py/src/ghidradbg/schema.xml||GHIDRA||||END|
|
||||||
|
src/main/py/src/ghidradbg/schema_exdi.xml||GHIDRA||||END|
|
||||||
src/main/py/src/ghidrattd/schema.xml||GHIDRA||||END|
|
src/main/py/src/ghidrattd/schema.xml||GHIDRA||||END|
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
::@menu-group local
|
::@menu-group local
|
||||||
::@icon icon.debugger
|
::@icon icon.debugger
|
||||||
::@help TraceRmiLauncherServicePlugin#dbgeng_kernel
|
::@help TraceRmiLauncherServicePlugin#dbgeng_kernel
|
||||||
|
::@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."
|
::@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
|
:: 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_TARGET_ARGS: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 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="" "Path to dbgeng.dll directory" "Path containing dbgeng and associated DLLS (if not Windows Kits)."
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ else:
|
||||||
def main():
|
def main():
|
||||||
# Delay these imports until sys.path is patched
|
# Delay these imports until sys.path is patched
|
||||||
from ghidradbg import commands as cmd
|
from ghidradbg import commands as cmd
|
||||||
|
from ghidradbg import util
|
||||||
from pybag.dbgeng import core as DbgEng
|
from pybag.dbgeng import core as DbgEng
|
||||||
from ghidradbg.hooks import on_state_changed
|
from ghidradbg.hooks import on_state_changed
|
||||||
from ghidradbg.util import dbg
|
from ghidradbg.util import dbg
|
||||||
|
@ -47,8 +48,17 @@ def main():
|
||||||
repl = cmd.repl
|
repl = cmd.repl
|
||||||
|
|
||||||
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
|
cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR'))
|
||||||
|
type = os.getenv('OPT_TARGET_FLAGS')
|
||||||
|
flags = 0
|
||||||
|
if type == "Local":
|
||||||
|
flags = 1
|
||||||
|
if type == "EXDI":
|
||||||
|
print(f"ConfigFile: {os.getenv('EXDI_GDBSRV_XML_CONFIG_FILE')}")
|
||||||
|
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_TARGET_ARGS')
|
||||||
cmd.ghidra_trace_attach_kernel(args, start_trace=False)
|
cmd.ghidra_trace_attach_kernel(args, flags, start_trace=False)
|
||||||
|
|
||||||
# TODO: HACK
|
# TODO: HACK
|
||||||
try:
|
try:
|
||||||
|
@ -56,7 +66,8 @@ def main():
|
||||||
except KeyboardInterrupt as ki:
|
except KeyboardInterrupt as ki:
|
||||||
dbg.interrupt()
|
dbg.interrupt()
|
||||||
|
|
||||||
cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
|
#cmd.ghidra_trace_start(os.getenv('OPT_TARGET_IMG'))
|
||||||
|
cmd.ghidra_trace_start("System")
|
||||||
cmd.ghidra_trace_sync_enable()
|
cmd.ghidra_trace_sync_enable()
|
||||||
|
|
||||||
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
|
on_state_changed(DbgEng.DEBUG_CES_EXECUTION_STATUS, DbgEng.DEBUG_STATUS_BREAK)
|
||||||
|
|
|
@ -38,6 +38,7 @@ data64_compiler_map = {
|
||||||
x86_compiler_map = {
|
x86_compiler_map = {
|
||||||
'windows': 'windows',
|
'windows': 'windows',
|
||||||
'Cygwin': 'windows',
|
'Cygwin': 'windows',
|
||||||
|
'default': 'windows',
|
||||||
}
|
}
|
||||||
|
|
||||||
default_compiler_map = {
|
default_compiler_map = {
|
||||||
|
|
|
@ -32,6 +32,7 @@ from pybag.dbgeng.win32.kernel32 import STILL_ACTIVE
|
||||||
|
|
||||||
from . import util, arch, methods, hooks
|
from . import util, arch, methods, hooks
|
||||||
from .dbgmodel.imodelobject import ModelObjectKind
|
from .dbgmodel.imodelobject import ModelObjectKind
|
||||||
|
from .exdi import exdi_commands, exdi_methods
|
||||||
|
|
||||||
PAGE_SIZE = 4096
|
PAGE_SIZE = 4096
|
||||||
|
|
||||||
|
@ -209,6 +210,9 @@ def start_trace(name):
|
||||||
STATE.trace.register_mapper = arch.compute_register_mapper(language)
|
STATE.trace.register_mapper = arch.compute_register_mapper(language)
|
||||||
|
|
||||||
parent = os.path.dirname(inspect.getfile(inspect.currentframe()))
|
parent = os.path.dirname(inspect.getfile(inspect.currentframe()))
|
||||||
|
if util.is_exdi():
|
||||||
|
schema_fn = os.path.join(parent, 'schema_exdi.xml')
|
||||||
|
else:
|
||||||
schema_fn = os.path.join(parent, 'schema.xml')
|
schema_fn = os.path.join(parent, 'schema.xml')
|
||||||
with open(schema_fn, 'r') as schema_file:
|
with open(schema_fn, 'r') as schema_file:
|
||||||
schema_xml = schema_file.read()
|
schema_xml = schema_file.read()
|
||||||
|
@ -314,17 +318,19 @@ def ghidra_trace_attach(pid=None, attach_flags='0', initial_break=True, timeout=
|
||||||
|
|
||||||
|
|
||||||
@util.dbg.eng_thread
|
@util.dbg.eng_thread
|
||||||
def ghidra_trace_attach_kernel(command=None, initial_break=True, timeout=DbgEng.WAIT_INFINITE, start_trace=True):
|
def ghidra_trace_attach_kernel(command=None, flags=DbgEng.DEBUG_ATTACH_KERNEL_CONNECTION, initial_break=True, timeout=DbgEng.WAIT_INFINITE, start_trace=True):
|
||||||
"""
|
"""
|
||||||
Create a session.
|
Create a session.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dbg = util.dbg._base
|
dbg = util.dbg._base
|
||||||
util.set_kernel(True)
|
util.set_kernel(True)
|
||||||
|
if flags == 2:
|
||||||
|
util.set_exdi(True)
|
||||||
if initial_break:
|
if initial_break:
|
||||||
dbg._control.AddEngineOptions(DbgEng.DEBUG_ENGINITIAL_BREAK)
|
dbg._control.AddEngineOptions(DbgEng.DEBUG_ENGINITIAL_BREAK)
|
||||||
if command != None:
|
if command != None:
|
||||||
dbg._client.AttachKernel(command)
|
dbg._client.AttachKernel(command, flags=int(flags))
|
||||||
if start_trace:
|
if start_trace:
|
||||||
ghidra_trace_start(command)
|
ghidra_trace_start(command)
|
||||||
|
|
||||||
|
@ -593,6 +599,9 @@ def putreg():
|
||||||
name = regs._reg.GetDescription(i)[0]
|
name = regs._reg.GetDescription(i)[0]
|
||||||
try:
|
try:
|
||||||
value = regs._get_register_by_index(i)
|
value = regs._get_register_by_index(i)
|
||||||
|
except Exception:
|
||||||
|
value = 0
|
||||||
|
try:
|
||||||
values.append(mapper.map_value(nproc, name, value))
|
values.append(mapper.map_value(nproc, name, value))
|
||||||
robj.set_value(name, hex(value))
|
robj.set_value(name, hex(value))
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
|
@ -0,0 +1,244 @@
|
||||||
|
## ###
|
||||||
|
# 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.
|
||||||
|
##
|
||||||
|
from ghidratrace import sch
|
||||||
|
from ghidratrace.client import Client, Address, AddressRange, TraceObject
|
||||||
|
|
||||||
|
PAGE_SIZE = 4096
|
||||||
|
|
||||||
|
from ghidradbg import arch, commands, util
|
||||||
|
|
||||||
|
SESSION_PATH = 'Sessions[0]'
|
||||||
|
PROCESSES_PATH = SESSION_PATH + '.ExdiProcesses'
|
||||||
|
PROCESS_KEY_PATTERN = '[{pid}]'
|
||||||
|
PROCESS_PATTERN = PROCESSES_PATH + PROCESS_KEY_PATTERN
|
||||||
|
PROC_BREAKS_PATTERN = PROCESS_PATTERN + '.Breakpoints'
|
||||||
|
PROC_BREAK_KEY_PATTERN = '[{breaknum}.{locnum}]'
|
||||||
|
THREADS_PATTERN = PROCESS_PATTERN + '.Threads'
|
||||||
|
THREAD_KEY_PATTERN = '[{tnum}]'
|
||||||
|
THREAD_PATTERN = THREADS_PATTERN + THREAD_KEY_PATTERN
|
||||||
|
MEMORY_PATH = SESSION_PATH + '.Memory'
|
||||||
|
REGION_KEY_PATTERN = '[{start}]'
|
||||||
|
REGION_PATTERN = MEMORY_PATH + REGION_KEY_PATTERN
|
||||||
|
KMODULES_PATH = SESSION_PATH + '.Modules'
|
||||||
|
KMODULE_KEY_PATTERN = '[{modpath}]'
|
||||||
|
KMODULE_PATTERN = KMODULES_PATH + KMODULE_KEY_PATTERN
|
||||||
|
MODULES_PATTERN = PROCESS_PATTERN + '.Modules'
|
||||||
|
MODULE_KEY_PATTERN = '[{modpath}]'
|
||||||
|
MODULE_PATTERN = MODULES_PATTERN + MODULE_KEY_PATTERN
|
||||||
|
SECTIONS_ADD_PATTERN = '.Sections'
|
||||||
|
SECTION_KEY_PATTERN = '[{secname}]'
|
||||||
|
SECTION_ADD_PATTERN = SECTIONS_ADD_PATTERN + SECTION_KEY_PATTERN
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def ghidra_trace_put_processes_exdi():
|
||||||
|
"""
|
||||||
|
Put the list of processes into the trace's processes list.
|
||||||
|
"""
|
||||||
|
|
||||||
|
radix = util.get_convenience_variable('output-radix')
|
||||||
|
commands.STATE.require_tx()
|
||||||
|
with commands.STATE.client.batch() as b:
|
||||||
|
put_processes_exdi(commands.STATE, radix)
|
||||||
|
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def ghidra_trace_put_regions_exdi():
|
||||||
|
"""
|
||||||
|
Read the memory map, if applicable, and write to the trace's Regions
|
||||||
|
"""
|
||||||
|
|
||||||
|
commands.STATE.require_tx()
|
||||||
|
with commands.STATE.client.batch() as b:
|
||||||
|
put_regions_exdi(commands.STATE)
|
||||||
|
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def ghidra_trace_put_kmodules_exdi():
|
||||||
|
"""
|
||||||
|
Gather object files, if applicable, and write to the trace's Modules
|
||||||
|
"""
|
||||||
|
|
||||||
|
commands.STATE.require_tx()
|
||||||
|
with commands.STATE.client.batch() as b:
|
||||||
|
put_kmodules_exdi(commands.STATE)
|
||||||
|
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def ghidra_trace_put_threads_exdi(pid):
|
||||||
|
"""
|
||||||
|
Put the current process's threads into the Ghidra trace
|
||||||
|
"""
|
||||||
|
|
||||||
|
radix = util.get_convenience_variable('output-radix')
|
||||||
|
commands.STATE.require_tx()
|
||||||
|
with commands.STATE.client.batch() as b:
|
||||||
|
put_threads_exdi(commands.STATE, pid, radix)
|
||||||
|
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def ghidra_trace_put_all_exdi():
|
||||||
|
"""
|
||||||
|
Put everything currently selected into the Ghidra trace
|
||||||
|
"""
|
||||||
|
|
||||||
|
radix = util.get_convenience_variable('output-radix')
|
||||||
|
commands.STATE.require_tx()
|
||||||
|
with commands.STATE.client.batch() as b:
|
||||||
|
if util.dbg.use_generics == False:
|
||||||
|
put_processes_exdi(commands.STATE, radix)
|
||||||
|
put_regions_exdi(commands.STATE)
|
||||||
|
put_kmodules_exdi(commands.STATE)
|
||||||
|
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def put_processes_exdi(state, radix):
|
||||||
|
radix = util.get_convenience_variable('output-radix')
|
||||||
|
keys = []
|
||||||
|
result = util.dbg._base.cmd("!process 0 0")
|
||||||
|
lines = result.split("\n")
|
||||||
|
count = int((len(lines)-2)/5)
|
||||||
|
for i in range(0,count):
|
||||||
|
l1 = lines[i*5+1].strip().split() # PROCESS
|
||||||
|
l2 = lines[i*5+2].strip().split() # SessionId, Cid, Peb: ParentId
|
||||||
|
l3 = lines[i*5+3].strip().split() # DirBase, ObjectTable, HandleCount
|
||||||
|
l4 = lines[i*5+4].strip().split() # Image
|
||||||
|
id = int(l2[3], 16)
|
||||||
|
name = l4[1]
|
||||||
|
ppath = PROCESS_PATTERN.format(pid=id)
|
||||||
|
procobj = state.trace.create_object(ppath)
|
||||||
|
keys.append(PROCESS_KEY_PATTERN.format(pid=id))
|
||||||
|
pidstr = ('0x{:x}' if radix ==
|
||||||
|
16 else '0{:o}' if radix == 8 else '{}').format(id)
|
||||||
|
procobj.set_value('PID', id)
|
||||||
|
procobj.set_value('Name', name)
|
||||||
|
procobj.set_value('_display', '[{}] {}'.format(pidstr, name))
|
||||||
|
(base, addr) = commands.map_address(int(l1[1],16))
|
||||||
|
procobj.set_value('EPROCESS', addr, schema="ADDRESS")
|
||||||
|
(base, addr) = commands.map_address(int(l2[5],16))
|
||||||
|
procobj.set_value('PEB', addr, schema="ADDRESS")
|
||||||
|
(base, addr) = commands.map_address(int(l3[1],16))
|
||||||
|
procobj.set_value('DirBase', addr, schema="ADDRESS")
|
||||||
|
(base, addr) = commands.map_address(int(l3[3],16))
|
||||||
|
procobj.set_value('ObjectTable', addr, schema="ADDRESS")
|
||||||
|
#procobj.set_value('ObjectTable', l3[3])
|
||||||
|
tcobj = state.trace.create_object(ppath+".Threads")
|
||||||
|
procobj.insert()
|
||||||
|
tcobj.insert()
|
||||||
|
state.trace.proxy_object_path(PROCESSES_PATH).retain_values(keys)
|
||||||
|
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def put_regions_exdi(state):
|
||||||
|
radix = util.get_convenience_variable('output-radix')
|
||||||
|
keys = []
|
||||||
|
result = util.dbg._base.cmd("!address")
|
||||||
|
lines = result.split("\n")
|
||||||
|
init = False
|
||||||
|
for l in lines:
|
||||||
|
if "-------" in l:
|
||||||
|
init = True
|
||||||
|
continue
|
||||||
|
if init == False:
|
||||||
|
continue
|
||||||
|
fields = l.strip().replace('`','').split() # PROCESS
|
||||||
|
if len(fields) < 4:
|
||||||
|
continue
|
||||||
|
start = fields[0]
|
||||||
|
#finish = fields[1]
|
||||||
|
length = fields[2]
|
||||||
|
type = fields[3]
|
||||||
|
(sbase, saddr) = commands.map_address(int(start,16))
|
||||||
|
#(fbase, faddr) = commands.map_address(int(finish,16))
|
||||||
|
rng = saddr.extend(int(length,16))
|
||||||
|
rpath = REGION_PATTERN.format(start=start)
|
||||||
|
keys.append(REGION_KEY_PATTERN.format(start=start))
|
||||||
|
regobj = state.trace.create_object(rpath)
|
||||||
|
regobj.set_value('Range', rng, schema="RANGE")
|
||||||
|
regobj.set_value('Size', length)
|
||||||
|
regobj.set_value('Type', type)
|
||||||
|
regobj.set_value('_readable', True)
|
||||||
|
regobj.set_value('_writable', True)
|
||||||
|
regobj.set_value('_executable', True)
|
||||||
|
regobj.set_value('_display', '[{}] {}'.format(
|
||||||
|
start, type))
|
||||||
|
regobj.insert()
|
||||||
|
state.trace.proxy_object_path(MEMORY_PATH).retain_values(keys)
|
||||||
|
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def put_kmodules_exdi(state):
|
||||||
|
radix = util.get_convenience_variable('output-radix')
|
||||||
|
keys = []
|
||||||
|
result = util.dbg._base.cmd("lm")
|
||||||
|
lines = result.split("\n")
|
||||||
|
init = False
|
||||||
|
for l in lines:
|
||||||
|
if "start" in l:
|
||||||
|
continue
|
||||||
|
if "Unloaded" in l:
|
||||||
|
continue
|
||||||
|
fields = l.strip().replace('`','').split()
|
||||||
|
if len(fields) < 3:
|
||||||
|
continue
|
||||||
|
start = fields[0]
|
||||||
|
finish = fields[1]
|
||||||
|
name = fields[2]
|
||||||
|
sname = name.replace('.sys','').replace('.dll','')
|
||||||
|
(sbase, saddr) = commands.map_address(int(start,16))
|
||||||
|
(fbase, faddr) = commands.map_address(int(finish,16))
|
||||||
|
sz = faddr.offset - saddr.offset
|
||||||
|
rng = saddr.extend(sz)
|
||||||
|
mpath = KMODULE_PATTERN.format(modpath=sname)
|
||||||
|
keys.append(KMODULE_KEY_PATTERN.format(modpath=sname))
|
||||||
|
modobj = commands.STATE.trace.create_object(mpath)
|
||||||
|
modobj.set_value('Name', name)
|
||||||
|
modobj.set_value('Base', saddr, schema="ADDRESS")
|
||||||
|
modobj.set_value('Range', rng, schema="RANGE")
|
||||||
|
modobj.set_value('Size', hex(sz))
|
||||||
|
modobj.insert()
|
||||||
|
state.trace.proxy_object_path(KMODULES_PATH).retain_values(keys)
|
||||||
|
|
||||||
|
|
||||||
|
@util.dbg.eng_thread
|
||||||
|
def put_threads_exdi(state, pid, radix):
|
||||||
|
radix = util.get_convenience_variable('output-radix')
|
||||||
|
pidstr = ('0x{:x}' if radix == 16 else '0{:o}' if radix == 8 else '{}').format(pid)
|
||||||
|
keys = []
|
||||||
|
result = util.dbg._base.cmd("!process "+hex(pid)+" 4")
|
||||||
|
lines = result.split("\n")
|
||||||
|
for l in lines:
|
||||||
|
l = l.strip()
|
||||||
|
if "THREAD" not in l:
|
||||||
|
continue
|
||||||
|
fields = l.split()
|
||||||
|
cid = fields[3] # pid.tid (decimal)
|
||||||
|
tid = int(cid.split('.')[1],16)
|
||||||
|
tidstr = ('0x{:x}' if radix ==
|
||||||
|
16 else '0{:o}' if radix == 8 else '{}').format(tid)
|
||||||
|
tpath = THREAD_PATTERN.format(pid=pid, tnum=tid)
|
||||||
|
tobj = commands.STATE.trace.create_object(tpath)
|
||||||
|
keys.append(THREAD_KEY_PATTERN.format(tnum=tidstr))
|
||||||
|
tobj = state.trace.create_object(tpath)
|
||||||
|
tobj.set_value('PID', pidstr)
|
||||||
|
tobj.set_value('TID', tidstr)
|
||||||
|
tobj.set_value('_display', '[{}]'.format(tidstr))
|
||||||
|
tobj.set_value('ETHREAD', fields[1])
|
||||||
|
tobj.set_value('TEB', fields[5])
|
||||||
|
tobj.set_value('Win32Thread', fields[7])
|
||||||
|
tobj.set_value('State', fields[8])
|
||||||
|
tobj.insert()
|
||||||
|
commands.STATE.trace.proxy_object_path(
|
||||||
|
THREADS_PATTERN.format(pid=pidstr)).retain_values(keys)
|
|
@ -0,0 +1,54 @@
|
||||||
|
## ###
|
||||||
|
# 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 re
|
||||||
|
|
||||||
|
from ghidratrace import sch
|
||||||
|
from ghidratrace.client import MethodRegistry, ParamDesc, Address, AddressRange
|
||||||
|
from ghidradbg import util, commands, methods
|
||||||
|
from ghidradbg.methods import REGISTRY, SESSIONS_PATTERN, SESSION_PATTERN, extre
|
||||||
|
|
||||||
|
from . import exdi_commands
|
||||||
|
|
||||||
|
XPROCESSES_PATTERN = extre(SESSION_PATTERN, '\.ExdiProcesses')
|
||||||
|
XPROCESS_PATTERN = extre(XPROCESSES_PATTERN, '\[(?P<procnum>\\d*)\]')
|
||||||
|
XTHREADS_PATTERN = extre(XPROCESS_PATTERN, '\.Threads')
|
||||||
|
|
||||||
|
def find_pid_by_pattern(pattern, object, err_msg):
|
||||||
|
mat = pattern.fullmatch(object.path)
|
||||||
|
if mat is None:
|
||||||
|
raise TypeError(f"{object} is not {err_msg}")
|
||||||
|
pid = int(mat['procnum'])
|
||||||
|
return pid
|
||||||
|
|
||||||
|
|
||||||
|
def find_pid_by_obj(object):
|
||||||
|
return find_pid_by_pattern(XTHREADS_PATTERN, object, "an ExdiThreadsContainer")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@REGISTRY.method(action='refresh', display="Refresh Target Processes")
|
||||||
|
def refresh_exdi_processes(node: sch.Schema('ExdiProcessContainer')):
|
||||||
|
"""Refresh the list of processes in the target kernel."""
|
||||||
|
with commands.open_tracked_tx('Refresh Processes'):
|
||||||
|
exdi_commands.ghidra_trace_put_processes_exdi()
|
||||||
|
|
||||||
|
|
||||||
|
@REGISTRY.method(action='refresh', display="Refresh Process Threads")
|
||||||
|
def refresh_exdi_threads(node: sch.Schema('ExdiThreadContainer')):
|
||||||
|
"""Refresh the list of threads in the process."""
|
||||||
|
pid = find_pid_by_obj(node)
|
||||||
|
with commands.open_tracked_tx('Refresh Threads'):
|
||||||
|
exdi_commands.ghidra_trace_put_threads_exdi(pid)
|
|
@ -27,6 +27,7 @@ from pybag.dbgeng.callbacks import EventHandler
|
||||||
from pybag.dbgeng.idebugbreakpoint import DebugBreakpoint
|
from pybag.dbgeng.idebugbreakpoint import DebugBreakpoint
|
||||||
|
|
||||||
from . import commands, util
|
from . import commands, util
|
||||||
|
from .exdi import exdi_commands
|
||||||
|
|
||||||
|
|
||||||
ALL_EVENTS = 0xFFFF
|
ALL_EVENTS = 0xFFFF
|
||||||
|
@ -65,6 +66,8 @@ class ProcessState(object):
|
||||||
if first:
|
if first:
|
||||||
if util.is_kernel():
|
if util.is_kernel():
|
||||||
commands.create_generic("Sessions")
|
commands.create_generic("Sessions")
|
||||||
|
if util.is_exdi() and util.dbg.use_generics is False:
|
||||||
|
commands.create_generic("Sessions[0].ExdiProcesses")
|
||||||
commands.put_processes()
|
commands.put_processes()
|
||||||
commands.put_environment()
|
commands.put_environment()
|
||||||
commands.put_threads()
|
commands.put_threads()
|
||||||
|
@ -86,9 +89,13 @@ class ProcessState(object):
|
||||||
if first or hashable_frame not in self.visited:
|
if first or hashable_frame not in self.visited:
|
||||||
self.visited.add(hashable_frame)
|
self.visited.add(hashable_frame)
|
||||||
if first or self.regions:
|
if first or self.regions:
|
||||||
|
if util.is_exdi():
|
||||||
|
exdi_commands.put_regions_exdi(commands.STATE)
|
||||||
commands.put_regions()
|
commands.put_regions()
|
||||||
self.regions = False
|
self.regions = False
|
||||||
if first or self.modules:
|
if first or self.modules:
|
||||||
|
if util.is_exdi():
|
||||||
|
exdi_commands.put_kmodules_exdi(commands.STATE)
|
||||||
commands.put_modules()
|
commands.put_modules()
|
||||||
self.modules = False
|
self.modules = False
|
||||||
if first or self.breaks:
|
if first or self.breaks:
|
||||||
|
|
|
@ -0,0 +1,410 @@
|
||||||
|
<context>
|
||||||
|
<schema name="DbgRoot" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Configurable" />
|
||||||
|
<attribute name="Sessions" schema="SessionContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Settings" schema="ANY" />
|
||||||
|
<attribute name="State" schema="ANY" />
|
||||||
|
<attribute-alias from="_state" to="State" />
|
||||||
|
<attribute name="Utility" schema="ANY" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY"/>
|
||||||
|
</schema>
|
||||||
|
<schema name="SessionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Configurable" />
|
||||||
|
<element schema="Session" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY"/>
|
||||||
|
</schema>
|
||||||
|
<schema name="Session" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Activatable" />
|
||||||
|
<interface name="Access" />
|
||||||
|
<interface name="Attacher" />
|
||||||
|
<interface name="Interpreter" />
|
||||||
|
<interface name="Interruptible" />
|
||||||
|
<interface name="Launcher" />
|
||||||
|
<interface name="ActiveScope" />
|
||||||
|
<interface name="EventScope" />
|
||||||
|
<interface name="FocusScope" />
|
||||||
|
<interface name="Aggregate" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="ExdiProcesses" schema="ExdiProcessContainer" required="no" fixed="yes" />
|
||||||
|
<attribute name="Processes" schema="ProcessContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Available" schema="AvailableContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Memory" schema="Memory" required="no" fixed="yes" />
|
||||||
|
<attribute name="Modules" schema="ModuleContainer" required="no" fixed="yes" />
|
||||||
|
<attribute name="_event_thread" schema="OBJECT" hidden="yes" />
|
||||||
|
<attribute name="_focus" schema="Selectable" required="yes" hidden="yes" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY"/>
|
||||||
|
</schema>
|
||||||
|
<schema name="Selectable" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<element schema="OBJECT" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="DebugBreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Aggregate" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Breakpoints" schema="BreakpointContainer" required="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="BreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="BreakpointLocationContainer" />
|
||||||
|
<interface name="BreakpointSpecContainer" />
|
||||||
|
<element schema="BreakpointSpec" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY" />
|
||||||
|
</schema>
|
||||||
|
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
|
||||||
|
<interface name="Configurable" />
|
||||||
|
<element schema="Attachable" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ProcessContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Configurable" />
|
||||||
|
<element schema="Process" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY" />
|
||||||
|
</schema>
|
||||||
|
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="BreakpointSpec" />
|
||||||
|
<interface name="BreakpointLocation" />
|
||||||
|
<interface name="Deletable" />
|
||||||
|
<interface name="Togglable" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Expression" schema="STRING" required="yes" hidden="yes" />
|
||||||
|
<attribute-alias from="_expression" to="Expression" />
|
||||||
|
<attribute name="Kinds" schema="SET_BREAKPOINT_KIND" required="yes" hidden="yes" />
|
||||||
|
<attribute-alias from="_kinds" to="Kinds" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute name="Range" schema="RANGE" />
|
||||||
|
<attribute-alias from="_range" to="Range" />
|
||||||
|
<attribute name="Enabled" schema="BOOL" required="yes" />
|
||||||
|
<attribute-alias from="_enabled" to="Enabled" />
|
||||||
|
<attribute name="Commands" schema="STRING" />
|
||||||
|
<attribute name="Condition" schema="STRING" />
|
||||||
|
<attribute name="Hit Count" schema="INT" />
|
||||||
|
<attribute name="Ignore Count" schema="INT" />
|
||||||
|
<attribute name="Pending" schema="BOOL" />
|
||||||
|
<attribute name="Silent" schema="BOOL" />
|
||||||
|
<attribute name="Temporary" schema="BOOL" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Attachable" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Attachable" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="PID" schema="LONG" />
|
||||||
|
<attribute-alias from="_pid" to="PID" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Process" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Activatable" />
|
||||||
|
<interface name="Process" />
|
||||||
|
<interface name="Aggregate" />
|
||||||
|
<interface name="ExecutionStateful" />
|
||||||
|
<interface name="Attacher" />
|
||||||
|
<interface name="Deletable" />
|
||||||
|
<interface name="Detachable" />
|
||||||
|
<interface name="Killable" />
|
||||||
|
<interface name="Launcher" />
|
||||||
|
<interface name="Resumable" />
|
||||||
|
<interface name="Steppable" />
|
||||||
|
<interface name="Interruptible" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Debug" schema="DebugBreakpointContainer" required="yes" fixed="yes" />
|
||||||
|
<!-- attribute name="Breakpoints" schema="BreakpointLocationContainer" required="yes" fixed="yes" /-->
|
||||||
|
<attribute name="Exit Code" schema="LONG" />
|
||||||
|
<attribute-alias from="_exit_code" to="Exit Code" />
|
||||||
|
<attribute name="Environment" schema="Environment" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Memory" schema="ProcessMemory" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Modules" schema="ProcessModuleContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Handle" schema="STRING" fixed="yes" />
|
||||||
|
<attribute name="Id" schema="STRING" fixed="yes" />
|
||||||
|
<attribute name="PID" schema="LONG" hidden="yes" />
|
||||||
|
<attribute-alias from="_pid" to="PID" />
|
||||||
|
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
|
||||||
|
<attribute-alias from="_state" to="State" />
|
||||||
|
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Environment" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Environment" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="OS" schema="STRING" />
|
||||||
|
<attribute name="Arch" schema="STRING" />
|
||||||
|
<attribute name="Endian" schema="STRING" />
|
||||||
|
<attribute name="Debugger" schema="STRING" />
|
||||||
|
<attribute-alias from="_os" to="OS" />
|
||||||
|
<attribute-alias from="_arch" to="Arch" />
|
||||||
|
<attribute-alias from="_endian" to="Endian" />
|
||||||
|
<attribute-alias from="_debugger" to="Debugger" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ProcessModuleContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||||
|
<!-- interface name="ModuleContainer" /-->
|
||||||
|
<element schema="ProcessModule" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ProcessMemory" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<!-- interface name="Memory" /-->
|
||||||
|
<element schema="ProcessMemoryRegion" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="BreakpointLocation" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="BreakpointLocation" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Range" schema="RANGE" />
|
||||||
|
<attribute-alias from="_range" to="Range" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="BreakpointLocationContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="BreakpointLocationContainer" />
|
||||||
|
<element schema="BreakpointLocation" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ThreadContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Configurable" />
|
||||||
|
<element schema="Thread" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Method" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Method" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="_display" schema="STRING" required="yes" fixed="yes" hidden="yes" />
|
||||||
|
<attribute name="_return_type" schema="TYPE" required="yes" fixed="yes" hidden="yes" />
|
||||||
|
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" fixed="yes" hidden="yes" />
|
||||||
|
<attribute schema="VOID" fixed="yes" hidden="yes" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Thread" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Activatable" />
|
||||||
|
<interface name="Thread" />
|
||||||
|
<interface name="ExecutionStateful" />
|
||||||
|
<interface name="Steppable" />
|
||||||
|
<interface name="Aggregate" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Stack" schema="StackFramesContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Registers" schema="RegisterValueContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Environment" schema="ANY" fixed="yes" />
|
||||||
|
<attribute name="Id" schema="STRING" fixed="yes" />
|
||||||
|
<attribute name="TID" schema="LONG" />
|
||||||
|
<attribute-alias from="_tid" to="TID" />
|
||||||
|
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
|
||||||
|
<attribute-alias from="_state" to="State" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute name="Advance" schema="Method" required="yes" fixed="yes" hidden="yes" />
|
||||||
|
<attribute schema="ANY" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ProcessModule" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<!-- interface name="Module" /-->
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Sections" schema="SectionContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Symbols" schema="SymbolContainer" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Range" schema="RANGE" />
|
||||||
|
<attribute name="Name" schema="STRING" />
|
||||||
|
<attribute-alias from="_module_name" to="Name" />
|
||||||
|
<attribute-alias from="_range" to="Range" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute name="ToDisplayString" schema="BOOL" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ProcessMemoryRegion" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<!-- interface name="MemoryRegion" /-->
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Base" schema="LONG" required="yes" fixed="yes" />
|
||||||
|
<attribute name="Object File" schema="STRING" fixed="yes" />
|
||||||
|
<attribute name="_readable" schema="BOOL" required="yes" hidden="yes" />
|
||||||
|
<attribute name="_writable" schema="BOOL" required="yes" hidden="yes" />
|
||||||
|
<attribute name="_executable" schema="BOOL" required="yes" hidden="yes" />
|
||||||
|
<attribute name="Range" schema="RANGE" required="yes" hidden="yes" />
|
||||||
|
<attribute-alias from="_range" to="Range" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="SectionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="SectionContainer" />
|
||||||
|
<element schema="Section" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="StackFramesContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Aggregate" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Frames" schema="Stack" required="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Stack" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Stack" />
|
||||||
|
<element schema="StackFrame" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY" />
|
||||||
|
</schema>
|
||||||
|
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||||
|
<interface name="SymbolNamespace" />
|
||||||
|
<element schema="Symbol" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Symbol" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Symbol" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="StackFrame" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Activatable" />
|
||||||
|
<interface name="StackFrame" />
|
||||||
|
<interface name="Aggregate" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Function" schema="STRING" hidden="yes" />
|
||||||
|
<attribute-alias from="_function" to="Function" />
|
||||||
|
<attribute name="Instruction Offset" schema="ADDRESS" required="yes" />
|
||||||
|
<attribute-alias from="_pc" to="Instruction Offset" />
|
||||||
|
<attribute name="Stack Offset" schema="ADDRESS" />
|
||||||
|
<attribute name="Return Offset" schema="ADDRESS" />
|
||||||
|
<attribute name="Frame Offset" schema="ADDRESS" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="ANY" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Section" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Section" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Range" schema="RANGE" />
|
||||||
|
<attribute-alias from="_range" to="Range" />
|
||||||
|
<attribute name="Offset" schema="STRING" fixed="yes" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="RegisterValueContainer" attributeResync="ONCE">
|
||||||
|
<interface name="RegisterContainer" />
|
||||||
|
<interface name="RegisterBank" />
|
||||||
|
<attribute name="General Purpose Registers" schema="RegisterBank" />
|
||||||
|
<attribute name="Floating Point Registers" schema="RegisterBank" />
|
||||||
|
<attribute name="Advanced Vector Extensions" schema="RegisterBank" />
|
||||||
|
<attribute name="Memory Protection Extensions" schema="RegisterBank" />
|
||||||
|
<attribute name="FloatingPoint" schema="RegisterBank" />
|
||||||
|
<attribute name="SIMD" schema="RegisterBank" />
|
||||||
|
<attribute name="User" schema="RegisterBank" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="RegisterBank" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||||
|
<interface name="RegisterBank" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
|
||||||
|
<schema name="ExdiProcessContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||||
|
<element schema="ExdiProcess" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute name="_base" schema="INT" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ExdiProcess" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Process" />
|
||||||
|
<interface name="Aggregate" />
|
||||||
|
<interface name="ExecutionStateful" />
|
||||||
|
<interface name="Attacher" />
|
||||||
|
<interface name="Deletable" />
|
||||||
|
<interface name="Detachable" />
|
||||||
|
<interface name="Killable" />
|
||||||
|
<interface name="Launcher" />
|
||||||
|
<interface name="Resumable" />
|
||||||
|
<interface name="Steppable" />
|
||||||
|
<interface name="Interruptible" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Threads" schema="ExdiThreadContainer" required="yes" fixed="yes" />
|
||||||
|
<!-- attribute name="Modules" schema="ModuleContainer" required="yes" fixed="yes" /-->
|
||||||
|
<attribute name="PID" schema="LONG" />
|
||||||
|
<attribute-alias from="_pid" to="PID" />
|
||||||
|
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
|
||||||
|
<attribute-alias from="_state" to="State" />
|
||||||
|
<attribute name="_parameters" schema="MAP_PARAMETERS" required="yes" hidden="yes" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="OBJECT" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ModuleContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||||
|
<element schema="Module" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute name="_base" schema="INT" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Module" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Module" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="Range" schema="RANGE" />
|
||||||
|
<attribute name="Name" schema="STRING" />
|
||||||
|
<attribute-alias from="_module_name" to="Name" />
|
||||||
|
<attribute-alias from="_range" to="Range" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="OBJECT" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ExdiThreadContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||||
|
<element schema="ExdiThread" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute name="_base" schema="INT" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="ExdiThread" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="Thread" />
|
||||||
|
<interface name="ExecutionStateful" />
|
||||||
|
<interface name="Steppable" />
|
||||||
|
<interface name="Aggregate" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="TID" schema="LONG" />
|
||||||
|
<attribute-alias from="_tid" to="TID" />
|
||||||
|
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
|
||||||
|
<attribute-alias from="_state" to="State" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="OBJECT" />
|
||||||
|
</schema>
|
||||||
|
<schema name="Memory" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||||
|
<interface name="Memory" />
|
||||||
|
<element schema="MemoryRegion" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
<schema name="MemoryRegion" elementResync="NEVER" attributeResync="NEVER">
|
||||||
|
<interface name="MemoryRegion" />
|
||||||
|
<element schema="VOID" />
|
||||||
|
<attribute name="_memory" schema="Memory" />
|
||||||
|
<attribute name="Range" schema="RANGE" required="yes" />
|
||||||
|
<attribute-alias from="_range" to="Range" />
|
||||||
|
<attribute name="Size" schema="STRING" fixed="yes" />
|
||||||
|
<attribute name="_readable" schema="BOOL" hidden="yes" />
|
||||||
|
<attribute name="_writable" schema="BOOL" hidden="yes" />
|
||||||
|
<attribute name="_executable" schema="BOOL" hidden="yes" />
|
||||||
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
|
<attribute schema="VOID" />
|
||||||
|
</schema>
|
||||||
|
</context>
|
|
@ -238,6 +238,7 @@ class GhidraDbg(object):
|
||||||
]:
|
]:
|
||||||
setattr(self, name, self.eng_thread(getattr(base, name)))
|
setattr(self, name, self.eng_thread(getattr(base, name)))
|
||||||
self.IS_KERNEL = False
|
self.IS_KERNEL = False
|
||||||
|
self.IS_EXDI = False
|
||||||
|
|
||||||
def _new_base(self):
|
def _new_base(self):
|
||||||
self._protected_base = AllDbg()
|
self._protected_base = AllDbg()
|
||||||
|
@ -455,6 +456,8 @@ def get_breakpoints():
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def selected_process():
|
def selected_process():
|
||||||
try:
|
try:
|
||||||
|
if is_exdi():
|
||||||
|
return 0
|
||||||
if is_kernel():
|
if is_kernel():
|
||||||
do = dbg._base._systems.GetCurrentProcessDataOffset()
|
do = dbg._base._systems.GetCurrentProcessDataOffset()
|
||||||
id = c_ulong()
|
id = c_ulong()
|
||||||
|
@ -472,6 +475,8 @@ def selected_process():
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def selected_process_space():
|
def selected_process_space():
|
||||||
try:
|
try:
|
||||||
|
if is_exdi():
|
||||||
|
return 0
|
||||||
if is_kernel():
|
if is_kernel():
|
||||||
return dbg._base._systems.GetCurrentProcessDataOffset()
|
return dbg._base._systems.GetCurrentProcessDataOffset()
|
||||||
return selected_process()
|
return selected_process()
|
||||||
|
@ -759,6 +764,8 @@ def split_path(pathString):
|
||||||
segs = pathString.split(".")
|
segs = pathString.split(".")
|
||||||
for s in segs:
|
for s in segs:
|
||||||
if s.endswith("]"):
|
if s.endswith("]"):
|
||||||
|
if "[" not in s:
|
||||||
|
print(f"Missing terminator: {s}")
|
||||||
index = s.index("[")
|
index = s.index("[")
|
||||||
list.append(s[:index])
|
list.append(s[:index])
|
||||||
list.append(s[index:])
|
list.append(s[index:])
|
||||||
|
@ -907,3 +914,9 @@ def set_kernel(value):
|
||||||
|
|
||||||
def is_kernel():
|
def is_kernel():
|
||||||
return dbg.IS_KERNEL
|
return dbg.IS_KERNEL
|
||||||
|
|
||||||
|
def set_exdi(value):
|
||||||
|
dbg.IS_EXDI = value
|
||||||
|
|
||||||
|
def is_exdi():
|
||||||
|
return dbg.IS_EXDI
|
||||||
|
|
|
@ -825,6 +825,44 @@ bdcedit /dbgsettings NET HOSTIP:IP PORT:54321 KEY:1.1.1.1
|
||||||
'net:port=54321,key=1.1.1.1'.'</LI>
|
'net:port=54321,key=1.1.1.1'.'</LI>
|
||||||
</UL>
|
</UL>
|
||||||
|
|
||||||
|
<UL>
|
||||||
|
<LI><B>Type</B>: The type of kernel connection, either "Remote", "Local", or "EXDI".
|
||||||
|
"Remote", the most common type, indicates two-machine debugging over various
|
||||||
|
possible connection media, e.g. Ethernet, serial, USB, etc. "Local" is used for limited
|
||||||
|
introspection into the target on which the debugger is running. "EXDI" is arguably
|
||||||
|
the most exotic type - it essentially simulates the normal "Remote" connection using
|
||||||
|
the gdb Remote Serial Protocol. It can be used when connecting to gdbstubs in
|
||||||
|
platforms, such as QEMU, VMWare, Trace32, etc.</LI>
|
||||||
|
</UL>
|
||||||
|
|
||||||
|
<H4>EXDI</H4>
|
||||||
|
|
||||||
|
<P>Setup for EXDI connections is fairly complicated and difficult to get correct.
|
||||||
|
The argument string typically should be something like:</P>
|
||||||
|
<UL style='list-style-type: none'>
|
||||||
|
<LI>
|
||||||
|
<PRE>
|
||||||
|
exdi:CLSID={29f9906e-9dbe-4d4b-b0fb-6acf7fb6d014},Kd=Guess,DataBreaks=Exdi
|
||||||
|
</PRE>
|
||||||
|
</LI>
|
||||||
|
</UL>
|
||||||
|
<P>The CLSID here should match the CLSID in the <B>exdiConfigData.xml</B> file in the debugger architectural directory. If windbg has been
|
||||||
|
run using EXDI at some point, there will also be an entry in the System Registry for this CLSID. The InprocServer32 subentry
|
||||||
|
for this CLSID in the Registry should point to a copy of ExdiGdbSrv.dll, typically the one in the same directory. This DLL
|
||||||
|
must reside somewhere that the debugger has permission to load from, i.e. not in the WindowsApps directory tree.
|
||||||
|
The <B>exdiConfigData</B> file should be configured for the target you're using. We heavily recommend using <B>displayCommPackets==yes</B>,
|
||||||
|
as many of the tasks take considerable time, and this is the only indicator of progress.
|
||||||
|
</P>
|
||||||
|
|
||||||
|
<P>The <B>Kd=Guess</B> parameter causes the underlying engine to scan memory for the kernel's base address, which will probably not
|
||||||
|
be provided by the gdbstub. (<B>Kd=NtBaseAddr</B> is also a valid option, as is eliminating the parameter, but, currently, we have no
|
||||||
|
idea how to point the configuration at a correct value. Using this option will cause the load to spin pointlessly.) If you can,
|
||||||
|
we highly recommend breaking the target near the base address, as the search proceeds down through memory starting at the current
|
||||||
|
program counter. If the difference between the PC and the base address is large, the loading process will punt before useful
|
||||||
|
values are detected. If anyone understand how to extend this search (or knows how to set the base address to sidestep the scan),
|
||||||
|
we would really love some guidance.
|
||||||
|
</P>
|
||||||
|
|
||||||
<H3><A name="dbgeng_ttd"></A>TTD (Time-Travel Debugging)</H3>
|
<H3><A name="dbgeng_ttd"></A>TTD (Time-Travel Debugging)</H3>
|
||||||
|
|
||||||
<P>This is a nascent extension to our launcher for the Windows Debugger. The launcher itself
|
<P>This is a nascent extension to our launcher for the Windows Debugger. The launcher itself
|
||||||
|
|
|
@ -197,11 +197,17 @@ public class DebuggerRegionsPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
||||||
List<String> seedPath = object.getCanonicalPath().getKeyList();
|
List<String> seedPath = object.getCanonicalPath().getKeyList();
|
||||||
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
|
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
|
||||||
if (processPath != null) {
|
if (processPath != null) {
|
||||||
return successorRegions(rootSchema, processPath);
|
ModelQuery result = successorRegions(rootSchema, processPath);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
List<String> memoryPath = rootSchema.searchForSuitable(TargetMemory.class, seedPath);
|
List<String> memoryPath = rootSchema.searchForSuitable(TargetMemory.class, seedPath);
|
||||||
if (memoryPath != null) {
|
if (memoryPath != null) {
|
||||||
return successorRegions(rootSchema, memoryPath);
|
ModelQuery result = successorRegions(rootSchema, memoryPath);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return successorRegions(rootSchema, List.of());
|
return successorRegions(rootSchema, List.of());
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,4 +240,8 @@ public class ModelQuery {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return predicates.isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,13 +242,19 @@ public class DebuggerModulesPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
||||||
List<String> seedPath = object.getCanonicalPath().getKeyList();
|
List<String> seedPath = object.getCanonicalPath().getKeyList();
|
||||||
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
|
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
|
||||||
if (processPath != null) {
|
if (processPath != null) {
|
||||||
return successorModules(rootSchema, processPath);
|
ModelQuery result = successorModules(rootSchema, processPath);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
List<String> containerPath =
|
List<String> containerPath =
|
||||||
rootSchema.searchForSuitableContainer(TargetModule.class, seedPath);
|
rootSchema.searchForSuitableContainer(TargetModule.class, seedPath);
|
||||||
|
|
||||||
if (containerPath != null) {
|
if (containerPath != null) {
|
||||||
return successorModules(rootSchema, containerPath);
|
ModelQuery result = successorModules(rootSchema, containerPath);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return successorModules(rootSchema, List.of());
|
return successorModules(rootSchema, List.of());
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,14 +221,20 @@ public class DebuggerSectionsPanel extends AbstractObjectsTableBasedPanel<TraceO
|
||||||
List<String> seedPath = object.getCanonicalPath().getKeyList();
|
List<String> seedPath = object.getCanonicalPath().getKeyList();
|
||||||
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
|
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
|
||||||
if (processPath != null) {
|
if (processPath != null) {
|
||||||
return successorSections(rootSchema, processPath);
|
ModelQuery result = successorSections(rootSchema, processPath);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Yes, anchor on the *module* container when searching for sections
|
// Yes, anchor on the *module* container when searching for sections
|
||||||
List<String> containerPath =
|
List<String> containerPath =
|
||||||
rootSchema.searchForSuitableContainer(TargetModule.class, seedPath);
|
rootSchema.searchForSuitableContainer(TargetModule.class, seedPath);
|
||||||
|
|
||||||
if (containerPath != null) {
|
if (containerPath != null) {
|
||||||
return successorSections(rootSchema, containerPath);
|
ModelQuery result = successorSections(rootSchema, containerPath);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return successorSections(rootSchema, List.of());
|
return successorSections(rootSchema, List.of());
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,13 +347,19 @@ public class DebuggerThreadsPanel extends AbstractObjectsTableBasedPanel<TraceOb
|
||||||
List<String> seedPath = object.getCanonicalPath().getKeyList();
|
List<String> seedPath = object.getCanonicalPath().getKeyList();
|
||||||
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
|
List<String> processPath = rootSchema.searchForAncestor(TargetProcess.class, seedPath);
|
||||||
if (processPath != null) {
|
if (processPath != null) {
|
||||||
return successorThreads(rootSchema, processPath);
|
ModelQuery result = successorThreads(rootSchema, processPath);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
List<String> containerPath =
|
List<String> containerPath =
|
||||||
rootSchema.searchForSuitableContainer(TargetThread.class, seedPath);
|
rootSchema.searchForSuitableContainer(TargetThread.class, seedPath);
|
||||||
|
|
||||||
if (containerPath != null) {
|
if (containerPath != null) {
|
||||||
return successorThreads(rootSchema, containerPath);
|
ModelQuery result = successorThreads(rootSchema, containerPath);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return successorThreads(rootSchema, List.of());
|
return successorThreads(rootSchema, List.of());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue