/
__init__.py
85 lines (65 loc) · 2.38 KB
/
__init__.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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import abc
import re
import io
from typing import ByteString
from zlib import crc32
from .. import arg, Unit, RefineryPartialResult
from ...lib.decorators import unicoded
__all__ = [
'Deobfuscator',
'IterativeDeobfuscator',
'outside',
'unicoded',
]
class AutoDeobfuscationTimeout(RefineryPartialResult):
def __init__(self, partial):
super().__init__('The deobfuscation timeout was reached before the data stabilized.', partial=partial)
def outside(*exceptions):
"""
A decorator which allows to apply the transformation only to areas where
a set of given regular expressions does not match. Here, this is mostly
used to apply deobfuscations only to code outside of strings.
"""
exclusion = '|'.join(F'(?:{e})' for e in exceptions)
def excluded(method):
def wrapper(self, data):
with io.StringIO() as out:
cursor = 0
for m in re.finditer(exclusion, data, re.DOTALL):
out.write(method(self, data[cursor:m.start()]))
out.write(m[0])
cursor = m.end()
out.write(method(self, data[cursor:]))
return out.getvalue()
return wrapper
return excluded
class Deobfuscator(Unit, abstract=True):
def __init__(self): super().__init__()
@unicoded
def process(self, data: str) -> str:
return self.deobfuscate(data)
@abc.abstractmethod
def deobfuscate(self, data: str) -> str:
return data
class IterativeDeobfuscator(Deobfuscator, abstract=True):
def __init__(self, timeout: arg('-t', help='Maximum number of iterations; the default is 100.') = 100):
if timeout < 1:
raise ValueError('The timeout must be at least 1.')
super().__init__()
self.args.timeout = timeout
def process(self, data: ByteString) -> ByteString:
previous = crc32(data)
for _ in range(self.args.timeout):
try:
data = super().process(data)
except KeyboardInterrupt:
raise RefineryPartialResult('Returning partially deobfuscated data', partial=data)
checksum = crc32(data)
if checksum == previous:
break
previous = checksum
else:
raise AutoDeobfuscationTimeout(data)
return data