Автор: vit

  • Про ASM и манипуляции с байт-кодом.

    asm2Больше месяца назад автор статьи Decrypting Java Malware using ASM прислал мне оригинальный текст на русском языке для публикации в блоге, с целью донести широкому кругу лиц определенные аспекты защиты программ написанных на java от действий недоброжелателей. Автор статьи — разработчик, который долгое время занимается разработкой средств для противодействия реверс-инжирингу и взлому ПО, специалист в области информационной безопасности.
    К сожалению, в связи с большой загруженностью (казалось бы лето, все должны быть в отпусках, а нет — работы только привалило), никак не мог заняться блогом и выложить эту статью.

    Исправляюсь, надеюсь статья всё еще актуальна.

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

    В этой статье мы рассмотрим самый распространенный метод шифрования строк в Java Malware и напишем утилиту для снятия такой защиты.

    1) Небольшое введение в формат байткода class-файлов.

    Для дальнейшего понимания, необходимо знать следующие вещи – все константы (строки/примитивные типы) хранятся в специальной структуре внути class-файла, которая называется Constant Pool и для получения элемента из Constant Pool используется инструкция ldc.

    Посмотрим как выглядит байт код вызова метода System.out.println(“HelloWorld”);

    Пишем простой класс

    public class Hello {
      public static void main(String[] args) throws Exception {
        System.out.println("HelloWorld");
      }
    }

    Компилируем
    javac Hello.java

    Декомпилируем с помощью javap

    javap -c -v Hello

    ConstanPool:

      ... 
        const #3 = String	#20;	//  HelloWorld
        const #20 = Asciz	HelloWorld;
    
       3:	ldc	#3; //String HelloWorld
       5:	invokevirtual	#4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

    (далее…)

  • Let’s rock, everybody!

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

    Статья про рок-банды, новое время и программирование.

    rock-and-roll-xs

     

    Давно хотел провести аналогию между музыкой и программированием. Например команда разрабатывающая большие и сложные системы чем-то похожа на симфонический оркестр:
    blog_Classical_

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

    Если мы посмотрим на разработку программных продуктов по классической водопадной схеме, то состав участников также будет довольно обширным: архитектор, тим лид, ведущие программисты, несколько программистов разной специализации (java, c/с++, javascript и тд) и группа дизайнеров с верстальщиками. Естественно далеко не все компании могут себе позволить идеально укомплектованный состав. Наиболее успешные организации могут заинтересовать в профессиональном и материальном плане более сильных специалистов, остальные конторы довольствуются тем, кто соответствует их уровню.

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

    Под новым форматом я имею в виду небольшой творческий коллективов состоящий из 3-5 человек. Это еще не “оркестр”, но уже и не соло-программист. Естественно масштаб создаваемых произведений не сопоставим с творением Классики. Другими словами, если проводить аналогии, речь идет о коллективах создающие программы “по духу” более близкие к Yesterday Битлз, чем к Хорошо темперированному клавиру И.С. Баха.
    Все идет к тому, что в программировании наступит время аналогичное музыкальной эпохи 60-70гг прошлого века.

    У кого-то может возникнуть такая ассоциация:
    blog_beatles
    у других такая: (далее…)

  • Про старый добрый RMI


    Не так давно, после многолетнего перерыва, в одном небольшом проекте использовал такую древнюю технологию как RMI. В итоге хотел поделиться общими впечатлениями и сделать небольшие заметки “для себя” на будущее.
    Задача была типовой — перебросить выполнение некоторых функций с одного сервера на другой, на котором установлено специальным образом настроенное оборудование и программное обеспечение. В результате нескольких раундов переговоров с клиентом были получены следующие нефункциональные требования:

    1. Между серверами гигабитная сеть в доверенной зоне, без доступа в интернет.
    2. Физически сервера расположены рядом (в одной стойке).
    3. Размер передаваемых в функцию данных около нескольких сотен килобайт, максимум нескольких мегабайт.
    4. Количество запросов небольшое, но возможны пиковые нагрузки.
    5. Операционная системы и оборудование позволяет установить последнюю стабильную версию Java, но по возможности следует избегать большого количества сторонних библиотек и фреймворков.
    6. Клиентская и серверная часть должны работать не столько в рамках сервера приложения/веб-сервера, а скорее как обычное приложение.

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

    Кончено RMI давно уже не в тренде, но в данном случае он очень органично подходил для решения этой задачи. Другое дело, что явно пользовался им очень давно, во времена предшествующие Java 5. С тех пор для ремоутинга чего-только не приходилось применять. В зависимости от контекста: .NET Remoting, Hessian/Burlap, GWT-RPC, SOAP, ну и конечно различные самодельные реализации.
    Сейчас большинство моих заказчиков хотят веб-службы. Бизнесу нужен SOAP и WSDL, по крайней мере сейчас.

    Еще раз повторюсь, я не смотрел на RMI много лет, с тех пор многое изменилось (для меня). В первую очередь радует то, что уже давно можно не запускать rmic и колдовать со скелетонами как нас до сих пор учит википедия.
    С другой стороны классы Remote и RemoteException остались, т.е. преемственность базовых классов естественно остается. И это хорошо!

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

    • Системное свойство java.rmi.server.logCalls = true/false полезно для отладки.
    • Если две сетевые карты, то может будет полезно посмотреть на свойство java.rmi.server.hostname.
    • Если вдруг понадобится, то можно прочитать руководство по работе RMI и SSL.
    • Подробный список свойств находится на страницах javarmiproperties и sunrmiproperties.

    Резюмируя — мне понравилось, вернулись воспоминания моей java-молодости, во времена когда клепал Applet-ы, раскладывал GridBag-ом и писал сервера на голых ServerSocket-ах. В целом, не смотря на то, что RMI уже очень много лет, оказалось, что на нем до сих пор можно быстро делать простые связки Java-to-Java фактически “из коробки”.

  • Комиксы

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

    1. CommitStrip

    Французские авторы. Про жизнь небольшой команды занимающейся веб-разработкой.

    (далее…)

  • Java и лямбда-выражения.

    Lambda

    Ни для кого не секрет, что во второй половине 2013 года планируется выпуск Java 8 (UPD: на JavaOne 2013 в Москве сообщили, что выход восьмерки перенесут на 2014). Мне наконец-то надоело быть пассивным читателем всех этих многочисленных восторженных отзывов о нововведениях языка и я решил скачать предварительную версию JDK (благо она уже давно выложена) и начать свои экзерсисы.

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

    JDK с “Lambda Project” можно скачать c официальной страницы.
    Также в текущей сборке JDK 8 (на момент написания статьи) лямбды уже тоже есть, но API с коллекциями еще не полностью завершены.

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

    В бытовом, чисто утилитарном смысле, под этой пресловутой лямбдой (или лямбда-выражениями) многие программисты как правило подразумевают обычные анонимные функции (хотя конечно это не строгое определение). Причем под функцией имеется в виду первоклассный объект. Его можно передавать как объект в аргументы метода, присваивать какой-то переменной и т.д. С точки зрения конечного пользователя (в нашем случае программиста) мы получаем удобный способ сокращать количество строк кода, без сильной потери в его читаемости.

    Мои опыты

    Один из самых часто встречаемых примеров в интернете, демонстрирующих пользу от использования лямбды — замена старых добрых анонимных классов.
    Сравните. Это новый вариант:

       // Вот она, анонимная функция!
       Runnable r = () -> System.out.println("hello");
       Thread th = new Thread(r);
       th.start();
    

    Вот так по-старинке:

       
       Runnable r = new Runnable() {
            public void run() {
                System.out.println("hello");
            }
       };
       Thread th = new Thread(r);
       th.start();
    

    Естественно и логично применить такой подход для слушателей.
    Вот небольшой сниппет с формочкой и кнопкой.

    public class Main {
        public static void foo(ActionEvent e) {
            System.out.println("hello:" + e);        
        }
    
        public static void main(String arg[]) throws Exception {
            JFrame frame = new JFrame("Demo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            JButton button = new JButton("Hello");
            // магия происходит здесь
            button.addActionListener((ActionEvent e)-> { foo(e); });
    
            frame.getContentPane().add(button, BorderLayout.CENTER);
            frame.pack();
            frame.setVisible(true);
        }
    }

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

        // Можно присвоить listener-у
        ActionListener listener = (ActionEvent e)->{ foo(e); };
        // а вот так не скомпилируется ;)
        //Object o = (ActionEvent e) -> { foo(e); };
        button.addActionListener(listener);
    

    Или даже можно сделать так:

            
       button.addActionListener(Main::foo);
    

    Главное никаких отражений, используется invokedynamic.

    Естественно возникает желание посмотреть на API коллекций.

    Можно использовать в качестве Comparator-а функцию сортировщик:

      
       String arr[] = {"a","b","c"};
       Arrays.sort(arr, (x, y) -> x.compareToIgnoreCase(y));
    

    Также в Java 8 будет реализация многопоточной сортировки:

      
      String arr[] = {"a","b","c"};
      Arrays.parallelSort(arr, (x, y) -> x.compareToIgnoreCase(y));
    

    Функциональщики как раз любят такие многопоточные методы. К сожалению, на моих тестах в используемой версии JDK 8 от использования parallelSort польза была только на примитивных данных (например при сортировки массивов int-ов). На массивах с объектами никакой пользы не было, но ведь и релиз только через несколько месяцев, так что сейчас никаких серьезных тестов скорости проводить некорректно.

    Итог

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

  • Уменьшение размеров JavaScript и CSS файлов.

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

    Минификация – операция довольно рутинная и по-хорошему должна быть автоматизирована и встроена в процесс автоматической сборки.
    Тем не менее, иногда возникает необходимость сделать подобную минификацию кода в полевых условиях на сервере заказчика из командной строки. (далее…)

  • Java. Примеры копирования файлов. Эволюция и революция.

    Задачка копирование файлов в свое время была хорошим тестом для программистов.

    1. Streams.

    До появления пакета NIO (New I/O, версия Java 1.4) многие использовали обычные потоки.

        public static void copy(File source, File dest) throws IOException {
            FileInputStream is = new FileInputStream(source);
            try {
                FileOutputStream os = new FileOutputStream(dest);
                try {
                    byte[] buffer = new byte[4096];
                    int length;
                    while ((length = is.read(buffer)) > 0) {
                        os.write(buffer, 0, length);
                    }
                } finally {
                    os.close();
                }
            } finally {
                is.close();
            }
        }
    

    2. New I/O

    В 2000-ном году появился пакет java.nio. Акроним NIO означает New I/O (новый ввод/ввывод). Отчасти я согласен с мнением, что название было выбрано не очень удачным, т.к. не сложно было предположить, что пройдет время и будет нелепо называть новым пакет 12-летней давности.

    С помощью NIO копирование файлов смотрелось более изящно, решение эволюционировало следующим образом:

        public static void copy(File source, File dest) throws IOException {
            FileChannel sourceChannel = new FileInputStream(source).getChannel();
            try {
                FileChannel destChannel = new FileOutputStream(dest).getChannel();
                try {
                    destChannel.transferFrom(sourceChannel, 0, sourceChannel.size());
                } finally {
                    destChannel.close();
                }
            } finally {
                sourceChannel.close();
            }
        }
    

    Легко видеть, что здесь мы избавились от цикла, используем “новое” API и сократилось количество кода.

    3. Apache Commons IO.

    Тем не менее, многих ленивых программистов такое развитие не особо впечатлило и те кто знал, продолжил использовать Apache Commons IO.

        public static void copy(File source, File dest) throws IOException {
            FileUtils.copyFile(source, dest);
        }
    

    Единственным неудобством была необходимость в дополнительной сторонней библиотеке. Тем не менее, поскольку библиотека предоставляла программистам еще много другого удобного API для работы с I/O, по моим наблюдениям файл commons-io-*.jar стал присутствовать во многих крупных проектов того времени.

    4. Java 7.

    Революция произошла с выходом Java 7, релиз который был сделан уже Oracle, а не Sun Microsystems.
    Появился класс Files, с помощью которого копирование файлов стало не намного сложнее чем commons-io:

        public static void copy(File source, File dest) throws IOException {
            Files.copy(source.toPath(), dest.toPath());
        }
    

    При этом не нужно прописывать в мавене дополнительную зависимость.

    Понятно, что это доступно только для Java 7 и предыдущие ее версии во всю используются многими компаниями. Тем не менее, в связи с недавней новостью о том, что Oracle выпустил недавно свое последнее публичное обновление для Java 6, возможно многие все-таки будут постепенно переползать на семерку.

  • Сколько стоит талант программиста (и не только).

    gold
    Фото с wikipedia

    Давно уже ничего не писал на общие темы – о выборе профессии, жизненном пути или поиске предназначения. Последний раз подобных тем касался почти три года назад.

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

    Теперь можно приступать.

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

    Талант, в современном понимании, это определённые способности, которые раскрываются с приобретением навыка и опыта. Поиск источника такого толкования этого слова приведет нас к притче о талантах.

    В древнем мире талант был мерой веса. В той притче некий хозяин раздал своим рабам несколько  талантов золота. Одному дал пять, другом два, третьему один. Затем отлучился на некоторое время. Когда вернулся стал выяснять кто что сделал.

    Один приумножил, второй разменял, а третий закопал свой талант в землю. Того, кто закопал, хозяин отругал, других похвалил и наградил. Мораль — закапывать свой талант плохо, приумножать — хорошо.

    Недавно мне стало интересно, а сколько именно было закопано? Немного покопавшись в интернете нашел приближенные исходные данные и произвел следующий расчет.
    (далее…)

  • Java Security Update (Java 7u13)

    Вышло долгожданное обновление Java!

    Java
    Oracle выпустил релиз даже раньше запланированного срока (изначально должен был выйти 19 февраля 2013г).
    В анонсе сказано, что обновление содержит 50 исправлений безопасности:

    Due to the threat posed by a successful attack, Oracle strongly recommends that customers apply CPU fixes as soon as possible. This Critical Patch Update contains 50 new security fixes across Java SE products.

    Как обычно, обновление можно скачать с сайта java.com (JRE) или с сайта oracle.com (JDK, JRE и все остальное).

  • Липкий запуск сервисов в Android-e.

    В Android API есть такой абстрактный класс как Service. Он является наследником ContextWrapper-а, который в свою очередь является наследником Context-a. При некоторых допущениях можно относиться к сервисам как к “активити без UI” (хотя это не совсем правильно в деталях). Использовать сервис рекомендуется для задач не требующих прямого вмешательства пользователя.

    В документации особо акцентируется внимание на том, что Service не является ни процессом, ни ниткой. Если сервис должен делать какую-то “тяжелую” работу, то нужно самому выносить ее в отдельный thread, чтобы не получить ANR (Application Not Responding).

    Если делать свой thread лениво, то можно использовать готовый класс для асинхронной работы IntentService.

    Про него нужно знать следующее:

    • IntentService наследуется от Service.
    • Является абстрактным классом.
    • Нужно реализовать в нём метод onHandleIntent(Intent).
    • Обработка intent-ов идёт поочередно, но не в главном, а в своем выделенном thread-e.

    Диаграмма классов сервисов выглядит следующим образом: (далее…)