Русский
Русский
English
Статистика
Реклама

Eclipse

Укрощение Горыныча 2, или Символьное исполнение в Ghidra

01.10.2020 08:18:25 | Автор: admin


С удовольствием и даже гордостью публикуем эту статью. Во-первых, потому что автор участница нашей программы Summ3r of h4ck, Nalen98. А во-вторых, потому что это исследовательская работа с продолжением, что вдвойне интереснее. Ссылка на первую часть.


Добрый день!


Прошлогодняя стажировка в Digital Security не оставила меня равнодушной к компании и новым исследованиям, так что в этом году я взялась поработать над проектом так же охотно. Темой летней стажировки Summer of Hack 2020 для меня стала Символьное исполнение в Ghidra. Нужно было изучить существующие движки символьного исполнения, выбрать один из них и реализовать его в интерфейсе Ghidra. Казалось бы, зачем, ведь в основном движки представляют собой самостоятельные решения? Этот вопрос будет возникать до тех пор, пока не попробовать то, что автоматизирует действия и сделает их наглядными. Это и стало целью разработки.


Статья в какой-то степени является еще и продолжением статьи моего наставника, Андрея Акимова, о решении Kaos Toy Project с Triton. Только сейчас нам не придется писать ни строчки кода решить крякми можно будет практически двумя кликами.


Итак, начнем по порядку.


Пара слов о символьном исполнении


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


Если говорить об общей классификации движков символьного исполнения, то среди них выделяют статические символьные движки (SSE, emulated) и динамические символьные движки (DSE, concolic). Достоинством статических движков является поддержка эмуляции как всей программы, так и конкретной ее части. И поскольку не происходит непосредственного запуска на CPU, а лишь эмулируются инструкции, открываются возможности для анализа разнообразных архитектур. Однако, страдает масштабируемость, и могут возникнуть определенные трудности со входами в сторонние библиотеки.


DSE, в отличие от SSE, исполняет каждую ветку отдельно, и по своей сути он быстрее, поскольку символизирует не все подряд, а только входные данные пользователя (источник книга "Practical Binary Analysis" by Dennis Andriesse".


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


Выбор символьного движка


Первым наставники посоветовали изучить Triton. С ним хорошо получилось изучить теорию символьного исполнения. Движок может работать как в режиме SSE, так и в режиме DSE. Однако у него ограниченное количество поддерживаемых архитектур (x86, x86-64, ARM32, Arch64), и мне сложно было представить, каким образом можно реализовать его API в контексте интерфейса Ghidr-ы. Так что Triton пришлось отложить и ресерчить дальше.


Следующим подопытным стал KLEE. Он, несомненно, является самым мощным движком символьного исполнения, с его помощью можно работать с по-настоящему серьезными проектами и исследованиями. В контексте реализации архитектуры плагина здесь основной проблемой выступила генерация llvm-биткода. А все потому, что для полноценной работы KLEE необходимо подавать скомпилированные clang-ом в llvm-биткод (.bc) файлы исходников. Были идеи по передачи бинаря llvm-лифтеру (их ассортимент можно увидеть тут), однако ни один из этих вариантов не сработал, и KLEE выдавал ошибки. Говоря о наработках в области трансляции Pcode в llvm, есть лишь один Ghidra-to-LLVM. В рамках ресерча пришлось протестировать и его. Как оказалось, он не работает с 32-битными бинарями, и если и удавалось получить результат в виде .ll-файла, то после обработки llvm-ассемблером llvm-as и получения llvm-биткода KLEE все равно не хотел работать с подобным самопалом и выдавал ошибки. Так что KLEE также пришлось оставить, несмотря на его широкие возможности по символьному исполнению.


Наставники также посоветовали изучить движок S2E. Он расширяет возможности QEMU по трансляции бинарных инструкций в TCG и также транслирует сам TCG в LLVM. Это была заманчивая идея, однако для работы с ним требуется Python3. И, как известно, Ghidra использует старый Jython 2.x, что, казалось бы, полностью перекрывает поток возможностей по интеграции современных инструментов в Ghidr-у. Движок, который был выбран в итоге, тоже работает только с Python3, но в случае с ним возможно было придумать обходной вариант через системный интерпретатор. А поскольку S2E работает как отдельный инструмент, его использование из Ghidr-ы не представляется возможным.


На момент написания статьи вышел еще один движок символьного исполнения SymCC. Точнее, правильно его назвать оберткой компилятора для C-кода. Представьте: у вас на руках исходники, вы компилируете исполняемый файл, как в случае с KLEE и clang-ом, только здесь с SymCC. Компилятор интегрирует необходимый для символьного исполнения код и библиотеки в новоиспеченный исполняемый файл. После запуска получаем директорию с кейсами, сгенерированными во время выполнения. Все классно, но привязать такое к Ghidr-е невозможно, так как у нас на руках не исходники проекта, а результат дизассемблирования и декомпиляции.


Финальным выбором стал angr. Он популярен, у него доступный и подробно задокументированный API, и интегрировать данный движок было действительно реально. Конечно, как уже отмечалось, без Python3 никуда, в Ghidra его поддержка отсутствует, но в случае с angr-ом мне показалось возможным написать универсальный скрипт, который смог бы запускаться на системном интерпретаторе, решать заданный бинарь и передавать результат обратно в Ghidr-у. Вот такой был план.


Сердито. Костыльно. Канонично.


Реализовать получилось так: графический интерфейс плагина получает необходимую информацию от пользователя, создается буферный JSON-файл, куда записывается необходимая конфигурация для работы универсального angr-скрипта, плагин запускает скрипт на системном интерпретаторе, скрипт передает найденное решение обратно в графический интерфейс.


Если изучить принцип работы декомпилятора в Ghidra и его взаимодействие с GUI, то можно понять, что основе лежит схожий костыльный алгоритм. Дело в том, что Ghidra работает с декомпилятором через stdin и stdout потоки, используя классы DecompileProcess и DecompInterface. Так что архитектуру плагина можно считать вполне каноничной в контексте Ghidra.


На написание логики скрипта не ушло много времени. Он, по сути, собирает в себя базовые возможности angr-a по символьному исполнению для решения ctf-тасков. На графический интерфейс пришлось потратить львиную долю времени, и его разработку не могу назвать захватывающей. Как и Ghidra, графический интерфейс плагина написан на Java, в роли IDE по традиции выступил Eclipse.


Для GUI плагина было создано 4 файла:


  • AngryGhidraPlugin.java в файле указывается основная информация о плагине и происходит его инициализация.
  • AngryGhidraProvider.java самый объемный файл, который инициализирует компоненты графического интерфейса основного окна плагина; здесь прописана логика создания файла конфигурации для скрипта, происходят запуск скрипта и чтение результатов, их передача в интерфейс.
  • AngryGhidraPopupMenu.java здесь прописаны дополнительные параметры контекстного меню окна дизассемблера Ghidr-ы. Благодаря этому файлу можно задавать необходимые адреса прямиком из окна дизассемблера, а также внедрять пропатченные байты памяти в контекст работы angr-а.
  • HookCreation.java инициализирует окно создания хуков.

Итак, пара слов о функциональных возможностях плагина.


  • Auto load libs определяет работу загрузчика необходимых библиотек для исполняемого файла. Пользователь определяет, нужна ему эта опция или нет.
  • Find Address адрес, куда вы хотите попасть во время выполнения программы (например, на адрес вывода строки License key is validated!).
  • Blank State адрес, с которого вы начинаете эмуляцию. Если не добавлять дополнительных параметров в дальнейшем, то по умолчанию все регистры и память обнулены. Удобно назначать на адресе точки входа или на адресе вызова функции проверки, если вы знаете ее расположение в коде и хотите ускорить процесс работы angr-a.
  • Avoid addresses адрес/адреса, которые в ходе символьного исполнения нужно избежать. При их нахождении angr автоматически отметет соответствующие им ветки с меткой avoid и не пройдет дальше. Чем больше таких адресов указать, тем чаще angr будет отбрасывать ненужные ветки кода и найдет решение быстрее (если это решение существует).
  • Arguments аргументы, поставляемые на вход программе (argv[1], argv[2] и т.д.). Иногда значение, которое необходимо сделать символьным, передается через аргумент(-ы) к программе.
  • Hooks хуки позволяют перехватить указанные инструкции и внести определенные значения в регистры. Например, когда необходимо записать в регистры символьные вектора, это будет продемонстрировано в дальнейшем решении Kaos Toy Project.
  • Store symbolic vector если необходимо создать символьный вектор в адресном пространстве определенной длины, а потом, например, поместить его в регистр. Если плагин найдет решение, он выведет содержимое созданного символьного вектора.
    • Write to memory иногда бывает необходимо, чтобы определенные участки памяти были заполнены конкретными значениями. Например, в случае Kaos Toy Project, это значение Installation ID, которое инициализируется по адресу 0x4093a8. Это поле окна плагина можно заполнить патчингом из Ghidr-ы, для этого необходимо пропатчить нужные вам байты, выделить их и открыть контекстное меню дизассемблера AngryGhidraPlugin -> Apply patched bytes.
  • Registers те значения регистров, которые вы самостоятельно инициализируете при запуске эмуляции с заданного адреса. Здесь также можно создать и сохранить символьные вектора нужной длины.

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


Продолжаем хорошую традицию


Наконец, решим Kaos Toy Project плагином AngryGhidra.



Первое, что сделаем запустим toyproject.exe в любом отладчике и отследим, по какому адресу записываются байты Installation ID.



Взглянем на байты по адресу 0x4093a8, это и есть наш Installation ID.



Нужно учитывать тот факт, что отладчик в Ghidra отсутствует, а angr осуществляет эмуляцию бинаря (за это отвечают компоненты PyVEX и SimEngine). Это значит, что значение Installation ID инициализировано не будет, нам нужно сделать это самостоятельно. Наш ход патчинг байтов в Ghidra.


Найдем адрес 0x4093a8 и запатчим нулевые значения байтами Installation ID, выделим их и выберем в контекстном меню AngryGhidraPlugin -> ApplyPatchedBytes:



Теперь решим вопрос с адресами куда хотим попасть, чего следует избегать и с чего вообще начнем.


Строка Congratulations! Now write a keygen and tutorial! однозначно для нас искомая, так что адресом для поиска станет адрес помещения в стек этой строки для вызова окна с сообщением. Выберем адрес 0x40123b, для этого можно вписать его в поле Find Address или, открыв контекстное меню, выбрать AngryGhidraPlugin -> Set -> Find Address. Теперь адрес будет перекрашен в зеленый цвет.


Строка That is just wrong. Try harder! говорит о неверном введенном ключе, так что отметим адрес 0x401250 в качестве Avoid Address. Теперь он будет красным в окне дизассемблера.


Чтобы сократить время поиска решения будет удобно выбрать начальное состояние (Blank State) по адресу, где вызывается функция проверки введенного ключа. Это функция 0x4010ec. Выделим адрес вызова этой функции в качестве Blank State Address, и он перекрасится в голубой цвет.


С назначением адресов мы закончили:



Остался последний момент. Заглянем в функцию проверки ключа по адресу 0x4010ec и изучим, каким образом нам стоит передать две части ключа в плагин.



Как можно увидеть, две части ключа передаются в функцию проверки в качестве аргументов. Поскольку наше начальное состояние не предусматривает наличия аргументов, мы должны перехватить момент записи этих аргументов в регистры EDX и EBX и внести символьные значения самостоятельно. Но что они из себя представляют? Вернемся в основную функцию программы и изучим этот момент.


Можно заметить, что первоначально введенные две части ключа обрабатываются функцией по адресу 0x40109d:



Таким образом, каждая часть ключа имеет длину 4 байта, причем второй аргумент для функции проверки будет являться результатом xor-а первой и второй части ключа.


Откроем окно AngryGhidraPlugin и создадим хук по адресу 0x4010ff, чтобы заполнить значения регистров EDX и EBX символьными векторами длиной по 4 байта.



Теперь все готово к запуску, жмем Run и получаем результат!



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



И проверяем:



Ключ подошел! И ни строчки кода! Плагин AngryGhidra сделал все за нас.


Большое спасибо компании Digital Security за интересную стажировку, которая прошла для меня в удаленном формате, наставникам Андрею (@e13fter) и Саше (@dura_lex), отдельная благодарность за поддержку Виктору Склярову и Борису Рютину!


Плагин на Github: AngryGhidra.

Подробнее..

Используем Xtend для прикладной кодогенерации сеанс чёрной магии с разоблачением

25.06.2020 10:15:49 | Автор: admin

Привет Хабр! Меня зовут Когунь Андрей. В КРОК я руковожу группой разработчиков Java (у нас большая распределённая по всей стране команда). Ещё я провожу встречи московского сообщества Java разработчиков JUG.MSK. Делаю это исключительно в корыстных целях: фотографируюсь там со всеми докладчиками, и однажды открою галерею с самыми интересными людьми в мире Java-разработки. Также помогаю делать конференции для разработчиков: JPoint, Joker и DevOops в качестве члена программного комитета. Ну и для души, так сказать, преподаю Java-технологии студентам.


В КРОК мы с коллегами в основном занимаемся заказной разработкой. Одно из наших направлений так называемые учётные системы. Их надо делать по возможности быстро. Они типовые, различия обычно наблюдаются только в доменной модели. Поэтому мы постоянно боремся за то, чтобы писать меньше бойлерплейт-кода, будь то тривиальные геттеры-сеттеры, конструкторы и т.п. или CRUD-репозитории и контроллеры. Мы для этого активно пользуем кодогенерацию.


Про неё сейчас и расскажу: покажу как взять кодогенерацию под контроль, чтобы она стала реально полезным инструментом разработчика. Попутно расскажу про технологию Xtend и покажу практические приёмы как с ней можно работать. Покажу как создавать собственные активные аннотации, писать и отлаживать код процессора аннотаций.



О чём статья и чего в статье не будет


За много лет работы с Java мы перепробовали много чего интересного:


  • поддержка генерации в IDE,
  • генерация байт-кода при помощи Lombok,
  • процессоры аннотаций, порождающие новый код,
  • фреймворки, позволяющие по описанию модели получить готовое (почти) приложение,
  • и много чего ещё, в том числе новые и не очень JVM-языки, которые позволяют писать более лаконичный код и реализовывать DSL для решения прикладных задач.

В какой-то момент, проанализировав сильные и слабые стороны всех этих подходов, их ограничения и практическую применимость, мы пришли к тому, что в нашем собственном фреймворке для быстрой разработки (jXFW) будем использовать Xtend. Использовать для кодогенерации исходного Java-кода по доменной модели и для аккумулирования того опыта, который мы накопили в работе с различными технологиями. Сейчас расскажу, как в jXFW это всё работает и покажу, как вы можете сделать то же самое для своих нужд. Причём первую версию вы сможете изготовить буквально за пару дней и дальше начать применять подход know-how как код.


Рассказывать буду на примере упрощённого демо-проекта, который был реализован в рамках доклада на JPoint.


Ремарка: чего в статье не будет:


  1. Я не хочу, чтобы мы в итоге делали выводы про то, что технология А лучше технологи Б. Или что там Eclipse лучше IDEA или наоборот. Поэтому я не буду напрямую сравнивать какие-то языки, технологии. Всё что упоминаю, это лишь для того, чтобы какую-то аналогию объяснить на понятных примерах.
  2. Я не буду делать введение в Spring и Spring Boot. Исхожу из того, что вы имеете хотя бы какой-то опыт работы с этими технологиями. Мне кажется, сейчас сложно найти джависта, который не работал с ними. Но если вы вдруг слышите о Spring и Spring Boot впервые, вам срочно надо посмотреть доклады и тренинги Евгения Борисова и Кирилла Толкачева, там мои коллеги рассказали об этих технологиях очень подробно.
  3. Не буду очень сильно погружаться в Xtend. Но поскольку, как показывает мой опыт выступления на Java-конференциях, эта технология мало кем используется, сделаю небольшой ликбез. Чтобы вы уже дальше могли для себя решить, нужен вам Xtend или нет.

Короткий ликбез по Xtend


Xtend это статически типизированный язык программирования, приемник Xpand, построенный с использованием Xtext и компилирующийся в исходный код Java. Технология Xtext нужна для того, чтобы реализовывать всевозможные DSL. По сути, Xtend это такой своеобразный DSL.


Xtend совсем не новый язык программирования. Его создали ещё в 2011, примерно тогда же, когда появлялось большинство JVM-языков. Интересно, что у Xtend был слоган: Java 10 сегодня! Да, сегодня Java 10 у нас уже есть, слоган морально устарел. Но, похоже, люди что-то знали про Java, когда создавали Xtend, и некоторые фичи, заложенные в Xtend, они вот как раз прямо в Java 10 и появились. В частности, вывод типа локальной переменной (var). Но есть в Xtend и такие фичи, которых у Java пока ещё нет:


  • активные аннотации,
  • шаблонные выражения,
  • Switch Expressions.

Как работает кодогенератор в jXFW


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


Запускаю Eclipse.



Как видите, здесь практически ничего нет. Только application.java (конфигурация для Spring Boot) и собственно исходник на Xtend, в нём реализована доменная модель.



Как видите, Xtend-исходник очень похож на Java. Здесь нет ничего особенного. Просто класс с полями и несколько аннотаций. А что в итоге? jXFW генерирует два приложения (см. рисунок ниже): одно выполняется на сервере (тот самый Spring Boot) и даёт нам апишечку, а другое на клиенте.



Если мы что-нибудь введём в клиентской части (например, как зовут спикера) и сохраним...



то получим соответствующую запись и на клиенте, и на сервере.



То есть всё по-честному.


Мы просто описали одну сущность доменной модели, и всё автоматически заработало.


Что за магия здесь под капотом? И как в ней замешан Xtend? Рассказываю. У нас есть класс, на нём проставлены аннотации, вернее активные аннотации. Вся магия скрывается в них. Аннотации в Xtend очень похожи на аннотации в Java. Просто в Xtend для них есть отдельное ключевое слово:annotation.



Активной аннотация становятся, если её, в свою очередь, пометить другой аннотацией: @Active, а в ней указать класс процессора, который активируется, когда эта аннотация поставлена над каким-то элементом.



Дальше всё как обычно.


Xtend из коробки имеет некоторое количество таких аннотаций.



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


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


Как активные аннотации помогают писать меньше кода


Открываем проект jp-boot-xtend-demo. Я его получил при помощи Spring Initializr.



Дополнительных зависимостей здесь практически нет (см. файл pom.xml). Есть только spring-boot-starter-data-jpa и spring-boot-starter-data-rest. Плюс, подключен модуль jp-boot-xtend-demo-compile, в котором реализована наша активная аннотация. Если вам доводилось работать с процессорами аннотаций, вы наверно в курсе, что сам процессор определяется в отдельном модуле. Xtend в этом смысле не исключение.


И уже здесь, в jp-boot-xtend-demo-compile (см. файл pom.xml), мы подключаем все Xtend-зависимости, которые нам нужны: org.eclipse.xtend.lib, org.eclipse.xtend.lib.macro. Плюс, подключаем плагин xtend-maven-plugin. На случай если захотим тестировать наш Xtend-код, нам понадобится ещё несколько зависимостей: org.eclipse.xtend.core, org.eclipse.xtext.testing, org.eclipse.xtext.xbase.testing.


Кроме того, в Eclipse, я соответственно подключил плагин, который называется Xtend IDE. Актуальная инструкция как установить плагин тут. Ещё один вариант: сразу взять дистрибутив, в котором этот плагин предустановлен Eclipse for Java and DSL Developers.


Давайте смотреть как тут всё работает. Как и в случае с jXFW здесь есть приложение (см. файл DemoApplication.java), а также Java-класс, который будет нашей Entity, на базе которой мы будем всё строить (см. файл Country.xtend).



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



Например, в нашем DemoApplication есть кусок кода, который пытается вызывать метод setName. Но пока он красненький.



Я добавляю в Xtend-исходник активную аннотацию @Accessors, и у меня в сгенерированном Java-коде автоматически появляются геттеры и сеттеры, в том числе setName.



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



Тут я ещё вписал в Xtend-файл аннотации @ToString и @EqualsHashCode, и в итоге получил Java-исходник прямо такой, как и хотел.


Небольшой лайфхак, который избавит вас от необходимости после каждой правки Xtend-исходника отыскивать в target сгенерированный Java-файл. В Eclipse есть специальная оснастка: Generated Code. Что она делает? Встаньте на любую строчку в Xtend-исходнике, и увидите в окне Generated Code Java-код, который для неё сгенерирован. А оттуда при необходимости уже можете пойти непосредственно в Java-исходник. Вот такая удобная штука.


Самый маленький кодогенератор на основе аннотаций


В принципе, всё хорошо работает. Но как только мы начинаем работать с кодогенерацией, тут же возникает вопрос: А можно такой же, но только с перламутровыми пуговицами? Так Что бы я ещё хотел? Я бы хотел наверно, чтобы у меня сеттеры мои вызывались в цепочке т.е. не просто устанавливалось значение, но ещё, чтобы и сам объект возвращался из этого сеттера, и я мог на нём следующий позвать.


Из коробки в Xtend такой аннотации нет. Поэтому нам придётся её делать ручками. И какие тут есть варианты?


В принципе, мы знаем, что существует аннотация @Accessors мы посмотрим на её исходный код, увидим, что там есть Accessors Processor, специально написанный. И вот мы уже смотрим на Xtend-код и пытаемся понять, а в каком месте мы могли бы здесь что-то подкрутить, чтобы у нас работало так, как надо. Но это не очень продуктивный путь. Мы по нему не пойдём.


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


Соответственно, вот эта наша аннотация (это я уже зашёл в проект jp-boot-xtend-demo-compile; см. файл EntityProcessor.xtend) @Active она нам говорит про те самые четыре фазы, к которым мы можем привязываться. На каждой фазе работает свой собственный Participant-вариант, и мы можем реализовать тот, который нам нужен.


В принципе, есть базовый специальный класс AbstractClassProcessor, в котором мы оверрайдим метод doTransform. В него нам будут приходить соответственно описания наших классов, помеченных этой аннотацией. И дальше мы, соответственно, что-то делаем.


Ну и вот весь код, собственно говоря, который нам нужно написать, чтобы наши сеттеры стали правильными такими, как мы хотим.



Мне кажется, это самый маленький по объёму код для генерации при помощи аннотаций который я видел в жизни.


Что здесь делает Xtend? У него есть вот эти самые шаблонные выражения. Мы ставим три одинарные кавычки, и дальше пишем то, что хотим получить на выходе. И при этом форматируем так, как нам удобно.



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


Код написан на Xtend. Мне кажется читать его, с одной стороны легко, потому что его мало. С другой стороны, он может мне быть понятен сходу. Например, почему мы позвали метод modifySetter, который я определил чуть ниже, и передали в него всего один аргумент?


Дело в том, что в Xtend есть такая вещь как Extension-методы. И у объекта того типа, которым является первый аргумент, можно этот Extension-метод позвать. Хорошо, а почему мы тогда его здесь не указали? Да потому что мы внутри лямбды, а в ней есть переменная it. Когда у нас есть переменная it, к лямбде можно обращаться, не указывая её. То же самое вот с it, который мы указали в качестве аргумента. Поэтому declaredFields-property у MutableClassDeclaration мы зовём напрямую, безо всяких префиксов.


Это вот всё, что в принципе придётся знать про Xtend.


А можно такой же, но только с перламутровыми пуговицами?


Давайте теперь посмотрим как это работает. Я определяю аннотацию @Entity. Затем иду вот в этот наш класс.



Заменяю текущую @Entity с javax.persistence на свою на активную аннотацию.



И вот теперь сеттер у нас такой как надо. Т.е. из Country возвращается this мы возвращаемое значение поменяли с void на тип объекта, над которым стоит аннотация: @Id Long id.


Но, допустим, я хочу, чтобы айдишник сеттился немножко по-другому (всё к той же идее хочу такое же, но с перламутровыми пуговицами). Тогда я вписываю в свой класс setID. И оно даже отчасти работает. Ведь сеттер появился в нужном месте сразу после id.



Вот только Eclipse мне здесь немножко подсвечивает и возмущается: ты мне, вообще, о чём здесь говоришь?



И хотя в том коде джавовом, который получился, ошибки нет, он скомпилируется и всё будет работать в коде есть проблема. Она заключается в том, что мы подменяем тело метода, который определили в Xtend-исходнике.


Поэтому нам надо внимательно следить за тем, чтобы таких казусов не возникало, когда пишем что-то на Xtend. Как такое отследить? Например, можно у того Transformation-контекста, который сюда приходит, прописать метод isThePrimaryGeneratedJavaElement, и соответственно передать туда сеттер. Получается прямо в таком же стиле, как мы обычно пишем на Java.



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



Теперь всё работает как надо. Ошибки компиляции больше нет, а сеттерный айдишник стал такой как я и хотел.



Насколько это сложно прикручивать новые улучшения? Не увеличивают ли они сложность кода?


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



Не знаю, для чего в жизни это может пригодиться вам, но лично мне в работе такая штука нужна. Что мы тут указываем? Мы здесь указали имя филда. И дальше опять вот эта наша квадратная скобочка открываем лямбду; здесь дальше соответственно указываем, что нас интересует. Причём, нам важно, чтобы поле было транзиентное.


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



Давайте посмотрим, насколько это нам помогло.



Да, всё хорошо! Причём dirty написано ровно в том месте, где и должно. Нет никаких выкрутасов с отступами и т.д. Код выглядит хорошо и там, и там. Несмотря на то, что получился в результате кодогенерации. Плюс, как видите, код всё ещё остался простым для понимания.


Пишем процессор на смешанном диалекте Xtend и Java


@Entity больше мучить не будем. Убираю её в комментарии. И объявляю ту же самую аннотацию, но на Java (см. файл Entity.java). Здесь, как и на Xtend, всё просто, только чуть больше букв.



Процессор тоже можно писать на Java (см. файл JavaEntityProcessor.java).



Что я тут сделал? Я добавил обработчик для ещё одной фазы: doRegisterGlobals и докинул в контекст классы, которые мне понадобятся: Service и Repository. Плюс, заоверрайдил метод doTransform тот самый doTransform, который написал чуть раньше на Xtend. Причём я тут нормально навигируюсь по коду. Могу попадать в Xtend-код



и обратно в Java-код.



Дальше (см. метод doTransform) я добавляю к нашей entity аннотацию. Обратите внимание, здесь, в отличие от Xtend все методы надо вызывать явно через context.


Затем идёт метод, который создаёт репозиторий: createRepository. Важный момент: для всего того что мы генерируем, важно указывать PrimarySource: context.setPrimarySourceElement(repositoryType, entity);. Зачем? Чтобы при кодогенерации, когда у нас появляется Java-файл, он был связан со своим Xtend-источником.


Дальше немного скучного кода: пользую типы из Spring Data, чтобы указать какой у репозитория должен быть интерфейс.



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



И смотрите, здесь видно, что лямбды в Java очень хорошо дружат с лямбдами в Xtend. Одно на другое взаимозаменяется. Т.е. функциональные интерфейсы все здесь работают. И API был задизайнен так, что сюда джавововые лямбды нормально встают.


Дальше добавляем к нашим филдам всякие разные findBy-методы. Причём смотрим на аннотацию @Column, которая стоит над филдом. Если она имеет установленный атрибут признака уникальности значения (isUnique), просто возвращаем entityType. Если нет, возвращаем List. В конце ставим аннотацию @Param, которая нужна для того чтобы работал Spring Data Rest.



Всё! Для Repository генератор готов. Теперь если откроем Xtend-исходник, на основе которого будет генерироваться Java-код, и посмотрим на Gentrated Code, то здесь у нас добавился ещё и репозиторий. Мы можем смотреть на него, вот он такой.



Дальше пишем генератор для Service. Там всё почти всё так же как и с Repository.



Вот и всё. Процессор готов. Можно запускать сгенерированное приложение.


Ещё несколько улучшений, и запускаем сгенерированное приложение


Хорошо, сервис и репозиторий есть. Но как нам узнать, что у нас с моделью нашей всё хорошо? Добавим ещё одну фазу фазу валидации. Я добавляю два валидатора.



Теперь, если разработчик, который пишет Extend-код, вдруг забудет поставить перед своим классом аннотацию @ToString, валидатор выведет на экран Warning.



Или если разработчик поставит аннотацию @ManyToOne, а под ней ещё и @Column, то это уже ошибка. А ошибиться-то очень легко. Мы же программируем очень часто на копи-пасте, особенно когда есть возможность всё в один и тот же файл писать, как в Xtend. Скопировали, вроде работает успокоились. Но можно нарваться на коварную ошибку.


Допустим, у меня в Country.xtend у филда lastName прописано nullable = false, и я хочу, чтобы у Country тоже было nullable = false. Так неправильно. Поэтому Eclipse предупреждает меня. Но при этом генерируется Java код, в котором вроде как нет проблем.



Я меняю на @JoinColumn(nullable = false), и теперь всё хорошо. Можно запускать приложение.



Давайте наберём в браузере localhost:8080



затем localhost:8080/users/search.



Все наши findBy на месте. Приложение работает!


Пишите меньше кода, делайте меньше ошибок, применяйте технологии правильно


Ну вот и всё. Теперь вы тоже можете брать кодогенерацию под контроль, эффективно использовать её в своей работе. То есть проводить время с пользой: пару дней потерять на то, чтобы создать кодогенаратор, а потом за 5 минут долететь. Будете писать меньше кода, будете делать меньше ошибок.


Вы теперь умеете создавать собственные активные аннотации, писать и отлаживать код процессора. Причём делать всё это на смешанном диалекте Java и Xtend, без необходимости переносить всю свою кодовую базу на Xtend.


Демо-проект, который мы с вами прямо в этой статье сейчас разработали, я заопенсорсил на гитхабе. Скачивайте, изучайте, пользуйте. А если информацию легче воспринимаете на слух и с видео, вот мой доклад с конференции JPoint, где рассказываю всё то же самое, что и здесь в статье.
У меня всё. Пишите меньше скучного кода, делайте меньше ошибок, применяйте технологии осознанно. Буду рад ответить на ваши вопросы. Можете писать мне на akogun@croc.ru. Кстати, помните, я в начале статьи говорил, что участвую в подготовке конференций для джавистов? JPoint 2020 из-за известных причин будет проходить онлайн, но это даже совсем неплохо, у нас много отличных спикеров, которые не смогли бы приехать и выступить очно, а сама конференция будет идти целых 5 дней! С 29 июня по 3 июля jpoint.ru. Приходите!

Подробнее..

Шпаргалка по Ansible k8s, практичный учебник по awk, а также 4 причины использовать Jamstack при веб-разработке

24.09.2020 14:19:46 | Автор: admin


Традиционно короткий дайджест полезных материалов, найденных нами в сети за последние две недели.

Начни новое:



Качай:


  • Шпаргалка по Ansible k8s
    Ansible k8s это специальный модуль для управления объектами Kubernetes из плейбуков Ansible. Как объединить Ansible и Kubernetes при автоматизации облака? Ответ: использовать модуль Ansible k8s, чтобы управлять объектами Kubernetes прямо из плейбуков. И поможет в этом наша шпаргалка, которая содержит полезные советы и сведения по ключевым командам этого модуля.
  • Шпаргалка по тестированию приложений Quarkus


  • Книжка-раскраска Контейнерные супергерои
    Децентрализованная команда опенсорсных контейнерных супергероев в лице Podman, CRI-O, Buildah, Skopeo и OpenShift спасает Землю от атаки астероидов, развертывая над планетой защитный экран.



Почитать на досуге:



Мероприятия:


  • 30 сентября, jconf.dev
    Бесплатная виртуальная Java-конференция прямо у вас на экране. Четыре технотрека с экспертами по Java и облаку, 28 углубленных сессий и два потрясающих основных доклада.
  • 13-14 октября, AnsibleFest
    Выступления, демонстрации, практические занятия и все это в онлайне. Отличная возможность виртуально пообщаться с девелоперами, админами и ЛПР-ами, которые успешно справляются с вызовами перемен с помощью опенсорсных технологий ИТ-автоматизации.

По-русски:


Мы продолжаем серию пятничных вебинаров про нативный опыт использования Red Hat OpenShift Container Platform и Kubernetes. Регистрируйтесь и приходите:

Император Оператор: Операторы в OpenShift и Kubernetes
Упс, вебинар прошел, но есть запись.

OpenShift-специфичные волшебные вещи для сборки и развертывания приложений
Вебинар кончился, но остался в истории ловите запись.

Подробнее..

Фирма 1С приглашает вас принять участие в нашей первой конференции для системных разработчиков

15.01.2021 12:16:15 | Автор: admin
Всем добрый день!

Фирма 1С приглашает вас принять участие в нашей первой конференции для системных
разработчиков, которая пройдет 23 января в онлайн-формате.

Наверное, вы сейчас думаете да 1С это ж бухгалтерия, какая системная разработка?

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

Например, знаете ли Вы, что среди технологий 1С есть высоконагруженный кластер, с
продвинутой балансировкой нагрузки и обеспечением отказоустойчивости?

Или зачем нам вдруг понадобилось использовать NoSQL DB при разработке собственной IDE? (Да-да, у нас есть собственная IDE, да не одна, а целых три!)

Чем же мы на самом деле занимаемся
Если же говорить, чем же мы на самом деле занимаемся наш ключевой продукт это фреймворк для создания бизнес-приложений 1С: Предприятие. Написан он на C++, Java, и JS. Умеет работать на разных платформах (Windows, Linux, MacOS, Android, iOS), в вебе, поддерживает разные СУБД и многое другое. Да и не просто работать, а инкапсулировать особенности каждой СУБД и выглядеть одинаково на разных платформах (интерфейсы генерируются автоматически про это, кстати, будет отдельный доклад).

Платформа 1С: Предприятие, на самом деле, двойственна она объединяет в себе как инструменты разработки, так и среду исполнения в различных вариантах (локальном, клиент-серверном, кластерном, мобильном, облачном, распределенном). Да, кстати, про облака тоже будет без них сейчас никуда.

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

Еще немного спойлеров:

  • Расскажем, зачем нам понадобился GraalVM
  • Как заставить Xtext эффективно работать с миллионами строк программного кода?

Так что приходите, очень ждем!
Программа конференции и регистрация по ссылке.
Ну и на сладкое какая конференция без машинного обучения? Расскажем о нашем собственном механизме распознавания документов (и покажем детали)!
Подробнее..

Перевод Удаленная отладка Spring Boot приложений (IntelliJ Eclipse)

01.10.2020 00:23:40 | Автор: admin

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


System.out.println (Теперь мы находимся здесь, а переменная X is = + x); 

делает код вашего приложения довольно громоздким и его выполнение занимает много времени. К счастью в Java есть зрелая отладочная экосистема. Это позволяет нам удаленно отлаживать приложения Spring Boot и анализировать его рабочий процесс на удаленном сервере / облаке.


Чтобы показать вам, насколько на самом деле проста удаленная отладка с помощью Java, я буду использовать приложение Spring Boot 2.3, работающее на Java 11. Я разверну приложение как в виде контейнера Docker, так и с помощью старой школы java -jar way. Наконец, вы узнаете, как удаленно отлаживать интерфейс REST с помощью IntelliJ IDEA (2019.1) и Eclipse (2019-03).


Настройка проекта


Для приложения я выбрал простое приложение Spring Boot 2.3. Он включает в себя встроенную базу данных H2 и JPA для обслуживания книг, которые генерируются случайным образом при запуске.


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


@Slf4j@RestController@RequestMapping("/api/books")public class BookController {    @Autowired    private BookRepository bookRepository;    @GetMapping    public List<Book> getAllBooks() {        log.info("Retrieving all available books");        List<Book> allAvailableBooks = bookRepository.findAll();        return allAvailableBooks;    }    @GetMapping("/{id}")    public Book getBookById(@PathVariable("id") Long id) {        log.info("Retrieving book with id: {}", id);        Optional<Book> book = bookRepository.findById(id);        if (book.isEmpty()) {            throw new BookNotFoundException("Can't find book with id: " + id);        }        return book.get();    }}

Остальная часть приложения опущена, но вы можете найти весь исходный код на GitHub.


Развертывание


Чтобы иметь возможность удаленной отладки вашего Java-приложения Spring Boot, мы должны передать в JVM следующие аргументы:


-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000

Указанный порт в этом аргументе позже используется для подключения наших IDE к работающей JVM и не должен совпадать с портом приложения.


Аргумент может быть передан в JVM с помощью следующей команды:


java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000 -jar target/remote-debugging-spring-boot-application.jar

При использовании Docker мы можем добавить этот аргумент в нашу ENTRYPOINT и просто нужно отобразить дополнительный порт при запуске Docker контейнера:


FROM openjdk:11-jdk-slimVOLUME /tmpCOPY target/remote-debugging-spring-boot-application.jar app.jarENTRYPOINT ["java","-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8000","-jar","/app.jar"]

docker run -d -p 8080:8080 -p 8000:8000 --name debug-me debug-me

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


Удаленная отладка приложений Spring Boot с помощью IntelliJ IDEA
Удаленная отладка приложения Spring Boot с IntelliJ IDEA требует, чтобы вы открыли проект (исходный код) с IntelliJ. Затем мы можем перейти к редактированию конфигурации в правом верхнем углу рядом с зеленой кнопкой запуска:



Выберите создание новой конфигурации Run / Debug, нажимая кнопку +, и выберите Remote. Старые версии IntelliJ могут иметь разные названия, такие как Remote Debugging (удаленная отладка), Debugging (отладка) и т.д.:



Затем введите имя для выбранной вами конфигурации удаленной отладки и укажите порт и хост, к которому вы хотите подключиться (в нашем примере это порт 8000). Убедитесь, что вы выбрали правильный проект для Use module classpath (Использовать classpath модуля) и нажмите Apply или Ok:



Теперь отметьте в исходном коде строку, которую вы хотите отладить, и запустите конфигурацию удаленной отладки Remote debugging configuration(убедитесь, что ваше приложение уже запущено):



Теперь попробуйте получить доступ к конечной точке (http://localhost:8080/api/books в этом примере) с помощью браузера или клиента API, и вы сможете отладить указанную часть вашего приложения в вашей IDEA:



Чтобы остановить удаленную отладку приложения, просто нажмите красную кнопку остановки.


Удаленная отладка приложений Spring Boot в Eclipse


Для Eclipse вы также сначала должны импортировать проект, а затем перейти к пункту меню Run -> Debug Configurations:

Подробнее..
Категории: Java , Eclipse , Spring boot , Debug , Intellij idea

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru