Merge remote-tracking branch

'origin/GP-4290_d-millar_traceRMI_dbgmodel--SQUASHED'

 Conflicts:
	Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/commands.py
	Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/schema.xml
This commit is contained in:
Ryan Kurtz 2024-02-27 11:31:59 -05:00
commit 9934159e25
19 changed files with 2386 additions and 45 deletions

View File

@ -21,6 +21,7 @@ apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/debugger/hasNodepJar.gradle"
apply from: "$rootProject.projectDir/gradle/debugger/hasPythonPackage.gradle"
apply from: "buildNatives.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Debug Debugger-agent-dbgeng'
@ -36,6 +37,14 @@ dependencies {
testImplementation project(path: ":Debugger-gadp", configuration: 'testArtifacts')
}
// Include buildable native source in distribution
rootProject.assembleDistribution {
from (this.project.projectDir.toString()) {
include "src/**"
into { getZipPath(this.project) }
}
}
tasks.nodepJar {
manifest {
attributes['Main-Class'] = 'agent.dbgeng.gadp.DbgEngGadpServer'

View File

@ -0,0 +1,49 @@
/* ###
* 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.
*/
if ("win_x86_64".equals(getCurrentPlatformName())) {
String makeName = "win_x86_64TlbMake"
task(type: Exec, makeName) {
def projectPath = projectDir.toString()
def solutionBatchFilePath = projectPath + "/build/buildSolution.bat"
def projectPathWindows = projectPath.replace("/", File.separator)
doFirst {
file("build/os/win_x86_64").mkdirs()
def srcdir = "src/main/py/src/dbgmodel"
def msbuildCmd = "midl /tlb build/os/win_x86_64/dbgmodel.tlb ${srcdir}/DbgModel.idl"
println "Executing: " + msbuildCmd
new File(solutionBatchFilePath).withWriter { out ->
out.println "call " + VISUAL_STUDIO_VCVARS_CMD
out.println msbuildCmd
}
}
doLast {
assert file("build/os/win_x86_64/dbgmodel.tlb").exists() : "Failed to build dbgmodel.tlb"
}
executable "cmd"
args "/c"
args solutionBatchFilePath.replace("/", File.separator)
}
}

View File

@ -5,4 +5,5 @@ data/debugger-launchers/local-dbgeng.bat||GHIDRA||||END|
src/main/py/LICENSE||GHIDRA||||END|
src/main/py/README.md||GHIDRA||||END|
src/main/py/pyproject.toml||GHIDRA||||END|
src/main/py/src/dbgmodel/DbgModel.idl||GHIDRA||||END|
src/main/py/src/ghidradbg/schema.xml||GHIDRA||||END|

View File

@ -14,6 +14,8 @@
:: Use env instead of args, because "all args except first" is terrible to implement in batch
::@env OPT_TARGET_IMG:str="" "Image" "The target binary executable image"
::@env OPT_TARGET_ARGS:str="" "Arguments" "Command-line arguments to pass to the target"
::@env OPT_USE_DBGMODEL:bool=true "Use dbgmodel" "Load and use dbgmodel.dll if it is available."
::@env OPT_DBGMODEL_PATH:str="" "Path to dbgeng" "Path to dbgeng and associated DLLS (if not Windows Kits)."
@echo off

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
## ###
# 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.hresult import S_OK, S_FALSE
from comtypes.gen import DbgMod
from pybag.dbgeng import exception
import dbgmodel.imodelobject as mo
class DataModelManager(object):
def __init__(self, mgr):
self._mgr = mgr
exception.wrap_comclass(self._mgr)
def Release(self):
cnt = self._mgr.Release()
if cnt == 0:
self._mgr = None
return cnt
# DataModelManager
def GetRootNamespace(self):
root = POINTER(DbgMod.IModelObject)()
hr = self._mgr.GetRootNamespace(byref(root))
exception.check_err(hr)
return mo.ModelObject(root)
def AcquireNamedModel(self, modelName, modelObject):
raise exception.E_NOTIMPL_Error
def Close(self):
raise exception.E_NOTIMPL_Error
def CreateNoValue(self, object):
raise exception.E_NOTIMPL_Error
def CreateErrorObject(self, error, message, object):
raise exception.E_NOTIMPL_Error
def CreateTypedObject(self, context, objectLocation, objectType, object):
raise exception.E_NOTIMPL_Error
def CreateTypedObjectByReference(self, context, objectLocation, objectType, object):
raise exception.E_NOTIMPL_Error
def CreateSyntheticObject(self, context, object):
raise exception.E_NOTIMPL_Error
def CreateDataModelObject(self, dataModel, object):
raise exception.E_NOTIMPL_Error
def CreateTypedIntrinsicObject(self, intrinsicData, type, object):
raise exception.E_NOTIMPL_Error
def CreateIntrinsicObject(self, objectKind, intrinsicData, object):
raise exception.E_NOTIMPL_Error
def GetModelForTypeSignature(self, typeSignature, dataModel):
raise exception.E_NOTIMPL_Error
def GetModelForType(self, type, dataModel, typeSignature, wildcardMatches):
raise exception.E_NOTIMPL_Error
def RegisterExtensionForTypeSignature(self, typeSignature, dataModel):
raise exception.E_NOTIMPL_Error
def RegisterModelForTypeSignature(self, typeSignature, dataModel):
raise exception.E_NOTIMPL_Error
def RegisterNamedModel(self, modelName, modelObject):
raise exception.E_NOTIMPL_Error
def UnregisterExtensionForTypeSignature(self, dataModel, typeSignature):
raise exception.E_NOTIMPL_Error
def UnregisterModelForTypeSignature(self, dataModel, typeSignature):
raise exception.E_NOTIMPL_Error
def UnregisterNamedModel(self, modelName):
raise exception.E_NOTIMPL_Error

View File

@ -0,0 +1,48 @@
## ###
# 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.hresult import S_OK, S_FALSE
from comtypes.gen import DbgMod
from pybag.dbgeng import exception
from pybag.dbgeng import win32
class DebugHost(object):
def __init__(self, host):
self._host = host
exception.wrap_comclass(self._host)
def Release(self):
cnt = self._host.Release()
if cnt == 0:
self._host = None
return cnt
# DebugHost
def GetCurrentContext(self, context):
raise exception.E_NOTIMPL_Error
def GetDefaultMetadata(self, metadata):
raise exception.E_NOTIMPL_Error
def GetHostDefinedInterface(self, hostUnk):
raise exception.E_NOTIMPL_Error

View File

@ -0,0 +1,46 @@
## ###
# 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.hresult import S_OK, S_FALSE
from comtypes.gen import DbgMod
from pybag.dbgeng import exception
from .idatamodelmanager import DataModelManager
from .idebughost import DebugHost
class HostDataModelAccess(object):
def __init__(self, hdma):
self._hdma = hdma
exception.wrap_comclass(self._hdma)
def Release(self):
cnt = self._hdma.Release()
if cnt == 0:
self._hdma = None
return cnt
# HostDataModelAccess
def GetDataModel(self):
manager = POINTER(DbgMod.IDataModelManager)()
host = POINTER(DbgMod.IDebugHost)()
hr = self._hdma.GetDataModel(byref(manager), byref(host))
exception.check_err(hr)
return (DataModelManager(manager), DebugHost(host))

View File

@ -0,0 +1,44 @@
## ###
# 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 COMError
from comtypes.hresult import S_OK, S_FALSE
from comtypes.gen import DbgMod
from pybag.dbgeng import exception
from .imodeliterator import ModelIterator
class IterableConcept(object):
def __init__(self, concept):
self._concept = concept
concept.AddRef()
# IterableConcept
def GetDefaultIndexDimensionality(self, context, dimensionality):
raise exception.E_NOTIMPL_Error
def GetIterator(self, context):
iterator = POINTER(DbgMod.IModelIterator)()
try:
self._concept.GetIterator(context._obj, byref(iterator))
except COMError as ce:
return None
return ModelIterator(iterator)

View File

@ -0,0 +1,51 @@
## ###
# 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
from comtypes.hresult import S_OK, S_FALSE
from comtypes.gen import DbgMod
from pybag.dbgeng import exception
import dbgmodel.imodelobject as mo
class KeyEnumerator(object):
def __init__(self, keys):
self._keys = keys
exception.wrap_comclass(self._keys)
def Release(self):
cnt = self._keys.Release()
if cnt == 0:
self._keys = None
return cnt
# KeyEnumerator
def GetNext(self):
key = BSTR()
value = POINTER(DbgMod.IModelObject)()
store = POINTER(DbgMod.IKeyStore)()
hr = self._keys.GetNext(byref(key), byref(value), byref(store))
if hr != S_OK:
return (None, None)
return (key, mo.ModelObject(value))
def Reset(self):
hr = self._keys.Reset()
exception.check_err(hr)

View File

@ -0,0 +1,48 @@
## ###
# 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 COMError
from comtypes.hresult import S_OK, S_FALSE
from comtypes.gen import DbgMod
from pybag.dbgeng import exception
import dbgmodel.imodelobject as mo
class ModelIterator(object):
def __init__(self, iter):
self._iter = iter
iter.AddRef()
# ModelIterator
def GetNext(self, dimensions):
object = POINTER(DbgMod.IModelObject)()
indexer = POINTER(DbgMod.IModelObject)()
metadata = POINTER(DbgMod.IKeyStore)()
try:
self._iter.GetNext(byref(object), dimensions, byref(indexer), byref(metadata))
except COMError as ce:
return None
index = mo.ModelObject(indexer)
id = index.GetIntrinsicValue().value
return (id, mo.ModelObject(object))
def Reset(self):
hr = self._keys.Reset()
exception.check_err(hr)

View File

@ -0,0 +1,273 @@
## ###
# 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 IUnknown, COMError
from comtypes.automation import IID, VARIANT
from comtypes.hresult import S_OK, S_FALSE
from comtypes.gen.DbgMod import *
from enum import Enum
from comtypes.gen import DbgMod
from pybag.dbgeng import exception
from .ikeyenumerator import KeyEnumerator
from .iiterableconcept import IterableConcept
class ModelObjectKind(Enum):
PROPERTY_ACCESSOR = 0
CONTEXT = 1
TARGET_OBJECT = 2
TARGET_OBJECT_REFERENCE = 3
SYNTHETIC = 4
NO_VALUE = 5
ERROR = 6
INTRINSIC = 7
METHOD = 8
KEY_REFERENCE = 9
class ModelObject(object):
def __init__(self, obj):
self._obj = obj
self.concept = None
exception.wrap_comclass(self._obj)
def Release(self):
print("RELEASE ModelObject")
breakpoint()
cnt = self._obj.Release()
if cnt == 0:
self._obj = None
return cnt
# ModelObject
def AddParentModel(self, model, contextObject, override):
raise exception.E_NOTIMPL_Error
def ClearConcepts(self):
raise exception.E_NOTIMPL_Error
def ClearKeys(self):
raise exception.E_NOTIMPL_Error
def Compare(self, other, equal):
raise exception.E_NOTIMPL_Error
def Dereference(self, object):
raise exception.E_NOTIMPL_Error
def EnumerateKeyReferences(self):
raise exception.E_NOTIMPL_Error
def EnumerateKeys(self):
keys = POINTER(DbgMod.IKeyEnumerator)()
hr = self._obj.EnumerateKeys(byref(keys))
if hr != S_OK:
return None
return KeyEnumerator(keys)
def EnumerateKeyValues(self):
raise exception.E_NOTIMPL_Error
def EnumerateRawReferences(self, kind, searchFlags):
raise exception.E_NOTIMPL_Error
def EnumerateRawValues(self, kind, searchFlag):
keys = POINTER(DbgMod.IRawEnumerator)()
hr = self._obj.EnumerateRawValues(kind, searchFlag, byref(keys))
if hr != S_OK:
return None
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:
return None
return cast(ifc, POINTER(ref))
def GetContext(self, context):
raise exception.E_NOTIMPL_Error
def GetContextForDataModel(self, dataModelObject, context):
raise exception.E_NOTIMPL_Error
def GetIntrinsicValue(self):
var = VARIANT()
hr = self._obj.GetIntrinsicValue(var)
if hr != S_OK:
return None
return var
def GetIntrinsicValueAs(self, vt):
raise exception.E_NOTIMPL_Error
def GetKey(self, key, object, metadata):
raise exception.E_NOTIMPL_Error
def GetKeyReference(self, key, objectReference, metadata):
raise exception.E_NOTIMPL_Error
def GetKeyValue(self, key):
kbuf = cast(c_wchar_p(key),POINTER(c_ushort))
value = POINTER(DbgMod.IModelObject)()
store = POINTER(DbgMod.IKeyStore)()
hr = self._obj.GetKeyValue(kbuf, byref(value), byref(store))
if hr != S_OK:
return None
return ModelObject(value)
def GetKind(self):
kind = c_long()
hr = self._obj.GetKind(kind)
exception.check_err(hr)
return kind
def GetLocation(self, location):
raise exception.E_NOTIMPL_Error
def GetNumberOfParentModels(self, numModels):
raise exception.E_NOTIMPL_Error
def GetParentModel(self, i, model, context):
raise exception.E_NOTIMPL_Error
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 GetTargetInfo(self):
location = POINTER(DbgMod._Location)()
type = POINTER(DbgMod.IDebugHostType)()
hr = self._obj.GetTargetInfo(location, byref(type))
exception.check_err(hr)
return type
def GetTypeInfo(self, type):
raise exception.E_NOTIMPL_Error
def IsEqualTo(self, other, equal):
raise exception.E_NOTIMPL_Error
def RemoveParentModel(self, model):
raise exception.E_NOTIMPL_Error
def SetConcept(self, ref, interface, metadata):
raise exception.E_NOTIMPL_Error
def SetContextForDataModel(self, modelObject, context):
raise exception.E_NOTIMPL_Error
def SetKey(self, key, object, metadata):
raise exception.E_NOTIMPL_Error
def SetKeyValue(self, key, object):
raise exception.E_NOTIMPL_Error
def TryCastToRuntimeType(self, runtimeTypedObject):
raise exception.E_NOTIMPL_Error
# Auxiliary
def GetKeyValueMap(self):
map = {}
keys = self.EnumerateKeys()
(k,v) = keys.GetNext()
while k is not None:
map[k.value] = self.GetKeyValue(k.value)
(k,v) = keys.GetNext()
return map
def GetRawValueMap(self):
map = {}
kind = self.GetKind()
keys = self.EnumerateRawValues(kind, c_long(0))
(k,v) = keys.GetNext()
while k is not None:
map[k.value] = v
(k,v) = keys.GetNext()
return map
def GetAttributes(self):
map = {}
kind = self.GetKind()
if kind == ModelObjectKind.ERROR:
return map
if kind == ModelObjectKind.INTRINSIC or \
kind == ModelObjectKind.TARGET_OBJECT or \
kind == ModelObjectKind.TARGET_OBJECT_REFERENCE:
return self.GetRawValueMap()
return self.GetKeyValueMap()
def GetElements(self):
list = []
if self.concept is None:
iconcept = self.GetConcept(DbgMod.IIterableConcept)
if iconcept is None:
return list
self.concept = IterableConcept(iconcept)
iter = self.concept.GetIterator(self)
if iter is None:
print("WARNING: iter is None")
return list
next = iter.GetNext(1)
while next is not None:
list.append(next)
next = iter.GetNext(1)
return list
def GetElement(self, key):
list = self.GetElements()
for k, v in list:
if k == key:
return v
return None
def GetOffspring(self, path):
next = self
for element in path:
if element.startswith("["):
idx = element[1:len(element)-1]
if "x" not in idx:
idx = int(idx)
else:
idx = int(idx,16)
next = next.GetElement(idx)
else:
next = next.GetKeyValue(element)
if next is None:
print(f"{element} not found")
return next
def GetValue(self):
value = self.GetIntrinsicValue()
if value is None:
return None
if value.vt == 0xd:
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

View File

@ -0,0 +1,51 @@
## ###
# 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
from comtypes.hresult import S_OK, S_FALSE
from comtypes.gen import DbgMod
from pybag.dbgeng import exception
import dbgmodel.imodelobject as mo
class RawEnumerator(object):
def __init__(self, keys, kind):
self._keys = keys
self._kind = kind
exception.wrap_comclass(self._keys)
def Release(self):
cnt = self._keys.Release()
if cnt == 0:
self._keys = None
return cnt
# KeyEnumerator
def GetNext(self):
key = BSTR()
value = POINTER(DbgMod.IModelObject)()
hr = self._keys.GetNext(byref(key), byref(self._kind), byref(value))
if hr != S_OK:
return (None, None)
return (key, mo.ModelObject(value))
def Reset(self):
hr = self._keys.Reset()
exception.check_err(hr)

View File

@ -14,7 +14,44 @@
# limitations under the License.
##
from . import util, commands, methods, hooks
from dbgmodel.ihostdatamodelaccess import HostDataModelAccess
import ctypes
import platform
import os
ctypes.windll.kernel32.SetErrorMode(0x0001 | 0x0002 | 0x8000)
if platform.architecture()[0] == '64bit':
dbgdirs = [os.getenv('OPT_DBGMODEL_PATH'),
r'C:\Program Files\Windows Kits\10\Debuggers\x64',
r'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64']
else:
dbgdirs = [os.getenv('OPT_DBGMODEL_PATH'),
r'C:\Program Files\Windows Kits\10\Debuggers\x86',
r'C:\Program Files (x86)\Windows Kits\10\Debuggers\x86']
dbgdir = None
for _dir in dbgdirs:
if os.path.exists(_dir):
dbgdir = _dir
break
if not dbgdir:
raise RuntimeError("Windbg install directory not found!")
# preload these to get correct DLLs loaded
try:
ctypes.windll.LoadLibrary(os.path.join(dbgdir, 'dbghelp.dll'))
except Exception as exc:
print(f"LoadLibrary failed: {dbgdir}\dbghelp.dll {exc}")
pass
try:
ctypes.windll.LoadLibrary(os.path.join(dbgdir, 'dbgeng.dll'))
except Exception as exc:
print(f"LoadLibrary failed: {dbgdir}\dbgeng.dll {exc}")
pass
try:
ctypes.windll.LoadLibrary(os.path.join(dbgdir, 'DbgModel.dll'))
except Exception as exc:
print(f"LoadLibrary failed: {dbgdir}\dbgmodel.dll {exc}")
pass

View File

@ -25,6 +25,7 @@ import time
from pybag import pydbg, userdbg, kerneldbg
from pybag.dbgeng import core as DbgEng
from pybag.dbgeng import exception
from dbgmodel.imodelobject import ModelObjectKind
from ghidratrace import sch
from ghidratrace.client import Client, Address, AddressRange, TraceObject
@ -37,20 +38,21 @@ PAGE_SIZE = 4096
AVAILABLES_PATH = 'Available'
AVAILABLE_KEY_PATTERN = '[{pid}]'
AVAILABLE_PATTERN = AVAILABLES_PATH + AVAILABLE_KEY_PATTERN
PROCESSES_PATH = 'Processes'
PROCESSES_PATH = 'Sessions[0].Processes'
PROCESS_KEY_PATTERN = '[{procnum}]'
PROCESS_PATTERN = PROCESSES_PATH + PROCESS_KEY_PATTERN
PROC_BREAKS_PATTERN = PROCESS_PATTERN + '.Breakpoints'
PROC_BREAKS_PATTERN = PROCESS_PATTERN + '.Debug.Breakpoints'
PROC_BREAK_KEY_PATTERN = '[{breaknum}]'
PROC_BREAK_PATTERN = PROC_BREAKS_PATTERN + PROC_BREAK_KEY_PATTERN
ENV_PATTERN = PROCESS_PATTERN + '.Environment'
THREADS_PATTERN = PROCESS_PATTERN + '.Threads'
THREAD_KEY_PATTERN = '[{tnum}]'
THREAD_PATTERN = THREADS_PATTERN + THREAD_KEY_PATTERN
STACK_PATTERN = THREAD_PATTERN + '.Stack'
STACK_PATTERN = THREAD_PATTERN + '.Stack.Frames'
FRAME_KEY_PATTERN = '[{level}]'
FRAME_PATTERN = STACK_PATTERN + FRAME_KEY_PATTERN
REGS_PATTERN = THREAD_PATTERN + '.Registers'
USER_REGS_PATTERN = THREAD_PATTERN + '.Registers.User'
MEMORY_PATTERN = PROCESS_PATTERN + '.Memory'
REGION_KEY_PATTERN = '[{start:08x}]'
REGION_PATTERN = MEMORY_PATTERN + REGION_KEY_PATTERN
@ -60,6 +62,7 @@ MODULE_PATTERN = MODULES_PATTERN + MODULE_KEY_PATTERN
SECTIONS_ADD_PATTERN = '.Sections'
SECTION_KEY_PATTERN = '[{secname}]'
SECTION_ADD_PATTERN = SECTIONS_ADD_PATTERN + SECTION_KEY_PATTERN
GENERIC_KEY_PATTERN = '[{key}]'
# TODO: Symbols
@ -209,7 +212,7 @@ def start_trace(name):
with open(schema_fn, 'r') as schema_file:
schema_xml = schema_file.read()
with STATE.trace.open_tx("Create Root Object"):
root = STATE.trace.create_root_object(schema_xml, 'DbgengSession')
root = STATE.trace.create_root_object(schema_xml, 'Root')
root.set_value('_display', util.DBG_VERSION.full + ' via pybag')
util.set_convenience_variable('_ghidra_tracing', "true")
@ -481,6 +484,18 @@ def ghidra_trace_delmem(address, length):
@util.dbg.eng_thread
def putreg():
if util.dbg.use_generics:
nproc = util.selected_process()
if nproc < 0:
return
nthrd = util.selected_thread()
rpath = REGS_PATTERN.format(procnum=nproc, tnum=nthrd)
create_generic(rpath)
STATE.trace.create_overlay_space('register', rpath)
path = USER_REGS_PATTERN.format(procnum=nproc, tnum=nthrd)
(values, keys) = create_generic(path)
return {'missing': STATE.trace.put_registers(rpath, values)}
nproc = util.selected_process()
if nproc < 0:
return
@ -834,6 +849,17 @@ def compute_proc_state(nproc=None):
def put_processes(running=False):
# | always displays PID in hex
# TODO: I'm not sure about the engine id
# NB: This speeds things up, but desirable?
if running:
return
if util.dbg.use_generics and not running:
ppath = PROCESSES_PATH
(values, keys) = create_generic(ppath)
STATE.trace.proxy_object_path(PROCESSES_PATH).retain_values(keys)
return
keys = []
# Set running=True to avoid process changes, even while stopped
for i, p in enumerate(util.process_list(running=True)):
@ -979,8 +1005,18 @@ def put_single_breakpoint(bp, ibobj, nproc, ikeys):
@util.dbg.eng_thread
def put_breakpoints():
target = util.get_target()
nproc = util.selected_process()
# NB: Am leaving this code here in case we change our minds, but the cost
# of using put_generic here outweighs the advantage of uniformity
#
# if util.dbg.use_generics:
# path = PROC_BREAKS_PATTERN.format(procnum=nproc)
# (values, keys) = create_generic(path)
# STATE.trace.proxy_object_path(path).retain_values(keys)
# return
target = util.get_target()
ibpath = PROC_BREAKS_PATTERN.format(procnum=nproc)
ibobj = STATE.trace.create_object(ibpath)
keys = []
@ -1010,7 +1046,8 @@ def ghidra_trace_put_breakpoints():
def put_environment():
epath = ENV_PATTERN.format(procnum=util.selected_process())
nproc = util.selected_process()
epath = ENV_PATTERN.format(procnum=nproc)
envobj = STATE.trace.create_object(epath)
envobj.set_value('_debugger', 'pydbg')
envobj.set_value('_arch', arch.get_arch())
@ -1036,8 +1073,7 @@ def put_regions():
regions = util.dbg._base.memory_list()
except Exception:
regions = []
if len(regions) == 0 and util.selected_thread() != None:
regions = [util.REGION_INFO_READER.full_mem()]
mapper = STATE.trace.memory_mapper
keys = []
# r : MEMORY_BASIC_INFORMATION64
@ -1045,9 +1081,7 @@ def put_regions():
rpath = REGION_PATTERN.format(procnum=nproc, start=r.BaseAddress)
keys.append(REGION_KEY_PATTERN.format(start=r.BaseAddress))
regobj = STATE.trace.create_object(rpath)
start_base, start_addr = mapper.map(nproc, r.BaseAddress)
if start_base != start_addr.space:
STATE.trace.create_overlay_space(start_base, start_addr.space)
(start_base, start_addr) = map_address(r.BaseAddress)
regobj.set_value('_range', start_addr.extend(r.RegionSize))
regobj.set_value('_readable', r.Protect ==
None or r.Protect & 0x66 != 0)
@ -1078,8 +1112,15 @@ def ghidra_trace_put_regions():
@util.dbg.eng_thread
def put_modules():
target = util.get_target()
nproc = util.selected_process()
if util.dbg.use_generics:
mpath = MODULES_PATTERN.format(procnum=nproc)
(values, keys) = create_generic(mpath)
STATE.trace.proxy_object_path(
MODULES_PATTERN.format(procnum=nproc)).retain_values(keys)
return
target = util.get_target()
modules = util.dbg._base.module_list()
mapper = STATE.trace.memory_mapper
mod_keys = []
@ -1141,9 +1182,21 @@ def compute_thread_display(i, pid, tid, t):
def put_threads(running=False):
# ~ always displays PID:TID in hex
# TODO: I'm not sure about the engine id
# NB: This speeds things up, but desirable?
if running:
return
nproc = util.selected_process()
if nproc is None:
return
if util.dbg.use_generics and not running:
tpath = THREADS_PATTERN.format(procnum=nproc)
(values, keys) = create_generic(tpath)
STATE.trace.proxy_object_path(
THREADS_PATTERN.format(procnum=nproc)).retain_values(keys)
return
pid = util.dbg.pid
keys = []
@ -1192,10 +1245,19 @@ def ghidra_trace_put_threads():
@util.dbg.eng_thread
def put_frames():
nproc = util.selected_process()
mapper = STATE.trace.memory_mapper
if nproc < 0:
return
nthrd = util.selected_thread()
if nthrd is None:
return
if util.dbg.use_generics:
path = STACK_PATTERN.format(procnum=nproc, tnum=nthrd)
(values, keys) = create_generic(path)
STATE.trace.proxy_object_path(path).retain_values(keys)
return
mapper = STATE.trace.memory_mapper
keys = []
# f : _DEBUG_STACK_FRAME
for f in util.dbg._base.backtrace_list():
@ -1228,6 +1290,134 @@ def ghidra_trace_put_frames():
put_frames()
def update_by_container(np, index, obj):
if np.endswith("Processes") or np.endswith("Threads"):
istate = compute_proc_state(index)
obj.set_value('_state', istate)
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))
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 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('_pc', pc_addr)
obj.set_value('_display', '#{:x} 0x{:x}'.format(index, pc))
if np.endswith("Modules"):
create_generic(obj.path)
mo = util.get_object(obj.path)
map = util.get_attributes(mo)
base = util.get_value(map["BaseAddress"])
size = util.get_value(map["Size"])
name = util.get_value(map["Name"])
obj.set_value('_module_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))
obj.set_value('Base', hex(base))
def create_generic(path):
obj = STATE.trace.create_object(path)
obj.insert()
result = put_generic(obj)
return result
def 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)
if kind is not None:
node.set_value("_kind", kind)
if type is not None:
node.set_value("_type", type.value)
# print(f"MO={mo}")
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
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)
return (values, keys)
def map_address(address):
nproc = util.selected_process()
mapper = STATE.trace.memory_mapper
base, addr = mapper.map(nproc, address)
if base != addr.space:
STATE.trace.create_overlay_space(base, addr.space)
return (base, addr)
def ghidra_trace_put_generic(node):
"""
Put the current thread's frames into the Ghidra trace
"""
STATE.require_tx()
with STATE.client.batch() as b:
put_generic(node)
def ghidra_trace_put_all():
"""
Put everything currently selected into the Ghidra trace

View File

@ -30,7 +30,6 @@ from pybag.dbgeng.idebugbreakpoint import DebugBreakpoint
from . import commands, util
ALL_EVENTS = 0xFFFF
@ -103,8 +102,9 @@ class ProcessState(object):
commands.STATE.trace.snapshot(description)
proc = util.selected_process()
ipath = commands.PROCESS_PATTERN.format(procnum=proc)
commands.STATE.trace.proxy_object_path(
ipath).set_value('_exit_code', exit_code)
procobj = commands.STATE.trace.proxy_object_path(ipath)
procobj.set_value('_exit_code', exit_code)
procobj.set_value('_state', 'TERMINATED')
class BrkState(object):
@ -178,6 +178,8 @@ def on_state_changed(*args):
commands.put_state(proc)
if args[1] == DbgEng.DEBUG_STATUS_BREAK:
return on_stop(args)
elif args[1] == DbgEng.DEBUG_STATUS_NO_DEBUGGEE:
return on_exited(proc)
else:
return on_cont(args)
return S_OK
@ -376,6 +378,7 @@ def on_stop(*args):
def on_exited(proc):
# print("ON EXITED")
if proc not in PROC_STATE:
# print("not in state")
return

View File

@ -40,13 +40,16 @@ AVAILABLE_PATTERN = re.compile('Available\[(?P<pid>\\d*)\]')
WATCHPOINT_PATTERN = re.compile('Watchpoints\[(?P<watchnum>\\d*)\]')
BREAKPOINT_PATTERN = re.compile('Breakpoints\[(?P<breaknum>\\d*)\]')
BREAK_LOC_PATTERN = extre(BREAKPOINT_PATTERN, '\[(?P<locnum>\\d*)\]')
PROCESS_PATTERN = re.compile('Processes\[(?P<procnum>\\d*)\]')
PROC_BREAKS_PATTERN = extre(PROCESS_PATTERN, '\.Breakpoints')
SESSIONS_PATTERN = re.compile('Sessions')
SESSION_PATTERN = extre(SESSIONS_PATTERN, '\[(?P<snum>\\d*)\]')
PROCESSES_PATTERN = extre(SESSION_PATTERN, '\.Processes')
PROCESS_PATTERN = extre(PROCESSES_PATTERN, '\[(?P<procnum>\\d*)\]')
PROC_BREAKS_PATTERN = extre(PROCESS_PATTERN, '\.Debug.Breakpoints')
PROC_BREAKBPT_PATTERN = extre(PROC_BREAKS_PATTERN, '\[(?P<breaknum>\\d*)\]')
ENV_PATTERN = extre(PROCESS_PATTERN, '\.Environment')
THREADS_PATTERN = extre(PROCESS_PATTERN, '\.Threads')
THREAD_PATTERN = extre(THREADS_PATTERN, '\[(?P<tnum>\\d*)\]')
STACK_PATTERN = extre(THREAD_PATTERN, '\.Stack')
STACK_PATTERN = extre(THREAD_PATTERN, '\.Stack.Frames')
FRAME_PATTERN = extre(STACK_PATTERN, '\[(?P<level>\\d*)\]')
REGS_PATTERN0 = extre(THREAD_PATTERN, '.Registers')
REGS_PATTERN = extre(FRAME_PATTERN, '.Registers')
@ -204,14 +207,21 @@ def evaluate(expr: str):
return str(eval(expr, shared_globals))
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display="Refresh", condition=util.dbg.use_generics)
def refresh_generic(node: sch.OBJECT):
"""List processes on pydbg's host system."""
with commands.open_tracked_tx('Refresh Generic'):
commands.ghidra_trace_put_generic(node)
@REGISTRY.method(action='refresh', display='Refresh Available')
def refresh_available(node: sch.Schema('AvailableContainer')):
"""List processes on pydbg's host system."""
with commands.open_tracked_tx('Refresh Available'):
commands.ghidra_trace_put_available()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Breakpoints')
def refresh_breakpoints(node: sch.Schema('BreakpointContainer')):
"""
Refresh the list of breakpoints (including locations for the current
@ -221,14 +231,14 @@ def refresh_breakpoints(node: sch.Schema('BreakpointContainer')):
commands.ghidra_trace_put_breakpoints()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Processes')
def refresh_processes(node: sch.Schema('ProcessContainer')):
"""Refresh the list of processes."""
with commands.open_tracked_tx('Refresh Processes'):
commands.ghidra_trace_put_threads()
commands.ghidra_trace_put_processes()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Breakpoint Locations')
def refresh_proc_breakpoints(node: sch.Schema('BreakpointLocationContainer')):
"""
Refresh the breakpoint locations for the process.
@ -240,21 +250,21 @@ def refresh_proc_breakpoints(node: sch.Schema('BreakpointLocationContainer')):
commands.ghidra_trace_put_breakpoints()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Environment')
def refresh_environment(node: sch.Schema('Environment')):
"""Refresh the environment descriptors (arch, os, endian)."""
with commands.open_tracked_tx('Refresh Environment'):
commands.ghidra_trace_put_environment()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Threads')
def refresh_threads(node: sch.Schema('ThreadContainer')):
"""Refresh the list of threads in the process."""
with commands.open_tracked_tx('Refresh Threads'):
commands.ghidra_trace_put_threads()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Stack')
def refresh_stack(node: sch.Schema('Stack')):
"""Refresh the backtrace for the thread."""
tnum = find_thread_by_stack_obj(node)
@ -262,7 +272,7 @@ def refresh_stack(node: sch.Schema('Stack')):
commands.ghidra_trace_put_frames()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Registers')
def refresh_registers(node: sch.Schema('RegisterValueContainer')):
"""Refresh the register values for the frame."""
tnum = find_thread_by_regs_obj(node)
@ -270,14 +280,14 @@ def refresh_registers(node: sch.Schema('RegisterValueContainer')):
commands.ghidra_trace_putreg()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Memory')
def refresh_mappings(node: sch.Schema('Memory')):
"""Refresh the list of memory regions for the process."""
with commands.open_tracked_tx('Refresh Memory Regions'):
commands.ghidra_trace_put_regions()
@REGISTRY.method(action='refresh')
@REGISTRY.method(action='refresh', display='Refresh Modules')
def refresh_modules(node: sch.Schema('ModuleContainer')):
"""
Refresh the modules and sections list for the process.

View File

@ -1,5 +1,34 @@
<context>
<schema name="DbgengSession" elementResync="NEVER" attributeResync="NEVER">
<schema name="Root" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<attribute name="Sessions" schema="SessionContainer" required="yes" fixed="yes" />
<attribute name="Settings" schema="ANY" />
<attribute name="State" schema="ANY" />
<attribute name="Utility" schema="ANY" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_base" schema="INT" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="SessionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Configurable" />
<element schema="Session" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_base" schema="INT" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="Session" elementResync="NEVER" attributeResync="NEVER">
<interface name="Access" />
<interface name="Attacher" />
<interface name="Interpreter" />
@ -25,7 +54,7 @@
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="Selectable" elementResync="NEVER" attributeResync="NEVER">
<element schema="OBJECT" />
@ -38,6 +67,19 @@
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="DebugBreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="Breakpoints" schema="BreakpointContainer" required="yes" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="BreakpointContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointLocationContainer" />
<interface name="BreakpointSpecContainer" />
@ -50,7 +92,7 @@
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="AvailableContainer" canonical="yes" elementResync="ALWAYS" attributeResync="NEVER">
<interface name="Configurable" />
@ -76,7 +118,7 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_base" schema="INT" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="BreakpointSpec" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="BreakpointSpec" />
@ -134,12 +176,14 @@
<interface name="Interruptible" />
<element schema="VOID" />
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
<attribute name="Breakpoints" schema="BreakpointContainer" required="yes" fixed="yes" />
<attribute name="Debug" schema="DebugBreakpointContainer" required="yes" fixed="yes" />
<!-- attribute name="Breakpoints" schema="BreakpointLocationContainer" required="yes" fixed="yes" /-->
<attribute name="_exit_code" schema="LONG" />
<attribute name="Environment" schema="Environment" required="yes" fixed="yes" />
<attribute name="Memory" schema="Memory" required="yes" fixed="yes" />
<attribute name="Modules" schema="ModuleContainer" required="yes" fixed="yes" />
<attribute name="Handle" schema="STRING" fixed="yes" />
<attribute name="Id" schema="STRING" fixed="yes" />
<attribute name="_pid" schema="LONG" hidden="yes" />
<attribute name="_state" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute name="_supported_attach_kinds" schema="SET_ATTACH_KIND" required="yes" hidden="yes" />
@ -152,7 +196,7 @@
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="Environment" elementResync="NEVER" attributeResync="NEVER">
<interface name="Environment" />
@ -184,7 +228,7 @@
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="Memory" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Memory" />
@ -235,7 +279,7 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="_base" schema="INT" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="Method" elementResync="NEVER" attributeResync="NEVER">
<interface name="Method" />
@ -251,8 +295,10 @@
<interface name="Steppable" />
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="Stack" schema="Stack" required="yes" fixed="yes" />
<attribute name="Stack" schema="StackFramesContainer" required="yes" fixed="yes" />
<attribute name="Registers" schema="RegisterValueContainer" required="yes" fixed="yes" />
<attribute name="Environment" schema="ANY" fixed="yes" />
<attribute name="Id" schema="STRING" fixed="yes" />
<attribute name="_tid" schema="LONG" hidden="yes" />
<attribute name="_state" schema="EXECUTION_STATE" required="yes" hidden="yes" />
<attribute name="_supported_step_kinds" schema="SET_STEP_KIND" required="yes" fixed="yes" hidden="yes" />
@ -264,7 +310,7 @@
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="Advance" schema="Method" required="yes" fixed="yes" hidden="yes" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="Module" elementResync="NEVER" attributeResync="NEVER">
<interface name="Module" />
@ -282,6 +328,7 @@
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute name="ToDisplayString" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="MemoryRegion" elementResync="NEVER" attributeResync="NEVER">
@ -315,6 +362,19 @@
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="StackFramesContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="Frames" schema="Stack" required="yes" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
<attribute name="_display" schema="STRING" hidden="yes" />
<attribute name="_short_display" schema="STRING" hidden="yes" />
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
</schema>
<schema name="Stack" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
<interface name="Stack" />
<element schema="StackFrame" />
@ -325,7 +385,7 @@
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
<interface name="SymbolNamespace" />
@ -360,7 +420,6 @@
<interface name="Aggregate" />
<element schema="VOID" />
<attribute name="_function" schema="STRING" hidden="yes" />
<attribute name="Registers" schema="RegisterValueContainer" required="yes" fixed="yes" />
<attribute name="_pc" schema="ADDRESS" required="yes" hidden="yes" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />
@ -369,7 +428,7 @@
<attribute name="_kind" schema="STRING" fixed="yes" hidden="yes" />
<attribute name="_order" schema="INT" hidden="yes" />
<attribute name="_modified" schema="BOOL" hidden="yes" />
<attribute schema="VOID" />
<attribute schema="ANY" hidden="yes" />
</schema>
<schema name="Section" elementResync="NEVER" attributeResync="NEVER">
<interface name="Section" />
@ -396,6 +455,9 @@
<attribute name="Floating Point Registers" schema="RegisterBank" />
<attribute name="Advanced Vector Extensions" schema="RegisterBank" />
<attribute name="Memory Protection Extensions" schema="RegisterBank" />
<attribute name="FloatingPoint" schema="RegisterBank" />
<attribute name="SIMD" schema="RegisterBank" />
<attribute name="User" schema="RegisterBank" />
<attribute name="_descriptions" schema="RegisterValueContainer" />
<attribute name="_value" schema="ANY" hidden="yes" />
<attribute name="_type" schema="STRING" hidden="yes" />

View File

@ -29,12 +29,21 @@ import traceback
from comtypes import CoClass, GUID
import comtypes
from comtypes.hresult import S_OK
from pybag import pydbg, userdbg, kerneldbg, crashdbg
from pybag.dbgeng import core as DbgEng
from pybag.dbgeng import exception
from pybag.dbgeng import util as DbgUtil
from pybag.dbgeng.callbacks import DbgEngCallbacks
from dbgmodel.ihostdatamodelaccess import HostDataModelAccess
import comtypes.client
try:
from comtypes.gen import DbgMod
except:
tlb = "..\..\..\..\build\os\win_x86_64\dbgmodel.tlb"
comtypes.client.GetModule(tlb)
from comtypes.gen import DbgMod
DbgVersion = namedtuple('DbgVersion', ['full', 'name', 'dotted', 'arch'])
@ -134,12 +143,12 @@ class DbgExecutor(object):
self._thread.start()
self._executing = False
def submit(self, fn, / , *args, **kwargs):
def submit(self, fn, /, *args, **kwargs):
f = self._submit_no_exit(fn, *args, **kwargs)
self._ghidra_dbg.exit_dispatch()
return f
def _submit_no_exit(self, fn, / , *args, **kwargs):
def _submit_no_exit(self, fn, /, *args, **kwargs):
f = Future()
if self._executing:
f.set_exception(DebuggeeRunningException("Debuggee is Running"))
@ -199,6 +208,7 @@ class GhidraDbg(object):
# Wait for the executor to be operational before getting base
self._queue._submit_no_exit(lambda: None).result()
self._install_stdin()
self.use_generics = os.getenv('OPT_USE_DBGMODEL') == "true"
base = self._protected_base
for name in ['set_output_mask', 'get_output_mask',
@ -447,6 +457,8 @@ def get_breakpoints():
@dbg.eng_thread
def selected_process():
try:
if dbg.use_generics:
return dbg._base._systems.GetCurrentProcessSystemId()
return dbg._base._systems.GetCurrentProcessId()
except exception.E_UNEXPECTED_Error:
return None
@ -455,6 +467,8 @@ def selected_process():
@dbg.eng_thread
def selected_thread():
try:
if dbg.use_generics:
return dbg._base._systems.GetCurrentThreadSystemId()
return dbg._base._systems.GetCurrentThreadId()
except exception.E_UNEXPECTED_Error:
return None
@ -476,11 +490,15 @@ def selected_frame():
@dbg.eng_thread
def select_process(id: int):
if dbg.use_generics:
id = get_proc_id(id)
return dbg._base._systems.SetCurrentProcessId(id)
@dbg.eng_thread
def select_thread(id: int):
if dbg.use_generics:
id = get_thread_id(id)
return dbg._base._systems.SetCurrentThreadId(id)
@ -640,6 +658,101 @@ def thread_list(running=False):
_dbg._systems.SetCurrentThreadId(curid)
@dbg.eng_thread
def get_proc_id(pid):
"""Get the list of all processes"""
# TODO: Implement GetProcessIdBySystemId and replace this logic
_dbg = dbg._base
map = {}
try:
x = _dbg._systems.GetProcessIdsByIndex()
for i in range(0, len(x[0])):
map[x[1][i]] = x[0][i]
return map[pid]
except Exception:
pass
return None
@dbg.eng_thread
def get_thread_id(tid):
"""Get the list of all threads"""
# TODO: Implement GetThreadIdBySystemId and replace this logic
_dbg = dbg._base
map = {}
try:
x = _dbg._systems.GetThreadIdsByIndex()
for i in range(0, len(x[0])):
map[x[1][i]] = x[0][i]
return map[tid]
except Exception:
pass
return None
def split_path(pathString):
list = []
segs = pathString.split(".")
for s in segs:
if s.endswith("]"):
index = s.index("[")
list.append(s[:index])
list.append(s[index:])
else:
list.append(s)
return list
def IHostDataModelAccess():
return HostDataModelAccess(
dbg._base._client._cli.QueryInterface(interface=DbgMod.IHostDataModelAccess))
@dbg.eng_thread
def get_object(relpath):
"""Get the list of all threads"""
_cli = dbg._base._client._cli
access = HostDataModelAccess(_cli.QueryInterface(
interface=DbgMod.IHostDataModelAccess))
(mgr, host) = access.GetDataModel()
root = mgr.GetRootNamespace()
pathstr = "Debugger"
if relpath != '':
pathstr += "."+relpath
path = split_path(pathstr)
return root.GetOffspring(path)
@dbg.eng_thread
def get_attributes(obj):
"""Get the list of attributes"""
return obj.GetAttributes()
@dbg.eng_thread
def get_elements(obj):
"""Get the list of all threads"""
return obj.GetElements()
@dbg.eng_thread
def get_kind(obj):
"""Get the list of all threads"""
return obj.GetKind().value
@dbg.eng_thread
def get_type(obj):
"""Get the list of all threads"""
return obj.GetTypeKind()
@dbg.eng_thread
def get_value(obj):
"""Get the list of all threads"""
return obj.GetValue()
conv_map = {}