Хостинг серверов Minecraft playvds.com
  1. Вы находитесь в русском сообществе Bukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на русский язык плагины наших собратьев из других стран.
    Скрыть объявление

reinterpret_cast под яву

Тема в разделе "Разработка плагинов для новичков", создана пользователем RawCode, 13 июл 2014.

  1. Автор темы
    RawCode

    RawCode Ньюби Пользователь

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

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

    Я не буду повторяться многократно, ссылка на класс ниже, по тексту будет только сигнатура метода или указатель на строку:
    https://github.com/RawCode/UBT/blob/master/src/rc/ubt/impl/UnsafeImpl.java

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

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

    Так вот, всё это весело но не надо, от того и потому что класс объекта хранится в специальном поле -1 и может быть прочитан или изменён через unsafe.

    Если менять классы который объявлены final - придётся или прописывать им magicaccessor или цепочку наследования вручную иначе JVM заметить несоответствие сигнатур в констант пуле и приклеит бороду вам и вашему коду. Но речь не об этом.

    Структура объекта:
    -8 недоступный для чтения заголовок в два слова
    0 сведения о блокировках
    4 верхний регистр указателя класса или указатель класса (64\32)
    8 нижный регистр указателя класса или данные класса (64\32)

    верхний регистр указателя класса всегда равен нулю если применяется compressed OOP

    на основании вышеуказанных достаточно простых и понятных свойств объекта написан следующий код лишенный документации по умолчанию:
    Код:
    Object[] tester = {new Object(),new Object()}; //создаём массив под 2 объекта
    if (unsafe.getInt(tester, 0x4) != 0) //если верхний регистр не равен нулю, то у нас однозначно не применяются сжатые заголовки - narrow references
    nref = false;
    if (unsafe.getInt(tester, 0x8) == 2) //если нижный регистр равен двум - это размер массива то перед нами JVM32 соответственно у нас узкая подложка и размер указателей равен 4l
    wpad = false; 
    
    Расширяем целевой класс, в нашем случае:
    public class DedicatedPlayerListImpl extends DedicatedPlayerList

    если вы планируете перехватывать класс объявленный final расширять придётся в рантайме, остальное так-же (не предмет данной статьи)

    если вы планируете добавить новые поля - плохая новость, менять размер существующих объектов (как и существующих массивов) НЕЛЬЗЯ, вообще нельзя, даже через свои собственные нативки вам потребуется делать новый объект и регенерировать ссылки на него.
    если вы добавите новые поля, ждите проблем.
    данные хранить в дополнительном классе где всё статик и паблик, так можно.

    получаем указатель на целевой класс:
    Object o = MinecraftServer.getServer().getPlayerList();
    не важно, что и как, только убедитесь чтобы метод не возращал копию или коллекцию иначе будете долго страдать от непонятных проблем.

    static методы перехватываются также но целью модицификации памяти будет прототип класса, там 100500 всяких секретных полей и чтобы сделать грамотно придётся читать сорцы JVM, это кстати всё равно потребуется для final методов, но не сейчас.

    как уже сказано выше, работа с классами КУДА сложнее чем работа с инстансами объектов, начиная от другого порядка полей в зависимости от версии JVM и заканчивая иным значением полей, который выглядят внешне точно также.

    поэтому доставать искомый указатель на класс мы будем из инстанса нужного нам объекта, например так:
    x = UnsafeImpl.unsafe.allocateInstance(DedicatedPlayerListImpl.class);
    targetref = wpad ? UnsafeImpl.unsafe.getInt(x, 8l) : UnsafeImpl.unsafe.getInt(x, 4l)

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


    Вот собственно и всё, мы тупо берём и переписываем указатель на класс в инстансе тем самым меняя класс объекта и все методы, оставляя ссылки нетронутыми.
     
  2. Хостинг MineCraft
    <
  3. ql_Nik_lp

    ql_Nik_lp Старожил Девелопер Пользователь

    Баллы:
    173
    Skype:
    q-nik-p
    Имя в Minecraft:
    ql_Nik_lp
    Конечно все выглядит очень сложно, интересно и наверное очень полезно, но зачем это?
     
  4. Автор темы
    RawCode

    RawCode Ньюби Пользователь

    Баллы:
    1
    если вы не понимаете, оно не для вас.
     
  5. Shevchik

    Shevchik Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    _Shevchik_
    Подробный гайд как прострелить себе ногу на жабе.
    Лучше уж через javaassist работать.
     
  6. Автор темы
    RawCode

    RawCode Ньюби Пользователь

    Баллы:
    1
    а вы сорцы этих утилит почитайте...
    а хотя кому я это объясняю.
     
  7. Shevchik

    Shevchik Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    _Shevchik_
    Я читал исходники многих asm библиотек, и в большистве случаев они используют встроенные в JVM отладчики, либо делают свой собственный класслоадер, либо ещё что.
    Unsafe используется крааааайне редко.

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

Поделиться этой страницей