-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshellcode_encoder.py
139 lines (100 loc) · 3.78 KB
/
shellcode_encoder.py
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
from binascii import hexlify
from pwn import *
from z3 import *
def parse_badchars():
bad_chars = []
filters = raw_input("Enter bad chars in hex format separated by ',' : \n").strip()
if filters == '':
return []
filters = filters.replace(" ", "").split(',')
for filter in filters:
bad_chars.append(int(filter, 16))
return bad_chars
def constraints(solver, x, bad_chars):
for i in xrange(4):
# Constraint alpha numerical bytes of the variables
solver.add(Or(And((x>>8*i)&0xff >= 0x30, (x>>8*i)&0xff <= 0x39), And((x>>8*i)&0xff >= 0x41, (x>>8*i)&0xff <= 0x5a), And((x>>8*i)&0xff >= 0x61, (x>>8*i)&0xff <= 0x7a)))
for bad_char in bad_chars:
for i in xrange(4):
# Constraint for the bad chars
solver.add((x>>8*i)&0xff != bad_char)
return solver
def encode_shellcode(offset_r_address='', register='esp', bad_chars=[], shellcode='', scripting=False):
if not scripting:
bad_chars = parse_badchars()
shellcode = raw_input('Enter shellcode to encode: ').strip()
register = raw_input('Enter start register: ').strip()
offset_r_address = int(raw_input('Enter the offset between the register specified to the start address of the shellcode in hex format: ').strip(), 16)
else:
shellcode = hexlify(shellcode)
log.success("bad chars: ")
print [hex(i) for i in bad_chars]
log.success("shellcode: \n%#s", shellcode)
pack = make_packer(32, endian='little')
unpack = make_unpacker(32, endian='big')
shellcode = shellcode.replace('\\x', '').strip()
values = [unpack(pack(int(shellcode[i:i+8].ljust(8,'0'), 16))) for i in range(0,len(shellcode), 8)]
# reverse the list so that we push the last bytes of the shellcode first
values = values[::-1]
enc_shellcode = ""
# Create a solver, add constraints and then saving the context of the solver(push)
solver = Solver()
x = BitVec("x", 8*4)
y = BitVec("y", 8*4)
z = BitVec("z", 8*4)
a = BitVec("a", 8*4)
constraints(solver, x, bad_chars)
constraints(solver, y, bad_chars)
constraints(solver, z, bad_chars)
constraints(solver, a, bad_chars)
solver.push()
enc_shellcode += "push " + register + ";"
enc_shellcode += "pop eax;"
solver.pop()
solver.push()
# Calculate difference between esp and shellcode address
to_add = offset_r_address
# Calculate the number of bytes required to jump to the end of the encoded shellcode from the shellcode address
to_add += 1*2 + (4*5 + 2) + 5*2 + len(values)*21 + len(values)*4
solver.add(to_add == 0 - x - y - z - a)
solver.check()
model = solver.model()
# point eax to the end of the shellcode
enc_shellcode += "sub eax," + hex(int(str(model[x]))) + ";"
enc_shellcode += "sub eax," + hex(int(str(model[y]))) + ";"
enc_shellcode += "sub eax," + hex(int(str(model[z]))) + ";"
enc_shellcode += "sub eax," + hex(int(str(model[a]))) + ";"
enc_shellcode += "push eax" + ";"
enc_shellcode += "pop esp" + ";"
eax = 0
solver.pop()
solver.push()
solver.add(0 == x&y)
solver.check()
model = solver.model()
enc_shellcode += "and eax," + hex(int(str(model[x]))) + ";"
enc_shellcode += "and eax," + hex(int(str(model[y]))) + ";"
for val in values:
solver.pop()
solver.push()
solver.add(val == eax - x - y - z - a)
while True:
solver.check()
model = solver.model()
# mov eax, val
enc_shellcode += "sub eax," + hex(int(str(model[x]))) + ";"
enc_shellcode += "sub eax," + hex(int(str(model[y]))) + ";"
enc_shellcode += "sub eax," + hex(int(str(model[z]))) + ";"
enc_shellcode += "sub eax," + hex(int(str(model[a]))) + ";"
enc_shellcode += "push eax" + ";"
eax = val
break
for i in xrange(len(values)*4):
enc_shellcode += "inc ecx" + ";"
log.success('Assembly code generated')
print enc_shellcode.replace(";", "\n")
log.success('Compiled assembly code')
print repr(asm(enc_shellcode))
return asm(enc_shellcode)
if __name__ == '__main__':
encode_shellcode()