Однажды мы пришли на проект, который ранее сопровождала команда N. Заказчик не имел доступа к кастомизированному коду, ничего не знал о технических деталях устройства своей системы и не имел документации. Вся экспертиза была сконцентрирована на этой команде N, которая в череде недавних событий покинула российский рынок, фактически бросив заказчика наедине с проблемами. Придя к нам, заказчик знал только о бизнес-логике системы и имел инфраструктурную карту. Нашей задачей было нарастить экспертизу по проекту и начать быстро и эффективно исправлять инциденты.Первым делом мы получили доступ к серверам и провели ресёрч директорий, запущенных процессов и логов. Сюрпризом оказалось то, что от логов были только access.log, то есть разработчик намеренно скрывал всю логику работы ПО, не выводя ничего даже в логи. В процессах мы тоже не нашли хоть чего-то полезного, а структура директорий и содержимое дали понять, что мы имеем дело с микросервисами на Java.
В процессе анализа мы записали все пункты, которые вызвали вопросы, составили карту исследования. Что делают микросервисы и как они взаимодействуют в кластере? С какими данными и с какими источниками работают? Какой логикой руководствуются? Всё это предстояло узнать. Мы решили использовать метод “снежного кома”: всякий раз, когда появляется новая деталь, записываются 3-4 следующих вопроса или шага к проверкам. Оценивая такой подход спустя время, стало очевидно, что именно он не дал нам зайти в тупик.
Итак, получив пока не понятно как связанные JAR микросервисов, мы решили, что было бы неплохо посмотреть на их исходный код и понять хотя бы верхнеуровнево, на каких технологиях они работают.
Мы начали с байт-кода. Он описывает стек и работу с ним, содержится в class-файлах, которые, в свою очередь, находятся в обнаруженных нами JAR. Это набор инструкций, который, подобно ассемблеру, содержит указания на то, как что-то положить в кусок памяти, как забрать и как переместить. Мы открыли
документацию о структуре байт-кода и на самых простых примерах изучили его работу. Чтобы объяснить, как именно мы это делали, приведём простой пример Java-программы, которую можно собрать в единственный class-файл, запустить и получить вывод строчки “Hello World!” в консоль.
Исходный код: