aboutsummaryrefslogtreecommitdiff
path: root/batch/genShellcode.py
blob: 7ec9addd520a093c81317c014e6698ce24f61da3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env python2.7

import sys
import os
import re
import subprocess
from optparse import OptionParser, OptionGroup


objdmp_bin  = os.path.dirname(sys.argv[0]) + '/../deps/sysroot/i686-w64-mingw32/bin/i686-w64-mingw32-objdump'
objdmp_args = '-z -D -j %s %s'
bname       = os.path.basename(sys.argv[0])


def objdump_section(section, binary):
    full_cmd = str(objdmp_bin)+' '+(str(objdmp_args) % (section,binary))
    p = subprocess.Popen(full_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    repat = re.compile(r'^(?:\s+[0-9A-Fa-f]+:\s+)(([0-9A-Fa-f]{2}\s{1})+)')
    insts = 0
    scode = bytearray()
    p.wait()
    if p.returncode != 0:
        sys.stderr.write(bname + ': objdump command failed with %d: %s\n' % (p.returncode, full_cmd))
        sys.exit(1)
    for line in p.stdout.readlines():
        r = repat.match(line)
        if r:
            insts += 1
            insthex = str(r.group(1))
            for byte in str(insthex).split(' '):
                if len(byte) == 2:
                    scode += str(byte).decode('hex')
                elif len(byte) != 0:
                    raise TypeError('Invalid byte in hex str: ' + str(byte))
    return (scode, insts)

def gen_cstr(bytebuf):
    cstr = str()
    for byte in bytebuf:
        cstr += '\\x'+str(hex(byte))[2:].zfill(2)
    return cstr

def write_header(path, dpref, cstr, csiz, insts):
    with open(path, 'a+b') as out_hdr:
        outstr = \
            '#undef {0}\n' \
            '#undef {0}_SIZE\n' \
            '#undef {0}_INSTS\n\n' \
            '#define {0} "{1}"\n' \
            '#define {0}_SIZE {2}\n' \
            '#define {0}_INSTS {3}\n\n\n'.format(dpref, cstr, csiz, insts)
        out_hdr.write(outstr)
        out_hdr.flush()

# example: genShellcode.py --section=.minit --binary=lib/libloader_x86.a --define-prefix=LOADER_SHELLCODE --file=include/loader_x86.h
if __name__ == '__main__':
    parser = OptionParser()
    parser.add_option('-o', '--objdump', dest='objdmp_bin', default=objdmp_bin,
                                                            help='path to objdump binary [default: %default]')
    parser.add_option('-s', '--section', dest='section',    help='target section which shellcode will be extracted [required]')
    parser.add_option('-b', '--binary',  dest='binary',     help='target binary which we want extract shellcode from [required]')
    parser.add_option('-d', '--define-prefix',
                                         dest='prefix',     help='set #define prefix name [required]')
    parser.add_option('-f', '--file',    dest='file',       help='set output header file [required]')
    (options, args) = parser.parse_args()

    doAbort = False
    if options.section is None:
        sys.stderr.write(bname + ': Target section is required.\n')
        doAbort = True
    if options.binary is None:
        sys.stderr.write(bname + ': Target binary is required.\n')
        doAbort = True
    if options.prefix is None:
        sys.stderr.write(bname + ': A `#define` prefix is required.\n')
        doAbort = True
    if options.file is None:
        sys.stderr.write(bname + ': A output header filename is required.\n')
        doAbort = True

    if doAbort is True:
        sys.exit(1)

    (shellcode, instructions) = objdump_section(options.section, options.binary)
    cstr = gen_cstr(shellcode)
    write_header(options.file, options.prefix, cstr, len(shellcode), instructions)

    sys.exit(0)