diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 7509457..0000000 --- a/.clang-format +++ /dev/null @@ -1,3 +0,0 @@ ---- -IndentWidth: 4 -ColumnLimit: 80 diff --git a/Malware/Malware.sln b/Malware/Malware.sln index 7538aa1..9bffedb 100644 --- a/Malware/Malware.sln +++ b/Malware/Malware.sln @@ -8,7 +8,6 @@ Global Debug + argument|Win32 = Debug + argument|Win32 Debug + mauvais argument|Win32 = Debug + mauvais argument|Win32 Debug|Win32 = Debug|Win32 - release bad argument|Win32 = release bad argument|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution @@ -18,8 +17,6 @@ Global {83D75E9A-7421-41B2-97EA-C052213D3562}.Debug + mauvais argument|Win32.Build.0 = Debug + mauvais argument|Win32 {83D75E9A-7421-41B2-97EA-C052213D3562}.Debug|Win32.ActiveCfg = Debug|Win32 {83D75E9A-7421-41B2-97EA-C052213D3562}.Debug|Win32.Build.0 = Debug|Win32 - {83D75E9A-7421-41B2-97EA-C052213D3562}.release bad argument|Win32.ActiveCfg = release bad argument|Win32 - {83D75E9A-7421-41B2-97EA-C052213D3562}.release bad argument|Win32.Build.0 = release bad argument|Win32 {83D75E9A-7421-41B2-97EA-C052213D3562}.Release|Win32.ActiveCfg = Release|Win32 {83D75E9A-7421-41B2-97EA-C052213D3562}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection diff --git a/Malware/Malware/Debug + argument/Malware.lastbuildstate b/Malware/Malware/Debug + argument/Malware.lastbuildstate index 22b7188..f4b5fea 100644 --- a/Malware/Malware/Debug + argument/Malware.lastbuildstate +++ b/Malware/Malware/Debug + argument/Malware.lastbuildstate @@ -1,2 +1,2 @@ #v4.0:v100 -Debug + argument|Win32|Z:\malware-m2-2026\Malware\| +Debug + argument|Win32|Z:\Malware\| diff --git a/Malware/Malware/Malware.cpp b/Malware/Malware/Malware.cpp index d9d1bac..e5527f7 100644 --- a/Malware/Malware/Malware.cpp +++ b/Malware/Malware/Malware.cpp @@ -1,40 +1,15 @@ -#include "stdafx.h" // IWYU pragma: keep -#include -#include -#pragma clang diagnostic ignored "-Wwritable-strings" -#include +#include "stdafx.h" #include +#include #include - -#include "encryption.h" -#include "functions.h" #include "lonesha256.h" -#include "tables_poly.h" -#ifdef _WIN32 -#include -#endif +#include "tables_poly.h" // Macros d'obfuscation pour cacher les "Magic Numbers" #define POLY ((uint8_t)(0xAA ^ 0xB1)) // 170 ^ 177 = 27 = 0x1B #define MSB ((uint8_t)(0x40 << 1)) // 64 << 1 = 128 = 0x80 #define SHIFT ((uint8_t)(14 >> 1)) // 14 / 2 = 7 -// Constantes d'états pour le Control Flow Flattening -#define STATE_INIT (0xAA ^ 0x11) // 0xBB -#define STATE_KEY_DERIV (0xCC ^ 0x22) // 0xEE -#define STATE_DECRYPT (0x77 ^ 0x44) // 0x33 -#define STATE_HASH (0x88 ^ 0x11) // 0x99 -#define STATE_EXIT (0xDE ^ 0xAD) // 0x73 - -#define M_INIT (0xFA ^ 0xAF) // 0x55 -#define M_EXPAND (0xDE ^ 0x9A) // 0x44 -#define M_ORACLE (0xCC ^ 0xFF) // 0x33 -#define M_DECOY (0x88 ^ 0xEE) // 0x66 -#define M_EXEC (0x11 ^ 0x88) // 0x99 -#define M_EXIT (0xDE ^ 0xAD) // 0x73 -// Identité de Boole pour M_EXIT (toujours 0x73) -#define GET_EXIT_STATE(x) (((x | 0x73) & 0x7F) ^ (x & 0)) - /* ============================================================================== * MATHÉMATIQUES SUR LE CORPS DE GALOIS GF(2^8) * Polynôme irréductible standard (AES) : x^8 + x^4 + x^3 + x + 1 (0x1B) @@ -51,98 +26,9 @@ typedef struct { uint8_t junk; } GF_CONTEXT; -typedef struct { - uint8_t input_x; - uint8_t* p_coeffs; - uint8_t final_result; - uint8_t current_x_pow; - uint32_t junk_data; - uint32_t state; // On l'intègre ici pour le flux - GF_CONTEXT inner_ctx; -} POLY_CONTEXT; - -typedef struct { - char* hidden_buffer; // Le pointeur qui remplace le "return useful;" - uint32_t chaos_seed; // Pour le générateur de lag - uint32_t opaque_counter; // Variable de contrôle bidon -} RED_HERRING_CTX; - -typedef struct { - char* input_decoded; // L'argument entrant - int final_match_result; // Le retour sortant - - unsigned char computed_hash[32]; // Buffer interne - uint32_t chaos_state; // Pour le générateur de lag -} HASH_CTX; - -int __declspec(noinline) main(int argc, char *argv[]); -void __declspec(noinline) boundary_end(); - -unsigned char shellcode[] = { - 0x31, 0xFF, // [0] xor edi, edi - // : - 0x8A, 0x87, 0x00, 0x00, 0x00, 0x00, // [2] mov al, [edi + p_enc_delta] - 0x32, 0x87, 0x00, 0x00, 0x00, 0x00, // [8] xor al, [edi + p_h2] - 0x8A, 0x0D, 0x00, 0x00, 0x00, 0x00, // [14] mov cl, [p_mask] - 0x20, 0xC8, // [20] and al, cl - 0x8A, 0x8F, 0x00, 0x00, 0x00, 0x00, // [22] mov cl, [edi + p_leurre] - 0x30, 0xC1, // [28] xor cl, al - 0x30, 0x8F, 0x00, 0x00, 0x00, 0x00, // [30] xor [edi + p_payload], cl - 0x47, // [36] inc edi - 0x83, 0xFF, 0x07, // [37] cmp edi, 7 - 0x7C, 0xD8, // [40] jl (-40 octets) - - // Finition du payload - 0xC6, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, // [42] mov byte ptr [p_payload+7], 0 - - // Récupération de argv[1] - 0x8B, 0x55, 0x0C, // [49] mov edx, [ebp+0x0C] - 0x8B, 0x52, 0x04, // [52] mov edx, [edx+4] - 0x52, // [55] push edx - - // Appel de la fonction - 0x68, 0x00, 0x00, 0x00, 0x00, // [56] push p_payload - - // --- L'INJECTION ABSOLUE EST ICI --- - 0xB8, 0x00, 0x00, 0x00, 0x00, // [61] mov eax, p_funcs - 0x90, 0x90, // [66] NOP, NOP (On supprime le déréférencement) - 0xFF, 0xD0, // [68] call eax // [68] call eax - 0x83, 0xC4, 0x08, // [70] add esp, 8 - - // Sortie (selector = 3) - 0xC7, 0x85, 0x48, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, // [73] mov dword ptr [ebp-B8h], 3 - - 0x90, 0x90 // [83] NOPs (Taille totale : 85 octets) -}; - -void apply_smc_patch(void* target, void* p_enc_delta, void* p_h2, void* p_mask, void* p_leurre, void* p_payload, void* p_funcs) -{ - *(uint32_t*)(shellcode + 4) = (uint32_t)p_enc_delta; - *(uint32_t*)(shellcode + 10) = (uint32_t)p_h2; - *(uint32_t*)(shellcode + 16) = (uint32_t)p_mask; - *(uint32_t*)(shellcode + 24) = (uint32_t)p_leurre; - *(uint32_t*)(shellcode + 32) = (uint32_t)p_payload; - *(uint32_t*)(shellcode + 44) = (uint32_t)p_payload + 7; - *(uint32_t*)(shellcode + 57) = (uint32_t)p_payload; - - // NOUVEAU : Injection de l'adresse de ton pointeur de fonction - *(uint32_t*)(shellcode + 62) = (uint32_t)p_funcs; - - // (La modification de selector reste inchangée car ton image montre que ça marche parfaitement !) - - DWORD oldProtect; - if (VirtualProtect(target, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &oldProtect)) - { - memcpy(target, shellcode, sizeof(shellcode)); - VirtualProtect(target, sizeof(shellcode), oldProtect, &oldProtect); - FlushInstructionCache(GetCurrentProcess(), target, sizeof(shellcode)); - } -} - - uint8_t gf_mul(GF_CONTEXT* ctx, uint8_t key_stream) { ctx->p = 0; - + //Sert à rien ctx->junk = key_stream ^ 0x33; @@ -187,7 +73,7 @@ uint8_t gf_mul(GF_CONTEXT* ctx, uint8_t key_stream) { //Itération 4 ctx->p = (ctx->p | (ctx->a & (-(ctx->b & 1)))) - (ctx->p & (ctx->a & (-(ctx->b & 1)))); - ctx->mask = -((ctx->a >> SHIFT) & 1); + ctx->mask = -((ctx->a >> SHIFT) & 1); ctx->a <<= 1; ctx->a ^= (POLY & ctx->mask); ctx->b >>= 1; @@ -225,547 +111,144 @@ uint8_t gf_mul(GF_CONTEXT* ctx, uint8_t key_stream) { return ctx->p; } -void evaluate_polynomial(POLY_CONTEXT* pctx) { - pctx->final_result = (pctx->input_x & (~pctx->input_x)); - pctx->current_x_pow = (uint8_t)((0xDE >> 7) | (0x01 & 0x01)); - pctx->junk_data = 0x1337BEEF; - - - uint32_t j = 0; - pctx->state = 0xDEAD6666; // Point d'entrée - while (pctx->state != 0xBAADF00D) { - switch (pctx->state) { - case 0xDEAD6666: // BLOC : Calcul du terme (coeff * x^j) - { - pctx->inner_ctx.a = pctx->p_coeffs[j]; - pctx->inner_ctx.b = pctx->current_x_pow; - - uint8_t m_term = gf_mul(&(pctx->inner_ctx), 0x55); - pctx->final_result = (pctx->final_result | m_term) - (pctx->final_result & m_term); - - pctx->state = 0xFEED1111; - break; - } - - case 0xFEED1111: // BLOC : x_pow = x_pow * x - { - pctx->inner_ctx.a = pctx->current_x_pow; - pctx->inner_ctx.b = pctx->input_x; - - pctx->current_x_pow = gf_mul(&(pctx->inner_ctx), 0xAA); - - //Condition toujours vraie - if (((pctx->junk_data * (pctx->junk_data + 1)) + 1) % 2 != 0) { - pctx->state = 0xCAFE2222; // Chemin normal - } else { - pctx->state = 0x00000000; // Branche morte - } - break; - } - - case 0xCAFE2222: // BLOC : Incrémentation & Boucle - { - j = -~j; - // On compare j à 8 (0x40 >> 3) - if (j < (0x80 >> 4)) { - pctx->state = 0xDEAD6666; // Reboucle - } else { - pctx->state = 0xBAADF00D; // Sortie - } - - pctx->junk_data ^= (j << 13) | (pctx->final_result); - break; - } - - default: - // Anti-debug / Anti-tamper : si le state est corrompu - pctx->state = 0xBAADF00D; - break; - } +// Évaluation d'un polynôme de degré 7 sur GF(256) +uint8_t evaluate_polynomial(uint8_t x, const uint8_t coeffs[8]) { + uint8_t result = 0; + uint8_t x_pow = 1; + for (int j = 0; j < 8; j++) { + GF_CONTEXT ctx; + ctx.a = coeffs[j]; + ctx.b = x_pow; + result ^= gf_mul(&ctx, 0x55); + ctx.a = x_pow; + ctx.b = x; + x_pow = gf_mul(&ctx, 0xAA); } + return result; } -typedef struct { - void (*p1)(RED_HERRING_CTX* pctx); - void (*p2)(HASH_CTX* pctx); -} FuncList; - -void this_is_useful_fr_dont_miss_it(RED_HERRING_CTX* pctx) { - uint32_t magic_size = (0xFF ^ 0x9B); - pctx->chaos_seed = 0xC0DEF00D; - - pctx->opaque_counter = (magic_size * 2) - 200; - - pctx->hidden_buffer = (char*)malloc( (magic_size | 0x00) + pctx->opaque_counter ); - - if (pctx->hidden_buffer == NULL) return; // Sécurité basique - - // Générateur de Lag & Boucle poubelle - // Boucle qui tourne dans le vide pour exploser le Graphe de Flux de Contrôle - for (int lag = 0; lag < ((0x64 ^ 0x07) & 0x3F); lag++) { - pctx->chaos_seed += (lag ^ 0xAA); - pctx->chaos_seed = (pctx->chaos_seed << 3) | (pctx->chaos_seed >> 29); // ROR 29 +/* ============================================================================== + * MOTEUR D'OBFUSCATION BRANCHLESS (POINT-FUNCTION OBFUSCATION) + * ============================================================================== */ +int main(int argc, char* argv[]) { + if (argc < 2 || strlen(argv[1]) < 8) { + printf("Arguments invalides.\n"); + return 1; } - for (uint32_t j = 0; j < (magic_size - (0xFF / 0xFF)); j++) { - - // Entrelacement : on met à jour le chaos au milieu des calculs "utiles" - pctx->chaos_seed ^= pctx->hidden_buffer[j]; + uint8_t input[8]; + memcpy(input, argv[1], 8); - uint8_t constant_c = (0xC6 >> 1); - uint8_t next_val = pctx->hidden_buffer[j + 1]; - uint8_t current_val = pctx->hidden_buffer[j]; + /* -------------------------------------------------------------------------- + * 1. EXPANSION SPATIALE (FORWARD-COMPUTATION) + * Objectif : Projeter l'entrée (8 octets) sur un espace pseudo-aléatoire de + * 64 octets (512 bits) pour remplir parfaitement un bloc de compression + * SHA-256 sans ajout de bits de padding prévisibles. + * + * Équation de récurrence non-linéaire : + * S_{c, i+1} = P_{c, i}(S_{c, i} \oplus x_i) + * où: + * - c : Index de la chaîne d'évaluation parallèle (de 0 à 7). + * - i : Index du caractère de l'entrée en cours de traitement (de 0 à 7). + * - S_{c, i} : État interne de la chaîne 'c' à l'étape 'i'. + * - x_i : i-ème octet (caractère) de l'entrée fournie. + * - P_{c, i} : Polynôme de transition aléatoire sur GF(2^8) spécifique à cette étape. + * -------------------------------------------------------------------------- */ - //x + y = (x ^ y) + 2*(x & y) - uint8_t added_val = (next_val ^ constant_c) + ((next_val & constant_c) << 1); - - //Sert à rien : condition impossible - if (((pctx->chaos_seed * pctx->chaos_seed) + pctx->chaos_seed) % 2 != 0) { - pctx->hidden_buffer[j] = pctx->opaque_counter & 0xFF; - pctx->chaos_seed /= pctx->opaque_counter; - } - pctx->hidden_buffer[j] = (current_val | added_val) & ~(current_val & added_val); //x ^ y = (x | y) & ~(x & y) - } - - // Pas de return ! Le résultat est discrètement caché dans pctx->hidden_buffer -} - -void cmp_hash(HASH_CTX* pctx) { - - uint32_t len_57 = (0xFF ^ 0xC6); - uint32_t len_32 = (0x80 >> 2); - - pctx->chaos_state = 0xDEADBEEF; - pctx->final_match_result = 0; - - lonesha256(pctx->computed_hash, (unsigned char*)pctx->input_decoded, len_57); - - //(XOR Key = 0x55) - const unsigned char obfuscated_target[32] = { - 0xA1, 0xB8, 0x7F, 0x6D, 0x87, 0xAA, 0x99, 0x6D, - 0xE9, 0x36, 0x7D, 0x13, 0xFA, 0xB7, 0x1A, 0x61, - 0x78, 0x8D, 0xED, 0x0B, 0x21, 0xE8, 0x26, 0xCC, - 0x78, 0xC4, 0x03, 0x71, 0xE1, 0x26, 0x08, 0xBB - }; - - for (uint32_t i = 0; i < len_32; i++) { - - // Générateur de Lag - for(uint32_t lag = 0; lag < ((i & 0x03) + 2); lag++) { - pctx->chaos_state ^= (lag << (i % 4)); - } - - // Déchiffrement à la volée du vrai byte ciblé - uint8_t real_target_byte = obfuscated_target[i] ^ 0x55; - uint8_t current_computed = pctx->computed_hash[i]; - - uint8_t is_different = (real_target_byte ^ current_computed); - - if (is_different != 0) { - - //Condition toujours vraie - if (((pctx->chaos_state * pctx->chaos_state) + pctx->chaos_state) % 2 == 0) { - // Vrai calcul : on simule le (hash[i] - hash_computed[i]) - // x - y = (x + (~y) + 1) - pctx->final_match_result = real_target_byte + (~current_computed) + 1; - return; // On sort discrètement, le résultat est dans pctx - - } else { - // Branche morte - pctx->final_match_result = 0xFF; - pctx->chaos_state /= (is_different - is_different); // Division par zéro - } - } - // Entrelacement de bruit - pctx->chaos_state = (pctx->chaos_state >> 3) | (pctx->chaos_state << 29); - } -} - -int fakemain(int argc, wchar_t *argv[]) { - // Vérifie si argc < 2 - if ((((argc << 1) - argc) | 0) <= (0xFF / 0xFF)) { - return (0xBAD & 0); - } - - // Initialisation de la machine à états - uint32_t current_state = STATE_INIT; - uint32_t junk_register = 0; - - // Déclarations remontées pour le switch - Obfuscated_stdFunclist *stdfunclist = nullptr; - FuncList list = {this_is_useful_fr_dont_miss_it, cmp_hash}; - char *encoded = nullptr; - char *key = nullptr; - RED_HERRING_CTX fake_context; - HASH_CTX my_hash_ctx; - - //Aplatissement du flux de contrôle - while (current_state != STATE_EXIT) { - switch (current_state) { - - case STATE_INIT: - { - stdfunclist = new Obfuscated_stdFunclist(); - - encoded = "\x64\x55\x56\x41\x43\x14\x56\x13\x46\x5b\x47\x40\x14\x5e\x52" - "\x47\x13\x56\x5e\x5d\x40\x1f\x13\x53\x54\x14\x42\x5b\x41\x40" - "\x13\x53\x47\x58\x5d\x46\x14\x53\x51\x54\x5b\x5b\x52\x54\x41" - "\x51\x12\x54\x51\x13\x44\x47\x46\x5a\x5d\x54"; - - key = (char *)malloc(sizeof(char) * (0x12 >> 1)); - - list.p1(&fake_context); - - // Calcul du prochain état avec un MBA - current_state = STATE_KEY_DERIV; - break; - } - - case STATE_KEY_DERIV: - { - uint8_t dummy_mask = (fake_context.chaos_seed == (junk_register & 0)) ? 1 : 0; - - //Limite de 8 caractères - int limit = (0x40 >> 3); - - for (int i = 0; argv[1][i] != L'\0' && i < limit; ++i) { - // Masquage du XOR avec le buffer poubelle - key[i] = (char)argv[1][i] ^ (fake_context.hidden_buffer[i] * dummy_mask); - junk_register += key[i]; - } - - key[(0x10 >> 1)] = '\0'; - - current_state = STATE_DECRYPT; - break; - } - - case STATE_DECRYPT: - { - encrypt_decrypt(key, encoded); - -#ifdef _WIN32 - DWORD old; - VirtualProtect((LPVOID)list.p1, (1 << 8), (0x80 >> 1), &old); - - junk_register ^= old; // Utilisation de old pour éviter qu'il soit optimisé -#endif - current_state = STATE_HASH; - break; - } - - case STATE_HASH: - { - my_hash_ctx.input_decoded = encoded; - - list.p2(&my_hash_ctx); - - // Si final_match_result == 0, alors (0 | 0) == 0. - if ((my_hash_ctx.final_match_result | 0) == 0) { - // On affiche le flag avec le printf obfusqué - stdfunclist->obfusc_printf("%s\n", encoded); - } - - // Sortie du labyrinthe - current_state = STATE_EXIT; - break; - } - - default: - // Anti-tampering : si l'analyste modifie la mémoire et casse l'état - current_state = STATE_EXIT; - break; + uint8_t super_bloc[64]; + for (int c = 0; c < 8; c++) { + uint8_t state = INITIAL_STATES[c]; + for (int i = 0; i < 8; i++) { + // Mélange non-linéaire du caractère d'entrée avec l'état courant + state = evaluate_polynomial(state ^ input[i], POLY_COEFFS[c][i]); + // Capture de la trace pour former le bloc final + super_bloc[c * 8 + i] = state; } } - // Le retour utilise la variable poubelle annulée (0) - return (junk_register - junk_register); -} - -void fake_exit(char* msg){ - printf("%s\n",msg); - for (int i = 0; i < INT_MAX; i++) { - printf(""); - } - exit(0); -} - -uint32_t get_anti_debug_score() { - int res = 0; - #ifdef _WIN32 - CheckRemoteDebuggerPresent(GetCurrentProcess(), &res); - #endif - return (uint32_t)res; -} - -uint32_t get_checksum_diff() { - const unsigned char* start_ptr = (const unsigned char*) main; - const unsigned char* end_ptr = (const unsigned char*) boundary_end; - - unsigned char hash[32]; - lonesha256(hash, start_ptr, (size_t) (end_ptr-start_ptr)); - - unsigned char compareto[32] = { - 0x53, 0x66, 0xc0, 0x21, 0x8d, 0xb2, 0xd4, 0xe2, - 0x3f, 0x23, 0xc4, 0xb3, 0xad, 0xc3, 0x71, 0x98, - 0x77, 0x01, 0x1d, 0x1c, 0x22, 0xe6, 0xfb, 0x93, - 0x7d, 0x4b, 0x7e, 0xdb, 0x1f, 0x2b, 0x33, 0x3a - }; + /* -------------------------------------------------------------------------- + * 2. VÉRIFICATION D'INTÉGRITÉ (ORACLE ALÉATOIRE) + * Calcul de l'empreinte H1 = SHA256(super_bloc) + * -------------------------------------------------------------------------- */ + unsigned char h1[32]; + lonesha256(h1, super_bloc, 64); + // Accumulation des erreurs bit-à-bit par rapport à la cible cryptographique + // Diff = \bigvee_{k=0}^{31} (H_1[k] ^ H_{cible}[k]) uint32_t diff = 0; - for(int i=0; i<32; i++) { - diff |= (hash[i] ^ compareto[i]); + for (int i = 0; i < 32; i++) { + diff |= (h1[i] ^ h_cible[i]); } - return diff; -} -typedef struct { - void (*evaluate_polynomial)(POLY_CONTEXT* pctx) ; - void *(*memcpy)(void *__restrict __dest, const void *__restrict __src, - size_t __n); - int (*lonesha256)(unsigned char out[32], const unsigned char *in, - size_t len); - unsigned long long (*rdtsc)(); -} FuncList2; - -int __declspec(noinline) main(int argc, char *argv[]) { - if (((uint64_t)argc * argc + 1) == 0) return 0xDEAD; - - uint32_t selector = M_INIT; - Obfuscated_stdFunclist *stdfunclist = nullptr; - FuncList2 list; - uint8_t input[8] = {0}; - unsigned long long time_start = __rdtsc(); - uint8_t super_bloc[64] = {0}; - unsigned char h1[32], h2[32], h_leurre[32]; - uint64_t mask = 0; - - // bool valid = true; - // TODO: UNCOMMENT THIS BEFORE SENDING AND VERIFY CHECKSUM!!!!!!!!!!!!!!!!!!!!!!!!!! - // valid = verif_checksum_prog(); - // if(!valid){ - // fake_exit(argv[1]); - // } - - // bool debug = verify_debuggers(); - // valid = valid && !debug; - // if(!valid){ - // fakemain(argc,(wchar_t**) argv); - // fake_exit(argv[1]); - // } + /* -------------------------------------------------------------------------- + * 3. FILTRE MATHÉMATIQUE "BRANCHLESS" (ZÉRO CONDITION) + * Transforme l'erreur accumulée en un masque binaire absolu. + * Formule : Mask = ( (Diff | (~Diff + 1)) >> 63 ) - 1 + * -------------------------------------------------------------------------- */ - while (selector != M_EXIT) { - switch (selector) { + uint64_t diff64 = diff; + + // Si diff > 0 (mot de passe faux) -> is_wrong = 1 + // Si diff == 0 (mot de passe bon) -> is_wrong = 0 + uint64_t is_wrong = (diff64 | (~diff64 + 1)) >> 63; - case M_INIT: { - stdfunclist = new Obfuscated_stdFunclist(); - list.evaluate_polynomial = evaluate_polynomial; - list.memcpy = stdfunclist->obfusc_memcpy; - list.lonesha256 = lonesha256; + // Si is_wrong == 1 -> Mask = 0x0000000000000000 (Ferme la porte au payload) + // Si is_wrong == 0 -> Mask = 0xFFFFFFFFFFFFFFFF (Ouvre la porte au payload) + uint64_t mask = is_wrong - 1; - fakemain(argc, (wchar_t **)argv); - - size_t sz = 0; - while(argv[1][sz] != '\0' && sz < 9) sz++; - if (sz > 8) return 0; + /* -------------------------------------------------------------------------- + * 4. DÉRIVATION DE LA CLÉ DE LEURRE (COMPORTEMENT GOODWARE) + * K_G = SHA256(L)_{[0..7]} où L est une chaîne d'apparence inoffensive. + * Permet une indistinguabilité totale lors d'une analyse statique (strings). + * -------------------------------------------------------------------------- */ + unsigned char leurre[] = "Microsoft_CRT_Initialization"; + unsigned char h_leurre[32]; + lonesha256(h_leurre, leurre, 28); // K_G correspond aux 8 premiers octets - list.memcpy(input, argv[1], sz); - - selector = (selector ^ 0x11); - break; - } + /* -------------------------------------------------------------------------- + * 5. SÉPARATION DES DOMAINES (DOMAIN SEPARATION) + * Calcul de l'empreinte de dérivation H2. + * H_2 = SHA256(super_bloc \parallel \text{"DERIVATION"}) + * Garantit l'indépendance mathématique entre la vérification (H1) et le déchiffrement (H2). + * -------------------------------------------------------------------------- */ + + unsigned char buffer_h2[74]; // 64 octets (SB) + 10 octets (Sel) + memcpy(buffer_h2, super_bloc, 64); + memcpy(buffer_h2 + 64, "DERIVATION", 10); + + unsigned char h2[32]; + lonesha256(h2, buffer_h2, 74); - case M_EXPAND: { - for (uint32_t c = 0; c < (0x40 >> 3); c++) { - uint8_t current_state = INITIAL_STATES[c]; - for (uint32_t i = 0; i < 8; i++) { - POLY_CONTEXT mctx; - mctx.input_x = (current_state | input[i]) - (current_state & input[i]); - mctx.p_coeffs = (uint8_t*)POLY_COEFFS[c][i]; - list.evaluate_polynomial(&mctx); - - current_state = mctx.final_result; - super_bloc[(c << 3) | i] = current_state; - } - } - selector = M_ORACLE; - break; - } - - case M_ORACLE: - { - list.lonesha256(h1, super_bloc, 64); - - uint32_t integrity_check = 0; - - for (int i = 0; i < 32; i++) { - integrity_check |= (h1[i] ^ h_cible[i]); - } - - integrity_check |= get_anti_debug_score(); - integrity_check |= get_checksum_diff(); - - // Génération du masque final - uint64_t d64 = integrity_check; - mask = ((d64 | (~d64 + 1)) >> 63) - 1; - - // Si tout est OK : mask = 0xFF... - // Si debug présent OU checksum faux OU mauvais mdp : mask = 0x00... - - selector = M_DECOY; - break; - } - - case M_DECOY: { - //"Microsoft..." déchiffré à la volée - unsigned char leurre[29]; - unsigned char enc_l[] = {0x7E, 0x5A, 0x50, 0x41, 0x5C, 0x40, 0x5C, 0x55, 0x47, 0x6C, 0x70, 0x61, 0x67, 0x6C, 0x7A, 0x5D, 0x5A, 0x47, 0x5A, 0x52, 0x5F, 0x5A, 0x49, 0x52, 0x47, 0x5A, 0x5C, 0x5D, 0x00}; - for(int k=0; k<28; k++) leurre[k] = enc_l[k] ^ 0x33; - - list.lonesha256(h_leurre, leurre, 28); - - unsigned char b2[74]; - list.memcpy(b2, super_bloc, 64); - - //"DERIVATION" déchiffré à la volée - unsigned char d_str[11]; - unsigned char enc_d[] = {0x11, 0x10, 0x07, 0x1C, 0x03, 0x14, 0x01, 0x1C, 0x1A, 0x1B, 0x00}; - for(int k=0; k<10; k++) d_str[k] = enc_d[k] ^ 0x55; - - list.memcpy(b2 + 64, d_str, 10); - list.lonesha256(h2, b2, 74); - - selector = M_EXEC; - break; - } - - case M_EXEC: { - //verif pintool - unsigned long long time_end = __rdtsc(); - // printf("%d\n",(int)(time_end-time_start)); - if(time_end-time_start > (unsigned long long) 1972021549 * (unsigned long long) 10){ - fake_exit(argv[1]); - } - - void* p_target; - __asm { mov p_target, offset smc_zone } - apply_smc_patch(p_target, &enc_delta, &h2, &mask, &h_leurre, &payload, stdfunclist->obfusc_printf); - - smc_zone: - __asm { - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - _emit 0x90 - } - - goto label_finish_exec; - - stdfunclist->obfusc_printf("%s", argv[1]); - - label_finish_exec: - selector = M_EXIT; - break; - } - - default: - selector = M_EXIT; - break; - } + /* -------------------------------------------------------------------------- + * 6. RÉSOLUTION ALGÉBRIQUE ET DÉCHIFFREMENT + * Formule maîtresse : K_{finale} = K_G ^ ( (E_\Delta ^ H_2) \ \& \ Mask ) + * - Si Mask == 0x00 : K_{finale} = K_G ^ 0 = K_G (Goodware) + * - Si Mask == 0xFF : K_{finale} = K_G ^ \Delta = K_G ^ (K_M ^ K_G) = K_M (Malware) + * -------------------------------------------------------------------------- */ + unsigned char derived_key[8]; + for (int i = 0; i < 8; i++) { + // Tentative de déchiffrement du secret (\Delta) + uint8_t computed_delta = enc_delta[i] ^ h2[i]; + + // Application du masque d'annihilation (filtre AND) + uint8_t applied_delta = computed_delta & (mask & 0xFF); + + // Recombinaison finale de la clé + derived_key[i] = h_leurre[i] ^ applied_delta; + + // Déchiffrement immédiat in-place du payload + payload[i] ^= derived_key[i]; } + payload[7] = '\0'; // Protection d'affichage C-String + + /* -------------------------------------------------------------------------- + * 7. EXÉCUTION DU PAYLOAD DÉCHIFFRÉ + * -------------------------------------------------------------------------- */ + printf((char*)payload, argv[1]); + + // Boucle infinie demandée pour suspendre le processus + while(1){} + return 0; -} -void __declspec(noinline) boundary_end() { __asm { nop }; } - - - +} \ No newline at end of file diff --git a/Malware/Malware/Malware.vcxproj b/Malware/Malware/Malware.vcxproj index 22b28eb..2903f38 100644 --- a/Malware/Malware/Malware.vcxproj +++ b/Malware/Malware/Malware.vcxproj @@ -13,10 +13,6 @@ Debug Win32 - - release bad argument - Win32 - Release Win32 @@ -49,12 +45,6 @@ true Unicode - - Application - false - true - Unicode - @@ -70,9 +60,6 @@ - - - true @@ -86,9 +73,6 @@ false - - false - Use @@ -129,38 +113,16 @@ Level3 Use - Disabled + MaxSpeed true - false + true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - Disabled Console true - false - false - false - false - - - - - Level3 - Use - Disabled - true - false - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - Disabled - - - Console - true - false - false - false - false + true + true @@ -168,23 +130,19 @@ - - - Create Create Create Create - Create diff --git a/Malware/Malware/Malware.vcxproj.filters b/Malware/Malware/Malware.vcxproj.filters index f32f7bd..d2b6ecb 100644 --- a/Malware/Malware/Malware.vcxproj.filters +++ b/Malware/Malware/Malware.vcxproj.filters @@ -33,12 +33,6 @@ Fichiers d%27en-tête - - Fichiers d%27en-tête - - - Fichiers d%27en-tête - @@ -53,8 +47,5 @@ Fichiers sources - - Fichiers sources - \ No newline at end of file diff --git a/Malware/Malware/encryption.cpp b/Malware/Malware/encryption.cpp index c3a7eea..50f426e 100644 --- a/Malware/Malware/encryption.cpp +++ b/Malware/Malware/encryption.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" // IWYU pragma: keep #include "encryption.h" #include "tree.h" -#include "functions.h" #ifdef _WIN32 #include #endif @@ -37,8 +36,7 @@ Node* gen_tree(){ } char* derive_key_from_tree(char* key){ - auto stdfunclist = new Obfuscated_stdFunclist(); - char* res = (char*) stdfunclist->obfusc_malloc(sizeof(char)*9*8); + char* res = (char*) malloc(sizeof(char)*9*8); Node* root = gen_tree(); Node* current = root; int i_key = 0; diff --git a/Malware/Malware/functions.cpp b/Malware/Malware/functions.cpp deleted file mode 100644 index aee90b6..0000000 --- a/Malware/Malware/functions.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "stdafx.h" // IWYU pragma: keep -#include -#include "functions.h" -#ifdef _WIN32 -#include -#endif - -bool verify_signature(unsigned char* signature, unsigned char* starting_loc){ - for(int i = 0; i < 12; i++){ - if (signature[i] != starting_loc[i]){ - return false; - } - } - return true; -} - -void print_signature(unsigned char* loc){\ - printf("{"); - for(int i = 0; i < 5; i++){ - printf("0x%x",loc[i]); - if (i != 11) printf(", "); - } - printf("}\n"); -} \ No newline at end of file diff --git a/Malware/Malware/functions.h b/Malware/Malware/functions.h deleted file mode 100644 index 608e135..0000000 --- a/Malware/Malware/functions.h +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include -#include - -bool verify_signature(unsigned char *signature, unsigned char *starting_loc); -void print_signature(unsigned char *loc); - -class Obfuscated_stdFunclist { - public: // list of functions - int (*obfusc_printf)(const char *__restrict, ...); - void *(*obfusc_malloc)(size_t __size); - void *(*obfusc_memcpy)(void *__restrict __dest, - const void *__restrict __src, size_t __n); - - private: - void find_obfusc_printf() { - // print_signature(printf) - /*unsigned char signature_printf[12] = {0x8b, 0xff, 0x55, 0x8b, - 0xec, 0x6a, 0xfe, 0x68, - 0xe0, 0xdb, 0x34, 0x10};*/ - unsigned char signature_printf[12] = { 0x6A, 0x0C, 0x68, 0x60, 0x57, 0xB0, 0x78, 0xE8, 0xC0, 0xB5, 0xFA, 0xFF }; - unsigned char *loc = (unsigned char *)ungetc; // after printf in memory - while (!verify_signature(signature_printf, loc)) { - loc--; // go back until we find printf - } - obfusc_printf = (int (*)(const char *__restrict, ...))loc; - } - void find_obfusc_malloc() { - // print_signature((unsigned char*)malloc); - /*unsigned char signature_malloc[12] = {0x8b, 0xff, 0x55, 0x8b, - 0xec, 0x51, 0x6a, 0x0, - 0x6a, 0x0, 0x6a, 0x1};*/ - unsigned char signature_malloc[12] = { 0x8B, 0xFF, 0x55, 0x8B, 0xEC, 0x53, 0x8B, 0x5D, 0x08, 0x83, 0xFB, 0xE0 }; - unsigned char *loc = (unsigned char *)free; // after malloc in memory - while (!verify_signature(signature_malloc, loc)) { - loc++; // go backwards until we find malloc - } - obfusc_malloc = (void *(*)(size_t __size))loc; - } - void find_obfusc_memcpy() { - auto a = memcpy; // sinon ça crash parce que memcpy est pas chargé en mémoire :c - /* - unsigned char signature_memcpy[12] = {0xe9, 0xdf, 0x39, 0x0, 0x0, 0xe9, - 0x20, 0x58, 0x0, 0x0, 0xe9, 0xb};*/ - unsigned char signature_memcpy[12] = { 0x55, 0x8B, 0xEC, 0x57, 0x56, 0x8B, 0x75, 0x0C, 0x8B, 0x4D, 0x10, 0x8B }; - unsigned char *loc = (unsigned char *)memset; // before memcpy in memory - while (!verify_signature(signature_memcpy, loc)) { - loc--; // go forwards until we find memcpy - } - obfusc_memcpy = - (void *(*)(void *__restrict __dest, const void *__restrict __src, - size_t __n))loc; - } - - public: // constructor - Obfuscated_stdFunclist() { - find_obfusc_printf(); - find_obfusc_malloc(); - find_obfusc_memcpy(); - } -}; \ No newline at end of file diff --git a/Malware/Malware/release bad argument/Malware.exe.intermediate.manifest b/Malware/Malware/release bad argument/Malware.exe.intermediate.manifest deleted file mode 100644 index 1c06b61..0000000 --- a/Malware/Malware/release bad argument/Malware.exe.intermediate.manifest +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/Malware/Malware/release bad argument/Malware.lastbuildstate b/Malware/Malware/release bad argument/Malware.lastbuildstate deleted file mode 100644 index 0d31753..0000000 --- a/Malware/Malware/release bad argument/Malware.lastbuildstate +++ /dev/null @@ -1,2 +0,0 @@ -#v4.0:v100 -release bad argument|Win32|Z:\Malware\| diff --git a/README.md b/README.md index 148403c..cb4c203 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,3 @@ # malware-m2-2026 -Source code for a "malware" made for the Malware class of the Cybersecurity Masters degree in Nancy (FST) -This code, while featuring malware-like behaviour, is not malicious and safe to execute. It is made to compile with Visual Studio on Windows XP. - -This program has the following behaviour: -- If the argument (argv[1]) is `V&7mH@t!`, it writes "GAGNE!" (WIN!) on the standard output -- If the argument is any other string of 8 or less characters, it writes it back on the standard output -- Otherwise, the behaviour is undefined (Intriguing, isn't it?) - -To load the projet in VS, open the "Malware.sln" project file. \ No newline at end of file +Code source du malware pour l'UE Malware de la M2 FST \ No newline at end of file