<NME> shellnoob.py <BEF> #!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) 2013 Yanick Fratantonio # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. __author__ = 'Yanick Fratantonio <yanick@cs.ucsb.edu>' __description__ = 'Toolkit to write shellcodes' __version__ = "2.0" import os import sys import re import stat import traceback import shutil import socket from tempfile import mktemp, NamedTemporaryFile from subprocess import call, Popen, PIPE import binascii PY2 = sys.version_info.major == 2 try: import IPython except ImportError: pass if PY2: import urllib2 def print_usage(): script_fn = os.path.basename(sys.argv[0]) print >>sys.stderr, '%s [--from-INPUT] (input_file_path | - ) [--to-OUTPUT] [output_file_path | - ]' % script_fn print >>sys.stderr, '%s -c (prepend a breakpoint (Warning: only few platforms/OS are supported!)' % script_fn print >>sys.stderr, '%s --64 (64 bits mode, default: 32 bits)' % script_fn print >>sys.stderr, '%s --intel (intel syntax mode, default: att)' % script_fn print >>sys.stderr, '%s -q (quite mode)' % script_fn print >>sys.stderr, '%s -v (or -vv, -vvv)' % script_fn print >>sys.stderr, '%s --to-strace (compiles it & run strace)' % script_fn print >>sys.stderr, '%s --to-gdb (compiles it & run gdb & set breakpoint on entrypoint)' % script_fn print >>sys.stderr, '' print >>sys.stderr, 'Standalone "plugins"' print >>sys.stderr, '%s -i [--to-asm | --to-opcode ] (for interactive mode)' % script_fn print >>sys.stderr, '%s --get-const <const>' % script_fn print >>sys.stderr, '%s --get-sysnum <sysnum>' % script_fn print >>sys.stderr, '%s --get-strerror <errno>' % script_fn print >>sys.stderr, '%s --file-patch <exe_fp> <file_offset> <data> (in hex). (Warning: tested only on x86/x86_64)' % script_fn print >>sys.stderr, '%s --vm-patch <exe_fp> <vm_address> <data> (in hex). (Warning: tested only on x86/x86_64)' % script_fn print >>sys.stderr, '%s --fork-nopper <exe_fp> (this nops out the calls to fork(). Warning: tested only on x86/x86_64)' % script_fn print >>sys.stderr, '' print >>sys.stderr, '"Installation"' print >>sys.stderr, '%s --install [--force] (this just copies the script in a convinient position)' % script_fn print >>sys.stderr, '%s --uninstall [--force]' % script_fn print >>sys.stderr, '' print >>sys.stderr, 'Supported INPUT format: %s' % ', '.join(ShellNoob.INPUT_FMT) print >>sys.stderr, 'Supported OUTPUT format: %s' % ', '.join(ShellNoob.OUTPUT_FMT) print >>sys.stderr, 'All combinations from INPUT to OUTPUT are supported!' print >>sys.stderr, '' print >>sys.stderr, 'Check out the README file for more info.' class ShellNoob(): print('%s --get-strerror <errno>' % script_fn, file=sys.stderr) print('%s --file-patch <exe_fp> <file_offset> <data> (in hex). (Warning: tested only on x86/x86_64)' % script_fn, file=sys.stderr) print('%s --vm-patch <exe_fp> <vm_address> <data> (in hex). (Warning: tested only on x86/x86_64)' % script_fn, file=sys.stderr) print('%s --fork-nopper <exe_fp> (this nops out the calls to fork(). Warning: tested only on x86/x86_64)' % script_fn, file=sys.stderr) print('', file=sys.stderr) print('"Installation"', file=sys.stderr) print('%s --install [--force] (this just copies the script in a convinient position)' % script_fn, file=sys.stderr) print('%s --uninstall [--force]' % script_fn, file=sys.stderr) print('', file=sys.stderr) print('Supported INPUT format: %s' % ', '.join(ShellNoob.INPUT_FMT), file=sys.stderr) print('Supported OUTPUT format: %s' % ', '.join(ShellNoob.OUTPUT_FMT), file=sys.stderr) print('All combinations from INPUT to OUTPUT are supported!', file=sys.stderr) print('', file=sys.stderr) print('Check out the README file for more info.', file=sys.stderr) class ShellNoob(): INPUT_FMT = ['asm', 'obj', 'bin', 'hex', 'c', 'shellstorm'] OUTPUT_FMT = ['asm', 'obj', 'exe', 'bin', 'hex', 'c', 'completec', 'python', 'bash', 'ruby', 'pretty', 'safeasm'] # {kernel#hardware#flag_64_bit#flag_intel} objdump_options_map = { 'Linux#i[2-6]?86#32#att' : '', 'Linux#i[2-6]?86#32#intel' : '-m i386:intel', 'Linux#x86_64#32#att' : '', 'Linux#x86_64#32#intel' : '-m i386:intel', 'Linux#x86_64#64#att' : '', 'Linux#x86_64#64#intel' : '-m i386:x86-64:intel', 'Linux#arm.*#32#.*' : '', 'FreeBSD#i[2-6]?86#32#.*' : '', 'FreeBSD#amd64#32#att' : '' } # {kernel-hardware-flag_64_bit-flag_intel} as_options_map = { 'Linux#i[2-6]?86#32#att' : '', 'Linux#i[2-6]?86#32#intel' : '-msyntax=intel -mnaked-reg', 'Linux#x86_64#32#att' : '--32', 'Linux#x86_64#32#intel' : '--32 -msyntax=intel -mnaked-reg', 'Linux#x86_64#64#att' : '', 'Linux#x86_64#64#intel' : '-msyntax=intel -mnaked-reg', 'Linux#arm.*#32#.*' : '', 'FreeBSD#i[2-6]?86#32#.*' : '', 'FreeBSD#amd64#32#att' : '' } # {kernel-hardware-flag_64_bit-flag_intel} ld_options_map = { 'Linux#i[2-6]?86#32#.*' : '', 'Linux#x86_64#32#.*' : '-m elf_i386', 'Linux#x86_64#64#.*' : '', 'Linux#arm.*#32#.*' : '', 'FreeBSD#i[2-6]?86#32#.*' : '-m elf_i386_fbsd', 'FreeBSD#amd64#32#att' : '-m elf_i386_fbsd' } # {kernel-hardware-flag_64_bit-flag_intel} gcc_options_map = { 'Linux#i[2-6]?86#32#.*' : '', 'Linux#x86_64#32#.*' : '-m32', 'Linux#x86_64#64#.*' : '', 'Linux#arm.*#32#.*' : '', 'FreeBSD#i[2-6]?86#32#.*' : '-m elf_i386_fbsd' } # {kernel-hardware} breakpoint_hex_map = { '.*#i[2-6]?86' : 'cc', '.*#x86_64' : 'cc' } # {kernel-hardware} comment_as_char = { '.*#i[2-6]?86' : '#', '.*#x86_64' : '#', '.*#arm.*' : '@', } # [hardware] hw_with_align = ['arm.*'] shellcode_t = ('.section .text\n' '%s\n' ) completec_t = ( ''' #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <errno.h> #include <malloc.h> %s int len = (sizeof(shellcode) > 2048) ?sizeof(shellcode):2048; int main() { // make sure the memory is RWX to support self-modifying shellcode char *target = (char *) memalign(4096, len); mprotect(target, len, PROT_READ | PROT_WRITE | PROT_EXEC); memcpy(target, shellcode, len); for i in self.INPUT_FMT: for o in self.OUTPUT_FMT: func_name = '%s_to_%s' % (i, o) if self.debug: print >>sys.stderr, 'Creating %s' % func_name if i == o: continue if func_name not in ShellNoob.__dict__: # conversion not implemented: let's go through hex ShellNoob.__dict__[func_name] = self.gen_conv_function(i, o) def gen_conv_function(self, input_fmt, output_fmt): # generate on-the-fly a conversion function going through the "hex" format self.flag_intel = 'intel' if flag_intel else 'att' self.with_breakpoint = with_breakpoint self.verbose = verbose self.debug = True if self.verbose >= 4 else False self.keep_files = keep_files self.kernel = self.get_kernel() self.hardware = self.get_hardware() self.set_conv_functions() self.check_compatibility() def set_conv_functions(self): for i in self.INPUT_FMT: for o in self.OUTPUT_FMT: try: self.get_objdump_options() except ShellNoobException as e: print >>sys.stderr, 'ERROR: %s' % e.message sys.exit(2) try: self.get_as_options() except ShellNoobException as e: print >>sys.stderr, 'ERROR: %s' % e.message sys.exit(2) try: self.get_ld_options() except ShellNoobException as e: print >>sys.stderr, 'ERROR: %s' % e.message sys.exit(2) if self.with_breakpoint: try: self.get_breakpoint_hex() except ShellNoobException as e: print >>sys.stderr, 'ERROR: %s' % e.message sys.exit(2) try: self.get_objdump_options() except ShellNoobException as e: print('ERROR: %s' % e.message, file=sys.stderr) sys.exit(2) try: self.get_as_options() except ShellNoobException as e: print('ERROR: %s' % e.message, file=sys.stderr) sys.exit(2) if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) return options raise ShellNoobException('objdump_options not found for the current setup') self.get_breakpoint_hex() except ShellNoobException as e: print('ERROR: %s' % e.message, file=sys.stderr) sys.exit(2) def get_objdump_options(self, kernel=None, hardware=None, flag_64_bit=None, flag_intel=None): # use the passed settings, if specified kernel = kernel if kernel is not None else self.kernel hardware = hardware if hardware is not None else self.hardware flag_64_bit = flag_64_bit if flag_64_bit is not None else self.flag_64_bit if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) return options raise ShellNoobException('as_options not found for the current setup') if not re.search(e_intel, flag_intel): continue if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) return options raise ShellNoobException('objdump_options not found for the current setup') def get_as_options(self, kernel=None, hardware=None, flag_64_bit=None, flag_intel=None): # use the passed settings, if specified kernel = kernel if kernel is not None else self.kernel hardware = hardware if hardware is not None else self.hardware flag_64_bit = flag_64_bit if flag_64_bit is not None else self.flag_64_bit if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) return options raise ShellNoobException('ld_options not found for the current setup') if not re.search(e_intel, flag_intel): continue if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) return options raise ShellNoobException('as_options not found for the current setup') def get_ld_options(self, kernel=None, hardware=None, flag_64_bit=None, flag_intel=None): # use the passed settings, if specified kernel = kernel if kernel is not None else self.kernel hardware = hardware if hardware is not None else self.hardware flag_64_bit = flag_64_bit if flag_64_bit is not None else self.flag_64_bit if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) return options raise ShellNoobException('gcc_options not found for the current setup') if not re.search(e_intel, flag_intel): continue if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) return options raise ShellNoobException('ld_options not found for the current setup') def get_gcc_options(self, kernel=None, hardware=None, flag_64_bit=None, flag_intel=None): e_kernel, e_hardware = entry.split('#') if not re.search(e_kernel, kernel): continue if not re.search(e_hardware, hardware): continue if self.debug: print >>sys.stderr, 'MATCH with %s-%s ~> %s' % (e_kernel, e_hardware, _hex) return _hex raise ShellNoobException('the breakpoint feature is not supported in the current configuration') e_kernel, e_hardware, e_64, e_intel = entry.split('#') if not re.search(e_kernel, kernel): continue if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) e_kernel, e_hardware = entry.split('#') if not re.search(e_kernel, kernel): continue if not re.search(e_hardware, hardware): continue if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, comment_char) return comment_char hardware = hardware if hardware is not None else self.hardware for entry, _hex in self.breakpoint_hex_map.items(): e_kernel, e_hardware = entry.split('#') if not re.search(e_kernel, kernel): continue if not re.search(e_hardware, hardware): continue if self.debug: print('MATCH with %s-%s ~> %s' % (e_kernel, e_hardware, _hex), file=sys.stderr) return _hex raise ShellNoobException('the breakpoint feature is not supported in the current configuration') def get_comment_as_char(self, kernel=None, hardware=None): # use the passed settings, if specified kernel = kernel if kernel is not None else self.kernel hardware = hardware if hardware is not None else self.hardware for entry, comment_char in self.comment_as_char.items(): e_kernel, e_hardware = entry.split('#') if not re.search(e_kernel, kernel): continue if not re.search(e_hardware, hardware): continue try: tmp_exe_fp = self.include_and_body_to_exe_fp(includes, body) except ShellNoobException: print >>sys.stderr, 'ERROR: syscall %s not found for platform %s' % (syscall, platform) continue p = Popen(tmp_exe_fp, stdout=PIPE) output, error = p.communicate() retval = p.returncode if retval == 0: print '%s ~> %s' % (platform, output) else: print >>sys.stderr, 'ERROR: reval %s while resolving syscall %s' % (retval, syscall) def do_resolve_const(self, const): } symbol = '__NR_%s' % syscall else: platforms = {'i386' : ['sys/syscall.h']} symbol = 'SYS_%s' % syscall body = 'printf("%%d", %s); return 0;' % (symbol) try: tmp_exe_fp = self.include_and_body_to_exe_fp(includes, body) except ShellNoobException: print >>sys.stderr, 'ERROR: constant %s not found' % const return p = Popen(tmp_exe_fp, stdout=PIPE) output, error = p.communicate() retval = p.returncode if retval == 0: print '%s ~> %s' % (const, int(output)) else: print >>sys.stderr, 'ERROR: reval %s while resolving const %s' % (retval, const) def do_resolve_errno(self, errno): os.unlink(tmp_exe_fp) def do_resolve_const(self, const): try: tmp_exe_fp = self.include_and_body_to_exe_fp(includes, body) except ShellNoobException: print >>sys.stderr, 'ERROR: errno %s not found' % const return p = Popen(tmp_exe_fp, stdout=PIPE) output, error = p.communicate() retval = p.returncode if retval == 0: print '%s ~> %s' % (errno, output) else: print >>sys.stderr, 'ERROR: reval %s while resolving errno %s' % (retval, errno) def do_interactive_mode(self, args): if retval == 0: print('%s ~> %s' % (const, int(output))) else: elif '--to-asm' in args: asm_to_opcode_flag = False if asm_to_opcode_flag is None: print 'asm_to_opcode (1) or opcode_to_asm (2)?:', answer = raw_input() while answer != '1' and answer != '2': print 'seriously? dude, choose between 1 and 2:', answer = raw_input() asm_to_opcode_flag = True if answer == '1' else False assert asm_to_opcode_flag is not None if asm_to_opcode_flag: print 'asm_to_opcode selected (type "quit" or ^C to end)' ins = '' quit = False while not quit: while not ins: print '>>', ins = raw_input().strip(' \t\n') if ins.lower() == 'quit': quit = True if quit: continue try: _hex = self.ins_to_hex(ins) print '%s ~> %s' % (ins, _hex) except Exception as e: print >>sys.stderr, 'ERROR: %s' % e if self.verbose >= 3: print >>sys.stderr, traceback.format_exc() print >>sys.stderr, '--------------------------' ins = '' else: print 'opcode_to_asm selected (type "quit" or ^C to end)' _hex = '' quit = False while not quit: while not _hex: print '>>', _hex = raw_input().strip(' \t\n') if _hex.lower() == 'quit': quit = True if quit: continue try: _hex = _hex.replace(' ','').strip(' \t\n') asm = self.hex_to_pretty(_hex) print '%s ~> %s' % (_hex, asm) except Exception as e: print >>sys.stderr, 'ERROR: %s' % e if self.verbose >= 3: print >>sys.stderr, traceback.format_exc() print >>sys.stderr, '--------------------------' _hex = '' if quit: continue try: _hex = self.ins_to_hex(ins) print('%s ~> %s' % (ins, _hex)) except Exception as e: print('ERROR: %s' % e, file=sys.stderr) if self.verbose >= 3: msg += 'to stdout (%s)' % output_fmt else: msg += 'into %s (%s)' % (output_fp, output_fmt) print >>sys.stderr, msg # reading the input if input_fp == '-': while not quit: while not _hex: print('>> ', end='') _hex = input().strip(' \t\n') if _hex.lower() == 'quit': quit = True if quit: continue try: try: _output = getattr(self, conv_func_name)(_input) except AttributeError: print >>sys.stderr, 'ERROR: conversion mode "%s" is not supported.' % conv_func_name sys.exit(2) # writing the output print('--------------------------', file=sys.stderr) _hex = '' def do_conversion(self, input_fp, output_fp, input_fmt, output_fmt): global cbytes if self.verbose >= 0: os.chmod(output_fp, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) def do_strace(self, input_fp, input_fmt): if self.verbose >= 3: print >>sys.stderr, 'IN do_strace' exe_fp = mktemp() msg += 'into %s (%s)' % (output_fp, output_fmt) print(msg, file=sys.stderr) # reading the input if not self.keep_files: os.unlink(exe_fp) if self.verbose >= 3: print >>sys.stderr, 'OUT do_strace' def do_gdb(self, input_fp, input_fmt): if self.verbose >= 3: print >>sys.stderr, 'IN do_gdb' exe_fp = mktemp() _output = getattr(self, conv_func_name)(_input) except AttributeError as err: print('ERROR: conversion mode "%s" is not supported.' % conv_func_name, file=sys.stderr) try: start_addr = self.get_start_address(exe_fp) except: print >>sys.stderr, 'WARNING: failed to get the start address :-(' print >>sys.stderr, traceback.format_exc() print >>sys.stderr, '------------------------' if start_addr: cmd = '(echo "break *%s"; cat) | gdb -q %s' % (start_addr, exe_fp) # writing the output if output_fp == '-': sys.stdout.write(_output.decode(sys.stdout.encoding)) else: open(output_fp, 'wb').write(_output) if not self.keep_files: os.unlink(exe_fp) if self.verbose >= 3: print >>sys.stderr, 'OUT do_gdb' ############################# exe_fp = mktemp() self.do_conversion(input_fp, exe_fp, input_fmt, 'exe') p = Popen('strace %s' % exe_fp, shell=True) p.wait() if not self.keep_files: os.unlink(exe_fp) if self.verbose >= 3: print('OUT do_strace', file=sys.stderr) def do_gdb(self, input_fp, input_fmt): if self.verbose >= 3: print('IN do_gdb', file=sys.stderr) exe_fp = mktemp() self.do_conversion(input_fp, exe_fp, input_fmt, 'exe') start_addr = None try: start_addr = self.get_start_address(exe_fp) except: print('WARNING: failed to get the start address :-(', file=sys.stderr) print(traceback.format_exc(), file=sys.stderr) print('------------------------', file=sys.stderr) if start_addr: cmd = 'gdb -ex "break *%s" -q %s' % (start_addr, exe_fp) else: cmd = 'gdb -q %s' % exe_fp p = Popen(cmd, shell=True) p.wait() if not self.keep_files: os.unlink(exe_fp) if self.verbose >= 3: print('OUT do_gdb', file=sys.stderr) ############################# # executable patching utils # ############################# def get_bits(self, exe_fp): bits = None if '32-bit' in os.popen('file %s' % exe_fp).read(): bits = 32 elif '64-bit' in os.popen('file %s' % exe_fp).read(): def do_fork_nopper(self, exe_fp): lines = os.popen('objdump -d %s' % exe_fp).read().split('\n') for line in lines: print line m = re.search('([0-9a-f]+):\s+[0-9a-f ]+\s+call.*fork', line) if not m: continue vm_address = int(m.group(1), 16) print 'FOUND A CALL TO FORK @ 0x%x' % vm_address file_offset = self.get_file_offset_from_vm_address(exe_fp, vm_address) print 'fileoffset @ 0x%x' % file_offset self.do_exe_patch(exe_fp, '\x90\x90\x90\x31\xc0', file_offset) def do_exe_patch(self, exe_fp, data, file_offset=None, vm_address=None, replace=True): file_offset = int(m.group(2), 16) size = int(m.group(3), 16) break elif bits == 64: for line in lines: if vm_address is None and file_offset is None: m = re.search('.text\s+\w+\s+([0-9a-f]+)\s+([0-9a-f]+)', line) if not m: continue vm_address = int(m.group(1), 16) file_offset = int(m.group(2), 16) continue else: m = re.search('\s+([0-9a-f]+)\s+[0-9a-f]+', line) if not m: raise Exception('error while parsing readelf -S (64bit)') size = int(m.group(1), 16) break else: ################### def asm_to_hex(self, asm, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN asm_to_hex' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint obj = self.asm_to_obj(asm, with_breakpoint) _hex = self.obj_to_hex(obj, with_breakpoint=False) if self.verbose >= 3: print >>sys.stderr, 'OUT asm_to_hex' return _hex def bin_to_hex(self, _bin, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN bin_to_hex' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint prepend = self.get_breakpoint_hex() if with_breakpoint else '' if self.verbose >= 3: print >>sys.stderr, 'OUT bin_to_hex' return prepend + _bin.encode('hex') def obj_to_hex(self, obj, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN obj_to_hex' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint tmp_obj_f = NamedTemporaryFile(delete=False) raise Exception('unsupported') if file_offset is None and vm_address is None: raise Exception('you need to specify at least one of the two ;)') if file_offset is None: file_offset = self.get_file_offset_from_vm_address(exe_fp, vm_address) f = open(exe_fp, 'rb+') f.seek(file_offset) f.write(data) f.close() ################### ### conversions ### ################### os.unlink(tmp_obj_fp) os.unlink(tmp_bin_fp) if self.verbose >= 3: print >>sys.stderr, 'OUT obj_to_hex' return _hex def c_to_hex(self, c, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN c_to_hex' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint print >>sys.stderr, 'WARNING: c_to_hex just extracts the \\xXX looking parts. Check that everything it\'s fine!' def get_next_hex(buf): slash_x_idx = buf.find('\\x') with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint prepend = self.get_breakpoint_hex() if with_breakpoint else '' if self.verbose >= 3: print('OUT bin_to_hex', file=sys.stderr) return cbytes(prepend) + binascii.hexlify(_bin) def obj_to_hex(self, obj, with_breakpoint=None): if self.verbose >= 3: print('IN obj_to_hex', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint _hex += hex_byte _hex = prepend + _hex if self.verbose >= 3: print >>sys.stderr, 'OUT c_to_hex' return _hex def shellstorm_to_hex(self, shellstorm_id, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN shellstorm_to_hex' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint print >>sys.stderr, 'WARNING: shellstorm_to_hex just extracts the \\xXX looking parts. Check that everything it\'s fine!' # TODO handle shellcode not found _bin = open(tmp_bin_fp, 'rb').read() _hex = self.bin_to_hex(_bin, with_breakpoint) if not self.keep_files: os.unlink(tmp_obj_fp) os.unlink(tmp_bin_fp) if self.verbose >= 3: print('OUT obj_to_hex', file=sys.stderr) _hex = self.c_to_hex(content, with_breakpoint) if self.verbose >= 3: print >>sys.stderr, 'OUT shellstorm_to_hex' return _hex def get_next_hex(buf): slash_x_idx = buf.find('\\x') ################ def hex_to_asm(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_asm' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint obj = self.hex_to_obj(_hex, with_breakpoint) asm = self.obj_to_asm(obj, with_breakpoint=False) if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_asm' return asm def hex_to_obj(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_obj' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if len(_hex) != 0 and _hex.endswith('\n'): _hex = _hex.rstrip('\n') print >>sys.stderr, 'Warning: stripped a \'\\n\' at the end of the hex' if len(_hex) == 0 or len(_hex) % 2 != 0: raise Exception('Not valid _hex: %s' % _hex) shellstorm_url = self.shellstorm_t % shellstorm_id try: asm = self.hex_to_asm_bytes(_hex) obj = self.asm_to_obj(asm, with_breakpoint=False) if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_obj' return obj def hex_to_exe(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_exe' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint completec = self.hex_to_completec(_hex, with_breakpoint) exe = self.c_to_exe(completec, with_breakpoint=False) if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_exe' return exe def hex_to_bin(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_bin' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if len(_hex) != 0 and _hex.endswith('\n'): _hex = _hex.rstrip('\n') print >>sys.stderr, 'Warning: stripped a \'\\n\' at the end of the hex' if len(_hex) == 0 or len(_hex) % 2 != 0: raise Exception('Not valid _hex: %s' % _hex) prepend = self.get_breakpoint_hex() if with_breakpoint else '' _hex = prepend + _hex if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_bin' return _hex.decode('hex') def hex_to_c(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_c' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if len(_hex) != 0 and _hex.endswith('\n'): _hex = _hex.rstrip('\n') print >>sys.stderr, 'Warning: stripped a \'\\n\' at the end of the hex' if len(_hex) == 0 or len(_hex) % 2 != 0: raise Exception('Not valid _hex: %s' % _hex) prepend = self.get_breakpoint_hex() if with_breakpoint else '' _hex = prepend + _hex asm = self.hex_to_asm_bytes(_hex) for idx in range(0, len(_hex), 2): content += '\\x%s' % _hex[idx:idx+2] out = template % content if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_c' return out def hex_to_python(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_python' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if len(_hex) != 0 and _hex.endswith('\n'): _hex = _hex.rstrip('\n') print >>sys.stderr, 'Warning: stripped a \'\\n\' at the end of the hex' if len(_hex) == 0 or len(_hex) % 2 != 0: raise Exception('Not valid _hex: %s' % _hex) if self.verbose >= 3: print('IN hex_to_bin', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if not isinstance(_hex, str): _hex = cstr(_hex) if len(_hex) != 0 and _hex.endswith('\n'): content += '\\x%s' % _hex[idx:idx+2] out = template % content if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_python' return out def hex_to_bash(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_bash' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint out = self.hex_to_python(_hex, with_breakpoint) if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_bash' return out class AreYouFuckingKiddingMeException(Exception): pass def hex_to_ruby(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_ruby' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint # I'm not a ruby fan, and I really needed to put an easter egg :-) raise AreYouFuckingKiddingMeException() def hex_to_pretty(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_pretty' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint obj = self.hex_to_obj(_hex, with_breakpoint) exe = self.obj_to_pretty(obj, with_breakpoint=False) if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_pretty' return exe def obj_to_pretty(self, obj, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN obj_to_pretty' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if with_breakpoint: if not isinstance(_hex, str): if self.need_to_align(): _hex = self.obj_to_hex(obj) if self.debug: print >>sys.stderr, 'hex lenght: ',len(_hex) aligned_hex = self.align_hex(_hex) if self.debug: print >>sys.stderr, 'aligned hex lenght: ' , len(aligned_hex) if _hex != aligned_hex: obj = self.hex_to_obj(aligned_hex, with_breakpoint=False) template = '%s' content = '' for idx in range(0, len(_hex), 2): content += '\\x%s' % _hex[idx:idx+2] out = template % content if self.verbose >= 3: print('OUT hex_to_python', file=sys.stderr) return out def hex_to_bash(self, _hex, with_breakpoint=None): if self.verbose >= 3: print('IN hex_to_bash', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint out = self.hex_to_python(_hex, with_breakpoint) if self.verbose >= 3: print('OUT hex_to_bash', file=sys.stderr) return out class AreYouFuckingKiddingMeException(Exception): pass def hex_to_ruby(self, _hex, with_breakpoint=None): if self.verbose >= 3: print('IN hex_to_ruby', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint os.unlink(tmp_obj_fp) os.unlink(tmp_pretty_fp) if self.verbose >= 3: print >>sys.stderr, 'OUT obj_to_pretty' return pretty obj = self.hex_to_obj(_hex, with_breakpoint) exe = self.obj_to_pretty(obj, with_breakpoint=False) ######################### def asm_to_obj(self, asm, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN asm_to_obj' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint asm += '\n' # as complains if the asm doesn't end with newline if with_breakpoint: raise Exception('the with_breakpoint option is NOT supported in obj_to_exe') if self.need_to_align(): _hex = self.obj_to_hex(obj) if self.debug: print('hex lenght: ',len(_hex), file=sys.stderr) aligned_hex = self.align_hex(_hex) if self.debug: print('aligned hex lenght: ' , len(aligned_hex), file=sys.stderr) if _hex != aligned_hex: obj = self.hex_to_obj(aligned_hex, with_breakpoint=False) tmp_obj_f = NamedTemporaryFile(delete=False) tmp_obj_fp = tmp_obj_f.name tmp_obj_f.write(obj) tmp_obj_f.close() tmp_pretty_fp = mktemp() objdump_options = self.get_objdump_options() cmd = 'objdump -d %s %s > %s' % (objdump_options, tmp_obj_fp, tmp_pretty_fp ) self.exec_cmd(cmd, caller='obj_to_pretty') os.unlink(tmp_asm_fp) os.unlink(tmp_obj_fp) if self.verbose >= 3: print >>sys.stderr, 'OUT asm_to_obj' return obj def obj_to_asm(self, obj, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN obj_to_asm' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if self.need_to_align(): if not self.keep_files: os.unlink(tmp_obj_fp) os.unlink(tmp_pretty_fp) if self.verbose >= 3: print('OUT obj_to_pretty', file=sys.stderr) return pretty ######################### ### additional blocks ### ######################### cmd = 'objdump -d %s %s | tr -s " "' % (objdump_options, tmp_obj_fp, ) if self.verbose >= 2: print >>sys.stderr, '(obj_to_asm) Executing: %s' % cmd obj_out = os.popen(cmd).read() lines = obj_out.split('\n') started = False asm = cstr(asm) prepend = self.hex_to_asm_bytes(self.get_breakpoint_hex()) if with_breakpoint else '' asm = prepend + asm + '\n' tmp_asm_f = NamedTemporaryFile(delete=False) tmp_asm_fp = tmp_asm_f.name tmp_asm_f.write(asm.encode("utf-8")) tmp_asm_f.close() tmp_obj_fp = mktemp() as_options = self.get_as_options() cmd = 'as %s -o %s %s' % (as_options, tmp_obj_fp, tmp_asm_fp) self.exec_cmd(cmd, caller='asm_to_obj') if not os.path.isfile(tmp_obj_fp): raise Exception("not valid shellcode (asm_to_obj)") # delete all the symbols cmd = 'strip %s' % tmp_obj_fp self.exec_cmd(cmd, caller='asm_to_obj') obj = open(tmp_obj_fp, 'rb').read() if not self.keep_files: os.unlink(tmp_asm_fp) os.unlink(tmp_obj_fp) if self.verbose >= 3: print('OUT asm_to_obj', file=sys.stderr) return obj def obj_to_asm(self, obj, with_breakpoint=None): if self.verbose >= 3: print('IN obj_to_asm', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if self.need_to_align(): _hex = self.obj_to_hex(obj) aligned_hex = self.align_hex(_hex) if _hex != aligned_hex: obj = self.hex_to_obj(aligned_hex, with_breakpoint=False) tmp_obj_f = NamedTemporaryFile(delete=False) tmp_obj_fp = tmp_obj_f.name tmp_obj_f.write(obj) shellcode = self.shellcode_t % out if self.verbose >= 3: print >>sys.stderr, 'OUT obj_to_asm' return shellcode def asm_to_exe(self, asm, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN asm_to_exe' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint _hex = self.asm_to_hex(asm, with_breakpoint) exe = self.hex_to_exe(_hex, with_breakpoint=False) if self.verbose >= 3: print >>sys.stderr, 'OUT asm_to_exe' return exe def obj_to_exe(self, obj, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN obj_to_exe' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if with_breakpoint: comment_char = self.get_comment_as_char() # asm started m = re.search('[0-9a-f]+:\s+([0-9a-f ]+)\t(.*)$', line) if not m: continue _hex = m.group(1).replace(' ', '').strip(' \t\n') help_asm = self.hex_to_asm_bytes(_hex).rstrip('\n') try: _ascii = '.ascii "%s"' % _hex _ascii = _ascii.strip(' \t\n') except UnicodeDecodeError: _ascii = '' asm = m.group(2).strip(' \t\n') sc_idx = asm.find(';') if sc_idx != -1: asm = asm[:sc_idx] os.unlink(tmp_obj_fp) os.unlink(tmp_exe_fp) if self.verbose >= 3: print >>sys.stderr, 'OUT obj_to_exe' return exe def hex_to_safeasm(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_safeasm' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if len(_hex) != 0 and _hex.endswith('\n'): _hex = _hex.rstrip('\n') print >>sys.stderr, 'Warning: stripped a \'\\n\' at the end of the hex' if len(_hex) == 0 or len(_hex) % 2 != 0: raise Exception('Not valid _hex: %s' % _hex) shellcode = self.shellcode_t % out if self.verbose >= 3: print('OUT obj_to_asm', file=sys.stderr) asm = self.hex_to_asm_bytes(_hex) shellcode = self.shellcode_t % asm if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_safeasm' return shellcode def hex_to_completec(self, _hex, with_breakpoint=None): if self.verbose >= 3: print >>sys.stderr, 'IN hex_to_completec' with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint c = self.hex_to_c(_hex, with_breakpoint) completec = self.completec_t % c if self.verbose >= 3: print >>sys.stderr, 'OUT hex_to_completec' return completec def c_to_exe(self, c, with_breakpoint=None): # NOTE assumption: the input is "compileable C" if self.verbose >= 3: print >>sys.stderr, 'IN c_to_exe' if with_breakpoint: raise Exception('the with_breakpoint option is NOT supported in c_to_exe') tmp_obj_f.close() tmp_exe_fp = mktemp() ld_options = self.get_ld_options() # note: ld -V to list all the emulations cmd = 'ld -N %s %s -o %s' % (ld_options, tmp_obj_fp, tmp_exe_fp) retval = self.exec_cmd(cmd, True, caller='obj_to_exe') exe = open(tmp_exe_fp, 'rb').read() if not self.keep_files: os.unlink(tmp_obj_fp) os.unlink(tmp_exe_fp) os.unlink(tmp_c_fp) os.unlink(tmp_exe_fp) if self.verbose >= 3: print >>sys.stderr, 'OUT c_to_exe' return exe with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint if not isinstance(_hex, str): _hex = cstr(_hex) if len(_hex) != 0 and _hex.endswith('\n'): _hex = _hex.rstrip('\n') print('Warning: stripped a \'\\n\' at the end of the hex', file=sys.stderr) if len(_hex) == 0 or len(_hex) % 2 != 0: raise Exception('Not valid _hex: %s' % _hex) prepend = self.get_breakpoint_hex() if with_breakpoint else '' _hex = prepend + _hex asm = self.hex_to_asm_bytes(_hex) shellcode = self.shellcode_t % asm if self.verbose >= 3: print('OUT hex_to_safeasm', file=sys.stderr) return shellcode def hex_to_completec(self, _hex, with_breakpoint=None): if self.verbose >= 3: print('IN hex_to_completec', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint c = self.hex_to_c(_hex, with_breakpoint) completec = self.completec_t % c if self.verbose >= 3: print('OUT hex_to_completec', file=sys.stderr) return completec def c_to_exe(self, c, with_breakpoint=None): global cbytes # NOTE assumption: the input is "compileable C" if self.verbose >= 3: print('IN c_to_exe', file=sys.stderr) if with_breakpoint: raise Exception('the with_breakpoint option is NOT supported in c_to_exe') if not isinstance(c, bytes): c = cbytes(c) tmp_c_f = NamedTemporaryFile(suffix='.c', delete=False) tmp_c_fp = tmp_c_f.name tmp_c_f.write(c) tmp_c_f.close() tmp_exe_fp = mktemp() gcc_options = self.get_gcc_options() cmd = 'gcc %s -o %s %s' % (gcc_options, tmp_exe_fp, tmp_c_fp) retval = self.exec_cmd(cmd, True, caller='c_to_exe') exe = open(tmp_exe_fp, 'rb').read() if not self.keep_files: os.unlink(tmp_c_fp) os.unlink(tmp_exe_fp) if self.verbose >= 3: print('OUT c_to_exe', file=sys.stderr) return exe ######################## # additional functions # ######################## def ins_to_hex(self, ins): asm = self.inss_to_asm([ins]) _hex = self.asm_to_hex(asm) return _hex def hex_to_inss(self, _hex): asm = self.hex_to_asm(_hex) inss = asm.split('\n')[1:] inss = filter(lambda i:i.strip(' \t'), inss) inss = map(lambda i:i.split('#')[0], inss) inss = map(lambda i:i.strip(' \t'), inss) return list(inss) def inss_to_asm(self, inss): out = '\n'.join(inss) shellcode = self.shellcode_t % out return shellcode def asm_to_inss(self, asm): raise Exception('start address not found for %s' % exe_fp) def exec_cmd(self, cmd, redirect_stderr=False, caller=None): if self.verbose >= 2: print >>sys.stderr, '(exec_cmd: "%s") Executing: "%s"' % (caller, cmd) if redirect_stderr: with open('/dev/null', 'wb') as f: else: retval = call(cmd, shell=True) if self.verbose >= 2: print >>sys.stderr, '(exec_cmd: "%s") Ret value: %s' % (caller, retval) return retval def do_objdump_switch(self): return asm def include_and_body_to_exe_fp(self, includes, body): global cbytes std_includes = set(('stdio.h', 'stdlib.h', 'errno.h')) includes = set(includes) includes.update(std_includes) c_prog = '' for inc in includes: c_prog += '#include<%s>\n' % inc c_prog += 'int main() {\n' c_prog += body c_prog += '}\n' hardware = hardware if hardware is not None else self.hardware for e_hardware in self.hw_with_align: if not re.search(e_hardware, hardware): continue if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) return True return False retval = self.exec_cmd(cmd, 'include_and_body_to_exe_fp') if retval != 0: output = '' raise ShellNoobException() if not self.keep_files: os.unlink(tmp_c_fp) return tmp_exe_fp def get_start_address(self, exe_fp): cmd = 'objdump -f %s' % exe_fp p = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) _out, _err = p.communicate() assert p.returncode == 0 @staticmethod def do_install(force=False): if os.getuid() != 0: print >>sys.stderr, 'ERROR: I need root!' sys.exit(1) install_dir = '/usr/local/bin' shellnoob_fp = os.path.join(install_dir, 'snoob') print >>sys.stderr, 'This will copy shellnoob into %s' % shellnoob_fp if not force: raw_input('Press a key to proceed..') shutil.copyfile(__file__, shellnoob_fp) os.chmod(shellnoob_fp, stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH) print >>sys.stderr, 'SUCCESS. "snoob -h" should display shellnoob\'s help' @staticmethod def do_uninstall(force=False): if os.getuid() != 0: print >>sys.stderr, 'ERROR: I need root!' sys.exit(1) install_dir = '/usr/local/bin' shellnoob_fp = os.path.join(install_dir, 'snoob') print >>sys.stderr, 'This will delete shellnoob from %s' % shellnoob_fp if not force: raw_input('Press a key to proceed..') os.unlink(shellnoob_fp) # input: a hex string, like 34ab01ac # group them by 2 chars _hex = [_hex[i:i+2] for i in range(0, len(_hex), 2)] # reverse the list _hex = list(reversed(_hex)) # build a string _hex = ''.join(_hex) return _hex def need_to_align(self, hardware=None): # use the passed settings, if specified hardware = hardware if hardware is not None else self.hardware for e_hardware in self.hw_with_align: if not re.search(e_hardware, hardware): continue if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) return True return False def align_hex(self, _hex): assert len(_hex) % 2 == 0 if (len(_hex)/2) % 4 != 0: _hex = _hex + '00'*(4 - ((len(_hex)/2) % 4)) assert len(_hex) % 8 == 0 return _hex @staticmethod def get_kernel(): return os.popen('uname -s').read().strip() @staticmethod def get_hardware(): return os.popen('uname -m').read().strip() @staticmethod def do_install(force=False): if os.getuid() != 0: print('ERROR: I need root!', file=sys.stderr) sys.exit(1) install_dir = '/usr/local/bin' shellnoob_fp = os.path.join(install_dir, 'snoob') print('This will copy shellnoob into %s' % shellnoob_fp, file=sys.stderr) if not force: input('Press a key to proceed..') shutil.copyfile(__file__, shellnoob_fp) os.chmod(shellnoob_fp, stat.S_IRWXU | stat.S_IRWXG | stat.S_IROTH | stat.S_IXOTH) print('SUCCESS. "snoob -h" should display shellnoob\'s help', file=sys.stderr) @staticmethod def do_uninstall(force=False): if os.getuid() != 0: print('ERROR: I need root!', file=sys.stderr) sys.exit(1) install_dir = '/usr/local/bin' shellnoob_fp = os.path.join(install_dir, 'snoob') print('This will delete shellnoob from %s' % shellnoob_fp, file=sys.stderr) if not force: input('Press a key to proceed..') os.unlink(shellnoob_fp) class ShellNoobException(Exception): pass def main(): args = sys.argv[1:] ######################################################################## # WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING # # This is the most awful CLI argument parsing ever. I started to do # # it manually as I wanted a uber flexible CLI interface. I'm pretty # # sure it's possible to achieve the same with optparse/argparse, but # # I'm too noob for that. Somebody should write a OptParseNoob tool :-) # ######################################################################## # check for help if '-h' in args or '--help' in args or len(args) == 0: print_usage() sys.exit(0) # check for install/uninstall if '--install' in args: force = True if '--force' in args else False ShellNoob.do_install(force) sys.exit(0) elif '--uninstall' in args: force = True if '--force' in args else False ShellNoob.do_uninstall(force) sys.exit(0) # parse the switches flag_64_bit = False if '--64' in args: flag_64_bit = True args.remove('--64') flag_intel = False if '--intel' in args: flag_intel = True args.remove('--intel') with_breakpoint = False if '-c' in args: with_breakpoint = True args.remove('-c') keep_files = False if '-k' in args: keep_files = True args.remove('-k') verbose = 0 if '-vvvv' in args: verbose = 4 args.remove('-vvvv') if '-vvv' in args: verbose = 3 args.remove('-vvv') elif '-vv' in args: verbose = 2 args.remove('-vv') elif '-v' in args: verbose = 1 args.remove('-v') if '-q' in args: verbose = -1 args.remove('-q') snoob = ShellNoob(flag_64_bit=flag_64_bit, flag_intel=flag_intel, with_breakpoint=with_breakpoint, verbose=verbose, keep_files=keep_files ) # parse the plugin switches if '-i' in args: snoob.do_interactive_mode(args) sys.exit(0) if '--get-const' in args: idx = args.index('--get-const') const = args[idx+1] snoob.do_resolve_const(const) sys.exit(0) if '--get-sysnum' in args: idx = args.index('--get-sysnum') syscall = args[idx+1] snoob.do_resolve_syscall(syscall) sys.exit(0) if '--get-errno' in args: idx = args.index('--get-errno') errno = args[idx+1] snoob.do_resolve_errno(errno) sys.exit(0) do_strace_flag = False if '--to-strace' in args: do_strace_flag = True args.remove('--to-strace') do_gdb_flag = False if do_strace_flag: if snoob.verbose >= 1: print >>sys.stderr, 'do_strace mode selected' snoob.do_strace(input_fp, input_fmt) sys.exit(0) if do_gdb_flag: if snoob.verbose >= 1: print >>sys.stderr, 'do_gdb mode selected' snoob.do_gdb(input_fp, input_fmt) sys.exit(0) exe_fp = args[idx+1] file_offset = int(args[idx+2], 16) data = binascii.unhexlify(args[idx+3]) snoob.do_exe_patch(exe_fp, data, file_offset=file_offset) sys.exit(0) if '--vm-patch' in args: idx = args.index('--vm-patch') exe_fp = args[idx+1] vm_address = int(args[idx+2], 16) data = binascii.unhexlify(args[idx+3]) snoob.do_exe_patch(exe_fp, data, vm_address=vm_address) sys.exit(0) # parse the conversion arguments curr_arg_idx = 0 # determine the input format input_fmt = None curr_arg = args[curr_arg_idx] if curr_arg.startswith('--from-'): input_fmt = curr_arg[len('--from-'):].lower() if input_fmt not in snoob.INPUT_FMT: raise Exception('input format "%s" not supported' % input_fmt) curr_arg_idx += 1 input_fp = args[curr_arg_idx] if input_fmt != 'shellstorm' and input_fp != '-': input_fp = os.path.abspath(input_fp) if not os.path.isfile(input_fp): raise Exception('file %s does NOT exist' % input_fp) curr_arg_idx += 1 if not input_fmt: # ok, let's guess the input fmt dot_idx = input_fp.rfind('.') if dot_idx == -1: raise Exception('Failed to guess the input format :/') ext = input_fp[dot_idx+1:] if ext in ['asm', 's', 'S', 'shell']: input_fmt = 'asm' elif ext in ['o', 'obj']: input_fmt = 'obj' elif ext in ['bin']: input_fmt = 'bin' elif ext in ['hex']: input_fmt = 'hex' elif ext in ['c', 'C']: input_fmt = 'c' else: raise Exception('Input format "%s" is not supported' % input_fmt) if do_strace_flag: if snoob.verbose >= 1: print('do_strace mode selected', file=sys.stderr) snoob.do_strace(input_fp, input_fmt) sys.exit(0) if do_gdb_flag: if snoob.verbose >= 1: print('do_gdb mode selected', file=sys.stderr) snoob.do_gdb(input_fp, input_fmt) sys.exit(0) output_fmt = None curr_arg = args[curr_arg_idx] if curr_arg.startswith('--to-'): output_fmt = curr_arg[len('--to-'):].lower() if output_fmt not in snoob.OUTPUT_FMT: raise Exception('output format "%s" not supported' % output_fmt) curr_arg_idx += 1 output_fp = None if curr_arg_idx < len(args): output_fp = args[curr_arg_idx] curr_arg_idx += 1 if not output_fmt: # ok, let's guess the output fmt dot_idx = output_fp.rfind('.') if dot_idx == -1: raise Exception('Failed to guess the output format :/') ext = output_fp[dot_idx+1:] if ext in ['asm', 's', 'S', 'shell']: output_fmt = 'asm' elif ext in ['o', 'obj']: output_fmt = 'obj' elif ext in ['exe']: output_fmt = 'exe' elif ext in ['bin']: output_fmt = 'bin' elif ext in ['hex']: output_fmt = 'hex' elif ext in ['c', 'C']: output_fmt = 'c' elif ext in ['py', 'python']: output_fmt = 'python' elif ext in ['sh', 'bash']: output_fmt = 'bash' elif ext in ['rb', 'ruby']: output_fmt = 'ruby' elif ext in ['pretty']: output_fmt = 'pretty' elif ext in ['safeasm']: output_fmt = 'safeasm' else: raise Exception('Output format "%s" is not supported' % output_fmt) if output_fp == '-': pass elif output_fp != None: output_fp = os.path.abspath(output_fp) elif input_fp and input_fp != '-': # choose the output_fp starting from the input_fp and input_fmt input_pfx = input_fp[:input_fp.rfind('.')] if output_fmt == 'completec': output_ext = 'c' else: output_ext = output_fmt output_fp = '%s.%s' % (input_pfx, output_ext) else: raise Exception('Specify the input/output filename!') snoob.do_conversion(input_fp, output_fp, input_fmt, output_fmt) if __name__== '__main__': main() <MSG> converting print to python3 style * keeps compatibility to python2(>=2.6) by importing future print_function <DFF> @@ -21,6 +21,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +from __future__ import print_function __author__ = 'Yanick Fratantonio <yanick@cs.ucsb.edu>' __description__ = 'Toolkit to write shellcodes' __version__ = "2.0" @@ -47,33 +48,33 @@ except ImportError: def print_usage(): script_fn = os.path.basename(sys.argv[0]) - print >>sys.stderr, '%s [--from-INPUT] (input_file_path | - ) [--to-OUTPUT] [output_file_path | - ]' % script_fn - print >>sys.stderr, '%s -c (prepend a breakpoint (Warning: only few platforms/OS are supported!)' % script_fn - print >>sys.stderr, '%s --64 (64 bits mode, default: 32 bits)' % script_fn - print >>sys.stderr, '%s --intel (intel syntax mode, default: att)' % script_fn - print >>sys.stderr, '%s -q (quite mode)' % script_fn - print >>sys.stderr, '%s -v (or -vv, -vvv)' % script_fn - print >>sys.stderr, '%s --to-strace (compiles it & run strace)' % script_fn - print >>sys.stderr, '%s --to-gdb (compiles it & run gdb & set breakpoint on entrypoint)' % script_fn - print >>sys.stderr, '' - print >>sys.stderr, 'Standalone "plugins"' - print >>sys.stderr, '%s -i [--to-asm | --to-opcode ] (for interactive mode)' % script_fn - print >>sys.stderr, '%s --get-const <const>' % script_fn - print >>sys.stderr, '%s --get-sysnum <sysnum>' % script_fn - print >>sys.stderr, '%s --get-strerror <errno>' % script_fn - print >>sys.stderr, '%s --file-patch <exe_fp> <file_offset> <data> (in hex). (Warning: tested only on x86/x86_64)' % script_fn - print >>sys.stderr, '%s --vm-patch <exe_fp> <vm_address> <data> (in hex). (Warning: tested only on x86/x86_64)' % script_fn - print >>sys.stderr, '%s --fork-nopper <exe_fp> (this nops out the calls to fork(). Warning: tested only on x86/x86_64)' % script_fn - print >>sys.stderr, '' - print >>sys.stderr, '"Installation"' - print >>sys.stderr, '%s --install [--force] (this just copies the script in a convinient position)' % script_fn - print >>sys.stderr, '%s --uninstall [--force]' % script_fn - print >>sys.stderr, '' - print >>sys.stderr, 'Supported INPUT format: %s' % ', '.join(ShellNoob.INPUT_FMT) - print >>sys.stderr, 'Supported OUTPUT format: %s' % ', '.join(ShellNoob.OUTPUT_FMT) - print >>sys.stderr, 'All combinations from INPUT to OUTPUT are supported!' - print >>sys.stderr, '' - print >>sys.stderr, 'Check out the README file for more info.' + print('%s [--from-INPUT] (input_file_path | - ) [--to-OUTPUT] [output_file_path | - ]' % script_fn, file=sys.stderr) + print('%s -c (prepend a breakpoint (Warning: only few platforms/OS are supported!)' % script_fn, file=sys.stderr) + print('%s --64 (64 bits mode, default: 32 bits)' % script_fn, file=sys.stderr) + print('%s --intel (intel syntax mode, default: att)' % script_fn, file=sys.stderr) + print('%s -q (quite mode)' % script_fn, file=sys.stderr) + print('%s -v (or -vv, -vvv)' % script_fn, file=sys.stderr) + print('%s --to-strace (compiles it & run strace)' % script_fn, file=sys.stderr) + print('%s --to-gdb (compiles it & run gdb & set breakpoint on entrypoint)' % script_fn, file=sys.stderr) + print('', file=sys.stderr) + print('Standalone "plugins"', file=sys.stderr) + print('%s -i [--to-asm | --to-opcode ] (for interactive mode)' % script_fn, file=sys.stderr) + print('%s --get-const <const>' % script_fn, file=sys.stderr) + print('%s --get-sysnum <sysnum>' % script_fn, file=sys.stderr) + print('%s --get-strerror <errno>' % script_fn, file=sys.stderr) + print('%s --file-patch <exe_fp> <file_offset> <data> (in hex). (Warning: tested only on x86/x86_64)' % script_fn, file=sys.stderr) + print('%s --vm-patch <exe_fp> <vm_address> <data> (in hex). (Warning: tested only on x86/x86_64)' % script_fn, file=sys.stderr) + print('%s --fork-nopper <exe_fp> (this nops out the calls to fork(). Warning: tested only on x86/x86_64)' % script_fn, file=sys.stderr) + print('', file=sys.stderr) + print('"Installation"', file=sys.stderr) + print('%s --install [--force] (this just copies the script in a convinient position)' % script_fn, file=sys.stderr) + print('%s --uninstall [--force]' % script_fn, file=sys.stderr) + print('', file=sys.stderr) + print('Supported INPUT format: %s' % ', '.join(ShellNoob.INPUT_FMT), file=sys.stderr) + print('Supported OUTPUT format: %s' % ', '.join(ShellNoob.OUTPUT_FMT), file=sys.stderr) + print('All combinations from INPUT to OUTPUT are supported!', file=sys.stderr) + print('', file=sys.stderr) + print('Check out the README file for more info.', file=sys.stderr) class ShellNoob(): @@ -185,12 +186,12 @@ int main() { for i in self.INPUT_FMT: for o in self.OUTPUT_FMT: func_name = '%s_to_%s' % (i, o) - if self.debug: print >>sys.stderr, 'Creating %s' % func_name + if self.debug: print('Creating %s' % func_name, file=sys.stderr) if i == o: continue if func_name not in ShellNoob.__dict__: # conversion not implemented: let's go through hex - ShellNoob.__dict__[func_name] = self.gen_conv_function(i, o) + setattr(ShellNoob, func_name, self.gen_conv_function(i, o)) def gen_conv_function(self, input_fmt, output_fmt): # generate on-the-fly a conversion function going through the "hex" format @@ -210,23 +211,23 @@ int main() { try: self.get_objdump_options() except ShellNoobException as e: - print >>sys.stderr, 'ERROR: %s' % e.message + print('ERROR: %s' % e.message, file=sys.stderr) sys.exit(2) try: self.get_as_options() except ShellNoobException as e: - print >>sys.stderr, 'ERROR: %s' % e.message + print('ERROR: %s' % e.message, file=sys.stderr) sys.exit(2) try: self.get_ld_options() except ShellNoobException as e: - print >>sys.stderr, 'ERROR: %s' % e.message + print('ERROR: %s' % e.message, file=sys.stderr) sys.exit(2) if self.with_breakpoint: try: self.get_breakpoint_hex() except ShellNoobException as e: - print >>sys.stderr, 'ERROR: %s' % e.message + print('ERROR: %s' % e.message, file=sys.stderr) sys.exit(2) @@ -243,7 +244,7 @@ int main() { if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue - if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) + if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) return options raise ShellNoobException('objdump_options not found for the current setup') @@ -261,7 +262,7 @@ int main() { if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue - if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) + if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) return options raise ShellNoobException('as_options not found for the current setup') @@ -279,7 +280,7 @@ int main() { if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue - if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) + if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) return options raise ShellNoobException('ld_options not found for the current setup') @@ -297,7 +298,7 @@ int main() { if not re.search(e_hardware, hardware): continue if not re.search(e_64, flag_64_bit): continue if not re.search(e_intel, flag_intel): continue - if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, options) + if self.debug: print('MATCH with %s ~> %s' % (entry, options), file=sys.stderr) return options raise ShellNoobException('gcc_options not found for the current setup') @@ -311,7 +312,7 @@ int main() { e_kernel, e_hardware = entry.split('#') if not re.search(e_kernel, kernel): continue if not re.search(e_hardware, hardware): continue - if self.debug: print >>sys.stderr, 'MATCH with %s-%s ~> %s' % (e_kernel, e_hardware, _hex) + if self.debug: print('MATCH with %s-%s ~> %s' % (e_kernel, e_hardware, _hex), file=sys.stderr) return _hex raise ShellNoobException('the breakpoint feature is not supported in the current configuration') @@ -324,7 +325,7 @@ int main() { e_kernel, e_hardware = entry.split('#') if not re.search(e_kernel, kernel): continue if not re.search(e_hardware, hardware): continue - if self.debug: print >>sys.stderr, 'MATCH with %s ~> %s' % (entry, comment_char) + if self.debug: print('MATCH with %s ~> %s' % (entry, comment_char), file=sys.stderr) return comment_char @@ -350,16 +351,16 @@ int main() { try: tmp_exe_fp = self.include_and_body_to_exe_fp(includes, body) except ShellNoobException: - print >>sys.stderr, 'ERROR: syscall %s not found for platform %s' % (syscall, platform) + print('ERROR: syscall %s not found for platform %s' % (syscall, platform), file=sys.stderr) continue p = Popen(tmp_exe_fp, stdout=PIPE) output, error = p.communicate() retval = p.returncode if retval == 0: - print '%s ~> %s' % (platform, output) + print('%s ~> %s' % (platform, output)) else: - print >>sys.stderr, 'ERROR: reval %s while resolving syscall %s' % (retval, syscall) + print('ERROR: reval %s while resolving syscall %s' % (retval, syscall), file=sys.stderr) def do_resolve_const(self, const): @@ -372,16 +373,16 @@ int main() { try: tmp_exe_fp = self.include_and_body_to_exe_fp(includes, body) except ShellNoobException: - print >>sys.stderr, 'ERROR: constant %s not found' % const + print('ERROR: constant %s not found' % const, file=sys.stderr) return p = Popen(tmp_exe_fp, stdout=PIPE) output, error = p.communicate() retval = p.returncode if retval == 0: - print '%s ~> %s' % (const, int(output)) + print('%s ~> %s' % (const, int(output))) else: - print >>sys.stderr, 'ERROR: reval %s while resolving const %s' % (retval, const) + print('ERROR: reval %s while resolving const %s' % (retval, const), file=sys.stderr) def do_resolve_errno(self, errno): @@ -392,16 +393,16 @@ int main() { try: tmp_exe_fp = self.include_and_body_to_exe_fp(includes, body) except ShellNoobException: - print >>sys.stderr, 'ERROR: errno %s not found' % const + print('ERROR: errno %s not found' % const, file=sys.stderr) return p = Popen(tmp_exe_fp, stdout=PIPE) output, error = p.communicate() retval = p.returncode if retval == 0: - print '%s ~> %s' % (errno, output) + print('%s ~> %s' % (errno, output)) else: - print >>sys.stderr, 'ERROR: reval %s while resolving errno %s' % (retval, errno) + print('ERROR: reval %s while resolving errno %s' % (retval, errno), file=sys.stderr) def do_interactive_mode(self, args): @@ -411,53 +412,53 @@ int main() { elif '--to-asm' in args: asm_to_opcode_flag = False if asm_to_opcode_flag is None: - print 'asm_to_opcode (1) or opcode_to_asm (2)?:', answer = raw_input() + print('asm_to_opcode (1) or opcode_to_asm (2)?: ', end='') while answer != '1' and answer != '2': - print 'seriously? dude, choose between 1 and 2:', answer = raw_input() + print('seriously? dude, choose between 1 and 2: ', end='') asm_to_opcode_flag = True if answer == '1' else False assert asm_to_opcode_flag is not None if asm_to_opcode_flag: - print 'asm_to_opcode selected (type "quit" or ^C to end)' + print('asm_to_opcode selected (type "quit" or ^C to end)') ins = '' quit = False while not quit: while not ins: - print '>>', - ins = raw_input().strip(' \t\n') + print('>> ', end='') + ins = input().strip(' \t\n') if ins.lower() == 'quit': quit = True if quit: continue try: _hex = self.ins_to_hex(ins) - print '%s ~> %s' % (ins, _hex) + print('%s ~> %s' % (ins, _hex)) except Exception as e: - print >>sys.stderr, 'ERROR: %s' % e + print('ERROR: %s' % e, file=sys.stderr) if self.verbose >= 3: - print >>sys.stderr, traceback.format_exc() - print >>sys.stderr, '--------------------------' + print(traceback.format_exc(), file=sys.stderr) + print('--------------------------', file=sys.stderr) ins = '' else: - print 'opcode_to_asm selected (type "quit" or ^C to end)' + print('opcode_to_asm selected (type "quit" or ^C to end)') _hex = '' quit = False while not quit: while not _hex: - print '>>', _hex = raw_input().strip(' \t\n') + print('>> ', end='') if _hex.lower() == 'quit': quit = True if quit: continue try: _hex = _hex.replace(' ','').strip(' \t\n') asm = self.hex_to_pretty(_hex) - print '%s ~> %s' % (_hex, asm) + print('%s ~> %s' % (cbytes(_hex), asm)) except Exception as e: - print >>sys.stderr, 'ERROR: %s' % e + print('ERROR: %s' % e, file=sys.stderr) if self.verbose >= 3: - print >>sys.stderr, traceback.format_exc() - print >>sys.stderr, '--------------------------' + print(traceback.format_exc(), file=sys.stderr) + print('--------------------------', file=sys.stderr) _hex = '' @@ -471,7 +472,7 @@ int main() { msg += 'to stdout (%s)' % output_fmt else: msg += 'into %s (%s)' % (output_fp, output_fmt) - print >>sys.stderr, msg + print(msg, file=sys.stderr) # reading the input if input_fp == '-': @@ -486,7 +487,7 @@ int main() { try: _output = getattr(self, conv_func_name)(_input) except AttributeError: - print >>sys.stderr, 'ERROR: conversion mode "%s" is not supported.' % conv_func_name + print('ERROR: conversion mode "%s" is not supported.' % conv_func_name, file=sys.stderr) sys.exit(2) # writing the output @@ -500,7 +501,7 @@ int main() { os.chmod(output_fp, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR) def do_strace(self, input_fp, input_fmt): - if self.verbose >= 3: print >>sys.stderr, 'IN do_strace' + if self.verbose >= 3: print('IN do_strace', file=sys.stderr) exe_fp = mktemp() @@ -511,10 +512,10 @@ int main() { if not self.keep_files: os.unlink(exe_fp) - if self.verbose >= 3: print >>sys.stderr, 'OUT do_strace' + if self.verbose >= 3: print('OUT do_strace', file=sys.stderr) def do_gdb(self, input_fp, input_fmt): - if self.verbose >= 3: print >>sys.stderr, 'IN do_gdb' + if self.verbose >= 3: print('IN do_gdb', file=sys.stderr) exe_fp = mktemp() @@ -524,9 +525,9 @@ int main() { try: start_addr = self.get_start_address(exe_fp) except: - print >>sys.stderr, 'WARNING: failed to get the start address :-(' - print >>sys.stderr, traceback.format_exc() - print >>sys.stderr, '------------------------' + print('WARNING: failed to get the start address :-(', file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) + print('------------------------', file=sys.stderr) if start_addr: cmd = '(echo "break *%s"; cat) | gdb -q %s' % (start_addr, exe_fp) @@ -538,7 +539,7 @@ int main() { if not self.keep_files: os.unlink(exe_fp) - if self.verbose >= 3: print >>sys.stderr, 'OUT do_gdb' + if self.verbose >= 3: print('OUT do_gdb', file=sys.stderr) ############################# @@ -594,13 +595,13 @@ int main() { def do_fork_nopper(self, exe_fp): lines = os.popen('objdump -d %s' % exe_fp).read().split('\n') for line in lines: - print line + print(line) m = re.search('([0-9a-f]+):\s+[0-9a-f ]+\s+call.*fork', line) if not m: continue vm_address = int(m.group(1), 16) - print 'FOUND A CALL TO FORK @ 0x%x' % vm_address + print('FOUND A CALL TO FORK @ 0x%x' % vm_address) file_offset = self.get_file_offset_from_vm_address(exe_fp, vm_address) - print 'fileoffset @ 0x%x' % file_offset + print('fileoffset @ 0x%x' % file_offset) self.do_exe_patch(exe_fp, '\x90\x90\x90\x31\xc0', file_offset) def do_exe_patch(self, exe_fp, data, file_offset=None, vm_address=None, replace=True): @@ -624,25 +625,25 @@ int main() { ################### def asm_to_hex(self, asm, with_breakpoint=None): - if self.verbose >= 3: print >>sys.stderr, 'IN asm_to_hex' + if self.verbose >= 3: print('IN asm_to_hex', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint obj = self.asm_to_obj(asm, with_breakpoint) _hex = self.obj_to_hex(obj, with_breakpoint=False) - if self.verbose >= 3: print >>sys.stderr, 'OUT asm_to_hex' + if self.verbose >= 3: print('OUT asm_to_hex', file=sys.stderr) return _hex def bin_to_hex(self, _bin, with_breakpoint=None): - if self.verbose >= 3: print >>sys.stderr, 'IN bin_to_hex' + if self.verbose >= 3: print('IN bin_to_hex', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint prepend = self.get_breakpoint_hex() if with_breakpoint else '' - if self.verbose >= 3: print >>sys.stderr, 'OUT bin_to_hex' - return prepend + _bin.encode('hex') + if self.verbose >= 3: print('OUT bin_to_hex', file=sys.stderr) + return prepend + str(binascii.b2a_hex(_bin)) def obj_to_hex(self, obj, with_breakpoint=None): - if self.verbose >= 3: print >>sys.stderr, 'IN obj_to_hex' + if self.verbose >= 3: print('IN obj_to_hex', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint tmp_obj_f = NamedTemporaryFile(delete=False) @@ -666,14 +667,14 @@ int main() { os.unlink(tmp_obj_fp) os.unlink(tmp_bin_fp) - if self.verbose >= 3: print >>sys.stderr, 'OUT obj_to_hex' + if self.verbose >= 3: print('OUT obj_to_hex', file=sys.stderr) return _hex def c_to_hex(self, c, with_breakpoint=None): - if self.verbose >= 3: print >>sys.stderr, 'IN c_to_hex' + if self.verbose >= 3: print('IN c_to_hex', file=sys.stderr) with_breakpoint = with_breakpoint if with_breakpoint is not None else self.with_breakpoint - print >>sys.stderr, 'WARNING: c_to_hex just extracts the \\xXX looking parts. Check that everything it\'s fine!' + print('WARNING: c_to_hex just extracts the \\xXX looking parts. Check that everything it\'s fine!', file=sys.stderr) def get_next_hex(buf): slash_x_idx = buf.find('\\x') @@ -690,14
converting print to python3 style