Написать код — полбеды. Нужно ещё чтобы он выполнился. А прежде чем выполниться, код должен стать понятным для компьютера. Как же все эти операторы, объекты и функции становятся последовательностью единиц и нулей?
Интерпретатор
Интерпретатор — программа, которая выполняет код построчно. То есть прочитала строку — выполнила, прочитала — выполнила и так до конца. Когда интерпретатор читает команду, он сразу переводит её в понятный машине код. Интерпретирование останавливается, если в программе находится команда, написанная с ошибкой.
Интерпретируемые языки выгодно отличаются тем, что их можно выполнить на любой платформе, для которой существует соответствующий интерпретатор. Но выполнить код, без него невозможно. Кроме того такие программы выполняются о-о-о-очень медленно.
К интерпретируемым языкам относятся: Python, Lisp, Basic, PHP, Ruby, JavaScript.
Компилятор
Компилятор — программа, которая превращает код на языке высокого уровня в машинный код, проще говоря переводчик с более-менее понятного для нас языка, на язык понятный машинам. В отличие от интерпретатора, компилятор читает программу целиком, и если находятся ошибки, он говорит обо всех ошибках сразу. Но он не выполняет код, только переводит его.
Что такое Компиляция
Компилируемые языки в отличие от интерпретируемых, после компиляции могут быть выполнены и без компилятора. Но для каждой операционной системы существует своя версия компилятора. Это значит, что один и тот же код на Linux и Windows выполнить не получится. Кроме того, такие языки выполняются очень быстро, но вот компилируются. Не всегда быстро.
А разрабатывать компилятор под каждую ОС достаточно сложно. А больше всего удручает, что при каждом изменении кода, его нужно компилировать заново.
К таким языкам относятся: C/C++, Delphi, Haskell, Swift.
Байт-код
Как у компиляторов, так и у интерпретаторов есть свои недостатки. Чтобы их компенсировать, решили объединить два подхода. Основная идея заключается в том, чтобы преобразовывать код не в последовательность нулей и единиц, а в байт-код, который на него похож. Благодаря этому сохраняется скорость компилируемых языков, но не нужно компилировать код заново при каждом изменении, в точности как у интерпретируемых.
В байт-код преобразовываются языки с помощью виртуальных машин. Самый яркий пример — Java. Java-код можно запустить на всём, к чему есть Java VM.
Декомпилятор
Вот мы и добрались до самого необычного, непривычного и интересного. Декомпилятор преобразовывает машинный код программы в код какого-либо языка высокого уровня.
Как это происходит? Не обладая достаточными техническими знаниями понять это сложно, но возможно. При работе декомпилятора байты исходной программы группируются в фразы или предложения. Приведу пример таких фраз:
В общем, простейшие выражения. Но на данном этапе возникает проблема: отличить данные от инструкций очень сложно, ведь и те и другие просто нули и единицы. Дальше разными хитрыми способами декомпилятор старается понять где находятся инструкции, и что они делают, а где данные, и что делают с ними.
Что такое компиляция, линковка? Что такое run time?
В конце концов декомпилятор выводит код на нужном языке, но он может быть очень запутанным и непонятным. Может сильно отличаться от того кода, который написал программист. Но главное — работать он будет как надо.
#IT #посидеть подумать #как это работает
Источник: dzen.ru
IntelliJ Idea : Декомпиляция, Компиляция, Субституция (или как править чужие ошибки)
«Да не изобрети ты велосипед» — одно из главных правил успешной и эффективной работы. Но что делать, когда свой велосипед изобретать не хочется, а у чужого руль оказался кривой, а колёса квадратными? Данный обзор предназначен для по возможности краткого ознакомления с приёмом исправления в чужих библиотеках «на крайний случай» и о том, как это дело распространить дальше своего компьютера.
Введение
- Подготовить испытуемое приложение для примера (на примере Hibernate проекта)
- Поиск изменяемого места
- Выполнение изменения
- Разворачивание репозитория
Подготовка испытуемого
Итак, нам нужен подопытный проект. Нам идеально подойдёт Hibernate, т.к. это «стильно, модно, современно». Не буду особо вдаваться в детали, т.к. статья не про Hibernate. Будем делать всё быстро и по делу. И будем, как правильные разработчики , использовать систему сборки.
Например, нам так же подойдёт Gradle, который для данной статьи должен быть установлен (https://gradle.org/install/). Сначала, нам нужно создать проект. У Maven’а для этого есть архетипы, а у Gradle для этого есть особенный плагин: Gradle Init. Итак, открываем командную строку любым известным вам способом. Создаём каталог для проекта, переходим в него и выполняем комманду:
mkdir javarush cd javarush gradle init —type java-application
Прежде чем выполнять импорт проекта внесём некоторые изменения в файл, описывающий, каким образом нужно выполнять сборку. Этот файл называется build script’ом и имеет имя build.gradle. Находится он в том каталоге, в котором мы выполнили gradle init. Поэтому, просто открываем его (например, в windows командой start build.gradle). Находим там блок «dependencies», т.е. зависимости.
Тут описываются все сторонние jar, которые мы будем использовать. Теперь надо понять, что тут описывать. Перейдём на сайт Hibernate (http://hibernate.org/). Нас интересует Hibernate ORM. Нам нужен последний релиз. В меню слева есть подраздел «Releases». Выбираем «latest stable». Проматываем вниз и находим «Core implementation (includes JPA)».
Раньше нужно было поддержку JPA подключать отдельно, но теперь всё стало проще и достаточно только одной зависимости. Также нам понадобится при помощи Hibernate работать с базой данных. Для этого возьмём самый простой вариант – H2 Database. Выбор сделан, вот наши зависимости:
dependencies < // Базовая зависимость для Hibernate (новые версии включают и JPA) compile ‘org.hibernate:hibernate-core:5.2.17.Final’ // База данных, к которой мы будем подключаться compile ‘com.h2database:h2:1.4.197’ // Use JUnit test framework testCompile ‘junit:junit:4.12’ >
Отлично, что дальше? Надо настроить Hibernate. У Hibernate есть «Getting Started Guide», но он дурацкий и больше мешает, чем помогает. Поэтому пойдём как правильные люди сразу в «User Guide».
В оглавлении видим раздел «Bootstrap», что переводится как «Начальная загрузка». То что надо. Там написано много умных слов, но смысл в том, что на classpath должен быть каталог META-INF, а там файл persistence.xml. На classpath по стандарту попадает каталог «resources». Поэтому создаём указанный каталог: mkdir srcmainresourcesMETA-INF Создаём там файл persistence.xml и открываем его. Там же в документации есть пример «Example 268.
META-INF/persistence.xml configuration file» из которого мы возьмём содержимое и вставим в файл persistence.xml. Далее запускаем IDE и импортируем в неё наш созданный проект. Теперь нам нужно что-то сохранять в базу. Это что-то называется сущности. Сущности представляют что-то из так называемой доменной модели.
И в оглавлении, о чудо, видим «2. Domain Model». Спускаемся ниже по тексту и видим в главе «2.1. Mapping types» простой пример сущности. Забираем его к себе, чуть сократив:
Теперь у нас появился класс, представляющий сущность. Вернёмся в persistence.xml и поправим там одно место: Там где указан class укажем свой класс entity.Contact . Отлично, осталось запуститься. Возвращаемся в главу «Bootstrap».
Так как у нас нет сервера приложений, который нам предоставит особое EE окружение (т.е. окружение, которое реализует для нас определённое поведение системы), то мы работаем в SE окружении. Для него нам подойдёт только пример «Example 269. Application bootstrapped EntityManagerFactory». Например, сделаем так:
public class App < public static void main(String[] args) < EntityManagerFactory emf = Persistence.createEntityManagerFactory(«CRM»); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Contact contact = new Contact(«Vasya»); em.persist(contact); em.getTransaction().commit(); Query sqlQuery = em.createNativeQuery(«select count(*) from contact»); BigInteger count = (BigInteger) sqlQuery.getSingleResult(); emf.close(); System.out.println(«Entiries count: » + count); >>
Ура, наш испытуемый готов. Эту часть я не хотел опускать, т.к. для следующих глав желательно понимать то, как появился наш испытуемый.
Поиск изменяемого поведения
Давайте встанем на место инициализации поля count типа BigInteger и поставим там точки останова (BreakPoint). Встав на нужной строке это можно сделать при помощи Ctrl+F8 или через меню Run -> Toggle Line Breakpoint. После чего запускаем наш main метод в дебаге (Run -> Debug):
Немного неуклижий пример, но, допустим, мы хотим изменить количество query spaces при старте. Как мы видим, наш sqlQuery это NativeQueryImpl. Нажимаем Ctrl+N , пишем название класса, переходим в него. Чтоб при переход в класс нас перебрасывало на то место, где лежит этот класс включил автоскрол:
Сразу заметим, что Idea не знает сейчас, где можно найти исходный код программы (исходники, то есть). Поэтому она милостиво декомпилировала для нас из class файла содержимое:
Заметим так же, что в заголовке окна IntelliJ Idea пишется, где Gradle сохраняет для нас артефакт. Теперь, получим в Idea путь, где лежит наш артефакт:
Перейдём в этот каталог в командной строке при помощи команды cd путь к каталогу . Сразу сделаю замечание: если есть возможность собрать проект из исходников, лучше собирать из исходников. Например, исходный код Hibernate доступен на официальном сайте. Лучше забрать его для нужной версии и сделать все изменения там и собраться при помощи скриптов сборки, которые указаны в проекте.
Я же привожу в статье самый ужасный вариант – есть jar, а исходного кода нет. И замечание номер 2: Gradle может получить исходный код при помощи плагинов. Подробнее см. «How to download javadocs and sources for jar using Gradle.
Выполнение изменения
Нам нужно воссоздать структуру каталогов в соответствии с тем, в каком пакете лежит изменяемый нами класс. В данном случае: mkdir orghibernatequeryinternal , после чего создаём в этом каталоге файл NativeQueryImpl.java . Теперь открываем данный файл и копируем туда всё содержимое класса из IDE (то самое, которое для нас декомпилировала Idea). Изменяем нужные строки. Например:
- [1] — hibernate-core-5.2.17.Final.jar
- [2] — hibernate-jpa-2.1-api-1.0.0.Final.jar
Ура, теперь можно выполнить jar update. Можем руководствоваться официальными материалами: jar uf hibernate-core-5.2.17.Final.jar orghibernatequeryinternal*.class Открытая IntelliJ Idea, скорей всего, не даст изменять файлы. Поэтому до выполнения jar update, скорей всего, придётся закрыть Idea, а после обновления — открыть. После этого можно заново открываем IDE, опять выполняем dubug. Break Points не сбрасываются между перезапусками IDE.
Поэтому, выполнение программы остановится там, где и раньше. Вуаля, мы видим как работают наши изменения:
Отлично. Но тут возникает вопрос – благодаря чему? Просто благодаря тому, что когда gradle собирает проект, он анализирует блок dependencies и repositories. У грэдла есть некий build cache, который лежит в определённом месте (см. «How to set gradle cache location?». Если в кэше нет зависимости, то Gradle её скачает из репозитория.
Т.к. мы меняли jar в самом кэше, то Gradle думает, что в кэше библиотека есть и ничего не выкачивает. Но любая очистка кэша приведёт к тому, что наши изменения пропадут. Плюс, никто кроме нас не может просто взять и получить их. Сколько неудобств, не правда ли? Что же делать.
Хм, скачивает из репозитория? Значит, нам нужен наш репозиторий, с преферансом и поэтессами. Об этом следующий этап.
Разворачивание репозитория
Для разворачивания своего репозитория существуют разные бесплатные решения: одно из них Artifactory, а другое — Apache Archive. Артифактори выглядит модно, стильно, современно, но с ним у меня возникли трудности, никаких не хотел правильно размещать артефакты и генерировал ошибочные мавен метаданные. Поэтому, неожиданно для себя, у меня заработал апачевский вариант.
Он оказался не такой красивый, зато работает надёжно. На странице загрузки ищем Standalone версию, распаковываем. У них есть свой «Quick Start». После запуска надо дождаться, когда по адресу http://127.0.0.1:8080/#repositorylist . После этого выбираем «Upload Artifact»:
Нажимаем «Start Upload», а после «Save Files». После этого появится зелёное сообщение об успешности и артефакт станет доступен в разделе «Browse». Так надо сделать для jar и для pom файлов:
Это связано с тем, что в pom файле прописаны дополнительные зависимости хибернейта. А нам осталось только 1 шаг — указать репозиторий в нашем билд скрипте:
repositories < jcenter() maven < url «http://127.0.0.1:8080/repository/internal/» >>
И, соответственно, версия нашего хибернейта станет: compile ‘org.hibernate:hibernate-core:5.2.17.Final-JAVARUSH’ . Вот и всё, теперь наш проект использует исправленный нами вариант, а не изначальный.
Заключение
- Есть такой веб-сервер Undertow. До некоторого времени был баг, который при использовании прокси не давал узнать IP конечного пользователя.
- До поры до времени WildFly JPA определённым образом обрабатывал один не учтённый спефицикацией момент, из-за этого сыпались Exception. И это не настраивалось.
Источник: javarush.com
Что такое Декомпиляция?
Компиляция программы — это превращение команд, написанных на языке программирования в понятный компьютеру вид. Когда программа компилируется, на выходе мы получаем исполняемый файл, который можем запустить.
Приставка «де» означает отсутствие, отмену, устранение чего-либо. То есть, это обратный процесс.
То есть, мы берем уже готовую, рабочую программу и декомпилируем её, чтобы получить исходный код на понятном нам языке программирования
автор вопроса выбрал этот ответ лучшим
в избранное ссылка отблагодарить
Mbest4 [12.1K]
Вовсе нет!
Декомпилируя рабочую программу мы получим лишь ассемблерный код, который вовсе не является исходным, и тем более, он не обязан быть понятен для человека, привыкшего писать на Си или Дельфи. Дизассемблируя (декомпилируя) исходный код надо отдавать себе отчёт в том плане «зачем вам это надо». Придётся отбрасывать уйму «мусора» (загрузчики и стандартные библиотеки) пока доберётесь до авторской логики. И уж совсем «просто-понятно» будет разбираться с регистрами и постоянными отсылками в память «туда-сюда». Не вводите в заблуждение неискушённых читателей своего ответа. Ваш последний абзац просто ввергает меня в уныние, настолько оказывается всё просто, а я даже и не предполагал. — 5 лет назад
MaiAsim [43.2K]
Декомпилируя исполняемые файлы (и другие, вроде библиотек) мы получаем эквивалентный исходный код на языке высокого уровня (а это не нолики и единички). А современные декомпиляторы могут показывать код чуть ли не в первозданном виде. Прогресс идёт вперёд. — 5 лет назад
комментировать
Mbest 4 [12.1K]
5 лет назад
Декомпиляция — это не процесс получения исходных кодов, это получение кода на языке низкого уровня. Ниже ассемблера есть только машинный код. Все эти нолики и единички возможно представить на более удобочтимом языке, но вот только он посложнее китайского будет.
Опять же, очень разная картина будет от используемого компилятора. Ради примера, попробуйте закодить тот же баян, тот же «привет мир», или «хелло уорлд» на нескольких различных компиляторах. Декомпилируйте, и попробуйте отыскать команды вывода на экран. А если усложнить задачу, и выводить на экран не слова, но буквы, согласно некоей логике? Да задолбаетесь решать эту проблему.
Да, и ещё, не только исполнимые файлы получаются в результате компиляции. ДЛЛ-ки видели, слышали о них? Нет? Так вот, не только они компилируются, а ещё разная подобная хренотень, которая может и как сервис висеть, так и подгружаться в процессе.
Декомпилируйте себе на здоровье, в надежде получить исходный код. Желаю удачи! Я верю в вас, и в ваш уникальный декомпилятор, который даже авторские комментарии воссоздаёт!
P.S. Прошу прощения, но в этом своём ответе я обращался к предыдущему автору, MaiAsim, его (её) ответ выбран лучшим видимо по недоразумению, или просто не из чего было выбирать.
Источник: www.bolshoyvopros.ru