Configurable IDA Pro RPC endpoints (#139)

* Added PyCharm project dir (.idea) to .gitignore

* Reformat & optimize imports in ida xmlrpc sources

* Refactored ida_script.py

* Moved host to variable in ida_script.py

* Added info that server has been hosted in ida_script.py

* Added info to config/theme commands output

* Reformat & optimize imports in pwndbg/config.py

* Fix for configfile/themefile generation #137

Also generating the configs only for the changed parameters.

* Better info for config and theme commands

* Added Ida Pro rpc connection host, port parameters #132

* Fixed wrong Ida Pro idb save path on Windows #132

The problem happens on a NTFS filesystem as it supports ADS (Alternative
Data Streams) so that filepath with ':' is treated as ntfs ads.

* Added info on Ida Pro rpc successful connection #132

* Sorted imports with isort

* Added Ida Pro rpc auto connect when host/port has changed #132

* Better Ida Pro integration description in FEATURES.md #132

* Added info about config/theme into FEATURES.md

* Add PEP8 configuration file for pep8 command-line and PyCharm

* Review #139 fixes: ugly filter_cond cleanup

* Minor name refactor in pwndbg/config.py

* Review #139: added native_default to pwndbg.config.Parameter

* config: fix type checking of native translation by testing instance

* config: add optional 'all' parameter to {config,theme}file

this makes it easier to get a template of all configurable options.

* Removed trailing spaces in FEATURES.md
pull/143/head
Disconnect3d 9 years ago committed by Zach Riggle
parent 2b5e39474c
commit f728a2870a

3
.gitignore vendored

@ -58,3 +58,6 @@ target/
npm-debug.log
.gdb_history
# PyCharm project files
.idea/

@ -6,18 +6,18 @@ Pwndbg has a great deal of useful features. You can a list of all available com
All function call sites are annotated with the arguments to those functions. This works best with debugging symbols, but also works in the most common case where an imported function (e.g. libc function via GOT or PLT) is used.
![](caps/arguments_getenv.png)
![](caps/arguments_memcpy.png)
![](caps/arguments_sigsetjmp.png)
![](caps/arguments_strcpy.png)
![](caps/arguments_syscall.png)
![](caps/arguments_xtrace_init.png)
![](caps/arguments_getenv.png)
![](caps/arguments_memcpy.png)
![](caps/arguments_sigsetjmp.png)
![](caps/arguments_strcpy.png)
![](caps/arguments_syscall.png)
![](caps/arguments_xtrace_init.png)
## Context
A useful summary of the current execution context is printed every time GDB stops (e.g. breakpoint or single-step), displaying all registers, the stack, call frames, disassembly, and additionally recursively dereferencing all pointers. All memory addresses are color-coded to the type of memory they represent.
![](caps/context.png)
![](caps/context.png)
## Disassembly
@ -29,9 +29,9 @@ All absolute jumps are folded away, only displaying relevant instructions.
Additionally, if the current instruction is conditional, Pwndbg displays whether or not it is evaluated with a green check or a red X, and folds away instructions as necessary.
![](caps/disasm_taken_after.png)
![](caps/disasm_taken_before.png)
![](caps/disasn_taken_false.png)
![](caps/disasm_taken_after.png)
![](caps/disasm_taken_before.png)
![](caps/disasn_taken_false.png)
## Emulation
@ -39,20 +39,20 @@ Pwndbg leverages Unicorn Engine in order to only show instructions which will ac
This is incredibly useful when stepping through jump tables, PLT entries, and even while ROPping!
![](caps/emulate_vs_disasm.png)
![](caps/emulation_plt.png)
![](caps/emulation_rop.png)
![](caps/emulate_vs_disasm.png)
![](caps/emulation_plt.png)
![](caps/emulation_rop.png)
## Heap Inspection
Pwndbg enables introspection of the glibc allocator, ptmalloc2, via a handful of introspection functions.
![](caps/heap_arena.png)
![](caps/heap_bins.png)
![](caps/heap_heap.png)
![](caps/heap_heap2.png)
![](caps/heap_mallocchunk.png)
![](caps/heap_topchunk.png)
![](caps/heap_arena.png)
![](caps/heap_bins.png)
![](caps/heap_heap.png)
![](caps/heap_heap2.png)
![](caps/heap_mallocchunk.png)
![](caps/heap_topchunk.png)
## IDA Pro Integration
@ -60,12 +60,30 @@ Pwndbg flips traditional IDA Pro integration on its head. Rather than sticking
This allows extraction of comments, decompiled lines of source, breakpoints, and synchronized debugging (single-steps update the cursor in IDA).
![](caps/ida_comments.png)
![](caps/ida_function.png)
![](caps/ida_integration.png)
![](caps/ida_comments.png)
![](caps/ida_function.png)
![](caps/ida_integration.png)
Since the complete IDA API is exposed, new tools can be built on this functionality to further enhance Pwndbg's usefulness.
You can also connect to Ida Pro XMLRPC server hosted on different machine. In order to achieve it, you need to change:
* Ida Pro XMLRPC server host (in [ida_script](ida_script.py); as by default it binds to localhost)
* The config parameters responsible for connection (see `config` command)
## Configuration, customization
There are two commands to set various options:
* `theme` - to set particular output color/style
![](caps/theme.png)
* `config` - to set parameters like whether to emulate code near current instruction, ida rpc connection info, hexdump bytes/width (and more)
![](caps/config.png)
Of course you can generate and put it in `.gdbinit` after pwndbg initialization to keep it persistent between pwngdb sessions.
This can be seen and achieved by `configfile`/`themefile` commands.
## QEMU Compatibility
Pwndbg is designed to work with minimally-implemented or otherwise debugger-hostile implementations of the GDB Serial Protocol. One such implementation is that used by QEMU User-Mode Emulation (`qemu-user`) which is frequently used by CTF players to execute and debug cross-architecture binaries.
@ -74,27 +92,27 @@ Vanilla GDB, PEDA, and GEF all fail terribly in this scenario.
#### GEF
![](caps/qemu_gef.png)
![](caps/qemu_gef.png)
#### PEDA
![](caps/qemu_peda.png)
![](caps/qemu_peda.png)
#### Vanilla GDB
![](caps/qemu_vanilla.png)
![](caps/qemu_vanilla.png)
#### Pwndbg
However, Pwndbg works around the limitations of the GDB stub to give you the best debugger environment possible.
![](caps/qemu_pwndbg.png)
![](caps/qemu_pwndbg.png)
## Process State Inspection
Use the `procinfo` command in order to inspect the current process state, like UID, GID, Groups, SELinux context, and open file descriptors! Pwndbg works particularly well with remote GDB debugging like with Android phones, which PEDA, GEF, and vanilla GDB choke on.
![](caps/procinfo.png)
![](caps/procinfo.png)
## ROP Gadgets
@ -102,13 +120,13 @@ Pwndbg makes using ROPGadget easy with the actual addresses in the process.
Just use the `rop` command!
![](caps/rop_grep.png)
![](caps/rop_grep.png)
## Search
Pwndbg makes searching the target memory space easy, with a complete and easy-to-use interface. Whether you're searching for bytes, strings, or various sizes of integer values or pointers, it's a simple command away.
![](caps/search.png)
![](caps/search.png)
## Telescope
@ -118,14 +136,14 @@ Inspecting memory dumps is easy with the `telescope` command. It recursively de
Pwndbg enhances the standard memory map listing, and allows easy searching.
![](caps/vmmap.png)
![](caps/vmmap2.png)
![](caps/vmmap_pc.png)
![](caps/vmmap_register.png)
![](caps/vmmap_stack.png)
![](caps/vmmap.png)
![](caps/vmmap2.png)
![](caps/vmmap_pc.png)
![](caps/vmmap_register.png)
![](caps/vmmap_stack.png)
## Windbg Compatibility
Pwndbg has a complete windbg compatibility layer. You can `dd`, `dps`, `eq`, and even `eb eip 90` to your heart's content.
![](caps/windbg.png)
![](caps/windbg.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

@ -3,42 +3,53 @@
from __future__ import print_function
import datetime
import functools
import threading
import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer
import idaapi
import idautils
import idc
import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer
# Wait for any processing to get done
idaapi.autoWait()
# On Windows with NTFS filesystem a filepath with ':'
# is treated as NTFS ADS (Alternative Data Stream)
# and so saving file with such name fails
dt = datetime.datetime.now().isoformat().replace(':', '-')
# Save the database so nothing gets lost.
idc.SaveBase(idc.GetIdbPath() + '.' + datetime.datetime.now().isoformat())
idc.SaveBase(idc.GetIdbPath() + '.' + dt)
xmlrpclib.Marshaller.dispatch[type(0L)] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)
xmlrpclib.Marshaller.dispatch[type(0)] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)
port = 8888
host = '127.0.0.1'
port = 8888
orig_LineA = idc.LineA
def LineA(*a,**kw):
v = orig_LineA(*a,**kw)
def LineA(*a, **kw):
v = orig_LineA(*a, **kw)
if v and v.startswith('\x01\x04; '):
v = v[4:]
return v
idc.LineA = LineA
mutex = threading.Condition()
def wrap(f):
def wrapper(*a, **kw):
try:
rv = []
def work(): rv.append(f(*a,**kw))
def work():
rv.append(f(*a, **kw))
with mutex:
flags = idaapi.MFF_WRITE
if f == idc.SetColor:
@ -50,20 +61,25 @@ def wrap(f):
import traceback
traceback.print_exc()
raise
return wrapper
def register_module(module):
for name, function in module.__dict__.items():
if hasattr(function, '__call__'):
server.register_function(wrap(function), name)
server = SimpleXMLRPCServer(('127.0.0.1', port), logRequests=True, allow_none=True)
server = SimpleXMLRPCServer((host, port), logRequests=True, allow_none=True)
register_module(idc)
register_module(idautils)
register_module(idaapi)
server.register_function(lambda a: eval(a, globals(), locals()), 'eval')
server.register_introspection_functions()
print('Ida Pro xmlrpc hosted on http://%s:%s' % (host, port))
thread = threading.Thread(target=server.serve_forever)
thread.daemon = True
thread.start()

@ -10,6 +10,7 @@ from __future__ import unicode_literals
import pwndbg.commands
import pwndbg.config
from pwndbg.color import light_yellow
from pwndbg.color import ljust_colored
from pwndbg.color import strip
@ -22,11 +23,13 @@ def print_row(name, value, default, docstring, ljust_optname, ljust_value, empty
print(result)
return result
def extend_value_with_default(value, default):
if strip(value) != strip(default):
return '%s (%s)' % (value, default)
return value
@pwndbg.commands.Command
def config():
"""Shows pwndbg-specific configuration points"""
@ -42,24 +45,36 @@ def config():
for v in sorted(values):
print_row(v.optname, repr(v.value), repr(v.default), v.docstring, longest_optname, longest_value)
print(light_yellow('You can set config variable with `set <config-var> <value>`'))
print(light_yellow('You can generate configuration file using `configfile` '
'- then put it in your .gdbinit after initializing pwndbg'))
@pwndbg.commands.Command
def configfile():
def configfile(show_all=False):
"""Generates a configuration file for the current Pwndbg options"""
configfile_print_scope('config')
configfile_print_scope('config', show_all)
@pwndbg.commands.Command
def themefile():
def themefile(show_all=False):
"""Generates a configuration file for the current Pwndbg theme options"""
configfile_print_scope('theme')
configfile_print_scope('theme', show_all)
def configfile_print_scope(scope):
values = [v for k, v in pwndbg.config.__dict__.items()
if isinstance(v, pwndbg.config.Parameter) and v.scope == scope]
longest_optname = max(map(len, [v.optname for v in values]))
longest_value = max(map(len, [extend_value_with_default(repr(v.value), repr(v.default)) for v in values]))
for v in sorted(values):
print('# %s: %s' % (v.optname, v.docstring))
print('# default: %r' % v.default)
print('py pwndbg.config.%s=%r' % (v.name, v.value))
print()
def configfile_print_scope(scope, show_all=False):
params = pwndbg.config.get_params(scope)
if not show_all:
params = list(filter(lambda p: p.is_changed, params))
if params:
if not show_all:
print(light_yellow('Showing only changed values:'))
for p in params:
print('# %s: %s' % (p.optname, p.docstring))
print('# default: %s' % p.native_default)
print('set %s %s' % (p.optname, p.native_value))
print()
else:
print(light_yellow('No changed values. To see current values use `%s`.' % scope))

@ -52,6 +52,7 @@ if pwndbg.ida.available():
j()
@pwndbg.commands.Command
@pwndbg.commands.OnlyWhenRunning
def down(n=1):
@ -71,6 +72,7 @@ if pwndbg.ida.available():
j()
@pwndbg.commands.Command
def save_ida():
if not pwndbg.ida.available():
@ -95,7 +97,7 @@ def save_ida():
basename += ext
# Windows doesn't like colons in paths
basename = basename.replace(':','_')
basename = basename.replace(':', '_')
full_path = os.path.join(backups, basename)
@ -110,20 +112,23 @@ def save_ida():
# Remove old version
os.unlink(full_path)
class ida(gdb.Function):
"""Evaluate ida.LocByName() on the supplied value.
"""
def __init__(self):
super(ida, self).__init__('ida')
def invoke(self, name):
name = name.string()
name = name.string()
result = pwndbg.ida.LocByName(name)
if 0xffffe000 <= result <= 0xffffffff \
or 0xffffffffffffe000 <= result <= 0xffffffffffffffff:
if 0xffffe000 <= result <= 0xffffffff or 0xffffffffffffe000 <= result <= 0xffffffffffffffff:
raise ValueError("ida.LocByName(%r) == BADADDR" % name)
return result
ida()
save_ida()

@ -12,6 +12,7 @@ import pwndbg.color.theme
import pwndbg.commands
import pwndbg.config
from pwndbg.color import generateColorFunction
from pwndbg.color import light_yellow
from pwndbg.commands.config import extend_value_with_default
from pwndbg.commands.config import print_row
@ -37,3 +38,7 @@ def theme():
value = repr(v.value)
default = repr(v.default)
print_row(v.optname, value, default, v.docstring, longest_optname, longest_value)
print(light_yellow('You can set theme variable with `set <theme-var> <value>`'))
print(light_yellow('You can generate theme config file using `themefile` '
'- then put it in your .gdbinit after initializing pwndbg'))

@ -29,6 +29,7 @@ import types
import gdb
import six
TYPES = collections.OrderedDict()
# The value is a plain boolean.
@ -49,6 +50,7 @@ for type in six.string_types:
triggers = collections.defaultdict(lambda: [])
class Trigger(object):
def __init__(self, names):
if not isinstance(names, list):
@ -63,51 +65,86 @@ class Trigger(object):
return function
def getParam(value):
for k,v in TYPES.items():
def get_param(value):
for k, v in TYPES.items():
if isinstance(value, k):
return v
class Parameter(gdb.Parameter):
def get_params(scope):
module_attributes = globals()['module'].__dict__.values()
return sorted(filter(lambda p: isinstance(p, Parameter) and p.scope == scope, module_attributes))
def value_to_gdb_native(value):
"""Translates Python value into native GDB syntax string."""
mapping = collections.OrderedDict()
mapping[bool] = lambda value: 'on' if value else 'off'
for k, v in mapping.items():
if isinstance(value, k):
return v(value)
return value
class Parameter(gdb.Parameter):
def __init__(self, name, default, docstring, scope='config'):
self.docstring = docstring.strip()
self.optname = name
self.name = name.replace('-','_')
self.default = default
self.set_doc = 'Set ' + docstring
self.show_doc = docstring + ':'
self.optname = name
self.name = name.replace('-', '_')
self.default = default
self.set_doc = 'Set ' + docstring
self.show_doc = docstring + ':'
super(Parameter, self).__init__(name,
gdb.COMMAND_SUPPORT,
getParam(default))
get_param(default))
self.value = default
self.scope = scope
setattr(module, self.name, self)
@property
def native_value(self):
return value_to_gdb_native(self.value)
@property
def native_default(self):
return value_to_gdb_native(self.default)
@property
def is_changed(self):
return self.value != self.default
def get_set_string(self):
for trigger in triggers[self.name]:
trigger()
if isinstance(self.value, str):
self.value = self.value.replace("'", '').replace('"', '')
return 'Set %s to %r' % (self.docstring, self.value)
def get_show_string(self, svalue):
return 'Sets %s (currently: %r)' % (self.docstring, self.value)
def __int__(self):
return int(self.value)
def __str__(self):
return str(self.value)
def __bool__(self):
return bool(self.value)
def __lt__(self, other):
return self.optname <= other.optname
# Python2 compatibility
__nonzero__ = __bool__
class ConfigModule(types.ModuleType):
def __init__(self, name, module):
super(ConfigModule, self).__init__(name)
self.__dict__.update(module.__dict__)
Parameter = Parameter

@ -12,16 +12,15 @@ from __future__ import unicode_literals
import errno
import functools
import inspect
import os
import socket
import traceback
from contextlib import closing
import gdb
import pwndbg.arch
import pwndbg.color
import pwndbg.compat
import pwndbg.config
import pwndbg.elf
import pwndbg.events
import pwndbg.memoize
@ -34,53 +33,69 @@ except:
import xmlrpclib
ida_rpc_host = pwndbg.config.Parameter('ida-rpc-host', '127.0.0.1', 'ida xmlrpc server address')
ida_rpc_port = pwndbg.config.Parameter('ida-rpc-port', 8888, 'ida xmlrpc server port')
xmlrpclib.Marshaller.dispatch[int] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)
if pwndbg.compat.python2:
xmlrpclib.Marshaller.dispatch[long] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)
xmlrpclib.Marshaller.dispatch[type(0)] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)
_ida = None
xmlrpclib.Marshaller.dispatch[type(0)] = lambda _, v, w: w("<value><i8>%d</i8></value>" % v)
def setPort(port):
@pwndbg.config.Trigger([ida_rpc_host, ida_rpc_port])
def init_ida_rpc_client():
global _ida
_ida = xmlrpclib.ServerProxy('http://localhost:%s' % port)
addr = 'http://{host}:{port}'.format(host=ida_rpc_host, port=ida_rpc_port)
_ida = xmlrpclib.ServerProxy(addr)
try:
_ida.here()
print(pwndbg.color.green("Pwndbg successfully connected to Ida Pro xmlrpc: %s" % addr))
except socket.error as e:
if e.errno != errno.ECONNREFUSED:
traceback.print_exc()
_ida = None
class withIDA(object):
def __init__(self, fn):
self.fn = fn
functools.update_wrapper(self, fn)
def __call__(self, *args, **kwargs):
if _ida is None:
setPort(8888)
init_ida_rpc_client()
if _ida is not None:
return self.fn(*args, **kwargs)
return None
def takes_address(function):
@functools.wraps(function)
def wrapper(address, *args, **kwargs):
return function(l2r(address), *args, **kwargs)
return wrapper
def returns_address(function):
@functools.wraps(function)
def wrapper(*args, **kwargs):
return r2l(function(*args, **kwargs))
return wrapper
@withIDA
def available():
return True
def l2r(addr):
exe = pwndbg.elf.exe()
if not exe:
@ -88,6 +103,7 @@ def l2r(addr):
result = (addr - int(exe.address) + base()) & pwndbg.arch.ptrmask
return result
def r2l(addr):
exe = pwndbg.elf.exe()
if not exe:
@ -95,6 +111,7 @@ def r2l(addr):
result = (addr - base() + int(exe.address)) & pwndbg.arch.ptrmask
return result
def remote(function):
"""Runs the provided function in IDA's interpreter.
@ -109,42 +126,49 @@ def base():
return segaddr - base
@withIDA
@takes_address
def Comment(addr):
addr = l2r(addr)
return _ida.GetCommentEx(addr, 0) or _ida.GetCommentEx(addr)
@withIDA
@takes_address
@pwndbg.memoize.reset_on_objfile
def Name(addr):
return _ida.Name(addr)
@withIDA
@takes_address
@pwndbg.memoize.reset_on_objfile
def GetFuncOffset(addr):
rv = _ida.GetFuncOffset(addr)
rv = _ida.GetFuncOffset(addr)
return rv
@withIDA
@takes_address
@pwndbg.memoize.reset_on_objfile
def GetType(addr):
rv = _ida.GetType(addr)
rv = _ida.GetType(addr)
return rv
@withIDA
@returns_address
def here():
return _ida.here()
@withIDA
@takes_address
def Jump(addr):
return _ida.Jump(addr)
@withIDA
@takes_address
@pwndbg.memoize.reset_on_objfile
@ -159,21 +183,26 @@ def Anterior(addr):
lines.append(r)
return '\n'.join(lines)
@withIDA
def GetBreakpoints():
for i in range(GetBptQty()):
yield GetBptEA(i)
@withIDA
def GetBptQty():
return _ida.GetBptQty()
@withIDA
@returns_address
def GetBptEA(i):
return _ida.GetBptEA(i)
_breakpoints=[]
_breakpoints = []
@pwndbg.events.cont
@pwndbg.events.stop
@ -181,11 +210,11 @@ _breakpoints=[]
def UpdateBreakpoints():
# XXX: Remove breakpoints from IDA when the user removes them.
current = set(eval(b.location.lstrip('*')) for b in _breakpoints)
want = set(GetBreakpoints())
want = set(GetBreakpoints())
# print(want)
for addr in current-want:
for addr in current - want:
for bp in _breakpoints:
if int(bp.location.lstrip('*'), 0) == addr:
# print("delete", addr)
@ -193,7 +222,7 @@ def UpdateBreakpoints():
break
_breakpoints.remove(bp)
for bp in want-current:
for bp in want - current:
if not pwndbg.memory.peek(bp):
continue
@ -210,6 +239,7 @@ def SetColor(pc, color):
colored_pc = None
@pwndbg.events.stop
@withIDA
def Auto_Color_PC():
@ -217,6 +247,7 @@ def Auto_Color_PC():
colored_pc = pwndbg.regs.pc
SetColor(colored_pc, 0x7f7fff)
@pwndbg.events.cont
@withIDA
def Auto_UnColor_PC():
@ -225,12 +256,14 @@ def Auto_UnColor_PC():
SetColor(colored_pc, 0xffffff)
colored_pc = None
@withIDA
@returns_address
@pwndbg.memoize.reset_on_objfile
def LocByName(name):
return _ida.LocByName(str(name))
@withIDA
@takes_address
@returns_address
@ -238,6 +271,7 @@ def LocByName(name):
def PrevHead(addr):
return _ida.PrevHead(addr)
@withIDA
@takes_address
@returns_address
@ -245,37 +279,44 @@ def PrevHead(addr):
def NextHead(addr):
return _ida.NextHead(addr)
@withIDA
@takes_address
@pwndbg.memoize.reset_on_objfile
def GetFunctionName(addr):
return _ida.GetFunctionName(addr)
@withIDA
@takes_address
@pwndbg.memoize.reset_on_objfile
def GetFlags(addr):
return _ida.GetFlags(addr)
@withIDA
@pwndbg.memoize.reset_on_objfile
def isASCII(flags):
return _ida.isASCII(flags)
@withIDA
@takes_address
@pwndbg.memoize.reset_on_objfile
def ArgCount(address):
pass
@withIDA
def SaveBase(path):
return _ida.SaveBase(path)
@withIDA
def GetIdbPath():
return _ida.GetIdbPath()
@takes_address
@pwndbg.memoize.reset_on_stop
def has_cached_cfunc(addr):
@ -288,64 +329,79 @@ def has_cached_cfunc(addr):
def decompile(addr):
return _ida.decompile(addr)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetStrucQty():
return _ida.GetStrucQty()
@withIDA
@pwndbg.memoize.reset_on_stop
def GetStrucId(idx):
return _ida.GetStrucId(idx)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetStrucName(sid):
return _ida.GetStrucName(sid)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetStrucSize(sid):
return _ida.GetStrucSize(sid)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetMemberQty(sid):
return _ida.GetMemberQty(sid)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetMemberSize(sid, offset):
return _ida.GetMemberSize(sid, offset)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetMemberId(sid, offset):
return _ida.GetMemberId(sid, offset)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetMemberName(sid, offset):
return _ida.GetMemberName(sid, offset)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetMemberFlag(sid, offset):
return _ida.GetMemberFlag(sid, offset)
@withIDA
@pwndbg.memoize.reset_on_stop
def GetStrucNextOff(sid, offset):
return _ida.GetStrucNextOff(sid, offset)
class IDC(object):
query = "{k:v for k,v in globals()['idc'].__dict__.items() if type(v) in (int,long)}"
def __init__(self):
if available():
data = _ida.eval(self.query)
self.__dict__.update(data)
idc = IDC()
def print_member(sid, offset):
mid = GetMemberId(sid, offset)
mname = GetMemberName(sid, offset) or '(no name)'

Loading…
Cancel
Save