diff --git a/lib/config.py b/lib/config.py index 5704fc7..d50880c 100644 --- a/lib/config.py +++ b/lib/config.py @@ -35,6 +35,7 @@ "autosave" : ("on", "auto saving peda session, e.g: on|off"), "payload" : ("peda-payload-#FILENAME#.txt", "target file to save output of payload command"), "context" : ("register,code,stack", "context display setting, e.g: register, code, stack, all"), + "clearscr" : ("on", "clear screen for each context display"), "verbose" : ("off", "show detail execution of commands, e.g: on|off"), "debug" : ("off", "show detail error of peda commands, e.g: on|off"), "_teefd" : ("", "internal use only for tracelog/crashlog writing") diff --git a/lib/shellcode.py b/lib/shellcode.py index 957e90b..6b87b0d 100644 --- a/lib/shellcode.py +++ b/lib/shellcode.py @@ -21,7 +21,7 @@ import config from utils import msg, error_msg -if sys.version_info.major is 3: +if sys.version_info.major == 3: from urllib.request import urlopen from urllib.parse import urlencode pyversion = 3 @@ -356,7 +356,7 @@ def display(self, shellcodeId): try: s.request("GET", "/shellcode/files/shellcode-"+str(shellcodeId)+".php") res = s.getresponse() - data = res.read().split("
")[1].split("")[0]
+ data = res.read().decode('utf-8').split("")[1].split("")[0]
except:
error_msg("Failed to download shellcode from shell-storm.org")
return None
@@ -376,7 +376,7 @@ def zsc(self,os,job,encode):
'job': job,
'encode': encode})
shellcode = urlopen("http://api.z3r0d4y.com/index.py?%s\n"%(str(params))).read()
- if pyversion is 3:
+ if pyversion == 3:
shellcode = str(shellcode,encoding='ascii')
return '\n"'+shellcode.replace('\n','')+'"\n'
except:
diff --git a/lib/skeleton.py b/lib/skeleton.py
index 123210f..20c30c5 100644
--- a/lib/skeleton.py
+++ b/lib/skeleton.py
@@ -150,7 +150,7 @@ def exploit(vuln):
args = sys.argv[1:]
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
- P = Popen(args, stdin=PIPE)
+ P = Popen(args, stdin=PIPE, env=env)
P.stdin.write(payload + "\\n")
while True:
line = sys.stdin.readline()
diff --git a/lib/utils.py b/lib/utils.py
index 767f132..8f2b038 100644
--- a/lib/utils.py
+++ b/lib/utils.py
@@ -147,6 +147,10 @@ def blue(text, attrib=None):
"""Wrapper for colorize(text, 'blue')"""
return colorize(text, "blue", attrib)
+def clearscreen():
+ """Clear terminal screen"""
+ sys.stdout.write("\x1b[2J\x1b[H")
+
class message(object):
"""
Generic pretty printer with redirection.
@@ -564,7 +568,7 @@ def cyclic_pattern_charset(charset_type=None):
Args:
- charset_type: charset type
- 0: basic (0-9A-za-z)
+ 0: basic (0-9A-Za-z)
1: extended (default)
2: maximum (almost printable chars)
@@ -635,7 +639,7 @@ def cyclic_pattern(size=None, start=None, charset_type=None):
- size: size of generated pattern (Int)
- start: the start offset of the generated pattern (Int)
- charset_type: charset type
- 0: basic (0-9A-za-z)
+ 0: basic (0-9A-Za-z)
1: extended (default)
2: maximum (almost printable chars)
diff --git a/peda.py b/peda.py
index e087f90..14a7f5e 100644
--- a/peda.py
+++ b/peda.py
@@ -42,7 +42,7 @@
import config
from nasm import *
-if sys.version_info.major is 3:
+if sys.version_info.major == 3:
from urllib.request import urlopen
from urllib.parse import urlencode
pyversion = 3
@@ -50,7 +50,7 @@
from urllib import urlopen
from urllib import urlencode
pyversion = 2
-
+
REGISTERS = {
8 : ["al", "ah", "bl", "bh", "cl", "ch", "dl", "dh"],
16: ["ax", "bx", "cx", "dx"],
@@ -195,8 +195,7 @@ def string_to_argv(self, str):
str = str.encode('ascii', 'ignore')
except:
pass
- str = decode_string_escape(str)
- args = shlex.split(str)
+ args = list(map(lambda x: decode_string_escape(x), shlex.split(str.decode())))
# need more processing here
for idx, a in enumerate(args):
a = a.strip(",")
@@ -422,37 +421,8 @@ def getpid(self):
status = self.get_status()
if not status or status == "STOPPED":
return None
-
- if self.is_target_remote(): # remote target
- ctx = config.Option.get("context")
- config.Option.set("context", None)
- try:
- out = self.execute_redirect("call getpid()")
- except:
- pass
-
- config.Option.set("context", ctx)
-
- if out is None:
- return None
- else:
- out = self.execute_redirect("print $")
- if out:
- return to_int(out.split("=")[1])
- else:
- return None
-
- if self.getos() == "Linux":
- out = self.execute_redirect('info proc')
-
- if out is None: # non-Linux or cannot access /proc, fallback
- out = self.execute_redirect('info program')
- out = out.splitlines()[0]
- if "process" in out or "Thread" in out:
- pid = out.split()[-1].strip(".)")
- return int(pid)
- else:
- return None
+ pid = gdb.selected_inferior().pid
+ return int(pid) if pid else None
def getos(self):
"""
@@ -1195,9 +1165,9 @@ def get_eflags(self):
return flags
- def set_eflags(self, flagname, value=True):
+ def set_eflags(self, flagname, value):
"""
- Set/clear value of a flag register
+ Set/clear/toggle value of a flag register
Returns:
- True if success (Bool)
@@ -1217,6 +1187,8 @@ def set_eflags(self, flagname, value=True):
flags = {"carry": "CF", "parity": "PF", "adjust": "AF", "zero": "ZF", "sign": "SF",
"trap": "TF", "interrupt": "IF", "direction": "DF", "overflow": "OF"}
+ flagname = flagname.lower()
+
if flagname not in flags:
return False
@@ -1224,7 +1196,8 @@ def set_eflags(self, flagname, value=True):
if not eflags:
return False
- if eflags[flags[flagname]] != value: # switch value
+ # If value doesn't match the current, or we want to toggle, toggle
+ if value is None or eflags[flags[flagname]] != value:
reg_eflags = self.getreg("eflags")
reg_eflags ^= eval("EFLAGS_%s" % flags[flagname])
result = self.execute("set $eflags = 0x%x" % reg_eflags)
@@ -1237,7 +1210,7 @@ def eval_target(self, inst):
Evaluate target address of an instruction, used for jumpto decision
Args:
- - inst: AMS instruction text (String)
+ - inst: ASM instruction text (String)
Returns:
- target address (Int)
@@ -1250,10 +1223,11 @@ def eval_target(self, inst):
p = re.compile(".*?:\s*[^ ]*\s*(.* PTR ).*(0x[^ ]*)")
m = p.search(inst)
if not m:
- p = re.compile(".*?:\s.*(0x[^ ]*)")
+ p = re.compile(".*?:\s.*\s(0x[^ ]*|\w+)")
m = p.search(inst)
if m:
target = m.group(1)
+ target = self.parse_and_eval(target)
else:
target = None
else:
@@ -1450,6 +1424,30 @@ def _get_offline_maps():
return binmap
+ def _get_allmaps_osx(pid, remote=False):
+ maps = []
+ #_DATA 00007fff77975000-00007fff77976000 [ 4K] rw-/rw- SM=COW /usr/lib/system/libremovefile.dylib
+ pattern = re.compile("([^\n]*)\s* ([0-9a-f][^-\s]*)-([^\s]*) \[.*\]\s([^/]*).* (.*)")
+
+ if remote: # remote target, not yet supported
+ return maps
+ else: # local target
+ try: out = execute_external_command("/usr/bin/vmmap -w %s" % self.getpid())
+ except: error_msg("could not read vmmap of process")
+
+ matches = pattern.findall(out)
+ if matches:
+ for (name, start, end, perm, mapname) in matches:
+ if name.startswith("Stack"):
+ mapname = "[stack]"
+ start = to_int("0x%s" % start)
+ end = to_int("0x%s" % end)
+ if mapname == "":
+ mapname = name.strip()
+ maps += [(start, end, perm, mapname)]
+ return maps
+
+
def _get_allmaps_freebsd(pid, remote=False):
maps = []
mpath = "/proc/%s/map" % pid
@@ -1505,7 +1503,10 @@ def _get_allmaps_linux(pid, remote=False):
result = []
pid = self.getpid()
if not pid: # not running, try to use elfheader()
- return _get_offline_maps()
+ try:
+ return _get_offline_maps()
+ except:
+ return []
# retrieve all maps
os = self.getos()
@@ -1513,7 +1514,8 @@ def _get_allmaps_linux(pid, remote=False):
maps = []
try:
if os == "FreeBSD": maps = _get_allmaps_freebsd(pid, rmt)
- elif os == "Linux" : maps = _get_allmaps_linux(pid, rmt)
+ elif os == "Linux" : maps = _get_allmaps_linux(pid, rmt)
+ elif os == "Darwin" : maps = _get_allmaps_osx(pid, rmt)
except Exception as e:
if config.Option.get("debug") == "on":
msg("Exception: %s" %e)
@@ -1632,7 +1634,10 @@ def get_disasm(self, address, count=1):
- asm code (String)
"""
code = self.execute_redirect("x/%di 0x%x" % (count, address))
- return code.rstrip()
+ if code:
+ return code.rstrip()
+ else:
+ return ""
def dumpmem(self, start, end):
"""
@@ -2120,7 +2125,7 @@ def examine_data(value, bits=32):
return result
@memoized
- def examine_mem_reference(self, value):
+ def examine_mem_reference(self, value, depth=5):
"""
Deeply examine a value in memory for its references
@@ -2131,8 +2136,16 @@ def examine_mem_reference(self, value):
- list of tuple of (value(Int), type(String), next_value(Int))
"""
result = []
+ if depth <= 0:
+ depth = 0xffffffff
+
(v, t, vn) = self.examine_mem_value(value)
while vn is not None:
+ if len(result) > depth:
+ _v, _t, _vn = result[-1]
+ result[-1] = (_v, _t, "--> ...")
+ break
+
result += [(v, t, vn)]
if v == vn or to_int(v) == to_int(vn): # point to self
break
@@ -2226,7 +2239,7 @@ def elfheader(self, name=None):
if not out:
return {}
- p = re.compile("\s*(0x[^-]*)->(0x[^ ]*) at (.*):\s*([^ ]*)\s*(.*)")
+ p = re.compile("\s*(0x[^-]*)->(0x[^ ]*) at (0x[^:]*):\s*([^ ]*)\s*(.*)")
matches = p.findall(out)
for (start, end, offset, hname, attr) in matches:
@@ -3027,7 +3040,7 @@ def _is_running(self):
"""
pid = peda.getpid()
if pid is None:
- text = "not running or target is remote"
+ text = "not running"
warning_msg(text)
return None
#raise Exception(text)
@@ -4358,6 +4371,10 @@ def context(self, *arg):
if not self._is_running():
return
+ clearscr = config.Option.get("clearscr")
+ if clearscr == "on":
+ clearscreen()
+
status = peda.get_status()
# display registers
if "reg" in opt or "register" in opt:
@@ -4379,6 +4396,26 @@ def context(self, *arg):
return
+ def breakrva(self, *arg):
+ """
+ Set breakpoint by Relative Virtual Address (RVA)
+ Usage:
+ MYNAME rva
+ MYNAME rva module_name (e.g binary, shared module name)
+ """
+ (rva, module) = normalize_argv(arg, 2)
+ if rva is None or not to_int(rva):
+ self._missing_argument()
+ if module is None:
+ module = 'binary'
+
+ binmap = peda.get_vmmap(module)
+ if len(binmap) == 0:
+ msg("No module matches '%s'" % module)
+ else:
+ base_address = binmap[0][0]
+ peda.set_breakpoint(base_address+rva)
+ return
#################################
# Memory Operation Commands #
@@ -4708,6 +4745,8 @@ def telescope(self, *arg):
step = peda.intsize()
if not peda.is_address(address): # cannot determine address
+ msg("Invalid $SP address: 0x%x" % address, "red")
+ return
for i in range(count):
if not peda.execute("x/%sx 0x%x" % ("g" if step == 8 else "w", address + i*step)):
break
@@ -4734,10 +4773,10 @@ def telescope(self, *arg):
def eflags(self, *arg):
"""
- Display/set/clear value of eflags register
+ Display/set/clear/toggle value of eflags register
Usage:
MYNAME
- MYNAME [set|clear] flagname
+ MYNAME [set|clear|toggle] flagname
"""
FLAGS = ["CF", "PF", "AF", "ZF", "SF", "TF", "IF", "DF", "OF"]
FLAGS_TEXT = ["Carry", "Parity", "Adjust", "Zero", "Sign", "Trap",
@@ -4747,10 +4786,10 @@ def eflags(self, *arg):
if not self._is_running():
return
- if option and not flagname:
+ elif option and not flagname:
self._missing_argument()
- if option is None: # display eflags
+ elif option is None: # display eflags
flags = peda.get_eflags()
text = ""
for (i, f) in enumerate(FLAGS):
@@ -4762,14 +4801,17 @@ def eflags(self, *arg):
eflags = peda.getreg("eflags")
msg("%s: 0x%x (%s)" % (green("EFLAGS"), eflags, text.strip()))
- if option == "set":
- peda.set_eflags(flagname.lower())
+ elif option == "set":
+ peda.set_eflags(flagname, True)
- if option == "clear":
+ elif option == "clear":
peda.set_eflags(flagname, False)
+ elif option == "toggle":
+ peda.set_eflags(flagname, None)
+
return
- eflags.options = ["set", "clear"]
+ eflags.options = ["set", "clear", "toggle"]
def xinfo(self, *arg):
"""
@@ -4802,17 +4844,9 @@ def get_reg_text(r, v):
for r in REGISTERS[bits]:
if r in regs:
text += get_reg_text(r, regs[r])
- # text += green("%s" % r.upper().ljust(3)) + ": "
- # chain = peda.examine_mem_reference(regs[r])
- # text += format_reference_chain(chain)
- # text += "\n"
else:
for (r, v) in sorted(regs.items()):
text += get_reg_text(r, v)
- # text += green("%s" % r.upper().ljust(3)) + ": "
- # chain = peda.examine_mem_reference(v)
- # text += format_reference_chain(chain)
- # text += "\n"
if text:
msg(text.strip())
if regname is None or "eflags" in regname:
@@ -4823,7 +4857,7 @@ def get_reg_text(r, v):
warning_msg("not a register nor an address")
else:
# Address
- chain = peda.examine_mem_reference(address)
+ chain = peda.examine_mem_reference(address, depth=0)
text += format_reference_chain(chain) + "\n"
vmrange = peda.get_vmrange(address)
if vmrange:
@@ -5656,7 +5690,7 @@ def shellcode(self, *arg):
MYNAME generate [arch/]platform type [port] [host]
MYNAME search keyword (use % for any character wildcard)
MYNAME display shellcodeId (shellcodeId as appears in search results)
- MYNAME zsc [generate customize shellcode]
+ MYNAME zsc [generate customize shellcode]
For generate option:
default port for bindport shellcode: 16706 (0x4142)
@@ -5755,20 +5789,20 @@ def list_shellcode():
while True:
for os in oslist:
msg('%s %s'%(yellow('[+]'),green(os)))
- if pyversion is 2:
+ if pyversion == 2:
os = input('%s'%blue('os:'))
- if pyversion is 3:
+ if pyversion == 3:
os = input('%s'%blue('os:'))
- if os in oslist: #check if os exist
+ if os in oslist: #check if os exist
break
else:
warning_msg("Wrong input! Try Again.")
while True:
for job in joblist:
msg('%s %s'%(yellow('[+]'),green(job)))
- if pyversion is 2:
+ if pyversion == 2:
job = raw_input('%s'%blue('job:'))
- if pyversion is 3:
+ if pyversion == 3:
job = input('%s'%blue('job:'))
if job != '':
break
@@ -5777,9 +5811,9 @@ def list_shellcode():
while True:
for encode in encodelist:
msg('%s %s'%(yellow('[+]'),green(encode)))
- if pyversion is 2:
+ if pyversion == 2:
encode = raw_input('%s'%blue('encode:'))
- if pyversion is 3:
+ if pyversion == 3:
encode = input('%s'%blue('encode:'))
if encode != '':
break
@@ -6111,6 +6145,7 @@ def sigint_handler(signal, frame):
Alias("stack", "peda telescope $sp")
Alias("viewmem", "peda telescope")
Alias("reg", "peda xinfo register")
+Alias("brva", "breakrva")
# misc gdb settings
peda.execute("set confirm off")
diff --git a/python23-compatibility.md b/python23-compatibility.md
index e5b0036..d9b05a0 100644
--- a/python23-compatibility.md
+++ b/python23-compatibility.md
@@ -34,7 +34,7 @@ isinstance(x, six.integer_types)
## Strings
In Python 2, `bytes` is an alias for `str`. In Python 3, `str` is a unicode
-type and `bytes` is used for a sequece of arbitrary bytes. Use a leading 'b' to
+type and `bytes` is used for a sequence of arbitrary bytes. Use a leading 'b' to
signify that a string is a `bytes` object.
```python