mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +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: Apache License 2.0
|
||||||
##MODULE IP: MIT
|
##MODULE IP: MIT
|
||||||
Module.manifest||GHIDRA||||END|
|
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-dbgeng.bat||GHIDRA||||END|
|
||||||
data/debugger-launchers/local-ttd.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/LICENSE||GHIDRA||||END|
|
||||||
src/main/py/MANIFEST.in||GHIDRA||||END|
|
src/main/py/MANIFEST.in||GHIDRA||||END|
|
||||||
src/main/py/README.md||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
|
self.defaultSpace = defaultSpace
|
||||||
|
|
||||||
def map(self, proc: int, offset: int):
|
def map(self, proc: int, offset: int):
|
||||||
|
if proc == 0:
|
||||||
space = self.defaultSpace
|
space = self.defaultSpace
|
||||||
|
else:
|
||||||
|
space = f'{self.defaultSpace}{proc}'
|
||||||
return self.defaultSpace, Address(space, offset)
|
return self.defaultSpace, Address(space, offset)
|
||||||
|
|
||||||
def map_back(self, proc: int, address: Address) -> int:
|
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
|
return address.offset
|
||||||
raise ValueError(
|
if address.space == f'{self.defaultSpace}{proc}':
|
||||||
f"Address {address} is not in process {proc.GetProcessID()}")
|
return address.offset
|
||||||
|
raise ValueError(f"Address {address} is not in process {proc}")
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_MEMORY_MAPPER = DefaultMemoryMapper('ram')
|
DEFAULT_MEMORY_MAPPER = DefaultMemoryMapper('ram')
|
||||||
|
|
|
@ -22,6 +22,7 @@ import socket
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from comtypes import c_ulong
|
||||||
from ghidratrace import sch
|
from ghidratrace import sch
|
||||||
from ghidratrace.client import Client, Address, AddressRange, TraceObject
|
from ghidratrace.client import Client, Address, AddressRange, TraceObject
|
||||||
from pybag import pydbg, userdbg, kerneldbg
|
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 . import util, arch, methods, hooks
|
||||||
from .dbgmodel.imodelobject import ModelObjectKind
|
from .dbgmodel.imodelobject import ModelObjectKind
|
||||||
|
from .dbgeng.idebugclient5 import *
|
||||||
|
|
||||||
PAGE_SIZE = 4096
|
PAGE_SIZE = 4096
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ GENERIC_KEY_PATTERN = '[{key}]'
|
||||||
|
|
||||||
|
|
||||||
class ErrorWithCode(Exception):
|
class ErrorWithCode(Exception):
|
||||||
|
|
||||||
def __init__(self, code):
|
def __init__(self, code):
|
||||||
self.code = code
|
self.code = code
|
||||||
|
|
||||||
|
@ -216,6 +218,8 @@ def start_trace(name):
|
||||||
with STATE.trace.open_tx("Create Root Object"):
|
with STATE.trace.open_tx("Create Root Object"):
|
||||||
root = STATE.trace.create_root_object(schema_xml, 'DbgRoot')
|
root = STATE.trace.create_root_object(schema_xml, 'DbgRoot')
|
||||||
root.set_value('_display', util.DBG_VERSION.full + ' via pybag' + variant)
|
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")
|
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)
|
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
|
@util.dbg.eng_thread
|
||||||
def ghidra_trace_kill():
|
def ghidra_trace_kill():
|
||||||
"""
|
"""
|
||||||
|
@ -453,7 +518,7 @@ def putmem_state(address, length, state, pages=True):
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
base, addr = STATE.trace.memory_mapper.map(nproc, start)
|
base, addr = STATE.trace.memory_mapper.map(nproc, start)
|
||||||
if base != addr.space and state != 'unknown':
|
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)
|
STATE.trace.set_memory_state(addr.extend(end - start), state)
|
||||||
|
|
||||||
|
|
||||||
|
@ -718,6 +783,7 @@ def ghidra_trace_get_obj(path):
|
||||||
|
|
||||||
|
|
||||||
class TableColumn(object):
|
class TableColumn(object):
|
||||||
|
|
||||||
def __init__(self, head):
|
def __init__(self, head):
|
||||||
self.head = head
|
self.head = head
|
||||||
self.contents = [head]
|
self.contents = [head]
|
||||||
|
@ -735,6 +801,7 @@ class TableColumn(object):
|
||||||
|
|
||||||
|
|
||||||
class Tabular(object):
|
class Tabular(object):
|
||||||
|
|
||||||
def __init__(self, heads):
|
def __init__(self, heads):
|
||||||
self.columns = [TableColumn(h) for h in heads]
|
self.columns = [TableColumn(h) for h in heads]
|
||||||
self.columns[-1].is_last = True
|
self.columns[-1].is_last = True
|
||||||
|
@ -1077,6 +1144,8 @@ def put_regions():
|
||||||
regions = util.dbg._base.memory_list()
|
regions = util.dbg._base.memory_list()
|
||||||
except Exception:
|
except Exception:
|
||||||
regions = []
|
regions = []
|
||||||
|
if len(regions) == 0:
|
||||||
|
regions = util.full_mem()
|
||||||
|
|
||||||
mapper = STATE.trace.memory_mapper
|
mapper = STATE.trace.memory_mapper
|
||||||
keys = []
|
keys = []
|
||||||
|
@ -1096,6 +1165,8 @@ def put_regions():
|
||||||
regobj.set_value('AllocationBase', hex(r.AllocationBase))
|
regobj.set_value('AllocationBase', hex(r.AllocationBase))
|
||||||
regobj.set_value('Protect', hex(r.Protect))
|
regobj.set_value('Protect', hex(r.Protect))
|
||||||
regobj.set_value('Type', hex(r.Type))
|
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()
|
regobj.insert()
|
||||||
STATE.trace.proxy_object_path(
|
STATE.trace.proxy_object_path(
|
||||||
MEMORY_PATTERN.format(procnum=nproc)).retain_values(keys)
|
MEMORY_PATTERN.format(procnum=nproc)).retain_values(keys)
|
||||||
|
@ -1296,37 +1367,44 @@ def ghidra_trace_put_frames():
|
||||||
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"):
|
if np.endswith("Processes") or np.endswith("Threads"):
|
||||||
istate = compute_proc_state(index)
|
istate = compute_proc_state(index)
|
||||||
obj.set_value('State', istate)
|
obj.set_value('State', istate)
|
||||||
|
if np.endswith("Sessions"):
|
||||||
|
key = '[{:x}]'.format(index)
|
||||||
if np.endswith("Processes"):
|
if np.endswith("Processes"):
|
||||||
create_generic(obj.path)
|
create_generic(obj.path)
|
||||||
id = util.get_proc_id(index)
|
|
||||||
obj.set_value('PID', 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"):
|
if np.endswith("Breakpoints"):
|
||||||
create_generic(obj.path)
|
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"):
|
if np.endswith("Threads"):
|
||||||
create_generic(obj.path)
|
create_generic(obj.path)
|
||||||
id = util.get_thread_id(index)
|
|
||||||
obj.set_value('TID', 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"):
|
if np.endswith("Frames"):
|
||||||
mo = util.get_object(obj.path)
|
mo = util.get_object(obj.path)
|
||||||
map = util.get_attributes(mo)
|
map = util.get_attributes(mo)
|
||||||
attr = map["Attributes"]
|
attr = map["Attributes"]
|
||||||
if attr is None:
|
if attr is None:
|
||||||
return
|
return
|
||||||
create_generic(obj.path+".Attributes")
|
|
||||||
map = util.get_attributes(attr)
|
map = util.get_attributes(attr)
|
||||||
pc = util.get_value(map["InstructionOffset"])
|
pc = util.get_value(map["InstructionOffset"])
|
||||||
(pc_base, pc_addr) = map_address(pc)
|
(pc_base, pc_addr) = map_address(pc)
|
||||||
obj.set_value('Instruction Offset', pc_addr)
|
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"):
|
if np.endswith("Modules"):
|
||||||
create_generic(obj.path)
|
create_generic(obj.path)
|
||||||
mo = util.get_object(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))
|
obj.set_value('Name', '{}'.format(name))
|
||||||
(base_base, base_addr) = map_address(base)
|
(base_base, base_addr) = map_address(base)
|
||||||
obj.set_value('Range', base_addr.extend(size))
|
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):
|
def create_generic(path):
|
||||||
|
@ -1354,52 +1437,75 @@ def put_generic(node):
|
||||||
return
|
return
|
||||||
nthrd = util.selected_thread()
|
nthrd = util.selected_thread()
|
||||||
|
|
||||||
mapper = STATE.trace.memory_mapper
|
|
||||||
mo = util.get_object(node.path)
|
mo = util.get_object(node.path)
|
||||||
kind = util.get_kind(mo)
|
mapper = STATE.trace.register_mapper
|
||||||
type = util.get_type(mo)
|
|
||||||
vstr = util.get_value(mo)
|
|
||||||
# print(f"MO={mo}")
|
|
||||||
attributes = util.get_attributes(mo)
|
attributes = util.get_attributes(mo)
|
||||||
# print(f"ATTR={attributes}")
|
# print(f"ATTR={attributes}")
|
||||||
mapper = STATE.trace.register_mapper
|
|
||||||
values = []
|
values = []
|
||||||
|
if attributes is not None:
|
||||||
for key, value in attributes.items():
|
for key, value in attributes.items():
|
||||||
if value is None:
|
|
||||||
continue
|
|
||||||
kind = util.get_kind(value)
|
kind = util.get_kind(value)
|
||||||
vstr = util.get_value(value)
|
if kind == ModelObjectKind.METHOD.value:
|
||||||
#print(f"key={key} kind={kind} value={vstr} type={type}")
|
continue
|
||||||
if kind == ModelObjectKind.PROPERTY_ACCESSOR.value or \
|
# print(f"key={key} kind={kind}")
|
||||||
kind == ModelObjectKind.SYNTHETIC.value or \
|
if kind != ModelObjectKind.INTRINSIC.value:
|
||||||
kind == ModelObjectKind.METHOD.value:
|
|
||||||
if vstr is not None:
|
|
||||||
key += " : " + vstr
|
|
||||||
apath = node.path + '.' + key
|
apath = node.path + '.' + key
|
||||||
aobj = STATE.trace.create_object(apath)
|
aobj = STATE.trace.create_object(apath)
|
||||||
|
set_display(key, value, aobj)
|
||||||
aobj.insert()
|
aobj.insert()
|
||||||
else:
|
else:
|
||||||
|
val = util.get_value(value)
|
||||||
try:
|
try:
|
||||||
if node.path.endswith('.User'):
|
if node.path.endswith('.User'):
|
||||||
values.append(mapper.map_value(nproc, key, vstr))
|
# print(f"PUT_REG: {key} {val}")
|
||||||
node.set_value(key, hex(vstr))
|
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:
|
except Exception as e:
|
||||||
pass # Error is printed by another mechanism
|
print(f"Attribute exception for {key} {type(val)}: {e}")
|
||||||
elements = util.get_elements(mo)
|
elements = util.get_elements(mo)
|
||||||
# print(f"ELEM={elements}")
|
# print(f"ELEM={elements}")
|
||||||
keys = []
|
keys = []
|
||||||
|
if elements is not None:
|
||||||
for el in elements:
|
for el in elements:
|
||||||
index = el[0]
|
index = el[0]
|
||||||
key = GENERIC_KEY_PATTERN.format(key=index)
|
key = GENERIC_KEY_PATTERN.format(key=index)
|
||||||
lpath = node.path + key
|
lpath = node.path + key
|
||||||
lobj = STATE.trace.create_object(lpath)
|
lobj = STATE.trace.create_object(lpath)
|
||||||
update_by_container(node.path, index, lobj)
|
update_by_container(node.path, el, lobj)
|
||||||
lobj.insert()
|
lobj.insert()
|
||||||
keys.append(key)
|
keys.append(key)
|
||||||
node.retain_values(keys)
|
node.retain_values(keys)
|
||||||
return (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):
|
def map_address(address):
|
||||||
nproc = util.selected_process()
|
nproc = util.selected_process()
|
||||||
mapper = STATE.trace.memory_mapper
|
mapper = STATE.trace.memory_mapper
|
||||||
|
|
|
@ -155,6 +155,13 @@ library DbgMod
|
||||||
DWORD NotSupported;
|
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 {
|
struct _MEMORY_BASIC_INFORMATION64 {
|
||||||
ULONGLONG BaseAddress;
|
ULONGLONG BaseAddress;
|
||||||
|
|
|
@ -40,8 +40,10 @@ class ModelIterator(object):
|
||||||
except COMError as ce:
|
except COMError as ce:
|
||||||
return None
|
return None
|
||||||
index = mo.ModelObject(indexer)
|
index = mo.ModelObject(indexer)
|
||||||
id = index.GetIntrinsicValue().value
|
ival = index.GetIntrinsicValue()
|
||||||
return (id, mo.ModelObject(object))
|
if ival is None:
|
||||||
|
return (0, mo.ModelObject(object))
|
||||||
|
return (ival.value, mo.ModelObject(object))
|
||||||
|
|
||||||
def Reset(self):
|
def Reset(self):
|
||||||
hr = self._keys.Reset()
|
hr = self._keys.Reset()
|
||||||
|
|
|
@ -22,10 +22,13 @@ from comtypes.gen import DbgMod
|
||||||
from comtypes.hresult import S_OK, S_FALSE
|
from comtypes.hresult import S_OK, S_FALSE
|
||||||
from pybag.dbgeng import exception
|
from pybag.dbgeng import exception
|
||||||
|
|
||||||
|
from comtypes import BSTR
|
||||||
from comtypes.gen.DbgMod import *
|
from comtypes.gen.DbgMod import *
|
||||||
|
|
||||||
from .iiterableconcept import IterableConcept
|
from .iiterableconcept import IterableConcept
|
||||||
|
from .istringdisplayableconcept import StringDisplayableConcept
|
||||||
from .ikeyenumerator import KeyEnumerator
|
from .ikeyenumerator import KeyEnumerator
|
||||||
|
from .irawenumerator import RawEnumerator
|
||||||
|
|
||||||
|
|
||||||
class ModelObjectKind(Enum):
|
class ModelObjectKind(Enum):
|
||||||
|
@ -45,6 +48,7 @@ class ModelObject(object):
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
self._obj = obj
|
self._obj = obj
|
||||||
self.concept = None
|
self.concept = None
|
||||||
|
self.dconcept = None
|
||||||
exception.wrap_comclass(self._obj)
|
exception.wrap_comclass(self._obj)
|
||||||
|
|
||||||
def Release(self):
|
def Release(self):
|
||||||
|
@ -96,12 +100,16 @@ class ModelObject(object):
|
||||||
return RawEnumerator(keys, kind)
|
return RawEnumerator(keys, kind)
|
||||||
|
|
||||||
def GetConcept(self, ref):
|
def GetConcept(self, ref):
|
||||||
|
try:
|
||||||
ifc = POINTER(IUnknown)()
|
ifc = POINTER(IUnknown)()
|
||||||
metadata = POINTER(DbgMod.IKeyStore)()
|
metadata = POINTER(DbgMod.IKeyStore)()
|
||||||
hr = self._obj.GetConcept(ref._iid_, byref(ifc), byref(metadata))
|
hr = self._obj.GetConcept(ref._iid_, byref(ifc), byref(metadata))
|
||||||
if hr != S_OK:
|
if hr != S_OK:
|
||||||
return None
|
return None
|
||||||
return cast(ifc, POINTER(ref))
|
return cast(ifc, POINTER(ref))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"GetConcept exception: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def GetContext(self, context):
|
def GetContext(self, context):
|
||||||
raise exception.E_NOTIMPL_Error
|
raise exception.E_NOTIMPL_Error
|
||||||
|
@ -111,10 +119,14 @@ class ModelObject(object):
|
||||||
|
|
||||||
def GetIntrinsicValue(self):
|
def GetIntrinsicValue(self):
|
||||||
var = VARIANT()
|
var = VARIANT()
|
||||||
|
try:
|
||||||
hr = self._obj.GetIntrinsicValue(var)
|
hr = self._obj.GetIntrinsicValue(var)
|
||||||
if hr != S_OK:
|
if hr != S_OK:
|
||||||
return None
|
return None
|
||||||
return var
|
return var
|
||||||
|
except Exception as e:
|
||||||
|
print(f"GetIntrinsicValue exception: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def GetIntrinsicValueAs(self, vt):
|
def GetIntrinsicValueAs(self, vt):
|
||||||
raise exception.E_NOTIMPL_Error
|
raise exception.E_NOTIMPL_Error
|
||||||
|
@ -140,8 +152,31 @@ class ModelObject(object):
|
||||||
exception.check_err(hr)
|
exception.check_err(hr)
|
||||||
return kind
|
return kind
|
||||||
|
|
||||||
def GetLocation(self, location):
|
# DOESN"T WORK YET
|
||||||
raise exception.E_NOTIMPL_Error
|
# 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):
|
def GetNumberOfParentModels(self, numModels):
|
||||||
raise exception.E_NOTIMPL_Error
|
raise exception.E_NOTIMPL_Error
|
||||||
|
@ -152,18 +187,55 @@ class ModelObject(object):
|
||||||
def GetRawReference(self, kind, name, searchFlags, object):
|
def GetRawReference(self, kind, name, searchFlags, object):
|
||||||
raise exception.E_NOTIMPL_Error
|
raise exception.E_NOTIMPL_Error
|
||||||
|
|
||||||
def GetRawValue(self, kind, name, searchFlags, object):
|
def GetRawValue(self, kind, name, searchFlags):
|
||||||
raise exception.E_NOTIMPL_Error
|
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):
|
def GetTargetInfo(self):
|
||||||
location = POINTER(DbgMod._Location)()
|
location = DbgMod._Location()
|
||||||
type = POINTER(DbgMod.IDebugHostType)()
|
type = POINTER(DbgMod.IDebugHostType)()
|
||||||
hr = self._obj.GetTargetInfo(location, byref(type))
|
hr = self._obj.GetTargetInfo(location, byref(type))
|
||||||
exception.check_err(hr)
|
exception.check_err(hr)
|
||||||
return type
|
return ModelObject(type)
|
||||||
|
|
||||||
def GetTypeInfo(self, type):
|
def GetTypeInfo(self):
|
||||||
raise exception.E_NOTIMPL_Error
|
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):
|
def IsEqualTo(self, other, equal):
|
||||||
raise exception.E_NOTIMPL_Error
|
raise exception.E_NOTIMPL_Error
|
||||||
|
@ -198,23 +270,28 @@ class ModelObject(object):
|
||||||
return map
|
return map
|
||||||
|
|
||||||
def GetRawValueMap(self):
|
def GetRawValueMap(self):
|
||||||
|
# print(f"GetRawValueMap: {self}")
|
||||||
map = {}
|
map = {}
|
||||||
kind = self.GetKind()
|
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()
|
(k, v) = keys.GetNext()
|
||||||
while k is not None:
|
while k is not None:
|
||||||
map[k.value] = v
|
map[k.value] = v
|
||||||
(k, v) = keys.GetNext()
|
(k, v) = keys.GetNext()
|
||||||
|
# print(f"{k}:{v}")
|
||||||
return map
|
return map
|
||||||
|
|
||||||
def GetAttributes(self):
|
def GetAttributes(self):
|
||||||
map = {}
|
map = {}
|
||||||
kind = self.GetKind()
|
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
|
return map
|
||||||
if kind == ModelObjectKind.INTRINSIC or \
|
if kind.value == ModelObjectKind.INTRINSIC.value or \
|
||||||
kind == ModelObjectKind.TARGET_OBJECT or \
|
kind.value == ModelObjectKind.TARGET_OBJECT.value or \
|
||||||
kind == ModelObjectKind.TARGET_OBJECT_REFERENCE:
|
kind.value == ModelObjectKind.TARGET_OBJECT_REFERENCE.value:
|
||||||
return self.GetRawValueMap()
|
return self.GetRawValueMap()
|
||||||
return self.GetKeyValueMap()
|
return self.GetKeyValueMap()
|
||||||
|
|
||||||
|
@ -245,6 +322,9 @@ class ModelObject(object):
|
||||||
def GetOffspring(self, path):
|
def GetOffspring(self, path):
|
||||||
next = self
|
next = self
|
||||||
for element in path:
|
for element in path:
|
||||||
|
if next is None:
|
||||||
|
return None
|
||||||
|
kind = next.GetKind()
|
||||||
if element.startswith("["):
|
if element.startswith("["):
|
||||||
idx = element[1:len(element)-1]
|
idx = element[1:len(element)-1]
|
||||||
if "x" not in idx:
|
if "x" not in idx:
|
||||||
|
@ -252,12 +332,17 @@ class ModelObject(object):
|
||||||
else:
|
else:
|
||||||
idx = int(idx, 16)
|
idx = int(idx, 16)
|
||||||
next = next.GetElement(idx)
|
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:
|
else:
|
||||||
next = next.GetKeyValue(element)
|
next = next.GetKeyValue(element)
|
||||||
if next is None:
|
#if next is None:
|
||||||
print(f"{element} not found")
|
# print(f"{element} not found")
|
||||||
return next
|
return next
|
||||||
|
|
||||||
|
|
||||||
def GetValue(self):
|
def GetValue(self):
|
||||||
value = self.GetIntrinsicValue()
|
value = self.GetIntrinsicValue()
|
||||||
if value is None:
|
if value is None:
|
||||||
|
@ -266,9 +351,3 @@ class ModelObject(object):
|
||||||
return None
|
return None
|
||||||
return value.value
|
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:
|
if description is not None:
|
||||||
commands.STATE.trace.snapshot(description)
|
commands.STATE.trace.snapshot(description)
|
||||||
if first:
|
if first:
|
||||||
|
if util.is_kernel():
|
||||||
|
commands.create_generic("Sessions")
|
||||||
commands.put_processes()
|
commands.put_processes()
|
||||||
commands.put_environment()
|
commands.put_environment()
|
||||||
|
commands.put_threads()
|
||||||
if self.threads:
|
if self.threads:
|
||||||
commands.put_threads()
|
commands.put_threads()
|
||||||
self.threads = False
|
self.threads = False
|
||||||
|
@ -98,6 +101,7 @@ class ProcessState(object):
|
||||||
commands.put_threads(running=True)
|
commands.put_threads(running=True)
|
||||||
|
|
||||||
def record_exited(self, exit_code, description=None):
|
def record_exited(self, exit_code, description=None):
|
||||||
|
# print("RECORD_EXITED")
|
||||||
if description is not None:
|
if description is not None:
|
||||||
commands.STATE.trace.snapshot(description)
|
commands.STATE.trace.snapshot(description)
|
||||||
proc = util.selected_process()
|
proc = util.selected_process()
|
||||||
|
|
|
@ -536,6 +536,7 @@ def delete_breakpoint(breakpoint: sch.Schema('BreakpointSpec')):
|
||||||
|
|
||||||
|
|
||||||
@REGISTRY.method
|
@REGISTRY.method
|
||||||
|
@util.dbg.eng_thread
|
||||||
def read_mem(process: sch.Schema('Process'), range: AddressRange):
|
def read_mem(process: sch.Schema('Process'), range: AddressRange):
|
||||||
"""Read memory."""
|
"""Read memory."""
|
||||||
# print("READ_MEM: process={}, range={}".format(process, range))
|
# print("READ_MEM: process={}, range={}".format(process, range))
|
||||||
|
|
|
@ -8,13 +8,13 @@
|
||||||
<attribute name="Utility" schema="ANY" />
|
<attribute name="Utility" schema="ANY" />
|
||||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY"/>
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="SessionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="SessionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<interface name="Configurable" />
|
<interface name="Configurable" />
|
||||||
<element schema="Session" />
|
<element schema="Session" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY"/>
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="Session" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="Session" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<interface name="Activatable" />
|
<interface name="Activatable" />
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
<attribute name="_focus" schema="Selectable" required="yes" hidden="yes" />
|
<attribute name="_focus" schema="Selectable" required="yes" hidden="yes" />
|
||||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY"/>
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="Selectable" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="Selectable" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<element schema="OBJECT" />
|
<element schema="OBJECT" />
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
<interface name="BreakpointSpecContainer" />
|
<interface name="BreakpointSpecContainer" />
|
||||||
<element schema="BreakpointSpec" />
|
<element schema="BreakpointSpec" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
|
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
|
||||||
<interface name="Configurable" />
|
<interface name="Configurable" />
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
<interface name="Configurable" />
|
<interface name="Configurable" />
|
||||||
<element schema="Process" />
|
<element schema="Process" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<interface name="BreakpointSpec" />
|
<interface name="BreakpointSpec" />
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="Environment" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="Environment" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<interface name="Environment" />
|
<interface name="Environment" />
|
||||||
|
@ -152,7 +152,7 @@
|
||||||
<interface name="ModuleContainer" />
|
<interface name="ModuleContainer" />
|
||||||
<element schema="Module" />
|
<element schema="Module" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="Memory" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="Memory" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<interface name="Memory" />
|
<interface name="Memory" />
|
||||||
|
@ -178,7 +178,7 @@
|
||||||
<interface name="Configurable" />
|
<interface name="Configurable" />
|
||||||
<element schema="Thread" />
|
<element schema="Thread" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="Method" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="Method" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<interface name="Method" />
|
<interface name="Method" />
|
||||||
|
@ -207,7 +207,7 @@
|
||||||
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute name="Advance" schema="Method" required="yes" fixed="yes" hidden="yes" />
|
<attribute name="Advance" schema="Method" required="yes" fixed="yes" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="Module" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="Module" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<interface name="Module" />
|
<interface name="Module" />
|
||||||
|
@ -255,7 +255,7 @@
|
||||||
<element schema="StackFrame" />
|
<element schema="StackFrame" />
|
||||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||||
<interface name="SymbolNamespace" />
|
<interface name="SymbolNamespace" />
|
||||||
|
@ -284,7 +284,7 @@
|
||||||
<attribute name="Frame Offset" schema="ADDRESS" />
|
<attribute name="Frame Offset" schema="ADDRESS" />
|
||||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||||
<attribute name="_order" schema="INT" hidden="yes" />
|
<attribute name="_order" schema="INT" hidden="yes" />
|
||||||
<attribute schema="ANY" hidden="yes" />
|
<attribute schema="ANY" />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name="Section" elementResync="NEVER" attributeResync="NEVER">
|
<schema name="Section" elementResync="NEVER" attributeResync="NEVER">
|
||||||
<interface name="Section" />
|
<interface name="Section" />
|
||||||
|
|
|
@ -37,6 +37,7 @@ from pybag.dbgeng import util as DbgUtil
|
||||||
from pybag.dbgeng.callbacks import DbgEngCallbacks
|
from pybag.dbgeng.callbacks import DbgEngCallbacks
|
||||||
|
|
||||||
from ghidradbg.dbgmodel.ihostdatamodelaccess import HostDataModelAccess
|
from ghidradbg.dbgmodel.ihostdatamodelaccess import HostDataModelAccess
|
||||||
|
from _winapi import STILL_ACTIVE
|
||||||
|
|
||||||
|
|
||||||
DbgVersion = namedtuple('DbgVersion', ['full', 'name', 'dotted', 'arch'])
|
DbgVersion = namedtuple('DbgVersion', ['full', 'name', 'dotted', 'arch'])
|
||||||
|
@ -236,6 +237,7 @@ class GhidraDbg(object):
|
||||||
'load_dump'
|
'load_dump'
|
||||||
]:
|
]:
|
||||||
setattr(self, name, self.eng_thread(getattr(base, name)))
|
setattr(self, name, self.eng_thread(getattr(base, name)))
|
||||||
|
self.IS_KERNEL = False
|
||||||
|
|
||||||
def _new_base(self):
|
def _new_base(self):
|
||||||
self._protected_base = AllDbg()
|
self._protected_base = AllDbg()
|
||||||
|
@ -364,6 +366,8 @@ class GhidraDbg(object):
|
||||||
@check_thread
|
@check_thread
|
||||||
def pid(self):
|
def pid(self):
|
||||||
try:
|
try:
|
||||||
|
if is_kernel():
|
||||||
|
return 0
|
||||||
return self._base._systems.GetCurrentProcessSystemId()
|
return self._base._systems.GetCurrentProcessSystemId()
|
||||||
except exception.E_UNEXPECTED_Error:
|
except exception.E_UNEXPECTED_Error:
|
||||||
# There is no process
|
# There is no process
|
||||||
|
@ -451,10 +455,27 @@ def get_breakpoints():
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def selected_process():
|
def selected_process():
|
||||||
try:
|
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:
|
if dbg.use_generics:
|
||||||
return dbg._base._systems.GetCurrentProcessSystemId()
|
return dbg._base._systems.GetCurrentProcessSystemId()
|
||||||
return dbg._base._systems.GetCurrentProcessId()
|
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
|
# NB: we're intentionally returning 0 instead of None
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -462,10 +483,12 @@ def selected_process():
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def selected_thread():
|
def selected_thread():
|
||||||
try:
|
try:
|
||||||
|
if is_kernel():
|
||||||
|
return 0
|
||||||
if dbg.use_generics:
|
if dbg.use_generics:
|
||||||
return dbg._base._systems.GetCurrentThreadSystemId()
|
return dbg._base._systems.GetCurrentThreadSystemId()
|
||||||
return dbg._base._systems.GetCurrentThreadId()
|
return dbg._base._systems.GetCurrentThreadId()
|
||||||
except exception.E_UNEXPECTED_Error:
|
except (exception.E_UNEXPECTED_Error, exception.E_NOTIMPL_Error) as e:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@ -485,6 +508,10 @@ def selected_frame():
|
||||||
|
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def select_process(id: int):
|
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:
|
if dbg.use_generics:
|
||||||
id = get_proc_id(id)
|
id = get_proc_id(id)
|
||||||
return dbg._base._systems.SetCurrentProcessId(id)
|
return dbg._base._systems.SetCurrentProcessId(id)
|
||||||
|
@ -492,6 +519,10 @@ def select_process(id: int):
|
||||||
|
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def select_thread(id: int):
|
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:
|
if dbg.use_generics:
|
||||||
id = get_thread_id(id)
|
id = get_thread_id(id)
|
||||||
return dbg._base._systems.SetCurrentThreadId(id)
|
return dbg._base._systems.SetCurrentThreadId(id)
|
||||||
|
@ -586,14 +617,32 @@ def GetCurrentProcessPeb():
|
||||||
# TODO: upstream?
|
# TODO: upstream?
|
||||||
_dbg = dbg._base
|
_dbg = dbg._base
|
||||||
offset = c_ulonglong()
|
offset = c_ulonglong()
|
||||||
|
if dbg.is_kernel():
|
||||||
|
hr = _dbg._systems._sys.GetCurrentProcessDataOffset(byref(offset))
|
||||||
|
else:
|
||||||
hr = _dbg._systems._sys.GetCurrentProcessPeb(byref(offset))
|
hr = _dbg._systems._sys.GetCurrentProcessPeb(byref(offset))
|
||||||
exception.check_err(hr)
|
exception.check_err(hr)
|
||||||
return offset.value
|
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
|
||||||
|
|
||||||
|
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def GetExitCode():
|
def GetExitCode():
|
||||||
# TODO: upstream?
|
# TODO: upstream?
|
||||||
|
if is_kernel():
|
||||||
|
return STILL_ACTIVE
|
||||||
exit_code = c_ulong()
|
exit_code = c_ulong()
|
||||||
hr = dbg._base._client._cli.GetExitCode(byref(exit_code))
|
hr = dbg._base._client._cli.GetExitCode(byref(exit_code))
|
||||||
return exit_code.value
|
return exit_code.value
|
||||||
|
@ -669,6 +718,21 @@ def get_proc_id(pid):
|
||||||
return None
|
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
|
@dbg.eng_thread
|
||||||
def get_thread_id(tid):
|
def get_thread_id(tid):
|
||||||
"""Get the list of all threads"""
|
"""Get the list of all threads"""
|
||||||
|
@ -715,39 +779,107 @@ def get_object(relpath):
|
||||||
if relpath != '':
|
if relpath != '':
|
||||||
pathstr += "."+relpath
|
pathstr += "."+relpath
|
||||||
path = split_path(pathstr)
|
path = split_path(pathstr)
|
||||||
|
# print(f"PATH: {pathstr}")
|
||||||
return root.GetOffspring(path)
|
return root.GetOffspring(path)
|
||||||
|
|
||||||
|
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def get_attributes(obj):
|
def get_attributes(obj):
|
||||||
"""Get the list of attributes"""
|
"""Get the list of attributes"""
|
||||||
|
if obj is None:
|
||||||
|
return None
|
||||||
return obj.GetAttributes()
|
return obj.GetAttributes()
|
||||||
|
|
||||||
|
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def get_elements(obj):
|
def get_elements(obj):
|
||||||
"""Get the list of all threads"""
|
"""Get the list of all threads"""
|
||||||
|
if obj is None:
|
||||||
|
return None
|
||||||
return obj.GetElements()
|
return obj.GetElements()
|
||||||
|
|
||||||
|
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def get_kind(obj):
|
def get_kind(obj):
|
||||||
"""Get the list of all threads"""
|
"""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
|
return obj.GetKind().value
|
||||||
|
|
||||||
|
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def get_type(obj):
|
def get_type(obj):
|
||||||
"""Get the list of all threads"""
|
"""Get the list of all threads"""
|
||||||
|
if obj is None:
|
||||||
|
return None
|
||||||
return obj.GetTypeKind()
|
return obj.GetTypeKind()
|
||||||
|
|
||||||
|
|
||||||
@dbg.eng_thread
|
@dbg.eng_thread
|
||||||
def get_value(obj):
|
def get_value(obj):
|
||||||
"""Get the list of all threads"""
|
"""Get the list of all threads"""
|
||||||
|
if obj is None:
|
||||||
|
return None
|
||||||
return obj.GetValue()
|
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 = {}
|
conv_map = {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -762,3 +894,11 @@ def get_convenience_variable(id):
|
||||||
|
|
||||||
def set_convenience_variable(id, value):
|
def set_convenience_variable(id, value):
|
||||||
conv_map[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
|
Alternatively, if you are trying to quit, but typed "<TT>.exit</TT>", just type
|
||||||
"<TT>quit()</TT>" to terminate the session.</P>
|
"<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>
|
<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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue