Гайд [Nasrultan dump] [1/2] Пересобираем java и получаем защиту как в Shitkrien, Nusrultan, Shitlestial, ReachRekode.

гайд +- нормальный, но ты лучше скажи ебучим пастерам что им от части то что написано в этом гайде не поможет, тк любой человек сможет аттачнутся к их жвмке без проблем и переписать даже обоссаный паблик дампер с UC под кастомную джаву(ну если ты конечно не расскажешь им что надо пропатчить jni методы))))))
из имеющихся на данный момент паблик думперов для вмки тебе ничего не поможет
 
дефолт метод школопастера на этом форуме. Не можешь что-то внятное ответить = лезь в профиль и лазь по последней активности.
Самое забавное что ты свой профиль закрыл чтобы никто не смог глянуть твою последнюю активность)
А

А кряк нурлсултана или акриена сделаеш? типо как их крякать
Берем сначало укропу,
потом кошачью жопу!
Двадцать пять картошек,
семнадцать мандавошек.
Ведро воды и хуй туды
Охапку дров и кряк готов!
 
когда 2 туториал?
 
вообщета Richkokode, и wexshitcode
 
Обратите внимание, пользователь заблокирован на форуме. Не рекомендуется проводить сделки.
Всем привет!

В данном туториале вы найдете немного полезной информации на счет защиты своего чита от кряка.

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

  • Данный метод защиты - полный калл.Он спасает лишь потому, что майнкрафт комьюнити - абсолютно примитивные Java школокодеры.Иметь какие либо большие знания для создания данной защиты не надо.
  • Данные защиты абсолютно идентичны.Отличаются лишь версии OpenJDK, pad`ы(= измененные оффсеты) которые добавляют создатели данных "грандиозных" защит.

Ну что ж, теперь к описанию принципа работы данной защиты.

У Java класса есть формат. (
Пожалуйста, авторизуйтесь для просмотра ссылки.
)

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

Начнем со сборки OpenJDK.

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

У них есть building.md/html, но я все же напишу краткий гайд по сборке.

Все что нам нужно :

1) Cygwin (
Пожалуйста, авторизуйтесь для просмотра ссылки.
)
2) BootJDK (да, для сборки JDK, нам понадобится другая JDK) (
Пожалуйста, авторизуйтесь для просмотра ссылки.
)

Итак, мы получили setup-x86_64.exe.
В этой же директории открываем cmd, пишем
setup-x86_64.exe -q -P autoconf -P make -P unzip -P zip
Теперь достанем исходники openjdk на диск C:/
Пожалуйста, авторизуйтесь для просмотра ссылки.
Теперь создадим папку для нашей bootjdk в данной директории и разархивируем туда то что мы качнули чуть выше.
Пожалуйста, авторизуйтесь для просмотра ссылки.
А теперь к сборке.
В cygwin пишем :
bash configure --with-boot-jdk=bootjdk
make images
Это будет очень долго в первый раз.
Пока у меня идет сборка, расскажу вам что мы будем делать.
Формат класса состоит из :
CAFEBABE (первые 4 байта, "magic value" java класс файла).
Является отсылкой.(
Пожалуйста, авторизуйтесь для просмотра ссылки.
)
Minor версия, Major версия класса. (2/2 байта)
Дальше идет парсинг содержимого класса.
1) констант пул.
2) супер класс, интерфейсы.
3) поля класса.
4) методы класса.
5) аттрибуты класса.
Из описанного выше вам может стать не совсем понятным лишь константпул.
Константпул - основа всего класса.В нем содержится самая основная информация - строки, int/float/long/double значения.
Основная задача идет на JVM_CONSTANT_Utf8
Например : спарсив JVM_CONSTANT_Utf8, он может спарсить и JVM_CONSTANT_Class :
// const u2 name_index = cfs->get_u2_fast();
// cp->klass_index_at_put(index, name_index);
Также и с остальными константами.Я надеюсь принцип понятен.
  • Байткод методов также ссылается на индексы в константпуле и сам по себе какого либо значения не несет.
  • Все что парсится в классе после константпула - лишь его индексы и размер того, что нужно спарсить.
  • Для более подробного анализа вы можете скачать DirtyJOE
Все.java сбилжена.Но как нам что либо редактировать в ней?Лезть в notepad?Давайте это исправим.
Пожалуйста, авторизуйтесь для просмотра ссылки.
пишем
make hotspot-ide-project
и ждем.
Все!
C:\openjdk\build\windows-x86_64-server-release\ide\hotspot-visualstudio
Что ж, половина задачи уже выполнена.
Нам нужен classFileParser.cpp.В нем и происходит основная магия - парсинг класса из байтов.
Заходим в метод parse_stream и видим :
C++:
Expand Collapse Copy
void ClassFileParser::parse_stream(const ClassFileStream* const stream,
                                   TRAPS) {

  assert(stream != NULL, "invariant");
  assert(_class_name != NULL, "invariant");

  // BEGIN STREAM PARSING
  stream->guarantee_more(8, CHECK);  // magic, major, minor
  // Magic value
  const u4 magic = stream->get_u4_fast();
  guarantee_property(magic == JAVA_CLASSFILE_MAGIC,
                     "Incompatible magic value %u in class file %s",
                     magic, CHECK);

  // Version numbers
  _minor_version = stream->get_u2_fast();
  _major_version = stream->get_u2_fast();

  // Check version numbers - we check this even with verifier off
  verify_class_version(_major_version, _minor_version, _class_name, CHECK);

  stream->guarantee_more(3, CHECK); // length, first cp tag
  u2 cp_size = stream->get_u2_fast();

  guarantee_property(
    cp_size >= 1, "Illegal constant pool size %u in class file %s",
    cp_size, CHECK);

  _orig_cp_size = cp_size;
  if (is_hidden()) { // Add a slot for hidden class name.
    cp_size++;
  }

  _cp = ConstantPool::allocate(_loader_data,
                               cp_size,
                               CHECK);

  ConstantPool* const cp = _cp;

  parse_constant_pool(stream, cp, _orig_cp_size, CHECK);

  assert(cp_size == (const u2)cp->length(), "invariant");

  // ACCESS FLAGS
  stream->guarantee_more(8, CHECK);  // flags, this_class, super_class, infs_len

  // Access flags
  jint flags;
  // JVM_ACC_MODULE is defined in JDK-9 and later.
  if (_major_version >= JAVA_9_VERSION) {
    flags = stream->get_u2_fast() & (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_MODULE);
  } else {
    flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
  }

  if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
    // Set abstract bit for old class files for backward compatibility
    flags |= JVM_ACC_ABSTRACT;
  }

  verify_legal_class_modifiers(flags, CHECK);

  short bad_constant = class_bad_constant_seen();
  if (bad_constant != 0) {
    // Do not throw CFE until after the access_flags are checked because if
    // ACC_MODULE is set in the access flags, then NCDFE must be thrown, not CFE.
    classfile_parse_error("Unknown constant tag %u in class file %s", bad_constant, THREAD);
    return;
  }

  _access_flags.set_flags(flags);

  // This class and superclass
  _this_class_index = stream->get_u2_fast();
  check_property(
    valid_cp_range(_this_class_index, cp_size) &&
      cp->tag_at(_this_class_index).is_unresolved_klass(),
    "Invalid this class index %u in constant pool in class file %s",
    _this_class_index, CHECK);

  Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index);
  assert(class_name_in_cp != NULL, "class_name can't be null");

  // Don't need to check whether this class name is legal or not.
  // It has been checked when constant pool is parsed.
  // However, make sure it is not an array type.
  if (_need_verify) {
    guarantee_property(class_name_in_cp->char_at(0) != JVM_SIGNATURE_ARRAY,
                       "Bad class name in class file %s",
                       CHECK);
  }

#ifdef ASSERT
  // Basic sanity checks
  if (_is_hidden) {
    assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name");
  }
#endif

  // Update the _class_name as needed depending on whether this is a named, un-named, or hidden class.

  if (_is_hidden) {
    assert(_class_name != NULL, "Unexpected null _class_name");
#ifdef ASSERT
    if (_need_verify) {
      verify_legal_class_name(_class_name, CHECK);
    }
#endif

  } else {
    // Check if name in class file matches given name
    if (_class_name != class_name_in_cp) {
      if (_class_name != vmSymbols::unknown_class_name()) {
        ResourceMark rm(THREAD);
        Exceptions::fthrow(THREAD_AND_LOCATION,
                           vmSymbols::java_lang_NoClassDefFoundError(),
                           "%s (wrong name: %s)",
                           _class_name->as_C_string(),
                           class_name_in_cp->as_C_string()
                           );
        return;
      } else {
        // The class name was not known by the caller so we set it from
        // the value in the CP.
        update_class_name(class_name_in_cp);
      }
      // else nothing to do: the expected class name matches what is in the CP
    }
  }

  // Verification prevents us from creating names with dots in them, this
  // asserts that that's the case.
  assert(is_internal_format(_class_name), "external class name format used internally");

  if (!is_internal()) {
    LogTarget(Debug, class, preorder) lt;
    if (lt.is_enabled()){
      ResourceMark rm(THREAD);
      LogStream ls(lt);
      ls.print("%s", _class_name->as_klass_external_name());
      if (stream->source() != NULL) {
        ls.print(" source: %s", stream->source());
      }
      ls.cr();
    }
  }

  // SUPERKLASS
  _super_class_index = stream->get_u2_fast();
  _super_klass = parse_super_class(cp,
                                   _super_class_index,
                                   _need_verify,
                                   CHECK);

  // Interfaces
  _itfs_len = stream->get_u2_fast();
  parse_interfaces(stream,
                   _itfs_len,
                   cp,
                   &_has_nonstatic_concrete_methods,
                   CHECK);

  assert(_local_interfaces != NULL, "invariant");

  // Fields (offsets are filled in later)
  _fac = new FieldAllocationCount();
  parse_fields(stream,
               _access_flags.is_interface(),
               _fac,
               cp,
               cp_size,
               &_java_fields_count,
               CHECK);

  assert(_fields != NULL, "invariant");

  // Methods
  parse_methods(stream,
                _access_flags.is_interface(),
                &_has_localvariable_table,
                &_has_final_method,
                &_declares_nonstatic_concrete_methods,
                CHECK);

  assert(_methods != NULL, "invariant");

  if (_declares_nonstatic_concrete_methods) {
    _has_nonstatic_concrete_methods = true;
  }

  // Additional attributes/annotations
  _parsed_annotations = new ClassAnnotationCollector();
  parse_classfile_attributes(stream, cp, _parsed_annotations, CHECK);

  assert(_inner_classes != NULL, "invariant");

  // Finalize the Annotations metadata object,
  // now that all annotation arrays have been created.
  create_combined_annotations(CHECK);

  // Make sure this is the end of class file stream
  guarantee_property(stream->at_eos(),
                     "Extra bytes at the end of class file %s",
                     CHECK);

  // all bytes in stream read and parsed
}
Но что за u4, что за stream?
u4 - тайпдеф, который означает unsigned 4 byte.Либо же просто unsigned int.
В джаве их 4 вида :
u1, u2, u4, u8 (unsigned byte(C++ char), short, int, long long)
  • Довольно смешным фактом является то, что джава сама по себе отрицает значения которые записываются меньше чем в 4 байта.
  • Минимальный размер элемента стека - 4 байта.(локали также).wide значения(long,double) вписываются в 2 элемента.
  • И в целом byte,boolean,short,char (1-2 byte) реализованы лишь инструкциями взаимодействия с массивами.(ex : SALOAD, SASTORE)(за обработку байтов и булеанок они вообще используют одну инструкцию - BASTORE/BALOAD.Ущемление прав, никак иначе)
stream - обычный класс-ридер потока байтов.имеет на борту методы аля read_u1/2/4/8, и текущий индекс чтения.
Почему все засрано какими то постоянными guarantee_more, assert, check_property?
Если вам тоже интересен этот вопрос как и мне, то ответ хранится в документации openjdk, а именно кодстайлу.
В двух словах, их главным принципом является лучше все проверить, чем поймать рандомный краш вмки.
Для нашей джавы конечно же желательно отказаться от такого дебага(бтв, assert останутся лишь в debug билде).По хорошему их всех удалить, либо покрыть xorstr.
Окей, теперь давайте рассинхронизируем наши задачи, а именно будем параллельно делать парсер, изменять значения, также изменяя их в джаве.
Создадим новый проект в IDE.
Что нам понадобится? Такой же ридер, врайтер.За основу возьмем DataInputStream, DataOutputStream.Он имеет на борту методы read(1 byte), readShort(2 bytes), readInt(4 bytes), readLong(8 bytes), аналогично с write.
В целом такой класс можно и не делать, а юзать DataInputStream, DataOutputStream, но тогда вы теряете возможность добавлять какой либо алгоритм при записи байтов.(ex : xor++ на каждый write изуродует stream при парсинге)
Я сделал для себя 2 класса :
ClassFileStream, ClassFileWriter
Java:
Expand Collapse Copy
import java.io.*;

public class ClassFileStream {
    private final DataInputStream dataInputStream;

    public ClassFileStream(byte[] bytes) {
        this.dataInputStream = new DataInputStream(new ByteArrayInputStream(bytes));
    }

    /*
    в джава все числовые типы данных signed, unsigned отсутствует.
    поэтому лучше обернуть их в int, если понадобится дебаг
     */
    public int readByte() throws IOException {
        return dataInputStream.read();
    }

    public int readShort() throws IOException {
        return dataInputStream.readShort();
    }

    public int readInt() throws IOException {
        return dataInputStream.readInt();
    }

    public long readLong() throws IOException {
        return dataInputStream.readLong();
    }

    /*
    я не собираюсь переписывать вам полностью ClassFileFormat
    этот метод позволит мне дописать остальной стрим в output
     */
    public void writeToStream(OutputStream outputStream) throws IOException {
        int r;
        while ((r = dataInputStream.read()) >= 0) {
            outputStream.write(r);
        }
    }
}
Java:
Expand Collapse Copy
import java.io.*;

public class ClassFileWriter {
    private final ByteArrayOutputStream byteArrayOutputStream;
    private final DataOutputStream dataOutputStream;

    public ClassFileWriter() {
        this.dataOutputStream = new DataOutputStream(byteArrayOutputStream = new ByteArrayOutputStream());
    }

    /*
    в джава все числовые типы данных signed, unsigned отсутствует.
    поэтому лучше обернуть их в int, если понадобится дебаг
     */
    public void writeByte(int value) throws IOException {
        dataOutputStream.write(value);
    }

    public void writeShort(int value) throws IOException {
        dataOutputStream.writeShort(value);
    }

    public void writeInt(int value) throws IOException {
        dataOutputStream.writeInt(value);
    }

    public void writeLong(long value) throws IOException {
        dataOutputStream.writeLong(value);
    }

    public ByteArrayOutputStream getByteArrayOutputStream() {
        return this.byteArrayOutputStream;
    }
}
Подготовим парсер jar прямо в main методе :
Java:
Expand Collapse Copy
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.ProtectionDomain;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class Main {
    private static final byte BYTE_CA = (byte) 0xCA;
    private static final byte BYTE_FE = (byte) 0xFE;
    private static final byte BYTE_BA = (byte) 0xBA;
    private static final byte BYTE_BE = (byte) 0xBE;

    public static void main(String[] args) {
        if (args.length < 2) {
            ProtectionDomain protectionDomain = Main.class.getProtectionDomain();
            throw new IllegalArgumentException(String.format("Пример использования java -jar %s in.jar out.jar", protectionDomain.getCodeSource().getLocation().getFile()));
        }
        try {
            String inputJar = args[0];
            String outputJar = args[1];
            ZipFile inZip = new ZipFile(inputJar);
            Enumeration<? extends ZipEntry> zipEntries = inZip.entries();
            /*
            Создадим мапу path/byte[] для удобного использования ZipFile
             */
            Map<String, byte[]> map = new HashMap<>();
            while (zipEntries.hasMoreElements()) {
                ZipEntry zipEntry = zipEntries.nextElement();
                InputStream is = inZip.getInputStream(zipEntry);
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                int r;
                while ((r = is.read()) >= 0) {
                    byteArrayOutputStream.write(r);
                }
                map.put(zipEntry.getName(), byteArrayOutputStream.toByteArray());
            }
            ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(outputJar));
            for (Map.Entry<String, byte[]> entry : map.entrySet()) {
                byte[] bytes = entry.getValue();
                if (bytes.length > 3 && bytes[0] == BYTE_CA && bytes[1] == BYTE_FE && bytes[2] == BYTE_BA && bytes[3] == BYTE_BE) {
                    ClassFileWriter classFileWriter = new ClassFileWriter();
                    ClassFile classFile = new ClassFile(new ClassFileStream(bytes), classFileWriter);
                    classFile.parseStream();
                    bytes = classFileWriter.getByteArrayOutputStream().toByteArray();
                }
                zipOutputStream.putNextEntry(new ZipEntry(entry.getKey()));
                zipOutputStream.write(bytes);
                zipOutputStream.closeEntry();
            }
            zipOutputStream.close();
            inZip.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Ну и теперь самое страшное...
Создадим класс ClassFile.
Java:
Expand Collapse Copy
import java.io.IOException;

public class ClassFile {
    private ClassFileStream classFileStream;
    private ClassFileWriter classFileWriter;

    public ClassFile(ClassFileStream classFileStream, ClassFileWriter classFileWriter) {
        this.classFileStream = classFileStream;
        this.classFileWriter = classFileWriter;
    }

    public void parseStream() throws IOException {
        /*
        вот тут расположим наш код
         */
     
        /*
        запись всего "not dirty" стрима чо бы потом все воркало
         */
        classFileStream.writeToStream(classFileWriter.getByteArrayOutputStream());
    }
}
Поехали.
Вспоминаем что я писал выше.
первые четыре байта -> CAFEBABE.Проверим?
Java:
Expand Collapse Copy
    public void parseStream() throws IOException {
        int magic = classFileStream.readInt();
        System.out.println(String.format("0x%s", Integer.toHexString(magic).toUpperCase()));
        /*
        запись всего "not dirty" стрима чо бы потом все воркало
         */
        classFileStream.writeToStream(classFileWriter.getByteArrayOutputStream());
    }
Код:
Expand Collapse Copy
0xCAFEBABE

Process finished with exit code 0
Круть!
Теперь перезапишем это, но в другом виде.Это будет маркером в парсере, что класс зашифрован.
Java:
Expand Collapse Copy
    private static final int CUSTOM_MAGIC_VALUE = 0xDEADBEEF;
    public void parseStream() throws IOException {
        int magic = classFileStream.readInt();
        classFileWriter.writeInt(CUSTOM_MAGIC_VALUE);
        /*
        запись всего "not dirty" стрима чо бы потом все воркало
         */
        classFileStream.writeToStream(classFileWriter.getByteArrayOutputStream());
    }
Откроем hexed.it и посмотрим в out.jar -> Main.class
Пожалуйста, авторизуйтесь для просмотра ссылки.

Продолжение написания "защиты" во втором туторе.Там мы перепишем parse_constant_pool_entries, соберем и протестим данное дерьмо.

Nursultan Dump :
Пожалуйста, авторизуйтесь для просмотра ссылки.
кто поможет это написать? пж
 
Назад
Сверху Снизу