refactored wrapper (#280)

* added command got to display status of the got table

Signed-off-by: degrigis <degrigis@gmail.com>

* return when checksec is not available and added decorator OnlyWhenRunning

Signed-off-by: degrigis <degrigis@gmail.com>

* removed duplicated code for pie and not pie binaries

Signed-off-by: degrigis <degrigis@gmail.com>

* inserted support function to get checksec output and performed all requirements check initially

Signed-off-by: degrigis <degrigis@gmail.com>

* corrected typo

Signed-off-by: degrigis <degrigis@gmail.com>

* reorganized the command got splitting the code in library routines and moved the checksec internal function in a separate module

Signed-off-by: degrigis <degrigis@gmail.com>

* handled exception directly inside functions and enhanced code

Signed-off-by: degrigis <degrigis@gmail.com>

* extracted only column in readelf output and enhanced exception handling

Signed-off-by: degrigis <degrigis@gmail.com>

* fix exception handling returning subprocess error

Signed-off-by: degrigis <degrigis@gmail.com>

* removed unused import and reordered

Signed-off-by: degrigis <degrigis@gmail.com>

* reordered imports

Signed-off-by: degrigis <degrigis@gmail.com>

* added wrappers module and refactored some code

Signed-off-by: degrigis <degrigis@gmail.com>

* removed not useful comment

Signed-off-by: degrigis <degrigis@gmail.com>

* removed unused import

Signed-off-by: degrigis <degrigis@gmail.com>

* moved comments in docstring

Signed-off-by: degrigis <degrigis@gmail.com>

* refactored code to use partial functions, simplified code

Signed-off-by: degrigis <degrigis@gmail.com>

* simplified a loc

Signed-off-by: degrigis <degrigis@gmail.com>

* capslock char fixed

Signed-off-by: degrigis <degrigis@gmail.com>

* removed unuseful pwndbg.arch.ptrsize check

Signed-off-by: degrigis <degrigis@gmail.com>

* refactored code and added the new module wrapper that contains every new wrapper module

Signed-off-by: degrigis <degrigis@gmail.com>

* used class style decorator for wrapper and improved code style

Signed-off-by: degrigis <degrigis@gmail.com>

* changed return with print for errors

Signed-off-by: degrigis <degrigis@gmail.com>

* removed prints debug and statically linked check moved at the top of the got function

Signed-off-by: degrigis <degrigis@gmail.com>

* refactored OnlyWithCommand decorator

Signed-off-by: degrigis <degrigis@gmail.com>

* wrappers are OnlyWithFile now

Signed-off-by: degrigis <degrigis@gmail.com>

* redirected stderr to stdout in subprocess.check_output and memoized the wrappers for readelf/file/checksec

Signed-off-by: degrigis <degrigis@gmail.com>

* reordered an import

Signed-off-by: degrigis <degrigis@gmail.com>

* removed pdb

Signed-off-by: degrigis <degrigis@gmail.com>

* fixed format string and removed desc from got command

Signed-off-by: degrigis <degrigis@gmail.com>

* consolidated decorators

Signed-off-by: degrigis <degrigis@gmail.com>

* merging

Signed-off-by: degrigis <degrigis@gmail.com>

* reordered import for travis

Signed-off-by: degrigis <degrigis@gmail.com>

* refactored some code

Signed-off-by: degrigis <degrigis@gmail.com>

* resolve travis complains

Signed-off-by: degrigis <degrigis@gmail.com>

* docstring for _extract_jumps

Signed-off-by: degrigis <degrigis@gmail.com>

* fixed isort

Signed-off-by: degrigis <degrigis@gmail.com>

* f*** isort

Signed-off-by: degrigis <degrigis@gmail.com>
pull/305/head
degrigis 8 years ago committed by Disconnect3d
parent 5af436a60b
commit 8775073df0

@ -73,6 +73,8 @@ import pwndbg.ui
import pwndbg.version
import pwndbg.vmmap
import pwndbg.wrappers
import pwndbg.wrappers.checksec
import pwndbg.wrappers.readelf
__version__ = pwndbg.version.__version__
version = __version__

@ -7,7 +7,7 @@ from __future__ import unicode_literals
import pwndbg.commands
import pwndbg.which
import pwndbg.wrappers
import pwndbg.wrappers.checksec
@pwndbg.commands.Command
@ -17,5 +17,4 @@ def checksec(file=None):
Prints out the binary security settings. Attempts to call the binjitsu
checksec first, and then falls back to checksec.sh.
'''
local_path = file or pwndbg.file.get_file(pwndbg.proc.exe)
print(pwndbg.wrappers.checksec("--file",local_path))
print(pwndbg.wrappers.checksec.get_raw_out())

@ -12,7 +12,8 @@ import pwndbg.commands
import pwndbg.enhance
import pwndbg.file
import pwndbg.which
import pwndbg.wrappers
import pwndbg.wrappers.checksec
import pwndbg.wrappers.readelf
from pwndbg.color import green
from pwndbg.color import light_yellow
from pwndbg.color import red
@ -21,39 +22,23 @@ parser = argparse.ArgumentParser(description='Show the state of the Global Offse
parser.add_argument('name_filter', help='Filter results by passed name.',
type=str, nargs='?', default='')
@pwndbg.commands.ArgparsedCommand(parser)
@pwndbg.commands.OnlyWhenRunning
def got(name_filter=''):
local_path = pwndbg.file.get_file(pwndbg.proc.exe)
cs_out = pwndbg.wrappers.checksec("--file", local_path)
file_out = pwndbg.wrappers.file(local_path)
if "statically" in file_out:
print(red("Binary is statically linked."))
return
readelf_out = pwndbg.wrappers.readelf("--relocs", local_path)
jmpslots = '\n'.join(filter(lambda l: _extract_jumps(l),
readelf_out.splitlines()))
relro_status = pwndbg.wrappers.checksec.relro_status()
pie_status = pwndbg.wrappers.checksec.pie_status()
jmpslots = list(pwndbg.wrappers.readelf.get_jmpslots())
if not len(jmpslots):
print(red("NO JUMP_SLOT entries available in the GOT"))
return
if "PIE enabled" in cs_out:
if "PIE enabled" in pie_status:
bin_text_base = pwndbg.memory.page_align(pwndbg.elf.entry())
relro_status = "No RELRO"
if "Full RELRO" in cs_out:
relro_status = "Full RELRO"
elif "Partial RELRO" in cs_out:
relro_status = "Partial RELRO"
print("\nGOT protection: %s | GOT functions: %d\n " % (green(relro_status), len(jmpslots.splitlines())))
print("\nGOT protection: %s | GOT functions: %d\n " % (green(relro_status), len(jmpslots)))
for line in jmpslots.splitlines():
for line in jmpslots:
address, info, rtype, value, name = line.split()[:5]
if name_filter not in name:
@ -61,23 +46,8 @@ def got(name_filter=''):
address_val = int(address, 16)
if "PIE enabled" in cs_out: # if PIE, address is only the offset from the binary base address
if "PIE enabled" in pie_status: # if PIE, address is only the offset from the binary base address
address_val = bin_text_base + address_val
got_address = pwndbg.memory.pvoid(address_val)
print("[%s] %s -> %s" % (address, light_yellow(name), pwndbg.chain.format(got_address)))
def _extract_jumps(l):
try:
# Checks for records in `readelf --relocs <binary>` which has type e.g. `R_X86_64_JUMP_SLO`
# NOTE: Because of that we DO NOT display entries that are not writeable (due to FULL RELRO)
# as they have `R_X86_64_GLOB_DAT` type.
#
# Probably we should display them seperately.
if 'JUMP' in l.split()[2]:
return l
else:
return False
except IndexError:
return False
print("[0x%x] %s -> %s" % (address_val, light_yellow(name), pwndbg.chain.format(got_address)))

@ -1,33 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Wrappers to external utilities.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import functools
import subprocess
import pwndbg.which
def call_program(progname, *args):
program = pwndbg.which.which(progname)
if not program:
raise OSError('Could not find %s command in $PATH.' % progname)
cmd = [progname] + list(args)
try:
return subprocess.check_output(cmd, stderr=subprocess.STDOUT).decode('utf-8')
except Exception as e:
raise OSError('Error during execution of %s command: %s' % (progname, e))
checksec = functools.partial(call_program, 'checksec')
readelf = functools.partial(call_program, 'readelf')
file = functools.partial(call_program, 'file')

@ -0,0 +1,35 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import functools
import subprocess
from subprocess import STDOUT
import pwndbg.commands
import pwndbg.which
class OnlyWithCommand(object):
def __init__(self, command):
self.cmd_name = command
self.cmd_path = pwndbg.which.which(command)
def __call__(self, function):
function.cmd_path = self.cmd_path
@pwndbg.commands.OnlyWithFile
@functools.wraps(function)
def _OnlyWithCommand(*a,**kw):
if self.cmd_path:
return function(*a, **kw)
else:
raise OSError('Could not find command %s in $PATH' % self.cmd_name)
return _OnlyWithCommand
def call_cmd(cmd):
return subprocess.check_output(cmd, stderr=STDOUT).decode('utf-8')

@ -0,0 +1,46 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import pwndbg.commands
import pwndbg.wrappers
cmd_name = "checksec"
@pwndbg.wrappers.OnlyWithCommand(cmd_name)
def get_raw_out():
local_path = pwndbg.file.get_file(pwndbg.proc.exe)
cmd = [get_raw_out.cmd_path, "--file", local_path]
return pwndbg.wrappers.call_cmd(cmd)
@pwndbg.wrappers.OnlyWithCommand(cmd_name)
def relro_status():
relro = "No RELRO"
local_path = pwndbg.file.get_file(pwndbg.proc.exe)
cmd = [relro_status.cmd_path, "--file", local_path]
out = pwndbg.wrappers.call_cmd(cmd)
if "Full RELRO" in out:
relro = "Full RELRO"
elif "Partial RELRO" in out:
relro = "Partial RELRO"
return relro
@pwndbg.wrappers.OnlyWithCommand(cmd_name)
def pie_status():
pie = "No PIE"
local_path = pwndbg.file.get_file(pwndbg.proc.exe)
cmd = [pie_status.cmd_path, "--file", local_path]
out = pwndbg.wrappers.call_cmd(cmd)
if "PIE enabled" in out:
pie = "PIE enabled"
return pie

@ -0,0 +1,35 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import pwndbg.wrappers
cmd_name = "readelf"
@pwndbg.wrappers.OnlyWithCommand(cmd_name)
def get_jmpslots():
local_path = pwndbg.file.get_file(pwndbg.proc.exe)
cmd = [get_jmpslots.cmd_path, "--relocs", local_path]
readelf_out = pwndbg.wrappers.call_cmd(cmd)
return filter(_extract_jumps, readelf_out.splitlines())
def _extract_jumps(line):
'''
Checks for records in `readelf --relocs <binary>` which has type e.g. `R_X86_64_JUMP_SLO`
NOTE: Because of that we DO NOT display entries that are not writeable (due to FULL RELRO)
as they have `R_X86_64_GLOB_DAT` type.
It might be good to display them seperately in the future.
'''
try:
if "JUMP" in line.split()[2]:
return line
else:
return False
except IndexError:
return False
Loading…
Cancel
Save