Module refinery.units.obfuscation.vba.arithmetic
Expand source code Browse git
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations
import re
from refinery.units.obfuscation import Deobfuscator, StringLiterals
from refinery.lib.deobfuscation import cautious_eval
from refinery.lib.patterns import formats
def _cautious_vba_eval(e: str):
return cautious_eval(e.replace('^', '**'))
class deob_vba_arithmetic(Deobfuscator):
def deobfuscate(self, data):
strings = StringLiterals(formats.vbastr, data)
def vba_int_eval(match: re.Match[str]) -> str:
s = match[0].lower()
if not s.startswith('&'):
return s
t, s = s[1], s[2:].rstrip('&')
if t == 'h':
return str(int(s, 16))
if t == 'b':
return str(int(s, 2))
if t == 'o':
return str(int(s, 8))
@strings.outside
def evaluate(match: re.Match[str]):
expression = match[0]
expression = expression.strip()
if not any(c.isdigit() for c in expression):
return expression
expression = re.sub(str(formats.vbaint), vba_int_eval, expression)
brackets = 0
positions = []
ok = True
head = tail = rest = ''
for end, character in enumerate(expression):
if character == '(':
brackets += 1
positions.append(end)
continue
if character == ')':
brackets -= 1
if brackets < 0:
expression, tail = expression[:end], expression[end:]
break
else:
positions.pop()
if brackets == 0 and expression[0] == '(':
expression, rest = expression[:end + 1], expression[end + 1:]
break
if expression.isdigit():
return match[0]
if brackets > 0:
pos = positions[~0] + 1
head = expression[:pos]
expression = expression[pos:]
try:
result = str(_cautious_vba_eval(expression + rest))
except Exception:
ok = False
else:
rest = ''
if not ok and rest:
try:
result = str(_cautious_vba_eval(expression))
except Exception:
expression += rest
else:
ok = True
if not ok:
result = expression
self.log_info(F'error trying to parse arithmetic expression at offset {match.start()}: ({expression})')
else:
if expression.startswith('(') and expression.endswith(')'):
result = F'({result})'
if tail:
tail = self.deobfuscate(tail)
return F'{head}{result}{rest}{tail}'
pattern = re.compile(R'(?:{i}|{f}|[-+(])(?:[^\S\r\n]{{0,20}}(?:{i}|{f}|[-%|&~<>()+/*^]))+'.format(
i=str(formats.vbaint), f=str(formats.float)))
return pattern.sub(evaluate, data)
Classes
class deob_vba_arithmetic
-
Expand source code Browse git
class deob_vba_arithmetic(Deobfuscator): def deobfuscate(self, data): strings = StringLiterals(formats.vbastr, data) def vba_int_eval(match: re.Match[str]) -> str: s = match[0].lower() if not s.startswith('&'): return s t, s = s[1], s[2:].rstrip('&') if t == 'h': return str(int(s, 16)) if t == 'b': return str(int(s, 2)) if t == 'o': return str(int(s, 8)) @strings.outside def evaluate(match: re.Match[str]): expression = match[0] expression = expression.strip() if not any(c.isdigit() for c in expression): return expression expression = re.sub(str(formats.vbaint), vba_int_eval, expression) brackets = 0 positions = [] ok = True head = tail = rest = '' for end, character in enumerate(expression): if character == '(': brackets += 1 positions.append(end) continue if character == ')': brackets -= 1 if brackets < 0: expression, tail = expression[:end], expression[end:] break else: positions.pop() if brackets == 0 and expression[0] == '(': expression, rest = expression[:end + 1], expression[end + 1:] break if expression.isdigit(): return match[0] if brackets > 0: pos = positions[~0] + 1 head = expression[:pos] expression = expression[pos:] try: result = str(_cautious_vba_eval(expression + rest)) except Exception: ok = False else: rest = '' if not ok and rest: try: result = str(_cautious_vba_eval(expression)) except Exception: expression += rest else: ok = True if not ok: result = expression self.log_info(F'error trying to parse arithmetic expression at offset {match.start()}: ({expression})') else: if expression.startswith('(') and expression.endswith(')'): result = F'({result})' if tail: tail = self.deobfuscate(tail) return F'{head}{result}{rest}{tail}' pattern = re.compile(R'(?:{i}|{f}|[-+(])(?:[^\S\r\n]{{0,20}}(?:{i}|{f}|[-%|&~<>()+/*^]))+'.format( i=str(formats.vbaint), f=str(formats.float))) return pattern.sub(evaluate, data)
Ancestors
Class variables
var required_dependencies
var optional_dependencies
Methods
def deobfuscate(self, data)
-
Expand source code Browse git
def deobfuscate(self, data): strings = StringLiterals(formats.vbastr, data) def vba_int_eval(match: re.Match[str]) -> str: s = match[0].lower() if not s.startswith('&'): return s t, s = s[1], s[2:].rstrip('&') if t == 'h': return str(int(s, 16)) if t == 'b': return str(int(s, 2)) if t == 'o': return str(int(s, 8)) @strings.outside def evaluate(match: re.Match[str]): expression = match[0] expression = expression.strip() if not any(c.isdigit() for c in expression): return expression expression = re.sub(str(formats.vbaint), vba_int_eval, expression) brackets = 0 positions = [] ok = True head = tail = rest = '' for end, character in enumerate(expression): if character == '(': brackets += 1 positions.append(end) continue if character == ')': brackets -= 1 if brackets < 0: expression, tail = expression[:end], expression[end:] break else: positions.pop() if brackets == 0 and expression[0] == '(': expression, rest = expression[:end + 1], expression[end + 1:] break if expression.isdigit(): return match[0] if brackets > 0: pos = positions[~0] + 1 head = expression[:pos] expression = expression[pos:] try: result = str(_cautious_vba_eval(expression + rest)) except Exception: ok = False else: rest = '' if not ok and rest: try: result = str(_cautious_vba_eval(expression)) except Exception: expression += rest else: ok = True if not ok: result = expression self.log_info(F'error trying to parse arithmetic expression at offset {match.start()}: ({expression})') else: if expression.startswith('(') and expression.endswith(')'): result = F'({result})' if tail: tail = self.deobfuscate(tail) return F'{head}{result}{rest}{tail}' pattern = re.compile(R'(?:{i}|{f}|[-+(])(?:[^\S\r\n]{{0,20}}(?:{i}|{f}|[-%|&~<>()+/*^]))+'.format( i=str(formats.vbaint), f=str(formats.float))) return pattern.sub(evaluate, data)
Inherited members