ghidraxdbg 12.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ghidraxdbg/methods.py ADDED
@@ -0,0 +1,680 @@
1
+ ## ###
2
+ # IP: GHIDRA
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ ##
16
+ from concurrent.futures import Future, ThreadPoolExecutor
17
+ from contextlib import redirect_stdout
18
+ from io import StringIO
19
+ import re
20
+ import sys
21
+ from typing import Annotated, Any, Dict, Optional
22
+
23
+ from ghidratrace import sch
24
+ from ghidratrace.client import (MethodRegistry, ParamDesc, Address,
25
+ AddressRange, Schedule, TraceObject)
26
+
27
+ from x64dbg_automate.events import *
28
+ from x64dbg_automate.models import BreakpointType, HardwareBreakpointType, MemoryBreakpointType
29
+ from . import util, commands
30
+
31
+ REGISTRY = MethodRegistry(ThreadPoolExecutor(
32
+ max_workers=1, thread_name_prefix='MethodRegistry'))
33
+
34
+
35
+ def extre(base: re.Pattern, ext: str) -> re.Pattern:
36
+ return re.compile(base.pattern + ext)
37
+
38
+
39
+ WATCHPOINT_PATTERN = re.compile('Watchpoints\\[(?P<watchnum>\\d*)\\]')
40
+ BREAKPOINT_PATTERN = re.compile('Breakpoints\\[(?P<breaknum>\\d*)\\]')
41
+ BREAK_LOC_PATTERN = extre(BREAKPOINT_PATTERN, '\\[(?P<locnum>\\d*)\\]')
42
+ SESSIONS_PATTERN = re.compile('Sessions')
43
+ SESSION_PATTERN = extre(SESSIONS_PATTERN, '\\[(?P<snum>\\d*)\\]')
44
+ AVAILABLE_PATTERN = extre(SESSION_PATTERN, '\\.Available\\[(?P<pid>\\d*)\\]')
45
+ PROCESSES_PATTERN = extre(SESSION_PATTERN, '\\.Processes')
46
+ PROCESS_PATTERN = extre(PROCESSES_PATTERN, '\\[(?P<procnum>\\d*)\\]')
47
+ PROC_DEBUG_PATTERN = extre(PROCESS_PATTERN, '.Debug')
48
+ PROC_SBREAKS_PATTERN = extre(PROC_DEBUG_PATTERN, '\\.Software Breakpoints')
49
+ PROC_HBREAKS_PATTERN = extre(PROC_DEBUG_PATTERN, '\\.Hardware Breakpoints')
50
+ PROC_MBREAKS_PATTERN = extre(PROC_DEBUG_PATTERN, '\\.Memory Breakpoints')
51
+ PROC_SBREAKBPT_PATTERN = extre(PROC_SBREAKS_PATTERN, '\\[(?P<breaknum>\\d*)\\]')
52
+ PROC_HBREAKBPT_PATTERN = extre(PROC_HBREAKS_PATTERN, '\\[(?P<breaknum>\\d*)\\]')
53
+ PROC_MBREAKBPT_PATTERN = extre(PROC_MBREAKS_PATTERN, '\\[(?P<breaknum>\\d*)\\]')
54
+ ENV_PATTERN = extre(PROCESS_PATTERN, '\\.Environment')
55
+ THREADS_PATTERN = extre(PROCESS_PATTERN, '\\.Threads')
56
+ THREAD_PATTERN = extre(THREADS_PATTERN, '\\[(?P<tnum>\\d*)\\]')
57
+ STACK_PATTERN = extre(THREAD_PATTERN, '\\.Stack.Frames')
58
+ #FRAME_PATTERN = extre(STACK_PATTERN, '\\[(?P<level>\\d*)\\]')
59
+ REGS_PATTERN0 = extre(THREAD_PATTERN, '\\.Registers')
60
+ #REGS_PATTERN = extre(FRAME_PATTERN, '\\.Registers')
61
+ MEMORY_PATTERN = extre(PROCESS_PATTERN, '\\.Memory')
62
+ MODULES_PATTERN = extre(PROCESS_PATTERN, '\\.Modules')
63
+
64
+
65
+ def find_availpid_by_pattern(pattern: re.Pattern, object: TraceObject,
66
+ err_msg: str) -> int:
67
+ mat = pattern.fullmatch(object.path)
68
+ if mat is None:
69
+ raise TypeError(f"{object} is not {err_msg}")
70
+ pid = int(mat['pid'])
71
+ return pid
72
+
73
+
74
+ def find_availpid_by_obj(object: TraceObject) -> int:
75
+ return find_availpid_by_pattern(AVAILABLE_PATTERN, object, "an Attachable")
76
+
77
+
78
+ def find_proc_by_num(id: int) -> int:
79
+ return util.selected_process()
80
+
81
+
82
+ def find_proc_by_pattern(object: TraceObject, pattern: re.Pattern,
83
+ err_msg: str) -> int:
84
+ mat = pattern.fullmatch(object.path)
85
+ if mat is None:
86
+ raise TypeError(f"{object} is not {err_msg}")
87
+ procnum = int(mat['procnum'])
88
+ return find_proc_by_num(procnum)
89
+
90
+
91
+ def find_proc_by_obj(object: TraceObject) -> int:
92
+ return find_proc_by_pattern(object, PROCESS_PATTERN, "an Process")
93
+
94
+
95
+ def find_proc_by_env_obj(object: TraceObject) -> int:
96
+ return find_proc_by_pattern(object, ENV_PATTERN, "an Environment")
97
+
98
+
99
+ def find_proc_by_threads_obj(object: TraceObject) -> int:
100
+ return find_proc_by_pattern(object, THREADS_PATTERN, "a ThreadContainer")
101
+
102
+
103
+ def find_proc_by_mem_obj(object: TraceObject) -> int:
104
+ return find_proc_by_pattern(object, MEMORY_PATTERN, "a Memory")
105
+
106
+
107
+ def find_proc_by_modules_obj(object: TraceObject) -> int:
108
+ return find_proc_by_pattern(object, MODULES_PATTERN, "a ModuleContainer")
109
+
110
+
111
+ def find_thread_by_num(id: int) -> Optional[int]:
112
+ if id != util.selected_thread():
113
+ util.select_thread(id)
114
+ return util.selected_thread()
115
+
116
+
117
+ def find_thread_by_pattern(pattern: re.Pattern, object: TraceObject,
118
+ err_msg: str) -> Optional[int]:
119
+ mat = pattern.fullmatch(object.path)
120
+ if mat is None:
121
+ raise TypeError(f"{object} is not {err_msg}")
122
+ pnum = int(mat['procnum'])
123
+ tnum = int(mat['tnum'])
124
+ find_proc_by_num(pnum)
125
+ return find_thread_by_num(tnum)
126
+
127
+
128
+ def find_thread_by_obj(object: TraceObject) -> Optional[int]:
129
+ return find_thread_by_pattern(THREAD_PATTERN, object, "a Thread")
130
+
131
+
132
+ def find_thread_by_stack_obj(object: TraceObject) -> Optional[int]:
133
+ return find_thread_by_pattern(STACK_PATTERN, object, "a Stack")
134
+
135
+
136
+ def find_thread_by_regs_obj(object: TraceObject) -> Optional[int]:
137
+ return find_thread_by_pattern(REGS_PATTERN0, object,
138
+ "a RegisterValueContainer")
139
+
140
+
141
+ # TODO: if eventually exposed...
142
+ # def find_frame_by_level(level: int) -> DbgEng._DEBUG_STACK_FRAME:
143
+ # for f in util.dbg.client.backtrace_list():
144
+ # if f.FrameNumber == level:
145
+ # return f
146
+ # # return dbg().backtrace_list()[level]
147
+ #
148
+ #
149
+ # def find_frame_by_pattern(pattern: re.Pattern, object: TraceObject,
150
+ # err_msg: str) -> DbgEng._DEBUG_STACK_FRAME:
151
+ # mat = pattern.fullmatch(object.path)
152
+ # if mat is None:
153
+ # raise TypeError(f"{object} is not {err_msg}")
154
+ # pnum = int(mat['procnum'])
155
+ # tnum = int(mat['tnum'])
156
+ # level = int(mat['level'])
157
+ # find_proc_by_num(pnum)
158
+ # find_thread_by_num(tnum)
159
+ # return find_frame_by_level(level)
160
+ #
161
+ #
162
+ # def find_frame_by_obj(object: TraceObject) -> DbgEng._DEBUG_STACK_FRAME:
163
+ # return find_frame_by_pattern(FRAME_PATTERN, object, "a StackFrame")
164
+
165
+
166
+ def find_bpt_by_pattern(pattern: re.Pattern, object: TraceObject,
167
+ err_msg: str) -> int:
168
+ mat = pattern.fullmatch(object.path)
169
+ if mat is None:
170
+ return -1 #raise TypeError(f"{object} is not {err_msg}")
171
+ breaknum = int(mat['breaknum'])
172
+ return breaknum
173
+
174
+
175
+ def find_sbpt_by_obj(object: TraceObject) -> int:
176
+ return find_bpt_by_pattern(PROC_SBREAKBPT_PATTERN, object, "a BreakpointSpec")
177
+
178
+
179
+ def find_hbpt_by_obj(object: TraceObject) -> int:
180
+ return find_bpt_by_pattern(PROC_HBREAKBPT_PATTERN, object, "a BreakpointSpec")
181
+
182
+
183
+ def find_mbpt_by_obj(object: TraceObject) -> int:
184
+ return find_bpt_by_pattern(PROC_MBREAKBPT_PATTERN, object, "a BreakpointSpec")
185
+
186
+
187
+ shared_globals: Dict[str, Any] = dict()
188
+
189
+
190
+ class Session(TraceObject):
191
+ pass
192
+
193
+
194
+ class AvailableContainer(TraceObject):
195
+ pass
196
+
197
+
198
+ class BreakpointContainer(TraceObject):
199
+ pass
200
+
201
+
202
+ class ProcessContainer(TraceObject):
203
+ pass
204
+
205
+
206
+ class Environment(TraceObject):
207
+ pass
208
+
209
+
210
+ class ThreadContainer(TraceObject):
211
+ pass
212
+
213
+
214
+ class Stack(TraceObject):
215
+ pass
216
+
217
+
218
+ class RegisterValueContainer(TraceObject):
219
+ pass
220
+
221
+
222
+ class Memory(TraceObject):
223
+ pass
224
+
225
+
226
+ class ModuleContainer(TraceObject):
227
+ pass
228
+
229
+
230
+ class State(TraceObject):
231
+ pass
232
+
233
+
234
+ class Process(TraceObject):
235
+ pass
236
+
237
+
238
+ class Thread(TraceObject):
239
+ pass
240
+
241
+
242
+ class StackFrame(TraceObject):
243
+ pass
244
+
245
+
246
+ class Attachable(TraceObject):
247
+ pass
248
+
249
+
250
+ class BreakpointSpec(TraceObject):
251
+ pass
252
+
253
+
254
+ class EventContainer(TraceObject):
255
+ pass
256
+
257
+
258
+ class ExceptionContainer(TraceObject):
259
+ pass
260
+
261
+
262
+ class ContinueOption(TraceObject):
263
+ pass
264
+
265
+
266
+ class ExecutionOption(TraceObject):
267
+ pass
268
+
269
+
270
+ @REGISTRY.method()
271
+ def execute(cmd: str, to_string: bool=False):
272
+ """Execute a Python3 command or script."""
273
+ # print("***{}***".format(cmd))
274
+ # sys.stderr.flush()
275
+ # sys.stdout.flush()
276
+ if to_string:
277
+ data = StringIO()
278
+ with redirect_stdout(data):
279
+ exec(cmd, shared_globals)
280
+ return data.getvalue()
281
+ else:
282
+ exec(cmd, shared_globals)
283
+
284
+
285
+ @REGISTRY.method(action='evaluate', display='Evaluate')
286
+ def evaluate(
287
+ session: Session,
288
+ expr: Annotated[str, ParamDesc(display='Expr')]) -> str:
289
+ """Evaluate a Python3 expression."""
290
+ return str(eval(expr, shared_globals))
291
+
292
+
293
+ @REGISTRY.method(action='refresh', display='Refresh Available')
294
+ def refresh_available(node: AvailableContainer) -> None:
295
+ """List processes on x64dbg's host system."""
296
+ with commands.open_tracked_tx('Refresh Available'):
297
+ commands.ghidra_trace_put_available()
298
+
299
+
300
+ @REGISTRY.method(action='refresh', display='Refresh Breakpoints')
301
+ def refresh_breakpoints(node: BreakpointContainer) -> None:
302
+ """Refresh the list of breakpoints (including locations for the current
303
+ process)."""
304
+ with commands.open_tracked_tx('Refresh Breakpoints'):
305
+ commands.ghidra_trace_put_breakpoints()
306
+
307
+
308
+ @REGISTRY.method(action='refresh', display='Refresh Processes')
309
+ def refresh_processes(node: ProcessContainer) -> None:
310
+ """Refresh the list of processes."""
311
+ with commands.open_tracked_tx('Refresh Processes'):
312
+ commands.ghidra_trace_put_processes()
313
+
314
+
315
+ @REGISTRY.method(action='refresh', display='Refresh Environment')
316
+ def refresh_environment(node: Environment) -> None:
317
+ """Refresh the environment descriptors (arch, os, endian)."""
318
+ with commands.open_tracked_tx('Refresh Environment'):
319
+ commands.ghidra_trace_put_environment()
320
+
321
+
322
+ @REGISTRY.method(action='refresh', display='Refresh Threads')
323
+ def refresh_threads(node: ThreadContainer) -> None:
324
+ """Refresh the list of threads in the process."""
325
+ with commands.open_tracked_tx('Refresh Threads'):
326
+ commands.ghidra_trace_put_threads()
327
+
328
+
329
+ # TODO: if eventually exposed...
330
+ # @REGISTRY.method(action='refresh', display='Refresh Stack')
331
+ # def refresh_stack(node: Stack) -> None:
332
+ # """Refresh the backtrace for the thread."""
333
+ # tnum = find_thread_by_stack_obj(node)
334
+ # util.reset_frames()
335
+ # with commands.open_tracked_tx('Refresh Stack'):
336
+ # commands.ghidra_trace_put_frames()
337
+ # with commands.open_tracked_tx('Refresh Registers'):
338
+ # commands.ghidra_trace_putreg()
339
+
340
+
341
+ @REGISTRY.method(action='refresh', display='Refresh Registers')
342
+ def refresh_registers(node: RegisterValueContainer) -> None:
343
+ """Refresh the register values for the selected frame."""
344
+ tnum = find_thread_by_regs_obj(node)
345
+ with commands.open_tracked_tx('Refresh Registers'):
346
+ commands.ghidra_trace_putreg()
347
+
348
+
349
+ @REGISTRY.method(action='refresh', display='Refresh Memory')
350
+ def refresh_mappings(node: Memory) -> None:
351
+ """Refresh the list of memory regions for the process."""
352
+ with commands.open_tracked_tx('Refresh Memory Regions'):
353
+ commands.ghidra_trace_put_regions()
354
+
355
+
356
+ @REGISTRY.method(action='refresh', display='Refresh Modules')
357
+ def refresh_modules(node: ModuleContainer) -> None:
358
+ """Refresh the modules and sections list for the process.
359
+
360
+ This will refresh the sections for all modules, not just the
361
+ selected one.
362
+ """
363
+ with commands.open_tracked_tx('Refresh Modules'):
364
+ commands.ghidra_trace_put_modules()
365
+
366
+
367
+ @REGISTRY.method(action='activate')
368
+ def activate_process(process: Process,
369
+ time: Optional[str]=None) -> None:
370
+ """Switch to the process."""
371
+ find_proc_by_obj(process)
372
+
373
+
374
+ @REGISTRY.method(action='activate')
375
+ def activate_thread(thread: Thread,
376
+ time: Optional[str]=None) -> None:
377
+ """Switch to the thread."""
378
+ find_thread_by_obj(thread)
379
+
380
+
381
+ # TODO: if eventually exposed...
382
+ # @REGISTRY.method(action='activate')
383
+ # def activate_frame(frame: StackFrame,
384
+ # time: Optional[str]=None) -> None:
385
+ # """Select the frame."""
386
+ # do_maybe_activate_time(time)
387
+ # f = find_frame_by_obj(frame)
388
+ # util.select_frame(f.FrameNumber)
389
+ # with commands.open_tracked_tx('Refresh Stack'):
390
+ # commands.ghidra_trace_put_frames()
391
+ # with commands.open_tracked_tx('Refresh Registers'):
392
+ # commands.ghidra_trace_putreg()
393
+
394
+
395
+ @REGISTRY.method(action='delete')
396
+ def remove_process(process: Process) -> None:
397
+ """Remove the process."""
398
+ dbg().detach()
399
+
400
+
401
+ @REGISTRY.method(action='attach', display='Attach')
402
+ def attach_obj(target: Attachable) -> None:
403
+ """Attach the process to the given target."""
404
+ pid = find_availpid_by_obj(target)
405
+ dbg().attach(pid)
406
+ #dbg().wait_until_debugging()
407
+ commands.ghidra_trace_stop()
408
+ commands.ghidra_trace_start(str(pid))
409
+ commands.ghidra_trace_sync_enable()
410
+ with commands.open_tracked_tx('Put all'):
411
+ commands.ghidra_trace_put_all()
412
+
413
+
414
+ @REGISTRY.method(action='attach', display='Attach by pid')
415
+ def attach_pid(session: Session,
416
+ pid: Annotated[int, ParamDesc(display='PID')]) -> None:
417
+ """Attach the process to the given target."""
418
+ commands.ghidra_trace_stop()
419
+ commands.ghidra_trace_start(str(pid))
420
+ commands.ghidra_trace_sync_enable()
421
+ with commands.open_tracked_tx('Put all'):
422
+ commands.ghidra_trace_put_all()
423
+
424
+
425
+ @REGISTRY.method(action='detach', display='Detach')
426
+ def detach(process: Process) -> None:
427
+ """Detach the process's target."""
428
+ dbg().detach()
429
+
430
+
431
+ @REGISTRY.method(action='launch', display='Launch')
432
+ def launch(
433
+ Session: Session,
434
+ file: Annotated[str, ParamDesc(display='Image')],
435
+ args: Annotated[str, ParamDesc(display='Arguments')]='',
436
+ initial_dir: Annotated[str, ParamDesc(
437
+ display='Initial Directory')]='',
438
+ wait: Annotated[bool, ParamDesc(
439
+ display='Wait',
440
+ description='Perform the initial WaitForEvents')]=False) -> None:
441
+ """Run a native process with the given command line."""
442
+ commands.ghidra_trace_stop()
443
+ commands.ghidra_trace_create(command=file, args=args, initdir=initial_dir, start_trace=True, wait=wait)
444
+ commands.ghidra_trace_sync_enable()
445
+ with commands.open_tracked_tx('Put all'):
446
+ commands.ghidra_trace_put_all()
447
+
448
+
449
+ @REGISTRY.method()
450
+ def kill(process: Process) -> None:
451
+ """Kill execution of the process."""
452
+ commands.ghidra_trace_kill()
453
+
454
+
455
+ @REGISTRY.method(action='resume', display='Go')
456
+ def go(process: Process) -> None:
457
+ """Continue execution of the process."""
458
+ dbg().go()
459
+ proc = util.selected_process()
460
+ trace = commands.STATE.require_trace()
461
+ with trace.client.batch():
462
+ with trace.open_tx("Go proc {}".format(proc)):
463
+ commands.put_state(proc)
464
+
465
+
466
+ @REGISTRY.method()
467
+ def interrupt(process: Process) -> None:
468
+ """Interrupt the execution of the debugged program."""
469
+ # SetInterrupt is reentrant, so bypass the thread checks
470
+ dbg().pause()
471
+
472
+
473
+ @REGISTRY.method(action='Hide PEB')
474
+ def hide_peb(process: Process) -> None:
475
+ """Interrupt the execution of the debugged program."""
476
+ # SetInterrupt is reentrant, so bypass the thread checks
477
+ dbg().hide_debugger_peb()
478
+
479
+
480
+ @REGISTRY.method(action='step_into')
481
+ def step_into(thread: Thread,
482
+ n: Annotated[int, ParamDesc(display='N')]=1) -> None:
483
+ """Step one instruction exactly."""
484
+ # find_thread_by_obj(thread)
485
+ find_thread_by_obj(thread)
486
+ dbg().stepi(n)
487
+
488
+
489
+ @REGISTRY.method(action='step_over')
490
+ def step_over(thread: Thread,
491
+ n: Annotated[int, ParamDesc(display='N')]=1) -> None:
492
+ """Step one instruction, but proceed through subroutine calls."""
493
+ # find_thread_by_obj(thread)
494
+ find_thread_by_obj(thread)
495
+ dbg().stepo(n)
496
+
497
+
498
+ @REGISTRY.method(action='skip', display='Skip')
499
+ def skip(thread: Thread,
500
+ n: Annotated[int, ParamDesc(display='N')]=1) -> None:
501
+ """Step one instruction, but proceed through subroutine calls."""
502
+ # find_thread_by_obj(thread)
503
+ find_thread_by_obj(thread)
504
+ dbg().skip(n)
505
+
506
+
507
+ @REGISTRY.method(action='step_out')
508
+ def step_out(thread: Thread) -> None:
509
+ """Execute until the current stack frame returns."""
510
+ find_thread_by_obj(thread)
511
+ dbg().ret()
512
+
513
+
514
+ @REGISTRY.method(action='pause_thread', display='Pause')
515
+ def pause_thread(thread: Thread) -> None:
516
+ """Execute until the current stack frame returns."""
517
+ tid = find_thread_by_obj(thread)
518
+ if tid is not None:
519
+ dbg().thread_pause(tid)
520
+
521
+
522
+ @REGISTRY.method(action='resume_thread', display='Resume')
523
+ def resume_thread(thread: Thread) -> None:
524
+ """Execute until the current stack frame returns."""
525
+ tid = find_thread_by_obj(thread)
526
+ if tid is not None:
527
+ dbg().thread_resume(tid)
528
+
529
+
530
+ @REGISTRY.method(action='kill_thread', display='Kill')
531
+ def kill_thread(thread: Thread) -> None:
532
+ """Execute until the current stack frame returns."""
533
+ tid = find_thread_by_obj(thread)
534
+ if tid is not None:
535
+ dbg().thread_terminate(tid)
536
+
537
+
538
+ @REGISTRY.method(action='break_sw_execute')
539
+ def break_address(process: Process, address: Address) -> None:
540
+ """Set a breakpoint."""
541
+ find_proc_by_obj(process)
542
+ dbg().set_breakpoint(address_or_symbol=address.offset)
543
+
544
+
545
+ @REGISTRY.method(action='break_ext', display='Set Breakpoint')
546
+ def break_expression(expression: str) -> None:
547
+ """Set a breakpoint."""
548
+ # TODO: Escape?
549
+ dbg().set_breakpoint(address_or_symbol=expression)
550
+
551
+
552
+ @REGISTRY.method(action='break_hw_execute')
553
+ def break_hw_address(process: Process, address: Address) -> None:
554
+ """Set a hardware-assisted breakpoint."""
555
+ find_proc_by_obj(process)
556
+ dbg().set_hardware_breakpoint(address_or_symbol=address.offset)
557
+
558
+
559
+ @REGISTRY.method(action='break_ext', display='Set Hardware Breakpoint')
560
+ def break_hw_expression(expression: str) -> None:
561
+ """Set a hardware-assisted breakpoint."""
562
+ dbg().set_hardware_breakpoint(address_or_symbol=expression)
563
+
564
+
565
+ @REGISTRY.method(action='break_read')
566
+ def break_read_address(process: Process, address: Address, size: int) -> None:
567
+ """Set a read breakpoint."""
568
+ find_proc_by_obj(process)
569
+ dbg().set_hardware_breakpoint(address_or_symbol=address.offset, bp_type=HardwareBreakpointType.r, size=size)
570
+
571
+
572
+ @REGISTRY.method(action='break_ext', display='Set Read Breakpoint')
573
+ def break_read_expression(expression: str) -> None:
574
+ """Set a read breakpoint."""
575
+ dbg().set_hardware_breakpoint(address_or_symbol=expression, bp_type=HardwareBreakpointType.r)
576
+
577
+
578
+ @REGISTRY.method(action='break_write')
579
+ def break_write_address(process: Process, address: Address, size: int) -> None:
580
+ """Set a write breakpoint."""
581
+ find_proc_by_obj(process)
582
+ dbg().set_hardware_breakpoint(address_or_symbol=address.offset, bp_type=HardwareBreakpointType.w, size=size)
583
+
584
+
585
+ @REGISTRY.method(action='break_ext', display='Set Write Breakpoint')
586
+ def break_write_expression(expression: str) -> None:
587
+ """Set a write breakpoint."""
588
+ dbg().set_hardware_breakpoint(address_or_symbol=expression, bp_type=HardwareBreakpointType.w)
589
+
590
+
591
+ @REGISTRY.method(action='break_access')
592
+ def break_access_address(process: Process, address: Address) -> None:
593
+ """Set an access breakpoint."""
594
+ find_proc_by_obj(process)
595
+ dbg().set_memory_breakpoint(address_or_symbol=address.offset, bp_type=MemoryBreakpointType.a)
596
+
597
+
598
+ @REGISTRY.method(action='break_ext', display='Set Access Breakpoint')
599
+ def break_access_expression(expression: str) -> None:
600
+ """Set an access breakpoint."""
601
+ dbg().set_memory_breakpoint(address_or_symbol=expression, bp_type=MemoryBreakpointType.a)
602
+
603
+
604
+ @REGISTRY.method(action='toggle', display='Toggle Breakpoint')
605
+ def toggle_breakpoint(breakpoint: BreakpointSpec, enabled: bool) -> None:
606
+ """Toggle a breakpoint."""
607
+ bpt = find_sbpt_by_obj(breakpoint)
608
+ if bpt >= 0:
609
+ dbg().toggle_breakpoint(address_name_symbol_or_none=bpt, on=enabled)
610
+ with commands.open_tracked_tx('Toggle Breakpoints'):
611
+ commands.put_breakpoints(BreakpointType.BpNormal)
612
+ return
613
+ bpt = find_hbpt_by_obj(breakpoint)
614
+ if bpt >= 0:
615
+ dbg().toggle_breakpoint(address_name_symbol_or_none=bpt, on=enabled)
616
+ with commands.open_tracked_tx('Toggle Breakpoints'):
617
+ commands.put_breakpoints(BreakpointType.BpHardware)
618
+ return
619
+ bpt = find_mbpt_by_obj(breakpoint)
620
+ if bpt >= 0:
621
+ dbg().toggle_breakpoint(address_name_symbol_or_none=bpt, on=enabled)
622
+ with commands.open_tracked_tx('Toggle Breakpoints'):
623
+ commands.put_breakpoints(BreakpointType.BpMemory)
624
+
625
+
626
+ @REGISTRY.method(action='delete', display='Delete Breakpoint')
627
+ def delete_breakpoint(breakpoint: BreakpointSpec) -> None:
628
+ """Delete a breakpoint."""
629
+ bpt = find_sbpt_by_obj(breakpoint)
630
+ if bpt >= 0:
631
+ dbg().clear_breakpoint(address_name_symbol_or_none=bpt)
632
+ with commands.open_tracked_tx('Delete Breakpoints'):
633
+ commands.put_breakpoints(BreakpointType.BpNormal)
634
+ return
635
+ bpt = find_hbpt_by_obj(breakpoint)
636
+ if bpt >= 0:
637
+ dbg().clear_hardware_breakpoint(address_symbol_or_none=bpt)
638
+ with commands.open_tracked_tx('Delete Breakpoints'):
639
+ commands.put_breakpoints(BreakpointType.BpHardware)
640
+ return
641
+ bpt = find_mbpt_by_obj(breakpoint)
642
+ if bpt >= 0:
643
+ dbg().clear_memory_breakpoint(address_symbol_or_none=bpt)
644
+ with commands.open_tracked_tx('Delete Breakpoints'):
645
+ commands.put_breakpoints(BreakpointType.BpMemory)
646
+
647
+
648
+ @REGISTRY.method()
649
+ def read_mem(process: Process, range: AddressRange) -> None:
650
+ """Read memory."""
651
+ # print("READ_MEM: process={}, range={}".format(process, range))
652
+ nproc = find_proc_by_obj(process)
653
+ offset_start = process.trace.extra.require_mm().map_back(
654
+ nproc, Address(range.space, range.min))
655
+ with commands.open_tracked_tx('Read Memory'):
656
+ result = commands.put_bytes(
657
+ offset_start, offset_start + range.length() - 1, pages=True,
658
+ display_result=False)
659
+ if result['count'] == 0:
660
+ commands.putmem_state(
661
+ offset_start, offset_start + range.length() - 1, 'error')
662
+
663
+
664
+ @REGISTRY.method()
665
+ def write_mem(process: Process, address: Address, data: bytes) -> None:
666
+ """Write memory."""
667
+ nproc = find_proc_by_obj(process)
668
+ offset = process.trace.extra.required_mm().map_back(nproc, address)
669
+ dbg().write_memory(offset, data)
670
+
671
+
672
+ @REGISTRY.method(action='set_reg', display='Set Register')
673
+ def write_reg(reg: RegisterValueContainer, name: str, value: int) -> None:
674
+ """Write a register."""
675
+ nproc = util.selected_process()
676
+ dbg().set_reg(name, value)
677
+
678
+
679
+ def dbg():
680
+ return util.dbg.client
ghidraxdbg/py.typed ADDED
File without changes