mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-09-28 17:11:11 -09:00
GP-326: never say die
GP-326: recompiling to htmnl GP-326: recompiling to htmnl GP-326: last? GP-326: getting there GP-326: roll along GP-326: rolling along GP-326: test fix GP-326: miscellaneous post-review fixes GP-326: complicated stuff GP-326: more simple stuff GP-326: navhead fix GP-326: better docs GP-326: html for md GP-326: html for md GP-326: tutorial edits GP-326: tutorial edits GP-326: re-arranging docs GP-326: from review GP-326: adding a debugger GP-326: docs GP-326: using TestResources - tests pass GP-326: working tests GP-326: most cmd/meth tests working GP-326: cmd tests pass GP-326: passes thru putmem GP-326: one test running GP-326: better startup logic GP-326: first pass tests GP-326: misc cleanup GP-326: cleaner startup GP-326: cleanup GP-326: fixes for crash dump GP-326: util cleanup GP-326: objects cont. GP-326: first pass at objects GP-326: some cleanup GP-326: regions GP-326: sections GP-326: modules GP-326: alt launchers GP-326: symbols GP-326: memory GP-326: stack frame - regs + locals GP-326: frames GP-326: threads GP-326: better start sequence GP-326: working launcher GP-326: util.version GP-326: arch
This commit is contained in:
0
Ghidra/Debug/Debugger-agent-drgn/Module.manifest
Normal file
0
Ghidra/Debug/Debugger-agent-drgn/Module.manifest
Normal file
1
Ghidra/Debug/Debugger-agent-drgn/README.md
Normal file
1
Ghidra/Debug/Debugger-agent-drgn/README.md
Normal file
@@ -0,0 +1 @@
|
||||
# Debugger-agent-drgn
|
||||
20
Ghidra/Debug/Debugger-agent-drgn/build.gradle
Normal file
20
Ghidra/Debug/Debugger-agent-drgn/build.gradle
Normal file
@@ -0,0 +1,20 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
|
||||
apply from: "$rootProject.projectDir/gradle/hasPythonPackage.gradle"
|
||||
|
||||
apply plugin: 'eclipse'
|
||||
eclipse.project.name = 'Debug Debugger-agent-drgn'
|
||||
11
Ghidra/Debug/Debugger-agent-drgn/certification.manifest
Normal file
11
Ghidra/Debug/Debugger-agent-drgn/certification.manifest
Normal file
@@ -0,0 +1,11 @@
|
||||
##VERSION: 2.0
|
||||
##MODULE IP: Apache License 2.0
|
||||
##MODULE IP: Apache License 2.0 with LLVM Exceptions
|
||||
Module.manifest||GHIDRA||||END|
|
||||
README.md||GHIDRA||||END|
|
||||
build.gradle||GHIDRA||||END|
|
||||
src/main/py/LICENSE||GHIDRA||||END|
|
||||
src/main/py/MANIFEST.in||GHIDRA||||END|
|
||||
src/main/py/README.md||GHIDRA||||END|
|
||||
src/main/py/pyproject.toml||GHIDRA||||END|
|
||||
src/main/py/src/ghidradrgn/schema.xml||GHIDRA||||END|
|
||||
32
Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh
Executable file
32
Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/core-drgn.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env bash
|
||||
## ###
|
||||
# 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.
|
||||
##
|
||||
#@title drgn-core
|
||||
#@desc <html><body width="300px">
|
||||
#@desc <h3>Launch with <tt>drgn-core</tt></h3>
|
||||
#@desc <p>
|
||||
#@desc This will attach to an existing core dump using <tt>drgn</tt>.
|
||||
#@desc For setup instructions, press <b>F1</b>.
|
||||
#@desc </p>
|
||||
#@desc </body></html>
|
||||
#@menu-group drgn
|
||||
#@icon icon.debugger
|
||||
#@help TraceRmiLauncherServicePlugin#drgn-core
|
||||
#@env OPT_TARGET_IMG:file!="" "Core dump" "The target core dump"
|
||||
|
||||
export OPT_TARGET_KIND="coredump"
|
||||
drgn -c "$OPT_TARGET_IMG" ../support/local-drgn.py
|
||||
|
||||
31
Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/kernel-drgn.sh
Executable file
31
Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/kernel-drgn.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
## ###
|
||||
# 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.
|
||||
##
|
||||
#@title drgn-kernel
|
||||
#@desc <html><body width="300px">
|
||||
#@desc <h3>Launch with <tt>drgn-kernel</tt></h3>
|
||||
#@desc <p>
|
||||
#@desc This will attach to the local machine's kernel using <tt>drgn</tt>.
|
||||
#@desc For setup instructions, press <b>F1</b>.
|
||||
#@desc </p>
|
||||
#@desc </body></html>
|
||||
#@menu-group drgn
|
||||
#@icon icon.debugger
|
||||
#@help TraceRmiLauncherServicePlugin#drgn-kernel
|
||||
|
||||
export OPT_TARGET_KIND="kernel"
|
||||
sudo -E drgn ../support/local-drgn.py
|
||||
|
||||
34
Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/local-drgn.sh
Executable file
34
Ghidra/Debug/Debugger-agent-drgn/data/debugger-launchers/local-drgn.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
## ###
|
||||
# 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.
|
||||
##
|
||||
#@title drgn
|
||||
#@desc <html><body width="300px">
|
||||
#@desc <h3>Launch with <tt>drgn</tt></h3>
|
||||
#@desc <p>
|
||||
#@desc This will attach to a target running on the local machine using <tt>drgn</tt>.
|
||||
#@desc For setup instructions, press <b>F1</b>.
|
||||
#@desc </p>
|
||||
#@desc </body></html>
|
||||
#@menu-group drgn
|
||||
#@icon icon.debugger
|
||||
#@help TraceRmiLauncherServicePlugin#drgn
|
||||
#@env OPT_TARGET_PID:int=44068 "PID" "The target's process id"
|
||||
|
||||
export OPT_TARGET_KIND="user"
|
||||
# sudo -E drgn -p "$OPT_TARGET_PID" ../support/local-drgn.py
|
||||
# or 'echo 0 > /proc/sys/kernel/yama/ptrace_scope'
|
||||
drgn -p "$OPT_TARGET_PID" ../support/local-drgn.py
|
||||
|
||||
57
Ghidra/Debug/Debugger-agent-drgn/data/support/local-drgn.py
Normal file
57
Ghidra/Debug/Debugger-agent-drgn/data/support/local-drgn.py
Normal file
@@ -0,0 +1,57 @@
|
||||
## ###
|
||||
# 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 drgn:
|
||||
# EASY-INSTALL-ENTRY-SCRIPT: 'drgn==0.0.24','console_scripts','drgn'
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import drgn.cli
|
||||
|
||||
home = os.getenv('GHIDRA_HOME')
|
||||
|
||||
if os.path.isdir(f'{home}/ghidra/.git'):
|
||||
sys.path.append(
|
||||
f'{home}/ghidra/Ghidra/Debug/Debugger-agent-drgn/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-drgn/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-drgn/pypkg/src')
|
||||
sys.path.append(f'{home}/Ghidra/Debug/Debugger-rmi-trace/pypkg/src')
|
||||
|
||||
|
||||
def main():
|
||||
from ghidradrgn import commands as cmd
|
||||
cmd.ghidra_trace_connect(address=os.getenv('GHIDRA_TRACE_RMI_ADDR'))
|
||||
cmd.ghidra_trace_create(start_trace=True)
|
||||
cmd.ghidra_trace_txstart()
|
||||
cmd.ghidra_trace_put_all()
|
||||
cmd.ghidra_trace_txcommit()
|
||||
cmd.ghidra_trace_activate()
|
||||
drgn.cli.run_interactive(cmd.prog)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
11
Ghidra/Debug/Debugger-agent-drgn/src/main/py/LICENSE
Normal file
11
Ghidra/Debug/Debugger-agent-drgn/src/main/py/LICENSE
Normal file
@@ -0,0 +1,11 @@
|
||||
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.
|
||||
1
Ghidra/Debug/Debugger-agent-drgn/src/main/py/MANIFEST.in
Normal file
1
Ghidra/Debug/Debugger-agent-drgn/src/main/py/MANIFEST.in
Normal file
@@ -0,0 +1 @@
|
||||
include src/ghidradrgn/schema.xml
|
||||
3
Ghidra/Debug/Debugger-agent-drgn/src/main/py/README.md
Normal file
3
Ghidra/Debug/Debugger-agent-drgn/src/main/py/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Ghidra Trace RMI for drgn
|
||||
|
||||
Package for connecting drgn to Ghidra via Trace RMI.
|
||||
25
Ghidra/Debug/Debugger-agent-drgn/src/main/py/pyproject.toml
Normal file
25
Ghidra/Debug/Debugger-agent-drgn/src/main/py/pyproject.toml
Normal file
@@ -0,0 +1,25 @@
|
||||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "ghidradrgn"
|
||||
version = "11.3"
|
||||
authors = [
|
||||
{ name="Ghidra Development Team" },
|
||||
]
|
||||
description = "Ghidra's Plugin for drgn"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.7"
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
dependencies = [
|
||||
"ghidratrace==11.3",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://github.com/NationalSecurityAgency/ghidra"
|
||||
"Bug Tracker" = "https://github.com/NationalSecurityAgency/ghidra/issues"
|
||||
@@ -0,0 +1,16 @@
|
||||
## ###
|
||||
# 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 . import util, commands
|
||||
@@ -0,0 +1,209 @@
|
||||
## ###
|
||||
# IP: GHIDRA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
##
|
||||
from ghidratrace.client import Address, RegVal
|
||||
import drgn
|
||||
|
||||
from . import util
|
||||
|
||||
|
||||
# NOTE: This map is derived from the ldefs using a script
|
||||
language_map = {
|
||||
'AARCH64': ['AARCH64:BE:64:v8A', 'AARCH64:LE:64:AppleSilicon', 'AARCH64:LE:64:v8A'],
|
||||
'ARM': ['ARM:BE:32:v8', 'ARM:BE:32:v8T', 'ARM:LE:32:v8', 'ARM:LE:32:v8T'],
|
||||
'PPC64': ['PowerPC:BE:64:4xx', 'PowerPC:LE:64:4xx'],
|
||||
'S390': [],
|
||||
'S390X': [],
|
||||
'I386': ['x86:LE:32:default'],
|
||||
'X86_64': ['x86:LE:64:default'],
|
||||
'UNKNOWN': ['DATA:LE:64:default', 'DATA:LE:64:default'],
|
||||
}
|
||||
|
||||
data64_compiler_map = {
|
||||
None: 'pointer64',
|
||||
}
|
||||
|
||||
default_compiler_map = {
|
||||
'Language.C': 'default',
|
||||
}
|
||||
|
||||
x86_compiler_map = {
|
||||
'Language.C': 'gcc',
|
||||
}
|
||||
|
||||
compiler_map = {
|
||||
'DATA:BE:64:': data64_compiler_map,
|
||||
'DATA:LE:64:': data64_compiler_map,
|
||||
'x86:LE:32:': x86_compiler_map,
|
||||
'x86:LE:64:': x86_compiler_map,
|
||||
'AARCH64:LE:64:': default_compiler_map,
|
||||
'ARM:BE:32:': default_compiler_map,
|
||||
'ARM:LE:32:': default_compiler_map,
|
||||
'PowerPC:BE:64:': default_compiler_map,
|
||||
'PowerPC:LE:64:': default_compiler_map,
|
||||
}
|
||||
|
||||
|
||||
def get_arch():
|
||||
platform = drgn.host_platform
|
||||
return platform.arch.name
|
||||
|
||||
|
||||
def get_endian():
|
||||
parm = util.get_convenience_variable('endian')
|
||||
if parm != 'auto':
|
||||
return parm
|
||||
platform = drgn.host_platform
|
||||
order = platform.flags.IS_LITTLE_ENDIAN
|
||||
if order.value > 0:
|
||||
return 'little'
|
||||
else:
|
||||
return 'big'
|
||||
|
||||
|
||||
def get_size():
|
||||
parm = util.get_convenience_variable('size')
|
||||
if parm != 'auto':
|
||||
return parm
|
||||
platform = drgn.host_platform
|
||||
order = platform.flags.IS_64_BIT
|
||||
if order.value > 0:
|
||||
return '64'
|
||||
else:
|
||||
return '32'
|
||||
|
||||
|
||||
def get_osabi():
|
||||
return "Language.C"
|
||||
|
||||
|
||||
def compute_ghidra_language():
|
||||
# First, check if the parameter is set
|
||||
lang = util.get_convenience_variable('ghidra-language')
|
||||
if lang != 'auto':
|
||||
return lang
|
||||
|
||||
# Get the list of possible languages for the arch. We'll need to sift
|
||||
# through them by endian and probably prefer default/simpler variants. The
|
||||
# heuristic for "simpler" will be 'default' then shortest variant id.
|
||||
arch = get_arch()
|
||||
endian = get_endian()
|
||||
sz = get_size()
|
||||
lebe = ':BE:' if endian == 'big' else ':LE:'
|
||||
if not arch in language_map:
|
||||
return 'DATA' + lebe + sz +':default'
|
||||
langs = language_map[arch]
|
||||
matched_endian = sorted(
|
||||
(l for l in langs if lebe in l),
|
||||
key=lambda l: 0 if l.endswith(':default') else len(l)
|
||||
)
|
||||
if len(matched_endian) > 0:
|
||||
return matched_endian[0]
|
||||
# NOTE: I'm disinclined to fall back to a language match with wrong endian.
|
||||
return 'DATA' + lebe + sz + ':default'
|
||||
|
||||
|
||||
def compute_ghidra_compiler(lang):
|
||||
# First, check if the parameter is set
|
||||
comp = util.get_convenience_variable('ghidra-compiler')
|
||||
if comp != 'auto':
|
||||
return comp
|
||||
|
||||
# Check if the selected lang has specific compiler recommendations
|
||||
matched_lang = sorted(
|
||||
(l for l in compiler_map if l in lang),
|
||||
# key=lambda l: compiler_map[l]
|
||||
)
|
||||
if len(matched_lang) == 0:
|
||||
print(f"{lang} not found in compiler map - using default compiler")
|
||||
return 'default'
|
||||
|
||||
comp_map = compiler_map[matched_lang[0]]
|
||||
if comp_map == data64_compiler_map:
|
||||
print(f"Using the DATA64 compiler map")
|
||||
osabi = get_osabi()
|
||||
if osabi in comp_map:
|
||||
return comp_map[osabi]
|
||||
if lang.startswith("X86:"):
|
||||
print(f"{osabi} not found in compiler map - using gcc")
|
||||
return 'gcc'
|
||||
if None in comp_map:
|
||||
return comp_map[None]
|
||||
print(f"{osabi} not found in compiler map - using default compiler")
|
||||
return 'default'
|
||||
|
||||
|
||||
def compute_ghidra_lcsp():
|
||||
lang = compute_ghidra_language()
|
||||
comp = compute_ghidra_compiler(lang)
|
||||
return lang, comp
|
||||
|
||||
|
||||
class DefaultMemoryMapper(object):
|
||||
|
||||
def __init__(self, defaultSpace):
|
||||
self.defaultSpace = defaultSpace
|
||||
|
||||
def map(self, proc: drgn.Program, offset: int):
|
||||
space = self.defaultSpace
|
||||
return self.defaultSpace, Address(space, offset)
|
||||
|
||||
def map_back(self, proc: drgn.Program, address: Address) -> int:
|
||||
if address.space == self.defaultSpace:
|
||||
return address.offset
|
||||
raise ValueError(
|
||||
f"Address {address} is not in process {proc}")
|
||||
|
||||
|
||||
DEFAULT_MEMORY_MAPPER = DefaultMemoryMapper('ram')
|
||||
|
||||
memory_mappers = {}
|
||||
|
||||
|
||||
def compute_memory_mapper(lang):
|
||||
if not lang in memory_mappers:
|
||||
return DEFAULT_MEMORY_MAPPER
|
||||
return memory_mappers[lang]
|
||||
|
||||
|
||||
class DefaultRegisterMapper(object):
|
||||
|
||||
def __init__(self, byte_order):
|
||||
if not byte_order in ['big', 'little']:
|
||||
raise ValueError("Invalid byte_order: {}".format(byte_order))
|
||||
self.byte_order = byte_order
|
||||
self.union_winners = {}
|
||||
|
||||
def map_name(self, proc, name):
|
||||
return name
|
||||
|
||||
def map_value(self, proc, name, value):
|
||||
return RegVal(self.map_name(proc, name), value)
|
||||
|
||||
def map_name_back(self, proc, name):
|
||||
return name
|
||||
|
||||
def map_value_back(self, proc, name, value):
|
||||
return RegVal(self.map_name_back(proc, name), value)
|
||||
|
||||
|
||||
DEFAULT_BE_REGISTER_MAPPER = DefaultRegisterMapper('big')
|
||||
DEFAULT_LE_REGISTER_MAPPER = DefaultRegisterMapper('little')
|
||||
|
||||
def compute_register_mapper(lang):
|
||||
if ':BE:' in lang:
|
||||
return DEFAULT_BE_REGISTER_MAPPER
|
||||
else:
|
||||
return DEFAULT_LE_REGISTER_MAPPER
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,249 @@
|
||||
## ###
|
||||
# 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 threading
|
||||
import time
|
||||
|
||||
import drgn
|
||||
|
||||
from . import commands, util
|
||||
|
||||
|
||||
ALL_EVENTS = 0xFFFF
|
||||
|
||||
|
||||
class HookState(object):
|
||||
__slots__ = ('installed', 'mem_catchpoint')
|
||||
|
||||
def __init__(self):
|
||||
self.installed = False
|
||||
self.mem_catchpoint = None
|
||||
|
||||
|
||||
class ProcessState(object):
|
||||
__slots__ = ('first', 'regions', 'modules', 'threads',
|
||||
'breaks', 'watches', 'visited')
|
||||
|
||||
def __init__(self):
|
||||
self.first = True
|
||||
# For things we can detect changes to between stops
|
||||
self.regions = False
|
||||
self.modules = False
|
||||
self.threads = False
|
||||
self.breaks = False
|
||||
self.watches = False
|
||||
# For frames and threads that have already been synced since last stop
|
||||
self.visited = set()
|
||||
|
||||
def record(self, description=None):
|
||||
first = self.first
|
||||
self.first = False
|
||||
if description is not None:
|
||||
commands.STATE.trace.snapshot(description)
|
||||
if first:
|
||||
commands.put_processes()
|
||||
commands.put_environment()
|
||||
if self.threads:
|
||||
commands.put_threads()
|
||||
self.threads = False
|
||||
nthrd = util.selected_thread()
|
||||
if nthrd is not None:
|
||||
if first or nthrd not in self.visited:
|
||||
commands.put_frames()
|
||||
self.visited.add(nthrd)
|
||||
level = util.selected_frame()
|
||||
hashable_frame = (nthrd, level)
|
||||
if first or hashable_frame not in self.visited:
|
||||
commands.putreg()
|
||||
try:
|
||||
commands.putmem(commands.get_pc(), 1, True, True)
|
||||
except BaseException as e:
|
||||
print(f"Couldn't record page with PC: {e}")
|
||||
try:
|
||||
commands.putmem(commands.get_sp(), 1, True, True)
|
||||
except BaseException as e:
|
||||
print(f"Couldn't record page with SP: {e}")
|
||||
self.visited.add(hashable_frame)
|
||||
if first or self.regions or self.modules:
|
||||
# Sections, memory syscalls, or stack allocations
|
||||
commands.put_regions()
|
||||
self.regions = False
|
||||
if first or self.modules:
|
||||
commands.put_modules()
|
||||
self.modules = False
|
||||
|
||||
def record_continued(self):
|
||||
commands.put_processes()
|
||||
commands.put_threads()
|
||||
|
||||
def record_exited(self, exit_code):
|
||||
nproc = util.selected_process()
|
||||
ipath = commands.PROCESS_PATTERN.format(procnum=nproc)
|
||||
procobj = commands.STATE.trace.proxy_object_path(ipath)
|
||||
procobj.set_value('Exit Code', exit_code)
|
||||
procobj.set_value('State', 'TERMINATED')
|
||||
|
||||
|
||||
HOOK_STATE = HookState()
|
||||
PROC_STATE = {}
|
||||
|
||||
def on_new_process(event):
|
||||
trace = commands.STATE.trace
|
||||
if trace is None:
|
||||
return
|
||||
with commands.STATE.client.batch():
|
||||
with trace.open_tx("New Process {}".format(event.process.num)):
|
||||
commands.put_processes() # TODO: Could put just the one....
|
||||
|
||||
|
||||
def on_process_selected():
|
||||
nproc = util.selected_process()
|
||||
if nproc not in PROC_STATE:
|
||||
return
|
||||
trace = commands.STATE.trace
|
||||
if trace is None:
|
||||
return
|
||||
with commands.STATE.client.batch():
|
||||
with trace.open_tx("Process {} selected".format(nproc)):
|
||||
PROC_STATE[nproc].record()
|
||||
commands.activate()
|
||||
|
||||
|
||||
def on_new_thread(event):
|
||||
nproc = util.selected_process()
|
||||
if nproc not in PROC_STATE:
|
||||
return
|
||||
PROC_STATE[nproc].threads = True
|
||||
|
||||
|
||||
def on_thread_selected():
|
||||
nproc = util.selected_process()
|
||||
if nproc not in PROC_STATE:
|
||||
return
|
||||
trace = commands.STATE.trace
|
||||
if trace is None:
|
||||
return
|
||||
nthrd = util.selected_thread()
|
||||
with commands.STATE.client.batch():
|
||||
with trace.open_tx("Thread {}.{} selected".format(nproc, nthrd)):
|
||||
PROC_STATE[nproc].record()
|
||||
commands.put_threads()
|
||||
commands.activate()
|
||||
|
||||
|
||||
def on_frame_selected():
|
||||
nproc = util.selected_process()
|
||||
if nproc not in PROC_STATE:
|
||||
return
|
||||
trace = commands.STATE.trace
|
||||
if trace is None:
|
||||
return
|
||||
nthrd = util.selected_thread()
|
||||
level = util.selected_frame()
|
||||
with commands.STATE.client.batch():
|
||||
with trace.open_tx("Frame {}.{}.{} selected".format(nproc, nthrd, level)):
|
||||
PROC_STATE[nproc].record()
|
||||
commands.put_threads()
|
||||
commands.put_frames()
|
||||
commands.activate()
|
||||
|
||||
|
||||
def on_memory_changed(event):
|
||||
nproc = util.get_process()
|
||||
if nproc not in PROC_STATE:
|
||||
return
|
||||
trace = commands.STATE.trace
|
||||
if trace is None:
|
||||
return
|
||||
with commands.STATE.client.batch():
|
||||
with trace.open_tx("Memory *0x{:08x} changed".format(event.address)):
|
||||
commands.put_bytes(event.address, event.address + event.length,
|
||||
pages=False, is_mi=False, result=None)
|
||||
|
||||
|
||||
def on_register_changed(event):
|
||||
nproc = util.get_process()
|
||||
if nproc not in PROC_STATE:
|
||||
return
|
||||
trace = commands.STATE.trace
|
||||
if trace is None:
|
||||
return
|
||||
with commands.STATE.client.batch():
|
||||
with trace.open_tx("Register {} changed".format(event.regnum)):
|
||||
commands.putreg()
|
||||
|
||||
|
||||
def on_cont(event):
|
||||
nproc = util.selected_process()
|
||||
if nproc not in PROC_STATE:
|
||||
return
|
||||
trace = commands.STATE.trace
|
||||
if trace is None:
|
||||
return
|
||||
state = PROC_STATE[nproc]
|
||||
with commands.STATE.client.batch():
|
||||
with trace.open_tx("Continued"):
|
||||
state.record_continued()
|
||||
|
||||
|
||||
def on_stop(event):
|
||||
nproc = util.selected_process()
|
||||
if nproc not in PROC_STATE:
|
||||
PROC_STATE[nproc] = ProcessState()
|
||||
trace = commands.STATE.trace
|
||||
if trace is None:
|
||||
print("no trace")
|
||||
return
|
||||
state = PROC_STATE[nproc]
|
||||
state.visited.clear()
|
||||
with commands.STATE.client.batch():
|
||||
with trace.open_tx("Stopped"):
|
||||
state.record("Stopped")
|
||||
commands.put_threads()
|
||||
commands.put_frames()
|
||||
commands.activate()
|
||||
|
||||
|
||||
def modules_changed():
|
||||
nproc = util.selected_process()
|
||||
if nproc not in PROC_STATE:
|
||||
return
|
||||
PROC_STATE[nproc].modules = True
|
||||
|
||||
|
||||
def install_hooks():
|
||||
if HOOK_STATE.installed:
|
||||
return
|
||||
HOOK_STATE.installed = True
|
||||
|
||||
event_thread = EventThread()
|
||||
event_thread.start()
|
||||
|
||||
|
||||
def remove_hooks():
|
||||
if not HOOK_STATE.installed:
|
||||
return
|
||||
HOOK_STATE.installed = False
|
||||
|
||||
|
||||
def enable_current_process():
|
||||
nproc = util.selected_process()
|
||||
PROC_STATE[nproc] = ProcessState()
|
||||
|
||||
|
||||
def disable_current_process():
|
||||
nproc = util.selected_process()
|
||||
if nproc in PROC_STATE:
|
||||
del PROC_STATE[nproc]
|
||||
@@ -0,0 +1,388 @@
|
||||
## ###
|
||||
# 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 concurrent.futures import Future, ThreadPoolExecutor
|
||||
from contextlib import redirect_stdout
|
||||
from io import StringIO
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
import drgn
|
||||
import drgn.cli
|
||||
|
||||
from ghidratrace import sch
|
||||
from ghidratrace.client import MethodRegistry, ParamDesc, Address, AddressRange
|
||||
|
||||
from . import util, commands, hooks
|
||||
|
||||
|
||||
REGISTRY = MethodRegistry(ThreadPoolExecutor(
|
||||
max_workers=1, thread_name_prefix='MethodRegistry'))
|
||||
|
||||
|
||||
def extre(base, ext):
|
||||
return re.compile(base.pattern + ext)
|
||||
|
||||
|
||||
PROCESSES_PATTERN = re.compile('Processes')
|
||||
PROCESS_PATTERN = extre(PROCESSES_PATTERN, '\[(?P<procnum>\\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')
|
||||
FRAME_PATTERN = extre(STACK_PATTERN, '\[(?P<level>\\d*)\]')
|
||||
REGS_PATTERN = extre(FRAME_PATTERN, '.Registers')
|
||||
LOCALS_PATTERN = extre(FRAME_PATTERN, '.Locals')
|
||||
MEMORY_PATTERN = extre(PROCESS_PATTERN, '\.Memory')
|
||||
MODULES_PATTERN = extre(PROCESS_PATTERN, '\.Modules')
|
||||
MODULE_PATTERN = extre(MODULES_PATTERN, '\[(?P<modbase>.*)\]')
|
||||
|
||||
|
||||
def find_availpid_by_pattern(pattern, object, err_msg):
|
||||
mat = pattern.fullmatch(object.path)
|
||||
if mat is None:
|
||||
raise TypeError(f"{object} is not {err_msg}")
|
||||
pid = int(mat['pid'])
|
||||
return pid
|
||||
|
||||
|
||||
def find_availpid_by_obj(object):
|
||||
return find_availpid_by_pattern(AVAILABLE_PATTERN, object, "an Available")
|
||||
|
||||
|
||||
def find_proc_by_num(id):
|
||||
if id != util.selected_process():
|
||||
util.select_process(id)
|
||||
return util.selected_process()
|
||||
|
||||
|
||||
def find_proc_by_pattern(object, pattern, err_msg):
|
||||
mat = pattern.fullmatch(object.path)
|
||||
if mat is None:
|
||||
raise TypeError(f"{object} is not {err_msg}")
|
||||
procnum = int(mat['procnum'])
|
||||
return find_proc_by_num(procnum)
|
||||
|
||||
|
||||
def find_proc_by_obj(object):
|
||||
return find_proc_by_pattern(object, PROCESS_PATTERN, "an Process")
|
||||
|
||||
|
||||
def find_proc_by_env_obj(object):
|
||||
return find_proc_by_pattern(object, ENV_PATTERN, "an Environment")
|
||||
|
||||
|
||||
def find_proc_by_threads_obj(object):
|
||||
return find_proc_by_pattern(object, THREADS_PATTERN, "a ThreadContainer")
|
||||
|
||||
|
||||
def find_proc_by_mem_obj(object):
|
||||
return find_proc_by_pattern(object, MEMORY_PATTERN, "a Memory")
|
||||
|
||||
|
||||
def find_proc_by_modules_obj(object):
|
||||
return find_proc_by_pattern(object, MODULES_PATTERN, "a ModuleContainer")
|
||||
|
||||
|
||||
def find_thread_by_num(id):
|
||||
if id != util.selected_thread():
|
||||
util.select_thread(id)
|
||||
return util.selected_thread()
|
||||
|
||||
|
||||
def find_thread_by_pattern(pattern, object, err_msg):
|
||||
mat = pattern.fullmatch(object.path)
|
||||
if mat is None:
|
||||
raise TypeError(f"{object} is not {err_msg}")
|
||||
pnum = int(mat['procnum'])
|
||||
tnum = int(mat['tnum'])
|
||||
find_proc_by_num(pnum)
|
||||
return find_thread_by_num(tnum)
|
||||
|
||||
|
||||
def find_thread_by_obj(object):
|
||||
return find_thread_by_pattern(THREAD_PATTERN, object, "a Thread")
|
||||
|
||||
|
||||
def find_thread_by_stack_obj(object):
|
||||
return find_thread_by_pattern(STACK_PATTERN, object, "a Stack")
|
||||
|
||||
|
||||
def find_thread_by_regs_obj(object):
|
||||
return find_thread_by_pattern(REGS_PATTERN, object, "a RegisterValueContainer")
|
||||
|
||||
|
||||
def find_frame_by_level(level):
|
||||
tnum = util.selected_thread()
|
||||
thread = commands.prog.thread(tnum)
|
||||
try:
|
||||
frames = thread.stack_trace()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
for i,f in enumerate(frames):
|
||||
if i == level:
|
||||
if i != util.selected_frame():
|
||||
util.select_frame(i)
|
||||
return i,f
|
||||
|
||||
|
||||
def find_frame_by_pattern(pattern, object, err_msg):
|
||||
mat = pattern.fullmatch(object.path)
|
||||
if mat is None:
|
||||
raise TypeError(f"{object} is not {err_msg}")
|
||||
pnum = int(mat['procnum'])
|
||||
tnum = int(mat['tnum'])
|
||||
level = int(mat['level'])
|
||||
find_proc_by_num(pnum)
|
||||
find_thread_by_num(tnum)
|
||||
return find_frame_by_level(level)
|
||||
|
||||
|
||||
def find_frame_by_obj(object):
|
||||
return find_frame_by_pattern(FRAME_PATTERN, object, "a StackFrame")
|
||||
|
||||
|
||||
def find_frame_by_regs_obj(object):
|
||||
return find_frame_by_pattern(REGS_PATTERN, object, "a RegisterValueContainer")
|
||||
|
||||
|
||||
def find_frame_by_locals_obj(object):
|
||||
return find_frame_by_pattern(LOCALS_PATTERN, object, "a LocalsContainer")
|
||||
|
||||
|
||||
def find_module_by_base(modbase):
|
||||
for m in commands.prog.modules():
|
||||
if modbase == str(hex(m.address_range[0])):
|
||||
return m
|
||||
|
||||
|
||||
def find_module_by_pattern(pattern, object, err_msg):
|
||||
mat = pattern.fullmatch(object.path)
|
||||
if mat is None:
|
||||
raise TypeError(f"{object} is not {err_msg}")
|
||||
pnum = int(mat['procnum'])
|
||||
modbase = mat['modbase']
|
||||
find_proc_by_num(pnum)
|
||||
return find_module_by_base(modbase)
|
||||
|
||||
|
||||
def find_module_by_obj(object):
|
||||
return find_module_by_pattern(MODULE_PATTERN, object, "a Module")
|
||||
|
||||
|
||||
shared_globals = dict()
|
||||
|
||||
|
||||
@REGISTRY.method
|
||||
def execute(cmd: str, to_string: bool=False):
|
||||
"""Execute a Python3 command or script."""
|
||||
if to_string:
|
||||
data = StringIO()
|
||||
with redirect_stdout(data):
|
||||
exec(cmd, shared_globals)
|
||||
return data.getvalue()
|
||||
else:
|
||||
exec(cmd, shared_globals)
|
||||
|
||||
|
||||
@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_processes()
|
||||
|
||||
|
||||
@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', 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', display='Refresh Symbols')
|
||||
# def refresh_symbols(node: sch.Schema('SymbolContainer')):
|
||||
# """Refresh the list of symbols in the process."""
|
||||
# with commands.open_tracked_tx('Refresh Symbols'):
|
||||
# commands.ghidra_trace_put_symbols()
|
||||
|
||||
|
||||
@REGISTRY.method(action='show_symbol', display='Retrieve Symbols')
|
||||
def retrieve_symbols(
|
||||
session: sch.Schema('SymbolContainer'),
|
||||
pattern: ParamDesc(str, display='Pattern')):
|
||||
"""
|
||||
Load the symbol set matching the pattern.
|
||||
"""
|
||||
with commands.open_tracked_tx('Retrieve Symbols'):
|
||||
commands.put_symbols(pattern)
|
||||
|
||||
|
||||
@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)
|
||||
with commands.open_tracked_tx('Refresh Stack'):
|
||||
commands.ghidra_trace_put_frames()
|
||||
|
||||
|
||||
@REGISTRY.method(action='refresh', display='Refresh Registers')
|
||||
def refresh_registers(node: sch.Schema('RegisterValueContainer')):
|
||||
"""Refresh the register values for the selected frame"""
|
||||
level = find_frame_by_regs_obj(node)
|
||||
with commands.open_tracked_tx('Refresh Registers'):
|
||||
commands.ghidra_trace_putreg()
|
||||
|
||||
|
||||
@REGISTRY.method(action='refresh', display='Refresh Locals')
|
||||
def refresh_locals(node: sch.Schema('LocalsContainer')):
|
||||
"""Refresh the local values for the selected frame"""
|
||||
level = find_frame_by_locals_obj(node)
|
||||
with commands.open_tracked_tx('Refresh Registers'):
|
||||
commands.ghidra_trace_put_locals()
|
||||
|
||||
|
||||
@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', display='Refresh Modules')
|
||||
def refresh_modules(node: sch.Schema('ModuleContainer')):
|
||||
"""
|
||||
Refresh the modules list for the process.
|
||||
"""
|
||||
with commands.open_tracked_tx('Refresh Modules'):
|
||||
commands.ghidra_trace_put_modules()
|
||||
|
||||
|
||||
@REGISTRY.method(action='activate')
|
||||
def activate_process(process: sch.Schema('Process')):
|
||||
"""Switch to the process."""
|
||||
find_proc_by_obj(process)
|
||||
|
||||
|
||||
@REGISTRY.method(action='activate')
|
||||
def activate_thread(thread: sch.Schema('Thread')):
|
||||
"""Switch to the thread."""
|
||||
find_thread_by_obj(thread)
|
||||
|
||||
|
||||
@REGISTRY.method(action='activate')
|
||||
def activate_frame(frame: sch.Schema('StackFrame')):
|
||||
"""Select the frame."""
|
||||
i,f = find_frame_by_obj(frame)
|
||||
util.select_frame(i)
|
||||
with commands.open_tracked_tx('Refresh Stack'):
|
||||
commands.ghidra_trace_put_frames()
|
||||
with commands.open_tracked_tx('Refresh Registers'):
|
||||
commands.ghidra_trace_putreg()
|
||||
|
||||
|
||||
@REGISTRY.method
|
||||
def read_mem(process: sch.Schema('Process'), range: AddressRange):
|
||||
"""Read memory."""
|
||||
# print("READ_MEM: process={}, range={}".format(process, range))
|
||||
nproc = find_proc_by_obj(process)
|
||||
offset_start = process.trace.memory_mapper.map_back(
|
||||
nproc, Address(range.space, range.min))
|
||||
with commands.open_tracked_tx('Read Memory'):
|
||||
result = commands.put_bytes(
|
||||
offset_start, offset_start + range.length() - 1, pages=True, display_result=False)
|
||||
if result['count'] == 0:
|
||||
commands.putmem_state(
|
||||
offset_start, offset_start+range.length() - 1, 'error')
|
||||
|
||||
|
||||
@REGISTRY.method(action='attach', display='Attach by pid')
|
||||
def attach_pid(
|
||||
processes: sch.Schema('ProcessContainer'),
|
||||
pid: ParamDesc(str, display='PID')):
|
||||
"""Attach the process to the given target."""
|
||||
prog = drgn.Program()
|
||||
prog.set_pid(int(pid))
|
||||
util.selected_pid = int(pid)
|
||||
util.selected_tid = prog.main_thread().tid
|
||||
default_symbols = {"default": True, "main": True}
|
||||
try:
|
||||
prog.load_debug_info(None, **default_symbols)
|
||||
except drgn.MissingDebugInfoError as e:
|
||||
print(e)
|
||||
#commands.ghidra_trace_start(pid)
|
||||
commands.PROGRAMS[pid] = prog
|
||||
commands.prog = prog
|
||||
with commands.open_tracked_tx('Refresh Processes'):
|
||||
commands.ghidra_trace_put_processes()
|
||||
|
||||
|
||||
@REGISTRY.method(action='attach', display='Attach core dump')
|
||||
def attach_core(
|
||||
processes: sch.Schema('ProcessContainer'),
|
||||
core: ParamDesc(str, display='Core dump')):
|
||||
"""Attach the process to the given target."""
|
||||
prog = drgn.Program()
|
||||
prog.set_core_dump(core)
|
||||
default_symbols = {"default": True, "main": True}
|
||||
try:
|
||||
prog.load_debug_info(None, **default_symbols)
|
||||
except drgn.MissingDebugInfoError as e:
|
||||
print(e)
|
||||
|
||||
util.selected_pid += 1
|
||||
commands.PROGRAMS[util.selected_pid] = prog
|
||||
commands.prog = prog
|
||||
with commands.open_tracked_tx('Refresh Processes'):
|
||||
commands.ghidra_trace_put_processes()
|
||||
|
||||
|
||||
@REGISTRY.method(action='step_into')
|
||||
def step_into(thread: sch.Schema('Thread'), n: ParamDesc(int, display='N')=1):
|
||||
"""Step one instruction exactly."""
|
||||
find_thread_by_obj(thread)
|
||||
time.sleep(1)
|
||||
hooks.on_stop(None)
|
||||
|
||||
|
||||
# @REGISTRY.method
|
||||
# def kill(process: sch.Schema('Process')):
|
||||
# """Kill execution of the process."""
|
||||
# commands.ghidra_trace_kill()
|
||||
|
||||
|
||||
# @REGISTRY.method(action='resume')
|
||||
# def go(process: sch.Schema('Process')):
|
||||
# """Continue execution of the process."""
|
||||
# util.dbg.run_async(lambda: dbg().go())
|
||||
|
||||
|
||||
# @REGISTRY.method
|
||||
# def interrupt(process: sch.Schema('Process')):
|
||||
# """Interrupt the execution of the debugged program."""
|
||||
# # SetInterrupt is reentrant, so bypass the thread checks
|
||||
# util.dbg._protected_base._control.SetInterrupt(
|
||||
# DbgEng.DEBUG_INTERRUPT_ACTIVE)
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
<context>
|
||||
<schema name="DrgnRoot" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<attribute name="Processes" schema="ProcessContainer" required="yes" fixed="yes" />
|
||||
<attribute name="State" schema="ANY" />
|
||||
<attribute-alias from="_state" to="State" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY"/>
|
||||
</schema>
|
||||
<schema name="Selectable" elementResync="NEVER" attributeResync="NEVER">
|
||||
<element schema="OBJECT" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="ProcessContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<element schema="Process" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Process" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Activatable" />
|
||||
<interface name="Process" />
|
||||
<interface name="Aggregate" />
|
||||
<interface name="ExecutionStateful" />
|
||||
<element schema="VOID" />
|
||||
<attribute name="Threads" schema="ThreadContainer" required="yes" fixed="yes" />
|
||||
<attribute name="Symbols" schema="SymbolContainer" required="yes" fixed="yes" />
|
||||
<attribute name="Exit Code" schema="LONG" />
|
||||
<attribute-alias from="_exit_code" to="Exit Code" />
|
||||
<attribute name="Environment" schema="Environment" required="yes" fixed="yes" />
|
||||
<attribute name="Memory" schema="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-alias from="_pid" to="PID" />
|
||||
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
|
||||
<attribute-alias from="_state" to="State" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Environment" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Environment" />
|
||||
<element schema="VOID" />
|
||||
<attribute name="OS" schema="STRING" />
|
||||
<attribute name="Arch" schema="STRING" />
|
||||
<attribute name="Endian" schema="STRING" />
|
||||
<attribute name="Debugger" schema="STRING" />
|
||||
<attribute-alias from="_os" to="OS" />
|
||||
<attribute-alias from="_arch" to="Arch" />
|
||||
<attribute-alias from="_endian" to="Endian" />
|
||||
<attribute-alias from="_debugger" to="Debugger" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="ModuleContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||
<element schema="Module" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Memory" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Memory" />
|
||||
<element schema="MemoryRegion" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="ThreadContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<element schema="Thread" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Thread" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Activatable" />
|
||||
<interface name="Thread" />
|
||||
<interface name="ExecutionStateful" />
|
||||
<interface name="Aggregate" />
|
||||
<element schema="VOID" />
|
||||
<attribute name="Stack" schema="Stack" required="yes" fixed="yes" />
|
||||
<attribute name="Environment" schema="ANY" fixed="yes" />
|
||||
<attribute name="Id" schema="STRING" fixed="yes" />
|
||||
<attribute name="TID" schema="LONG" />
|
||||
<attribute-alias from="_tid" to="TID" />
|
||||
<attribute name="State" schema="EXECUTION_STATE" required="yes" hidden="yes" />
|
||||
<attribute-alias from="_state" to="State" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_short_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Module" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Module" />
|
||||
<element schema="VOID" />
|
||||
<attribute name="Sections" schema="SectionContainer" required="yes" fixed="yes" />
|
||||
<attribute name="Symbols" schema="SymbolContainer" required="yes" fixed="yes" />
|
||||
<attribute name="Range" schema="RANGE" />
|
||||
<attribute name="Name" schema="STRING" />
|
||||
<attribute-alias from="_module_name" to="Name" />
|
||||
<attribute-alias from="_range" to="Range" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute name="ToDisplayString" schema="BOOL" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="MemoryRegion" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="MemoryRegion" />
|
||||
<element schema="VOID" />
|
||||
<attribute name="Object File" schema="STRING" fixed="yes" />
|
||||
<attribute name="_readable" schema="BOOL" required="yes" hidden="yes" />
|
||||
<attribute name="_writable" schema="BOOL" required="yes" hidden="yes" />
|
||||
<attribute name="_executable" schema="BOOL" required="yes" hidden="yes" />
|
||||
<attribute name="Range" schema="RANGE" required="yes" />
|
||||
<attribute-alias from="_range" to="Range" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="SectionContainer" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<element schema="Section" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="Stack" canonical="yes" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Stack" />
|
||||
<element schema="StackFrame" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="SymbolContainer" canonical="yes" elementResync="ONCE" attributeResync="NEVER">
|
||||
<element schema="Symbol" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="Symbol" elementResync="NEVER" attributeResync="NEVER">
|
||||
<element schema="VOID" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="StackFrame" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Activatable" />
|
||||
<interface name="StackFrame" />
|
||||
<interface name="Aggregate" />
|
||||
<element schema="VOID" />
|
||||
<attribute name="Function" schema="STRING" hidden="yes" />
|
||||
<attribute-alias from="_function" to="Function" />
|
||||
<attribute name="PC" schema="ADDRESS" required="yes" />
|
||||
<attribute-alias from="_pc" to="PC" />
|
||||
<attribute name="SP" schema="ADDRESS" />
|
||||
<attribute name="Registers" schema="RegisterValueContainer" required="yes" fixed="yes" />
|
||||
<attribute name="Locals" schema="LocalsContainer" required="yes" fixed="yes" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
<schema name="Section" elementResync="NEVER" attributeResync="NEVER">
|
||||
<interface name="Section" />
|
||||
<element schema="VOID" />
|
||||
<attribute name="Range" schema="RANGE" />
|
||||
<attribute-alias from="_range" to="Range" />
|
||||
<attribute name="Offset" schema="STRING" fixed="yes" />
|
||||
<attribute name="_display" schema="STRING" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="RegisterValueContainer" attributeResync="ONCE">
|
||||
<interface name="RegisterContainer" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="VOID" />
|
||||
</schema>
|
||||
<schema name="LocalsContainer" attributeResync="ONCE">
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="Local" />
|
||||
</schema>
|
||||
<schema name="Local" attributeResync="ONCE">
|
||||
<attribute name="Address" schema="ADDRESS" />
|
||||
<attribute name="Kind" schema="ANY" hidden="yes" />
|
||||
<attribute name="_order" schema="INT" hidden="yes" />
|
||||
<attribute schema="ANY" />
|
||||
</schema>
|
||||
</context>
|
||||
@@ -0,0 +1,115 @@
|
||||
## ###
|
||||
# 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 collections import namedtuple
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
import drgn
|
||||
import drgn.cli
|
||||
|
||||
|
||||
DrgnVersion = namedtuple('DrgnVersion', ['display', 'full'])
|
||||
|
||||
selected_pid = 0
|
||||
selected_tid = 0
|
||||
selected_level = 0
|
||||
|
||||
|
||||
def _compute_drgn_ver():
|
||||
blurb = drgn.cli.version_header()
|
||||
top = blurb.split('\n')[0]
|
||||
full = top.split()[1] # "drgn x.y.z"
|
||||
return DrgnVersion(top, full)
|
||||
|
||||
|
||||
DRGN_VERSION = _compute_drgn_ver()
|
||||
|
||||
def full_mem(self):
|
||||
return Region(0, 1 << 64, 0, None, 'full memory')
|
||||
|
||||
|
||||
def get_debugger():
|
||||
return drgn
|
||||
|
||||
|
||||
def get_target():
|
||||
return commands.prog
|
||||
|
||||
|
||||
def get_process(name):
|
||||
return get_target()[name]
|
||||
|
||||
|
||||
def selected_process():
|
||||
return selected_pid
|
||||
|
||||
|
||||
def selected_thread():
|
||||
return selected_tid
|
||||
|
||||
|
||||
def selected_frame():
|
||||
return selected_level
|
||||
|
||||
|
||||
def select_process(id: int):
|
||||
global selected_pid
|
||||
selected_pid = id
|
||||
return selected_pid
|
||||
|
||||
|
||||
def select_thread(id: int):
|
||||
global selected_tid
|
||||
selected_tid = id
|
||||
return selected_tid
|
||||
|
||||
|
||||
def select_frame(id: int):
|
||||
global selected_level
|
||||
selected_level = id
|
||||
return selected_level
|
||||
|
||||
|
||||
conv_map = {}
|
||||
|
||||
|
||||
def get_convenience_variable(id):
|
||||
#val = get_target().GetEnvironment().Get(id)
|
||||
if id not in conv_map:
|
||||
return "auto"
|
||||
val = conv_map[id]
|
||||
if val is None:
|
||||
return "auto"
|
||||
return val
|
||||
|
||||
|
||||
def set_convenience_variable(id, value):
|
||||
#env = get_target().GetEnvironment()
|
||||
# return env.Set(id, value, True)
|
||||
conv_map[id] = value
|
||||
|
||||
|
||||
def escape_ansi(line):
|
||||
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]')
|
||||
return ansi_escape.sub('', line)
|
||||
|
||||
|
||||
def debracket(init):
|
||||
val = init
|
||||
val = val.replace("[", "(")
|
||||
val = val.replace("]", ")")
|
||||
return val
|
||||
Reference in New Issue
Block a user