Skip to content

Commit

Permalink
Improves structure of ast
Browse files Browse the repository at this point in the history
- Makes FCT scanner detect marshal.loads format as well
- Reformats ast matches to use a more consistent indentation style, and removes Load() and Store() context and other extraneous information
- Removes deprecated TextIO imports

Signed-off-by: stickie <[email protected]>
  • Loading branch information
FieryIceStickie committed Mar 27, 2024
1 parent 48fdbb0 commit f27ab80
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 77 deletions.
1 change: 0 additions & 1 deletion src/vipyr_deobf/deobfuscators/hyperion.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class _theory:
import re
import zlib
from ast import *
from typing import TextIO

from ..utils import WEBHOOK_REGEX

Expand Down
1 change: 0 additions & 1 deletion src/vipyr_deobf/deobfuscators/lzmaspam.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import codecs
import lzma
import re
from typing import TextIO

from ..utils import WEBHOOK_REGEX

Expand Down
1 change: 0 additions & 1 deletion src/vipyr_deobf/deobfuscators/vare.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import marshal
import re
import zlib
from typing import TextIO

from cryptography.fernet import Fernet

Expand Down
95 changes: 53 additions & 42 deletions src/vipyr_deobf/scanners/fct_scan.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
import ast
from ast import (Assign, Attribute, Call, Constant, Expr, Lambda, Load, Name,
Slice, Store, Subscript, UnaryOp, USub, arg, arguments)
from ast import (Assign, Attribute, Call, Constant, Expr, Lambda, Name,
Slice, Subscript, UnaryOp, USub, arg, arguments)


def match_inner_underscore_function(node: ast.Call):
match node:
case Call(
func=Attribute(
value=Call(
func=Name(id='__import__'),
args=[Constant(value='zlib')]
),
attr='decompress',
),
args=[
Call(
func=Attribute(
value=Call(
func=Name(id='__import__'),
args=[Constant(value='base64')]
),
attr='b64decode',
),
args=[
Subscript(
value=Name(id='__'),
slice=Slice(
step=UnaryOp(op=USub(), operand=Constant(value=1))),
)
]
)
]
):
return True
return False


class FCTScanner(ast.NodeVisitor):
Expand All @@ -11,59 +44,37 @@ def __init__(self):
def visit_Assign(self, node):
match node:
case Assign(
targets=[
Name(id='_', ctx=Store())],
targets=[Name(id='_')],
value=Lambda(
args=arguments(
args=[
arg(arg='__')],
kwonlyargs=[],
kw_defaults=[],
defaults=[]),
args=arguments(args=[arg(arg='__')]),
body=Call(
func=Attribute(
value=Call(
func=Name(id='__import__', ctx=Load()),
args=[
Constant(value='zlib')],
keywords=[]),
attr='decompress',
ctx=Load()),
args=[
Call(
func=Attribute(
value=Call(
func=Name(id='__import__', ctx=Load()),
args=[
Constant(value='base64')],
keywords=[]),
attr='b64decode',
ctx=Load()),
args=[
Subscript(
value=Name(id='__', ctx=Load()),
slice=Slice(
step=UnaryOp(
op=USub(),
operand=Constant(value=1))),
ctx=Load())],
keywords=[])],
keywords=[]))):
func=Name(id='__import__'),
args=[Constant(value='marshal')]
),
attr='loads',
),
args=[body]
) | body
)
) if match_inner_underscore_function(body):
self.underscore_function_found = True
return

def visit_Expr(self, node):
match node:
case Expr(
value=Call(
func=Name(id='exec', ctx=Load()),
func=Name(id='exec'),
args=[
Call(
func=Name(id='_', ctx=Load()),
args=[
Constant(value=payload)],
keywords=[])],
keywords=[])) if isinstance(payload, bytes):
func=Name(id='_'),
args=[Constant(value=payload)]
)
]
)
) if isinstance(payload, bytes):
self.payload_found = True
return

Expand Down
25 changes: 12 additions & 13 deletions src/vipyr_deobf/scanners/hyperion_scan.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,41 @@
import ast
import re
from ast import Assign, Constant, Load, Name, Store, Tuple
from ast import Assign, Constant, Name, Tuple


class HyperionScanner(ast.NodeVisitor):
def __init__(self):
self.characteristic_found = False
self.signature_found = False

def visit_Assign(self, node):
match node:
case Assign(
targets=[
Name(id='__obfuscator__', ctx=Store())],
targets=[Name(id='__obfuscator__')],
value=Constant(value='Hyperion'),
) | Assign(
targets=[
Name(id='__authors__', ctx=Store())],
targets=[Name(id='__authors__')],
value=Tuple(
elts=[
Constant(value='billythegoat356'),
Constant(value='BlueRed')],
ctx=Load())
Constant(value='billythegoat356'),
Constant(value='BlueRed')
],
)
) | Assign(
targets=[
Name(id='__github__', ctx=Store())],
targets=[Name(id='__github__')],
value=Constant(value='https://github.com/billythegoat356/Hyperion')
):
self.characteristic_found = True
self.signature_found = True
return


COMMENT_REGEX = re.compile(
r'# sourcery skip: collection-to-bool, remove-redundant-boolean, remove-redundant-except-handler'
)


def scan_hyperion(code: str):
if COMMENT_REGEX.search(code):
return True
hyp_scanner = HyperionScanner()
hyp_scanner.visit(ast.parse(code))
return hyp_scanner.characteristic_found
return hyp_scanner.signature_found
36 changes: 17 additions & 19 deletions src/vipyr_deobf/scanners/lzmaspam_scan.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ast
from ast import Attribute, Call, Constant, Expr, Import, Load, Name, alias
from ast import Attribute, Call, Constant, Expr, Import, Name, alias


class LZMAScanner(ast.NodeVisitor):
Expand All @@ -10,45 +10,43 @@ def __init__(self):

def visit_Import(self, node):
match node:
case Import(
names=[alias(name='base64')]
):
case Import(names=[alias(name='base64')]):
self.base64_import_found = True
return
case Import(
names=[alias(name='lzma')]
):
case Import(names=[alias(name='lzma')]):
self.lzma_import_found = True
return

def visit_Expr(self, node):
match node:
case Expr(
value=Call(
func=Name(id='print', ctx=Load()),
func=Name(id='print'),
args=[
Call(
func=Name(id='compile', ctx=Load()),
func=Name(id='compile'),
args=[
Call(
func=Attribute(
value=Name(id='lzma', ctx=Load()),
value=Name(id='lzma'),
attr='decompress',
ctx=Load()),
),
args=[
Call(
func=Attribute(
value=Name(id='base64', ctx=Load()),
value=Name(id='base64'),
attr='b64decode',
ctx=Load()),
args=[
Constant(value=payload)],
keywords=[])],
keywords=[]),
),
args=[Constant(value=payload)],
)
],
),
Constant(value='<string>'),
Constant(value='exec')],
keywords=[])],
keywords=[])) if isinstance(payload, bytes):
)
],
)
) if isinstance(payload, bytes):
self.payload_found = True
return

Expand Down

0 comments on commit f27ab80

Please sign in to comment.