diff --git a/Malware/Malware.sln b/Malware/Malware.sln index 9bffedb..7538aa1 100644 --- a/Malware/Malware.sln +++ b/Malware/Malware.sln @@ -8,6 +8,7 @@ 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 @@ -17,6 +18,8 @@ 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/Malware.cpp b/Malware/Malware/Malware.cpp index bd9db70..d9d1bac 100644 --- a/Malware/Malware/Malware.cpp +++ b/Malware/Malware/Malware.cpp @@ -1,5 +1,7 @@ -#pragma clang diagnostic ignored "-Wwritable-strings" #include "stdafx.h" // IWYU pragma: keep +#include +#include +#pragma clang diagnostic ignored "-Wwritable-strings" #include #include #include @@ -29,8 +31,9 @@ #define M_ORACLE (0xCC ^ 0xFF) // 0x33 #define M_DECOY (0x88 ^ 0xEE) // 0x66 #define M_EXEC (0x11 ^ 0x88) // 0x99 -#define M_TRAP (0x55 ^ 0xFF) // 0xAA #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) @@ -72,9 +75,74 @@ typedef struct { 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; @@ -119,7 +187,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; @@ -157,24 +225,6 @@ uint8_t gf_mul(GF_CONTEXT* ctx, uint8_t key_stream) { return ctx->p; } - -/* -// É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; -}*/ - 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)); @@ -241,7 +291,6 @@ typedef struct { void (*p2)(HASH_CTX* pctx); } FuncList; -// Fausse piste ultime - Draine le temps de l'analyste (VAGUE 3) void this_is_useful_fr_dont_miss_it(RED_HERRING_CTX* pctx) { uint32_t magic_size = (0xFF ^ 0x9B); pctx->chaos_seed = 0xC0DEF00D; @@ -282,7 +331,6 @@ void this_is_useful_fr_dont_miss_it(RED_HERRING_CTX* pctx) { // Pas de return ! Le résultat est discrètement caché dans pctx->hidden_buffer } -// Comparaison de Hash SHA-256 (VAGUES 1, 2 & 3 COMBINÉES) void cmp_hash(HASH_CTX* pctx) { uint32_t len_57 = (0xFF ^ 0xC6); @@ -360,7 +408,6 @@ int fakemain(int argc, wchar_t *argv[]) { { stdfunclist = new Obfuscated_stdFunclist(); - // Le payload. L'analyste le verra, mais ne saura pas quand il est utilisé. 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" @@ -436,29 +483,78 @@ int fakemain(int argc, wchar_t *argv[]) { 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 + }; + + uint32_t diff = 0; + for(int i=0; i<32; i++) { + diff |= (hash[i] ^ compareto[i]); + } + return diff; +} + typedef struct { void (*evaluate_polynomial)(POLY_CONTEXT* pctx) ; - //uint8_t (*evaluate_polynomial)(uint8_t x, const uint8_t coeffs[8]); 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; -// Identité de Boole pour M_EXIT (toujours 0x73) -#define GET_EXIT_STATE(x) (((x | 0x73) & 0x7F) ^ (x & 0)) - -int main(int argc, char *argv[]) { +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]); + // } + while (selector != M_EXIT) { switch (selector) { @@ -497,16 +593,26 @@ int main(int argc, char *argv[]) { break; } - case M_ORACLE: { + case M_ORACLE: + { list.lonesha256(h1, super_bloc, 64); - uint32_t diff = 0; + + uint32_t integrity_check = 0; + for (int i = 0; i < 32; i++) { - diff |= (h1[i] ^ h_cible[i]); + integrity_check |= (h1[i] ^ h_cible[i]); } - uint64_t d64 = diff; + 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; } @@ -535,28 +641,121 @@ int main(int argc, char *argv[]) { } case M_EXEC: { - for (int i = 0; i < 8; i++) { - uint8_t d = (enc_delta[i] ^ h2[i]) & (mask & 0xFF); - payload[i] ^= (h_leurre[i] ^ d); + //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]); } - payload[7] = (uint8_t)(0); - stdfunclist->obfusc_printf((char *)payload, argv[1]); - - selector = M_TRAP; - break; - } + 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); - case M_TRAP: { - // DEADLOCK MATHÉMATIQUE - // Un carré parfait + 1 n'est jamais nul sur les entiers non-signés 32 bits - uint32_t trap_sync = 1; - while ((trap_sync * trap_sync) + 1 != 0) { - trap_sync++; - if (trap_sync == 0) break; // Sécurité physique - } - selector = GET_EXIT_STATE(selector); - break; + 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: @@ -565,4 +764,8 @@ int main(int argc, char *argv[]) { } } return 0; -} \ No newline at end of file +} +void __declspec(noinline) boundary_end() { __asm { nop }; } + + + diff --git a/Malware/Malware/Malware.vcxproj b/Malware/Malware/Malware.vcxproj index 88845a2..22b28eb 100644 --- a/Malware/Malware/Malware.vcxproj +++ b/Malware/Malware/Malware.vcxproj @@ -13,6 +13,10 @@ Debug Win32 + + release bad argument + Win32 + Release Win32 @@ -45,6 +49,12 @@ true Unicode + + Application + false + true + Unicode + @@ -60,6 +70,9 @@ + + + true @@ -73,6 +86,9 @@ false + + false + Use @@ -128,6 +144,25 @@ false + + + Level3 + Use + Disabled + true + false + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + Disabled + + + Console + true + false + false + false + false + + @@ -149,6 +184,7 @@ Create Create Create + Create diff --git a/Malware/Malware/release bad argument/Malware.exe.intermediate.manifest b/Malware/Malware/release bad argument/Malware.exe.intermediate.manifest new file mode 100644 index 0000000..1c06b61 --- /dev/null +++ b/Malware/Malware/release bad argument/Malware.exe.intermediate.manifest @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Malware/Malware/release bad argument/Malware.lastbuildstate b/Malware/Malware/release bad argument/Malware.lastbuildstate new file mode 100644 index 0000000..0d31753 --- /dev/null +++ b/Malware/Malware/release bad argument/Malware.lastbuildstate @@ -0,0 +1,2 @@ +#v4.0:v100 +release bad argument|Win32|Z:\Malware\| diff --git a/README.md b/README.md index cb4c203..148403c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ # malware-m2-2026 -Code source du malware pour l'UE Malware de la M2 FST \ No newline at end of file +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