mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +02:00
GP-4686: more edits
GP-4686: formatting GP-4686: post-review fixes GP-4686: post-review fixes GP-4686: remote options GP-4686: remote options GP-4686: remote options GP-4686: post-review / readmem logic GP-4686: extended launch GP-4686: better desc for kernel GP-4686: aisle 9 GP-4686: basically working GP-4686: better display GP-4686: unnecessary? GP-4686: better attr display logic GP-4686: temp GP-4686: addresses for synthetics GP-4686: cleanup, minor errors, start on CreateProcess2 GP-4686: adding names & addresses GP-4686: print hell, but fixes TARGET_OBJECT GP-4686: first pass kernel stuff
This commit is contained in:
parent
715a8ba335
commit
1fab470a5b
18 changed files with 845 additions and 106 deletions
|
@ -2,8 +2,11 @@
|
|||
##MODULE IP: Apache License 2.0
|
||||
##MODULE IP: MIT
|
||||
Module.manifest||GHIDRA||||END|
|
||||
data/debugger-launchers/kernel-dbgeng.bat||GHIDRA||||END|
|
||||
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|
|
||||
src/main/py/LICENSE||GHIDRA||||END|
|
||||
src/main/py/MANIFEST.in||GHIDRA||||END|
|
||||
src/main/py/README.md||GHIDRA||||END|
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
::@title dbgeng-kernel
|
||||
::@desc <html><body width="300px">
|
||||
::@desc <h3>Kernel debugging using <tt>dbgeng</tt> (in a Python interpreter)</h3>
|
||||
::@desc <p>
|
||||
::@desc This will connect the kernel debugger to a remote machine using <tt>dbgeng.dll</tt>.
|
||||
::@desc For setup instructions, press <b>F1</b>.
|
||||
::@desc </p>
|
||||
::@desc </body></html>
|
||||
::@menu-group local
|
||||
::@icon icon.debugger
|
||||
::@help TraceRmiLauncherServicePlugin#dbgeng_kernel
|
||||
::@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_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\kernel-dbgeng.py
|
|
@ -0,0 +1,26 @@
|
|||
::@title dbgeng-ext
|
||||
::@desc <html><body width="300px">
|
||||
::@desc <h3>Launch with <tt>dbgeng</tt> (in a Python interpreter)</h3>
|
||||
::@desc <p>
|
||||
::@desc This will launch the target on the local machine using <tt>dbgeng.dll</tt>.
|
||||
::@desc For setup instructions, press <b>F1</b>.
|
||||
::@desc </p>
|
||||
::@desc </body></html>
|
||||
::@menu-group local
|
||||
::@icon icon.debugger
|
||||
::@help TraceRmiLauncherServicePlugin#dbgeng_ext
|
||||
::@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:file="" "Image" "The target binary executable image"
|
||||
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to 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 OPT_TARGET_DIR:str="" "Dir" "Initial directory"
|
||||
::@env OPT_TARGET_ENV:str="" "Env" "Environment variables (sep=/0)"
|
||||
::@env OPT_CREATE_FLAGS:str="1" "Create flags" "Creation flags"
|
||||
::@env OPT_CREATE_ENGFLAGS:str="0" "Create flags (Engine)" "Engine-specific creation flags"
|
||||
::@env OPT_VERIFIER_FLAGS:str="0" "Verifier flags" "Verifier flags"
|
||||
|
||||
@echo off
|
||||
|
||||
"%OPT_PYTHON_EXE%" -i ..\support\local-dbgeng-ext.py
|
|
@ -0,0 +1,22 @@
|
|||
::@title dbgeng-remote
|
||||
::@desc <html><body width="300px">
|
||||
::@desc <h3>Launch with <tt>dbgeng</tt> remotely (in a Python interpreter)</h3>
|
||||
::@desc <p>
|
||||
::@desc This will launch the target on a remote machine using <tt>dbgeng.dll</tt>.
|
||||
::@desc For setup instructions, press <b>F1</b>.
|
||||
::@desc </p>
|
||||
::@desc </body></html>
|
||||
::@menu-group local
|
||||
::@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:file="" "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\remote-dbgeng.py
|
|
@ -0,0 +1,67 @@
|
|||
## ###
|
||||
# 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')
|
||||
cmd.ghidra_trace_attach_kernel(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()
|
|
@ -0,0 +1,77 @@
|
|||
## ###
|
||||
# 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_create_ext(
|
||||
os.getenv('OPT_TARGET_IMG') + args,
|
||||
os.getenv('OPT_TARGET_DIR'),
|
||||
os.getenv('OPT_TARGET_ENV'),
|
||||
os.getenv('OPT_CREATE_FLAGS'),
|
||||
os.getenv('OPT_CREATE_ENGFLAGS'),
|
||||
os.getenv('OPT_VERIFIER_FLAGS'),
|
||||
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()
|
|
@ -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()
|
|
@ -204,14 +204,18 @@ class DefaultMemoryMapper(object):
|
|||
self.defaultSpace = defaultSpace
|
||||
|
||||
def map(self, proc: int, offset: int):
|
||||
space = self.defaultSpace
|
||||
if proc == 0:
|
||||
space = self.defaultSpace
|
||||
else:
|
||||
space = f'{self.defaultSpace}{proc}'
|
||||
return self.defaultSpace, Address(space, offset)
|
||||
|
||||
def map_back(self, proc: int, address: Address) -> int:
|
||||
if address.space == self.defaultSpace:
|
||||
if address.space == self.defaultSpace and proc == 0:
|
||||
return address.offset
|
||||
raise ValueError(
|
||||
f"Address {address} is not in process {proc.GetProcessID()}")
|
||||
if address.space == f'{self.defaultSpace}{proc}':
|
||||
return address.offset
|
||||
raise ValueError(f"Address {address} is not in process {proc}")
|
||||
|
||||
|
||||
DEFAULT_MEMORY_MAPPER = DefaultMemoryMapper('ram')
|
||||
|
|
|
@ -22,6 +22,7 @@ import socket
|
|||
import sys
|
||||
import time
|
||||
|
||||
from comtypes import c_ulong
|
||||
from ghidratrace import sch
|
||||
from ghidratrace.client import Client, Address, AddressRange, TraceObject
|
||||
from pybag import pydbg, userdbg, kerneldbg
|
||||
|
@ -31,7 +32,7 @@ from pybag.dbgeng.win32.kernel32 import STILL_ACTIVE
|
|||
|
||||
from . import util, arch, methods, hooks
|
||||
from .dbgmodel.imodelobject import ModelObjectKind
|
||||
|
||||
from .dbgeng.idebugclient5 import *
|
||||
|
||||
PAGE_SIZE = 4096
|
||||
|
||||
|
@ -68,10 +69,11 @@ GENERIC_KEY_PATTERN = '[{key}]'
|
|||
|
||||
|
||||
class ErrorWithCode(Exception):
|
||||
|
||||
def __init__(self, code):
|
||||
self.code = code
|
||||
|
||||
def __str__(self)->str:
|
||||
def __str__(self) -> str:
|
||||
return repr(self.code)
|
||||
|
||||
|
||||
|
@ -216,6 +218,8 @@ def start_trace(name):
|
|||
with STATE.trace.open_tx("Create Root Object"):
|
||||
root = STATE.trace.create_root_object(schema_xml, 'DbgRoot')
|
||||
root.set_value('_display', util.DBG_VERSION.full + ' via pybag' + variant)
|
||||
if util.dbg.use_generics:
|
||||
put_generic(root)
|
||||
util.set_convenience_variable('_ghidra_tracing', "true")
|
||||
|
||||
|
||||
|
@ -261,6 +265,67 @@ def ghidra_trace_create(command=None, initial_break=True, timeout=DbgEng.WAIT_IN
|
|||
ghidra_trace_start(command)
|
||||
|
||||
|
||||
@util.dbg.eng_thread
|
||||
def ghidra_trace_create_ext(command=None, initialDirectory='.', envVariables="\0\0", create_flags=1, create_flags_eng=0, verifier_flags=0, initial_break=True, timeout=DbgEng.WAIT_INFINITE, start_trace=True):
|
||||
"""
|
||||
Create a session.
|
||||
"""
|
||||
|
||||
dbg = util.dbg._base
|
||||
if command != None:
|
||||
if create_flags == "":
|
||||
create_flags = 1
|
||||
if create_flags_eng == "":
|
||||
create_flags_eng = 0
|
||||
if verifier_flags == "":
|
||||
verifier_flags = 0
|
||||
options = DbgEng._DEBUG_CREATE_PROCESS_OPTIONS()
|
||||
options.CreateFlags = c_ulong(int(create_flags))
|
||||
options.EngCreateFlags = c_ulong(int(create_flags_eng))
|
||||
options.VerifierFlags = c_ulong(int(verifier_flags))
|
||||
options.Reserved = c_ulong(int(0))
|
||||
if initialDirectory == "":
|
||||
initialDirectory = None
|
||||
if envVariables == "":
|
||||
envVariables = None
|
||||
if envVariables is not None and envVariables.endswith("/0/0") is False:
|
||||
envVariables += "/0/0"
|
||||
dbg._client.CreateProcess2(command, options, initialDirectory, envVariables)
|
||||
if initial_break:
|
||||
dbg._control.AddEngineOptions(DbgEng.DEBUG_ENGINITIAL_BREAK)
|
||||
if start_trace:
|
||||
ghidra_trace_start(command)
|
||||
|
||||
|
||||
@util.dbg.eng_thread
|
||||
def ghidra_trace_attach_kernel(command=None, initial_break=True, timeout=DbgEng.WAIT_INFINITE, start_trace=True):
|
||||
"""
|
||||
Create a session.
|
||||
"""
|
||||
|
||||
dbg = util.dbg._base
|
||||
util.set_kernel(True)
|
||||
if initial_break:
|
||||
dbg._control.AddEngineOptions(DbgEng.DEBUG_ENGINITIAL_BREAK)
|
||||
if command != None:
|
||||
dbg._client.AttachKernel(command)
|
||||
if start_trace:
|
||||
ghidra_trace_start(command)
|
||||
|
||||
|
||||
@util.dbg.eng_thread
|
||||
def ghidra_trace_connect_server(options=None):
|
||||
"""
|
||||
Connect to a process server session.
|
||||
"""
|
||||
|
||||
dbg = util.dbg._base
|
||||
if options != None:
|
||||
if isinstance(options, str):
|
||||
enc_options = options.encode()
|
||||
dbg._client.ConnectProcessServer(enc_options)
|
||||
|
||||
|
||||
@util.dbg.eng_thread
|
||||
def ghidra_trace_kill():
|
||||
"""
|
||||
|
@ -370,7 +435,7 @@ def ghidra_trace_set_snap(snap=None):
|
|||
|
||||
|
||||
def quantize_pages(start, end):
|
||||
return (start // PAGE_SIZE * PAGE_SIZE, (end+PAGE_SIZE-1) // PAGE_SIZE*PAGE_SIZE)
|
||||
return (start // PAGE_SIZE * PAGE_SIZE, (end + PAGE_SIZE - 1) // PAGE_SIZE * PAGE_SIZE)
|
||||
|
||||
|
||||
@util.dbg.eng_thread
|
||||
|
@ -453,7 +518,7 @@ def putmem_state(address, length, state, pages=True):
|
|||
nproc = util.selected_process()
|
||||
base, addr = STATE.trace.memory_mapper.map(nproc, start)
|
||||
if base != addr.space and state != 'unknown':
|
||||
trace.create_overlay_space(base, addr.space)
|
||||
STATE.trace.create_overlay_space(base, addr.space)
|
||||
STATE.trace.set_memory_state(addr.extend(end - start), state)
|
||||
|
||||
|
||||
|
@ -718,6 +783,7 @@ def ghidra_trace_get_obj(path):
|
|||
|
||||
|
||||
class TableColumn(object):
|
||||
|
||||
def __init__(self, head):
|
||||
self.head = head
|
||||
self.contents = [head]
|
||||
|
@ -735,6 +801,7 @@ class TableColumn(object):
|
|||
|
||||
|
||||
class Tabular(object):
|
||||
|
||||
def __init__(self, heads):
|
||||
self.columns = [TableColumn(h) for h in heads]
|
||||
self.columns[-1].is_last = True
|
||||
|
@ -1077,6 +1144,8 @@ def put_regions():
|
|||
regions = util.dbg._base.memory_list()
|
||||
except Exception:
|
||||
regions = []
|
||||
if len(regions) == 0:
|
||||
regions = util.full_mem()
|
||||
|
||||
mapper = STATE.trace.memory_mapper
|
||||
keys = []
|
||||
|
@ -1096,6 +1165,8 @@ def put_regions():
|
|||
regobj.set_value('AllocationBase', hex(r.AllocationBase))
|
||||
regobj.set_value('Protect', hex(r.Protect))
|
||||
regobj.set_value('Type', hex(r.Type))
|
||||
if hasattr(r, 'Name') and r.Name is not None:
|
||||
regobj.set_value('_display', r.Name)
|
||||
regobj.insert()
|
||||
STATE.trace.proxy_object_path(
|
||||
MEMORY_PATTERN.format(procnum=nproc)).retain_values(keys)
|
||||
|
@ -1296,37 +1367,44 @@ def ghidra_trace_put_frames():
|
|||
put_frames()
|
||||
|
||||
|
||||
def update_by_container(np, index, obj):
|
||||
def update_by_container(np, keyval, obj):
|
||||
index = keyval[0]
|
||||
key = ''
|
||||
if np.endswith("Processes") or np.endswith("Threads"):
|
||||
istate = compute_proc_state(index)
|
||||
obj.set_value('State', istate)
|
||||
if np.endswith("Sessions"):
|
||||
key = '[{:x}]'.format(index)
|
||||
if np.endswith("Processes"):
|
||||
create_generic(obj.path)
|
||||
id = util.get_proc_id(index)
|
||||
obj.set_value('PID', index)
|
||||
obj.set_value('_display', '{:x} {:x}'.format(id, index))
|
||||
create_generic(obj.path + ".Memory")
|
||||
if util.is_kernel():
|
||||
key = '[{:x}]'.format(index)
|
||||
else:
|
||||
id = util.get_proc_id(index)
|
||||
key = '{:x} [{:x}]'.format(id, index)
|
||||
if np.endswith("Breakpoints"):
|
||||
create_generic(obj.path)
|
||||
#id = util.get_thread_id(index)
|
||||
#obj.set_value('TID', index)
|
||||
#obj.set_value('_display','{:x} {:x}'.format(id, index))
|
||||
if np.endswith("Threads"):
|
||||
create_generic(obj.path)
|
||||
id = util.get_thread_id(index)
|
||||
obj.set_value('TID', index)
|
||||
obj.set_value('_display', '{:x} {:x}'.format(id, index))
|
||||
if util.is_kernel():
|
||||
key = '[{:x}]'.format(index)
|
||||
else:
|
||||
id = util.get_thread_id(index)
|
||||
key = '{:x} [{:x}]'.format(id, index)
|
||||
if np.endswith("Frames"):
|
||||
mo = util.get_object(obj.path)
|
||||
map = util.get_attributes(mo)
|
||||
attr = map["Attributes"]
|
||||
if attr is None:
|
||||
return
|
||||
create_generic(obj.path+".Attributes")
|
||||
map = util.get_attributes(attr)
|
||||
pc = util.get_value(map["InstructionOffset"])
|
||||
(pc_base, pc_addr) = map_address(pc)
|
||||
obj.set_value('Instruction Offset', pc_addr)
|
||||
obj.set_value('_display', '#{:x} 0x{:x}'.format(index, pc))
|
||||
key = '#{:x} 0x{:x}'.format(index, pc)
|
||||
if np.endswith("Modules"):
|
||||
create_generic(obj.path)
|
||||
mo = util.get_object(obj.path)
|
||||
|
@ -1337,7 +1415,12 @@ def update_by_container(np, index, obj):
|
|||
obj.set_value('Name', '{}'.format(name))
|
||||
(base_base, base_addr) = map_address(base)
|
||||
obj.set_value('Range', base_addr.extend(size))
|
||||
obj.set_value('_display', '{:x} {:x} {}'.format(index, base, name))
|
||||
key = '{:x} {:x} {}'.format(index, base, name)
|
||||
disp = util.to_display_string(keyval[1])
|
||||
if disp is not None:
|
||||
key += " " + disp
|
||||
if key is not None and key != "":
|
||||
obj.set_value('_display', key)
|
||||
|
||||
|
||||
def create_generic(path):
|
||||
|
@ -1348,58 +1431,81 @@ def create_generic(path):
|
|||
|
||||
|
||||
def put_generic(node):
|
||||
#print(f"put_generic: {node}")
|
||||
# print(f"put_generic: {node}")
|
||||
nproc = util.selected_process()
|
||||
if nproc is None:
|
||||
return
|
||||
nthrd = util.selected_thread()
|
||||
|
||||
mapper = STATE.trace.memory_mapper
|
||||
mo = util.get_object(node.path)
|
||||
kind = util.get_kind(mo)
|
||||
type = util.get_type(mo)
|
||||
vstr = util.get_value(mo)
|
||||
# print(f"MO={mo}")
|
||||
mapper = STATE.trace.register_mapper
|
||||
|
||||
attributes = util.get_attributes(mo)
|
||||
# print(f"ATTR={attributes}")
|
||||
mapper = STATE.trace.register_mapper
|
||||
values = []
|
||||
for key, value in attributes.items():
|
||||
if value is None:
|
||||
continue
|
||||
kind = util.get_kind(value)
|
||||
vstr = util.get_value(value)
|
||||
#print(f"key={key} kind={kind} value={vstr} type={type}")
|
||||
if kind == ModelObjectKind.PROPERTY_ACCESSOR.value or \
|
||||
kind == ModelObjectKind.SYNTHETIC.value or \
|
||||
kind == ModelObjectKind.METHOD.value:
|
||||
if vstr is not None:
|
||||
key += " : " + vstr
|
||||
apath = node.path+'.'+key
|
||||
aobj = STATE.trace.create_object(apath)
|
||||
aobj.insert()
|
||||
else:
|
||||
try:
|
||||
if node.path.endswith('.User'):
|
||||
values.append(mapper.map_value(nproc, key, vstr))
|
||||
node.set_value(key, hex(vstr))
|
||||
except Exception as e:
|
||||
pass # Error is printed by another mechanism
|
||||
if attributes is not None:
|
||||
for key, value in attributes.items():
|
||||
kind = util.get_kind(value)
|
||||
if kind == ModelObjectKind.METHOD.value:
|
||||
continue
|
||||
# print(f"key={key} kind={kind}")
|
||||
if kind != ModelObjectKind.INTRINSIC.value:
|
||||
apath = node.path + '.' + key
|
||||
aobj = STATE.trace.create_object(apath)
|
||||
set_display(key, value, aobj)
|
||||
aobj.insert()
|
||||
else:
|
||||
val = util.get_value(value)
|
||||
try:
|
||||
if node.path.endswith('.User'):
|
||||
# print(f"PUT_REG: {key} {val}")
|
||||
values.append(mapper.map_value(nproc, key, val))
|
||||
node.set_value(key, hex(val))
|
||||
elif isinstance(val, int):
|
||||
(v_base, v_addr) = map_address(val)
|
||||
node.set_value(key, v_addr, schema="ADDRESS")
|
||||
else:
|
||||
node.set_value(key, val)
|
||||
except Exception as e:
|
||||
print(f"Attribute exception for {key} {type(val)}: {e}")
|
||||
elements = util.get_elements(mo)
|
||||
# print(f"ELEM={elements}")
|
||||
keys = []
|
||||
for el in elements:
|
||||
index = el[0]
|
||||
key = GENERIC_KEY_PATTERN.format(key=index)
|
||||
lpath = node.path+key
|
||||
lobj = STATE.trace.create_object(lpath)
|
||||
update_by_container(node.path, index, lobj)
|
||||
lobj.insert()
|
||||
keys.append(key)
|
||||
node.retain_values(keys)
|
||||
if elements is not None:
|
||||
for el in elements:
|
||||
index = el[0]
|
||||
key = GENERIC_KEY_PATTERN.format(key=index)
|
||||
lpath = node.path + key
|
||||
lobj = STATE.trace.create_object(lpath)
|
||||
update_by_container(node.path, el, lobj)
|
||||
lobj.insert()
|
||||
keys.append(key)
|
||||
node.retain_values(keys)
|
||||
return (values, keys)
|
||||
|
||||
|
||||
def set_display(key, value, obj):
|
||||
kind = util.get_kind(value)
|
||||
vstr = util.get_value(value)
|
||||
# istr = util.get_intrinsic_value(value)
|
||||
if kind == ModelObjectKind.TARGET_OBJECT.value:
|
||||
hloc = util.get_location(value)
|
||||
ti = util.get_type_info(value)
|
||||
if ti is not None:
|
||||
name = util.get_name(ti)
|
||||
if name is not None:
|
||||
key += " : " + name
|
||||
obj.set_value('_display', key)
|
||||
if hloc is not None:
|
||||
key += " @ " + str(hloc)
|
||||
obj.set_value('_display', key)
|
||||
(hloc_base, hloc_addr) = map_address(int(hloc,0))
|
||||
obj.set_value('_address', hloc_addr, schema=Address)
|
||||
if vstr is not None:
|
||||
key += " : " + str(vstr)
|
||||
obj.set_value('_display', key)
|
||||
|
||||
|
||||
def map_address(address):
|
||||
nproc = util.selected_process()
|
||||
mapper = STATE.trace.memory_mapper
|
||||
|
|
|
@ -155,6 +155,13 @@ library DbgMod
|
|||
DWORD NotSupported;
|
||||
};
|
||||
|
||||
typedef struct _DEBUG_CREATE_PROCESS_OPTIONS {
|
||||
ULONG CreateFlags;
|
||||
ULONG EngCreateFlags;
|
||||
ULONG VerfierFlags;
|
||||
ULONG Reserved;
|
||||
} DEBUG_CREATE_PROCESS_OPTIONS, *PDEBUG_CREATE_PROCESS_OPTIONS;
|
||||
|
||||
/*
|
||||
struct _MEMORY_BASIC_INFORMATION64 {
|
||||
ULONGLONG BaseAddress;
|
||||
|
|
|
@ -40,8 +40,10 @@ class ModelIterator(object):
|
|||
except COMError as ce:
|
||||
return None
|
||||
index = mo.ModelObject(indexer)
|
||||
id = index.GetIntrinsicValue().value
|
||||
return (id, mo.ModelObject(object))
|
||||
ival = index.GetIntrinsicValue()
|
||||
if ival is None:
|
||||
return (0, mo.ModelObject(object))
|
||||
return (ival.value, mo.ModelObject(object))
|
||||
|
||||
def Reset(self):
|
||||
hr = self._keys.Reset()
|
||||
|
|
|
@ -22,10 +22,13 @@ from comtypes.gen import DbgMod
|
|||
from comtypes.hresult import S_OK, S_FALSE
|
||||
from pybag.dbgeng import exception
|
||||
|
||||
from comtypes import BSTR
|
||||
from comtypes.gen.DbgMod import *
|
||||
|
||||
from .iiterableconcept import IterableConcept
|
||||
from .istringdisplayableconcept import StringDisplayableConcept
|
||||
from .ikeyenumerator import KeyEnumerator
|
||||
from .irawenumerator import RawEnumerator
|
||||
|
||||
|
||||
class ModelObjectKind(Enum):
|
||||
|
@ -45,6 +48,7 @@ class ModelObject(object):
|
|||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
self.concept = None
|
||||
self.dconcept = None
|
||||
exception.wrap_comclass(self._obj)
|
||||
|
||||
def Release(self):
|
||||
|
@ -96,12 +100,16 @@ class ModelObject(object):
|
|||
return RawEnumerator(keys, kind)
|
||||
|
||||
def GetConcept(self, ref):
|
||||
ifc = POINTER(IUnknown)()
|
||||
metadata = POINTER(DbgMod.IKeyStore)()
|
||||
hr = self._obj.GetConcept(ref._iid_, byref(ifc), byref(metadata))
|
||||
if hr != S_OK:
|
||||
try:
|
||||
ifc = POINTER(IUnknown)()
|
||||
metadata = POINTER(DbgMod.IKeyStore)()
|
||||
hr = self._obj.GetConcept(ref._iid_, byref(ifc), byref(metadata))
|
||||
if hr != S_OK:
|
||||
return None
|
||||
return cast(ifc, POINTER(ref))
|
||||
except Exception as e:
|
||||
print(f"GetConcept exception: {e}")
|
||||
return None
|
||||
return cast(ifc, POINTER(ref))
|
||||
|
||||
def GetContext(self, context):
|
||||
raise exception.E_NOTIMPL_Error
|
||||
|
@ -111,10 +119,14 @@ class ModelObject(object):
|
|||
|
||||
def GetIntrinsicValue(self):
|
||||
var = VARIANT()
|
||||
hr = self._obj.GetIntrinsicValue(var)
|
||||
if hr != S_OK:
|
||||
try:
|
||||
hr = self._obj.GetIntrinsicValue(var)
|
||||
if hr != S_OK:
|
||||
return None
|
||||
return var
|
||||
except Exception as e:
|
||||
print(f"GetIntrinsicValue exception: {e}")
|
||||
return None
|
||||
return var
|
||||
|
||||
def GetIntrinsicValueAs(self, vt):
|
||||
raise exception.E_NOTIMPL_Error
|
||||
|
@ -140,8 +152,31 @@ class ModelObject(object):
|
|||
exception.check_err(hr)
|
||||
return kind
|
||||
|
||||
def GetLocation(self, location):
|
||||
raise exception.E_NOTIMPL_Error
|
||||
# DOESN"T WORK YET
|
||||
# def GetTypeKind(self):
|
||||
# typeKind = None
|
||||
# modelKind = self.GetKind()
|
||||
# if modelKind.value == ModelObjectKind.TARGET_OBJECT.value:
|
||||
# targetInfo = self.GetTargetInfo()
|
||||
# if targetInfo is not None:
|
||||
# typeKind = DbgMod.tagTYPEKIND()
|
||||
# hr = targetInfo._obj.GetTypeKind(byref(typeKind))
|
||||
# if hr != S_OK:
|
||||
# return None
|
||||
# if modelKind.value == ModelObjectKind.INTRINSIC.value:
|
||||
# typeInfo = self.GetTypeInfo()
|
||||
# if typeInfo is not None:
|
||||
# typeKind = DbgMod.tagTYPEKIND()
|
||||
# hr = typeInfo._obj.GetTypeKind(byref(typeKind))
|
||||
# if hr != S_OK:
|
||||
# return None
|
||||
# return typeKind
|
||||
|
||||
def GetLocation(self):
|
||||
loc = DbgMod._Location()
|
||||
hr = self._obj.GetLocation(loc)
|
||||
exception.check_err(hr)
|
||||
return loc
|
||||
|
||||
def GetNumberOfParentModels(self, numModels):
|
||||
raise exception.E_NOTIMPL_Error
|
||||
|
@ -152,18 +187,55 @@ class ModelObject(object):
|
|||
def GetRawReference(self, kind, name, searchFlags, object):
|
||||
raise exception.E_NOTIMPL_Error
|
||||
|
||||
def GetRawValue(self, kind, name, searchFlags, object):
|
||||
raise exception.E_NOTIMPL_Error
|
||||
def GetRawValue(self, kind, name, searchFlags):
|
||||
kbuf = cast(c_wchar_p(name), POINTER(c_ushort))
|
||||
value = POINTER(DbgMod.IModelObject)()
|
||||
hr = self._obj.GetRawValue(kind, kbuf, searchFlags, byref(value))
|
||||
if hr != S_OK:
|
||||
return None
|
||||
return ModelObject(value)
|
||||
|
||||
def GetTargetInfo(self):
|
||||
location = POINTER(DbgMod._Location)()
|
||||
location = DbgMod._Location()
|
||||
type = POINTER(DbgMod.IDebugHostType)()
|
||||
hr = self._obj.GetTargetInfo(location, byref(type))
|
||||
exception.check_err(hr)
|
||||
return type
|
||||
return ModelObject(type)
|
||||
|
||||
def GetTypeInfo(self, type):
|
||||
raise exception.E_NOTIMPL_Error
|
||||
def GetTypeInfo(self):
|
||||
type = POINTER(DbgMod.IDebugHostType)()
|
||||
hr = self._obj.GetTypeInfo(byref(type))
|
||||
exception.check_err(hr)
|
||||
return ModelObject(type)
|
||||
|
||||
def GetName(self):
|
||||
name = BSTR()
|
||||
hr = self._obj.GetName(name)
|
||||
exception.check_err(hr)
|
||||
return name
|
||||
|
||||
def ToDisplayString(self):
|
||||
if self.dconcept is None:
|
||||
dconcept = self.GetConcept(DbgMod.IStringDisplayableConcept)
|
||||
if dconcept is None:
|
||||
return None
|
||||
self.dconcept = StringDisplayableConcept(dconcept)
|
||||
return self.dconcept.ToDisplayString(self)
|
||||
|
||||
# This does NOT work - returns a null pointer for value. Why?
|
||||
# One possibility: casting is not a valid way to obtain an IModelMethod
|
||||
#
|
||||
# def ToDisplayString0(self):
|
||||
# map = self.GetAttributes()
|
||||
# method = map["ToDisplayString"]
|
||||
# mm = cast(method._obj, POINTER(DbgMod.IModelMethod))
|
||||
# context = self._obj
|
||||
# args = POINTER(DbgMod.IModelObject)()
|
||||
# value = POINTER(DbgMod.IModelObject)()
|
||||
# meta = POINTER(DbgMod.IKeyStore)()
|
||||
# hr = mm.Call(context, c_ulonglong(0), args, byref(value), byref(meta))
|
||||
# exception.check_err(hr)
|
||||
# return ModelObject(value)
|
||||
|
||||
def IsEqualTo(self, other, equal):
|
||||
raise exception.E_NOTIMPL_Error
|
||||
|
@ -198,23 +270,28 @@ class ModelObject(object):
|
|||
return map
|
||||
|
||||
def GetRawValueMap(self):
|
||||
# print(f"GetRawValueMap: {self}")
|
||||
map = {}
|
||||
kind = self.GetKind()
|
||||
keys = self.EnumerateRawValues(kind, c_long(0))
|
||||
# TODO: forcing kind to 0 because we can't GetTypeKind
|
||||
keys = self.EnumerateRawValues(c_long(0), 0)
|
||||
(k, v) = keys.GetNext()
|
||||
while k is not None:
|
||||
map[k.value] = v
|
||||
(k, v) = keys.GetNext()
|
||||
# print(f"{k}:{v}")
|
||||
return map
|
||||
|
||||
def GetAttributes(self):
|
||||
map = {}
|
||||
kind = self.GetKind()
|
||||
if kind == ModelObjectKind.ERROR:
|
||||
# print(f"GetAttributes: {kind}")
|
||||
if kind is not None and kind.value == ModelObjectKind.ERROR.value:
|
||||
print(f"ERROR from GetAttributes")
|
||||
return map
|
||||
if kind == ModelObjectKind.INTRINSIC or \
|
||||
kind == ModelObjectKind.TARGET_OBJECT or \
|
||||
kind == ModelObjectKind.TARGET_OBJECT_REFERENCE:
|
||||
if kind.value == ModelObjectKind.INTRINSIC.value or \
|
||||
kind.value == ModelObjectKind.TARGET_OBJECT.value or \
|
||||
kind.value == ModelObjectKind.TARGET_OBJECT_REFERENCE.value:
|
||||
return self.GetRawValueMap()
|
||||
return self.GetKeyValueMap()
|
||||
|
||||
|
@ -245,6 +322,9 @@ class ModelObject(object):
|
|||
def GetOffspring(self, path):
|
||||
next = self
|
||||
for element in path:
|
||||
if next is None:
|
||||
return None
|
||||
kind = next.GetKind()
|
||||
if element.startswith("["):
|
||||
idx = element[1:len(element)-1]
|
||||
if "x" not in idx:
|
||||
|
@ -252,12 +332,17 @@ class ModelObject(object):
|
|||
else:
|
||||
idx = int(idx, 16)
|
||||
next = next.GetElement(idx)
|
||||
# THIS IS RELATIVELY HORRIBLE - replace with GetRawValue?
|
||||
elif kind is not None and kind.value == ModelObjectKind.TARGET_OBJECT.value:
|
||||
map = next.GetAttributes()
|
||||
next = map[element]
|
||||
else:
|
||||
next = next.GetKeyValue(element)
|
||||
if next is None:
|
||||
print(f"{element} not found")
|
||||
#if next is None:
|
||||
# print(f"{element} not found")
|
||||
return next
|
||||
|
||||
|
||||
def GetValue(self):
|
||||
value = self.GetIntrinsicValue()
|
||||
if value is None:
|
||||
|
@ -266,9 +351,3 @@ class ModelObject(object):
|
|||
return None
|
||||
return value.value
|
||||
|
||||
def GetTypeKind(self):
|
||||
kind = self.GetKind()
|
||||
if kind == ModelObjectKind.TARGET_OBJECT or \
|
||||
kind == ModelObjectKind.INTRINSIC:
|
||||
return self.GetTargetInfo()
|
||||
return None
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
## ###
|
||||
# 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 ctypes import *
|
||||
|
||||
from comtypes import BSTR, COMError
|
||||
from comtypes.gen import DbgMod
|
||||
from comtypes.hresult import S_OK, S_FALSE
|
||||
from pybag.dbgeng import exception
|
||||
|
||||
|
||||
class StringDisplayableConcept(object):
|
||||
def __init__(self, concept):
|
||||
self._concept = concept
|
||||
concept.AddRef()
|
||||
|
||||
# StringDisplayableConcept
|
||||
|
||||
def ToDisplayString(self, context):
|
||||
try:
|
||||
val = BSTR()
|
||||
self._concept.ToDisplayString(context._obj, None, byref(val))
|
||||
except COMError as ce:
|
||||
return None
|
||||
return val.value
|
|
@ -64,8 +64,11 @@ class ProcessState(object):
|
|||
if description is not None:
|
||||
commands.STATE.trace.snapshot(description)
|
||||
if first:
|
||||
if util.is_kernel():
|
||||
commands.create_generic("Sessions")
|
||||
commands.put_processes()
|
||||
commands.put_environment()
|
||||
commands.put_threads()
|
||||
if self.threads:
|
||||
commands.put_threads()
|
||||
self.threads = False
|
||||
|
@ -98,6 +101,7 @@ class ProcessState(object):
|
|||
commands.put_threads(running=True)
|
||||
|
||||
def record_exited(self, exit_code, description=None):
|
||||
# print("RECORD_EXITED")
|
||||
if description is not None:
|
||||
commands.STATE.trace.snapshot(description)
|
||||
proc = util.selected_process()
|
||||
|
|
|
@ -536,6 +536,7 @@ def delete_breakpoint(breakpoint: sch.Schema('BreakpointSpec')):
|
|||
|
||||
|
||||
@REGISTRY.method
|
||||
@util.dbg.eng_thread
|
||||
def read_mem(process: sch.Schema('Process'), range: AddressRange):
|
||||
"""Read memory."""
|
||||
# print("READ_MEM: process={}, range={}".format(process, range))
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
<attribute name="Utility" schema="ANY" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" 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" hidden="yes" />
|
||||
<attribute schema="ANY"/>
|
||||
</schema>
|
||||
<schema name="Session" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Activatable" />
|
||||
|
@ -34,7 +34,7 @@
|
|||
<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" hidden="yes" />
|
||||
<attribute schema="ANY"/>
|
||||
</schema>
|
||||
<schema name="Selectable" elementResync="NEVER" attributeResync="NEVER">
|
||||
<element schema="OBJECT" />
|
||||
|
@ -53,7 +53,7 @@
|
|||
<interface name="BreakpointSpecContainer" />
|
||||
<element schema="BreakpointSpec" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
|
||||
<interface name="Configurable" />
|
||||
|
@ -65,7 +65,7 @@
|
|||
<interface name="Configurable" />
|
||||
<element schema="Process" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="BreakpointSpec" />
|
||||
|
@ -132,7 +132,7 @@
|
|||
<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" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Environment" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Environment" />
|
||||
|
@ -152,7 +152,7 @@
|
|||
<interface name="ModuleContainer" />
|
||||
<element schema="Module" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Memory" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Memory" />
|
||||
|
@ -178,7 +178,7 @@
|
|||
<interface name="Configurable" />
|
||||
<element schema="Thread" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Method" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Method" />
|
||||
|
@ -207,7 +207,7 @@
|
|||
<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" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Module" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Module" />
|
||||
|
@ -255,7 +255,7 @@
|
|||
<element schema="StackFrame" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||
<interface name="SymbolNamespace" />
|
||||
|
@ -284,7 +284,7 @@
|
|||
<attribute name="Frame Offset" schema="ADDRESS" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Section" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Section" />
|
||||
|
|
|
@ -37,6 +37,7 @@ from pybag.dbgeng import util as DbgUtil
|
|||
from pybag.dbgeng.callbacks import DbgEngCallbacks
|
||||
|
||||
from ghidradbg.dbgmodel.ihostdatamodelaccess import HostDataModelAccess
|
||||
from _winapi import STILL_ACTIVE
|
||||
|
||||
|
||||
DbgVersion = namedtuple('DbgVersion', ['full', 'name', 'dotted', 'arch'])
|
||||
|
@ -236,6 +237,7 @@ class GhidraDbg(object):
|
|||
'load_dump'
|
||||
]:
|
||||
setattr(self, name, self.eng_thread(getattr(base, name)))
|
||||
self.IS_KERNEL = False
|
||||
|
||||
def _new_base(self):
|
||||
self._protected_base = AllDbg()
|
||||
|
@ -364,6 +366,8 @@ class GhidraDbg(object):
|
|||
@check_thread
|
||||
def pid(self):
|
||||
try:
|
||||
if is_kernel():
|
||||
return 0
|
||||
return self._base._systems.GetCurrentProcessSystemId()
|
||||
except exception.E_UNEXPECTED_Error:
|
||||
# There is no process
|
||||
|
@ -451,10 +455,27 @@ def get_breakpoints():
|
|||
@dbg.eng_thread
|
||||
def selected_process():
|
||||
try:
|
||||
if is_kernel():
|
||||
do = dbg._base._systems.GetCurrentProcessDataOffset()
|
||||
id = c_ulong()
|
||||
offset = c_ulonglong(do)
|
||||
nproc = dbg._base._systems._sys.GetProcessIdByDataOffset(offset, byref(id))
|
||||
return id.value
|
||||
if dbg.use_generics:
|
||||
return dbg._base._systems.GetCurrentProcessSystemId()
|
||||
return dbg._base._systems.GetCurrentProcessId()
|
||||
except exception.E_UNEXPECTED_Error:
|
||||
except (exception.E_UNEXPECTED_Error, exception.E_NOTIMPL_Error) as e:
|
||||
# NB: we're intentionally returning 0 instead of None
|
||||
return 0
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def selected_process_space():
|
||||
try:
|
||||
if is_kernel():
|
||||
return dbg._base._systems.GetCurrentProcessDataOffset()
|
||||
return selected_process()
|
||||
except (exception.E_UNEXPECTED_Error, exception.E_NOTIMPL_Error) as e:
|
||||
# NB: we're intentionally returning 0 instead of None
|
||||
return 0
|
||||
|
||||
|
@ -462,10 +483,12 @@ def selected_process():
|
|||
@dbg.eng_thread
|
||||
def selected_thread():
|
||||
try:
|
||||
if is_kernel():
|
||||
return 0
|
||||
if dbg.use_generics:
|
||||
return dbg._base._systems.GetCurrentThreadSystemId()
|
||||
return dbg._base._systems.GetCurrentThreadId()
|
||||
except exception.E_UNEXPECTED_Error:
|
||||
except (exception.E_UNEXPECTED_Error, exception.E_NOTIMPL_Error) as e:
|
||||
return None
|
||||
|
||||
|
||||
|
@ -485,6 +508,10 @@ def selected_frame():
|
|||
|
||||
@dbg.eng_thread
|
||||
def select_process(id: int):
|
||||
if is_kernel():
|
||||
# TODO: Ideally this should get the data offset from the id and then call
|
||||
# SetImplicitProcessDataOffset
|
||||
return
|
||||
if dbg.use_generics:
|
||||
id = get_proc_id(id)
|
||||
return dbg._base._systems.SetCurrentProcessId(id)
|
||||
|
@ -492,6 +519,10 @@ def select_process(id: int):
|
|||
|
||||
@dbg.eng_thread
|
||||
def select_thread(id: int):
|
||||
if is_kernel():
|
||||
# TODO: Ideally this should get the data offset from the id and then call
|
||||
# SetImplicitThreadDataOffset
|
||||
return
|
||||
if dbg.use_generics:
|
||||
id = get_thread_id(id)
|
||||
return dbg._base._systems.SetCurrentThreadId(id)
|
||||
|
@ -586,7 +617,23 @@ def GetCurrentProcessPeb():
|
|||
# TODO: upstream?
|
||||
_dbg = dbg._base
|
||||
offset = c_ulonglong()
|
||||
hr = _dbg._systems._sys.GetCurrentProcessPeb(byref(offset))
|
||||
if dbg.is_kernel():
|
||||
hr = _dbg._systems._sys.GetCurrentProcessDataOffset(byref(offset))
|
||||
else:
|
||||
hr = _dbg._systems._sys.GetCurrentProcessPeb(byref(offset))
|
||||
exception.check_err(hr)
|
||||
return offset.value
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def GetCurrentThreadTeb():
|
||||
# TODO: upstream?
|
||||
_dbg = dbg._base
|
||||
offset = c_ulonglong()
|
||||
if is_kernel():
|
||||
hr = _dbg._systems._sys.GetCurrentThreadDataOffset(byref(offset))
|
||||
else:
|
||||
hr = _dbg._systems._sys.GetCurrentThreadTeb(byref(offset))
|
||||
exception.check_err(hr)
|
||||
return offset.value
|
||||
|
||||
|
@ -594,6 +641,8 @@ def GetCurrentProcessPeb():
|
|||
@dbg.eng_thread
|
||||
def GetExitCode():
|
||||
# TODO: upstream?
|
||||
if is_kernel():
|
||||
return STILL_ACTIVE
|
||||
exit_code = c_ulong()
|
||||
hr = dbg._base._client._cli.GetExitCode(byref(exit_code))
|
||||
return exit_code.value
|
||||
|
@ -669,6 +718,21 @@ def get_proc_id(pid):
|
|||
return None
|
||||
|
||||
|
||||
def full_mem():
|
||||
sizeptr = 64; #int(gdb.parse_and_eval('sizeof(void*)')) * 8
|
||||
infoLow = DbgEng._MEMORY_BASIC_INFORMATION64()
|
||||
infoLow.BaseAddress = 0
|
||||
infoLow.RegionSize = (1 << (sizeptr-1))
|
||||
infoLow.Protect = 0xFFF
|
||||
infoLow.Name = "UMEM"
|
||||
infoHigh = DbgEng._MEMORY_BASIC_INFORMATION64()
|
||||
infoHigh.BaseAddress = 1 << (sizeptr-1)
|
||||
infoHigh.RegionSize = (1 << (sizeptr-1))
|
||||
infoHigh.Protect = 0xFFF
|
||||
infoHigh.Name = "KMEM"
|
||||
return [ infoLow, infoHigh ]
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_thread_id(tid):
|
||||
"""Get the list of all threads"""
|
||||
|
@ -715,39 +779,107 @@ def get_object(relpath):
|
|||
if relpath != '':
|
||||
pathstr += "."+relpath
|
||||
path = split_path(pathstr)
|
||||
# print(f"PATH: {pathstr}")
|
||||
return root.GetOffspring(path)
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_attributes(obj):
|
||||
"""Get the list of attributes"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.GetAttributes()
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_elements(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.GetElements()
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_kind(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
kind = obj.GetKind()
|
||||
if kind is None:
|
||||
return None
|
||||
return obj.GetKind().value
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_type(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.GetTypeKind()
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_value(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.GetValue()
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_intrinsic_value(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.GetIntrinsicValue()
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_target_info(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.GetTargetInfo()
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_type_info(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.GetTypeInfo()
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_name(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.GetName().value
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def to_display_string(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
return obj.ToDisplayString()
|
||||
|
||||
|
||||
@dbg.eng_thread
|
||||
def get_location(obj):
|
||||
"""Get the list of all threads"""
|
||||
if obj is None:
|
||||
return None
|
||||
try:
|
||||
loc = obj.GetLocation()
|
||||
if loc is None:
|
||||
return None
|
||||
return hex(loc.Offset)
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
conv_map = {}
|
||||
|
||||
|
||||
|
@ -762,3 +894,11 @@ def get_convenience_variable(id):
|
|||
|
||||
def set_convenience_variable(id, value):
|
||||
conv_map[id] = value
|
||||
|
||||
|
||||
def set_kernel(value):
|
||||
dbg.IS_KERNEL = value
|
||||
|
||||
|
||||
def is_kernel():
|
||||
return dbg.IS_KERNEL
|
||||
|
|
|
@ -733,6 +733,77 @@ python3 -m pip install --no-index -f Debugger-rmi-trace\pypkg\dist -f Debugger-a
|
|||
Alternatively, if you are trying to quit, but typed "<TT>.exit</TT>", just type
|
||||
"<TT>quit()</TT>" to terminate the session.</P>
|
||||
|
||||
<H3><A name="dbgeng_ext"></A>dbgeng-ext</H3>
|
||||
|
||||
<P>This launcher extends the base dbgeng launcher adding extra options (a la IDebugClient's CreateProcess2).</P>
|
||||
|
||||
|
||||
<H4>Options</H4>
|
||||
|
||||
<UL>
|
||||
<LI><B>Dir</B>: This is the starting directory for the process.</LI>
|
||||
|
||||
<LI><B>Env</B>: 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'.</LI>
|
||||
|
||||
<LI><B>CreateFlags</B>: 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 processes. Other possible values
|
||||
are defined by processes.h's CreateProcessCreationFlags.</LI>
|
||||
|
||||
<LI><B>CreateFlags (Engine)</B>: Engine-specific flags used when creating the process (defined in dbgeng.h).
|
||||
Typically, these are set to 0.</LI>
|
||||
|
||||
<LI><B>VerifierFlags (Engine)</B>: Flags used by the Application Verifier. Typically unused, but, if desired,
|
||||
CreateEngineFlags must include DEBUG_ECREATE_PROCESS_USE_VERIFIER_FLAGS(2).</LI>
|
||||
</UL>
|
||||
|
||||
|
||||
<H3><A name="dbgeng_remote"></A>dbgeng-remote</H3>
|
||||
|
||||
<P>This launcher extends the base dbgeng launcher adding an option for connecting through a remote process server.
|
||||
</P>
|
||||
|
||||
|
||||
<H4>Options</H4>
|
||||
|
||||
<UL>
|
||||
<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 192.168.0.2 using:
|
||||
<PRE>
|
||||
dbgsrv -t tcp:port=12345
|
||||
</PRE>
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
|
||||
<H3><A name="dbgeng_kernel"></A>dbgeng-kernel</H3>
|
||||
|
||||
<P>This version of the dbgeng should be used for kernel-debugging of a remote machine. Options are the
|
||||
same as the base dbgeng, except for the connection-string arguments. For remote
|
||||
debugging, the target machine should be booted with the appropriate options, set using BCDEDIT or the
|
||||
equivalent, such as:
|
||||
</P>
|
||||
<UL style='list-style-type: none'><LI>
|
||||
<PRE>
|
||||
bcdedit /debug ON
|
||||
bdcedit /dbgsettings NET HOSTIP:IP PORT:54321 KEY:1.1.1.1
|
||||
</PRE>
|
||||
</LI></UL>
|
||||
<P>
|
||||
where IP= the address of the machine runing Ghidra.
|
||||
</P>
|
||||
|
||||
<H4>Options</H4>
|
||||
|
||||
<UL>
|
||||
<LI><B>Arguments</B>: This is the connection string specifying the transport options for
|
||||
communicating with the remote target. A typical example might be 'net:port=54321,key=1.1.1.1'.'
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
|
||||
<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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue