-
Notifications
You must be signed in to change notification settings - Fork 1
/
parser.py
159 lines (141 loc) · 5.73 KB
/
parser.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/python
import sys, argparse
import re
import random
class obfuscator():
# Setup variables
def __init__(self, filename, encoding):
self.filename = filename
self.encode_fmt = ['push', 'sub', 'xor']
if len(encoding) != len(self.encode_fmt):
raise ValueError(
"Invalid encoding given!\nlen({}) != len({})".format(
encoding, self.encode_fmt))
self.encoding = encoding
self.registers = ['eax', 'ebx', 'ecx', 'edx']
self.setup()
self.reset()
# Setup input_file list from file input
def setup(self):
# Replace \t chars and split by new line
input_file = open(self.filename, 'r').read().replace('\t',
'').split('\n')
# Remove spaces with length > 1 and remove comments
input_file = [
re.sub(' +', '',
i.split(';')[0]) for i in input_file if i
]
self.input_file = input_file
# Generate list of instructions to be obfuscated
def reset(self):
# Filter for strings in encode_fmt and output tuples with its original index
to_encode = [(self.input_file.index(i), i) for i in self.input_file
if sum([j in i for j in self.encode_fmt])]
# print(to_encode)
self.encode = to_encode
# To obfuscate push instructions (specifically with registers)
def push(self, to_encode):
# Obfuscate register push and output a tuple with original index
to_encode = [(i[0], '\n'.join([
'sub esp, 4', 'mov dword [esp], ' + i[1].split(' ')[1]
])) if len(i[1].split(' ')) == 2
and i[1].split(' ')[0] == self.encode_fmt[0] else i
for i in to_encode]
# print(to_encode)
return to_encode
# To obfuscate sub instructions
def sub(self, to_encode):
# Extract sub and output a tuple with original index and random choice of unused register
to_encode = [
(i,
random.choice(
[j for j in self.registers
if j != i[1].split(' ')[-1]])) if len(i[1].split(' ')) == 3
and i[1].split(' ')[0] == self.encode_fmt[1] else i
for i in to_encode
]
# Obfuscate sub and output a tuple with original index
to_encode = [(i[0][0], '\n'.join([
'push ' + i[1],
'mov ' + i[1] + ', ' + i[0][1].split(' ')[1].replace(',', ''),
'xchg [' + i[0][1].split(' ')[1].replace(',', '') + '], ' + i[1],
'pop ' + i[0][1].split(' ')[1].replace(',', '')
])) if type(i[0]) == tuple else i for i in to_encode]
# print(to_encode)
return to_encode
# To obfuscate xor instructions (specifically with different registers)
def xor(self, to_encode):
# Filter for xor instructions for only those of different registers, and obfuscate using xor swap trick
to_encode = [(i[0], '\n'.join([
'xor ' + i[1].replace(',', '').split(' ')[1] + ', ' +
i[1].split(' ')[2], 'xor ' + i[1].split(' ')[2] + ', ' +
i[1].replace(',', '').split(' ')[1], 'xor ' +
i[1].replace(',', '').split(' ')[1] + ', ' + i[1].split(' ')[2]
])) if i[1].split(' ')[1][:-1] != i[1].split(' ')[2]
and i[1].replace(',', '').split(' ')[1] in self.registers
and i[1].split(' ')[2] in self.registers else i
for i in to_encode]
# print(to_encode)
return to_encode
# Start obfuscation
def obfuscate(self):
if_push, if_sub, if_xor = self.encoding
# Replace push reg instructions
if (if_push):
self.encode = self.push(self.encode)
# Replace sub instructions
if (if_sub):
self.encode = self.sub(self.encode)
# Replace xor reg instructions
if (if_xor):
self.encode = self.xor(self.encode)
# Replace original instructions with amended instructions into output
output_file = '\n'.join([
self.encode[[
self.input_file.index(i) == j[0] for j in self.encode
].index(True)][1]
if sum([self.input_file.index(i) == j[0]
for j in self.encode]) else i for i in self.input_file
])
self.input_file = output_file.split('\n')
self.reset() # Regenerate to-be-encoded list
return output_file
# Reencode instructions using multiplier
def repeat(self, multiplier):
out = ""
for i in range(multiplier):
out = self.obfuscate()
return out
def main(filename, out, encode_mul, encoding):
obfuscation = obfuscator(filename, encoding)
if encode_mul < 1:
print("Invalid multiplier given!")
sys.exit()
else:
obf = obfuscation.repeat(encode_mul)
if out:
open(out, 'w').write(obf)
print("Outputted to {}".format(out))
else:
print(obf)
return
parser = argparse.ArgumentParser(description='ASM Encryption')
parser.add_argument('--input', '-i', help='File input')
parser.add_argument('--output', '-o', help='File output')
parser.add_argument('--mul', '-m', help='Encoding multiplier', default=1)
parser.add_argument(
'--encode', '-e', help='Allow: if_push, if_sub, if_xor', nargs='+')
args = parser.parse_args()
in_file = args.input
out_file = args.output
multiple = int(args.mul)
encode = args.encode
if __name__ == '__main__':
if not args.encode:
print("No encoding given!")
parser.print_help()
elif not in_file:
print("No input file given!")
parser.print_help()
else:
main(in_file, out_file, multiple, [int(i) for i in encode])