Перейти к содержанию

KRYPTOPUNK

Разработчики
  • Постов

    76
  • Зарегистрирован

  • Посещение

  • Победитель дней

    9

Сообщения, опубликованные KRYPTOPUNK

  1. Так в программе разные типы памяти.
    RAW DATA( или глобальные данные), стек и куча. 
    вот твой указатель и есть глобальные данные, которые хранятся непосредственно в exe-шнике. 

  2. 1 час назад, botmaker сказал:

    Направление камеры может быть задано, как вектор, а может быть, как два угла.

    Чаще всего "направление" это "поворот", так что это почти всегда вектор или кватернионы. Потому что камера почти всегда логический объект, который так же имеет позицию и поворот. 

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

     

    1 час назад, botmaker сказал:

    может быть есть желание поучаствовать в написании модуля за вознаграждение?

    К сожалению, у меня нет времени, так как основная работа есть, да и C# я не люблю и не пишу на нём. 

  3. 6 минут назад, botmaker сказал:

    Да, это так. Они смотрят в одном направлении относительно плоскости XY

    Так это же в Cheat Engine можно найти, а отличия искать уже в каком нибудь ReClass или в инспекторе структур Cheat Engine. Отличие по Z -- наша камера. 

  4. 18 часов назад, botmaker сказал:

    Предположительно, камера направлена на персонажа игры

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

  5. 3 минуты назад, botmaker сказал:

    Да, я пишу на C#, но без Юнити, это чит, читающий память игры.

    Очень странный выбор, но судить не буду :D

    А найти направление (или поворот) камеры и направить камеру на "таргет" не вариант? 

  6. В 22.05.2022 в 5:47 PM, botmaker сказал:

    погрешность примерно +/- 1 пиксель,

    У тебя не может быть погрешность примерно +- 1 пиксель, потому что каст к инту может отбросить только с одной стороны .9, так что глупо так считать.

    Если ты пишешь на C#, я так понимаю, у тебя игра на Юнити.  В этом случае есть штука, которая называется Camera.worldToCameraMatrix, которая отдаст тебе матрицу трансформирования мировых координат в координаты камеры. 
    Однако, там есть сноска 

    Цитата

    Note that camera space matches OpenGL convention: camera's forward is the negative Z axis. This is different from Unity's convention, where forward is the positive Z axis.

    о которой нужно помнить. 

  7. Ты бы хоть сказал, left-handed или right-handed координатная система, и что ты кодом делаешь. 
    Что за 250.0f?

    Ты спрашиваешь, как найти координаты цели, но говоришь, что они известны.
    В общем, подробнее объясни, что происходит и что ты делаешь 

  8. 50 минут назад, Antonshka сказал:

    Это Anchor система?

    Нет, это над-движковая система для проектирования UI в 3д мире.

    50 минут назад, Antonshka сказал:

    У тебя есть видео работы этой системы?

    Нет, и вряд ли будет, ибо NDA

  9. У меня есть система UI, которая считает свои размеры относительно родительского "окна" в процентах на каждом "эвенте" OnResize
    Правда там система скорее как в вебе, где отношения размеров "родитель"->"потомок" указывается в процентном соотношении. 
    Так вот, на каждый ресайз вызывается OnResize для каждого элемента системы и он пересчитывает свои размеры на основе размеров родителя и своих отступов от границ родительского окна. 
    Удобно, достаточно, и не сильно сложно по big-O. 

    И да, там уже можно не строить дерево руками, а у каждого элемента просто хранить вектор с детьми проходясь range-based циклом

  10. 41 минуту назад, Antonshka сказал:

    отображается "(parameter)float x".

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

    41 минуту назад, Antonshka сказал:

    И опять же, что если мне нужно получить значение из "х", которое поле класса, придется писать через this->x, или Point::x.

    Зачем тебе в конструкторе класса может понадобиться получить значение из поля объекта? Не нужно так делать. 
     

     Можешь глянуть тот же гугловский гаедлайн на тему кодстайла.

    И вообще, без разницы, как ты параметры назовёшь, ты их можешь вообще никак не называть) А для избегания путаницы, можно делать так

    Спойлер
    void func(int A)
    {
     a = A; 
    }


    Учитывая твой пример с огромным количеством аргументов, проще структуру сделать, 
     

    Спойлер
    struct ButtonData
    {
      bool isVisible;
      DWORD exStyle;
      DWORD style;
      LPCWSTR name;
      int xPos;
      int yPos;
      int width;
      int height;
      Window* parent;
    }
    
    Button(ButtonData&& data)
    {
    	isVisible = data.isVisible;
      	exStyle = data.exStyle;
      	style = data.style;
      	name = data.name;
      	xPos = data.xPos;
      	yPos = data.yPos;
      	width = data.width;
      	height = data.height;
       	parent = data.parent
    }

    и передавать её через move-семантику. и никаких проблем с неймингом. 

  11. 3 часа назад, Antonshka сказал:

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

    Компиляторы достаточно умные сейчас.
    Даже если я напишу так:
     

    Спойлер
    struct Point
    {
    	float x, y, z, w;
    	Point(float x, float y, float z, float w)
    	{
    		x = x; y = y; z = z; w = w;
    	}
    };

     

    никаких проблем не будет. 

  12. 2 часа назад, skip123 сказал:

    Игорь доброго времени суток =)) прочел ваше замечание и немного запутался у меня нет функции срытый текст =(( мож я не там смотрю просто - помогите с етим завертыванием в скрытый текст ну если не затруднит скиньте пример как ето делать а то я в етом вопросе не силен =((

    Код оберни в "код". 
    Кнопка специальная есть, выглядит как <>

  13. Предисловие:

    Я хотел сделать эту статью сообщением под статьей пользователя roma912, но потом решил вынести её отдельно, так как здесь мы будем описывать новую версию движка и более конкретно описывать те или иные действия. Использовать мы будем тот-же SDK GEN, что и в его статье, но здесь мы рассмотрим ситуацию, когда игр, нам нужных для разбора нет в пресетах (как чаще всего и бывает), и будем искать всеми нужные GNames и GObjects, ручками.

    Для этого нам понадобятся инструменты. Из обязательных: GHIDRA/IDA, Cheat Engine, ReClass.
    Опционально: исходный код Unreal Engine конкретной версии, как его получить, смотрите здесь --
    https://github.com/EpicGames/Signup, также сам движок подходящий по версии с вашей игрой.

    Что есть звери эти?

    Для того, чтобы понять, как искать эти самые GNames и GObjects, нужно понять, что они из себя представляют.

    Важно понимать, что в Unreal Engine 4 используется в основном язык C++, так что этот движок образный «ООП на стероидах». В нем используется сложная система наследования, практически каждый тип данных заменен на свой, с добавлением приставки “U”, такие как «UField», «UObject», «UArray», именно поэтому в нем будет разобраться не просто, даже имея исходный код на руках.

    Начнем с GObjects.
    Что это такое? Судя по названию, можно предположить, что это глобальная переменная, в которой хранятся все объекты.  Это отчасти верно, однако даже поиск по исходному коду движка этого названия нам ничего не даст.
    Нужно подумать, объектом какого класса может быть эта переменная.

    Достаточно длительный разбор исходного кода движка приводит нас к следующей картине: в файле UObjectArray.h есть класс с названием «class COREUOBJECT_API FUObjectArray».
    Звучит интересно. Смотрим в его приватные поля и видим

    Спойлер
    
    typedef FFixedUObjectArray TUObjectArray;
    
    	// note these variables are left with the Obj prefix so they can be related to the historical GObj versions
    
    	/** First index into objects array taken into account for GC.							*/
    	int32 ObjFirstGCIndex;
    	/** Index pointing to last object created in range disregarded for GC.					*/
    	int32 ObjLastNonGCIndex;
    	/** Maximum number of objects in the disregard for GC Pool */
    	int32 MaxObjectsNotConsideredByGC;
    
    	/** If true this is the intial load and we should load objects int the disregarded for GC range.	*/
    	bool OpenForDisregardForGC;
    	/** Array of all live objects.											*/
    	TUObjectArray ObjObjects;
    	/** Synchronization object for all live objects.											*/
    	FCriticalSection ObjObjectsCritical;
    	/** Available object indices.											*/
    	TLockFreePointerListUnordered<int32, PLATFORM_CACHE_LINE_SIZE> ObjAvailableList;
    #if UE_GC_TRACK_OBJ_AVAILABLE
    	/** Available object index count.										*/
    	FThreadSafeCounter ObjAvailableCount;
    #endif
    	/**
    	 * Array of things to notify when a UObjectBase is created
    	 */
    	TArray<FUObjectCreateListener* > UObjectCreateListeners;
    	/**
    	 * Array of things to notify when a UObjectBase is destroyed
    	 */
    	TArray<FUObjectDeleteListener* > UObjectDeleteListeners;
    #if THREADSAFE_UOBJECTS
    	FCriticalSection UObjectDeleteListenersCritical;
    #endif
    
    	/** Current master serial number **/
    	FThreadSafeCounter	MasterSerialNumber;

     

    Интересующий нас объект называется ObjObjects. Теперь посмотрим его класс.
    Объявление его класса находится в том же файле выше. Не забываем про typedef и ищем класс «FFixedUObjectArray». В его приватных полях находим 
    Спойлер
    
    /** Static master table to chunks of pointers **/
            FUObjectItem* Objects;
            /** Number of elements we currently have **/
            int32 MaxElements;
            /** Current number of UObject slots */
            int32 NumElements;

     

    Это то, что нужно! В итоге логика выглядит так:
    FUObjectArray.ObjObjects->Objects

    В файле UObjectHash.cpp находим использование этого класса в играх

    Спойлер

     

    
    // Global UObject array instance
    FUObjectArray GUObjectArray;

     

    Как видно, это статическая переменная, содержащая в себе класс «массив», который в свою очередь хранит в себе указатель на массив всех объектов в игре. Такие дела.
    Примечание: на многих источниках этот объект указывают как TArray<Object*>, что не совсем корректно для более поздних движков.

    GNames.

    Не буду долго распинаться, поэтому скажу в общих чертах:
    GNames так же статичная переменная, используемая для хранения имен всех объектов в игре.
    Имеет тип TNameEntryArray, что является typedef’ом от TStaticIndirectArrayThreadSafeRead<FNameEntry, 4 * 1024 * 1024, 16384>

    Больший интерес представляет сам класс FNameEntry, который и является классом хранения имени. Выглядит он так:

    Спойлер
    
    class FNameEntry {
    
                   public:
    
                           std::int32_t m_index = 0;
    
                           unsigned char _pad_0xC_0[0xC] = {};
    
     
    
                           union {
    
                                   char m_ansi[1024];
    
                                   wchar_t m_wide[1024];
    
                           };

     

    Именно m_ansi нас и интересует.

    Розыскные мероприятия.

    Мы знаем, что переменные GUObjectArray и Names, статические, значит, для целей их розыска и поимки, мы можем использовать GHIRA/IDA. Дизассемблируем программу, ждем конца автоанализа.

    Сейчас я расскажу, как действовать, если вы решили пойти по хитрому пути и скачать движок Unreal Engine версии, совпадающей с исследуемой игрой.
     Заходим в
    EGS-> Unreal Engine -> Библиотека.
    Потому нажимаем на + возле Версии
    Unreal Engine

    2138613011_.png.3c9f29120d9542f8aba1f45efeb39426.png

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

    ВАЖНЫЙ МОМЕНТ!

    2067763915_.png.33c0aa6b426693513949d5ea2162d213.png

    Заходите в настройки установки и отмечаете галочкой эту строку

    362724655_.png.1efe423b7173fc1b8b7b69611ae4a0d4.png

    Для того, чтобы потом можно было генерировать .pdb.

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

    Ждем загрузки…

    2086839758_.thumb.png.4263aed304967b675ab573ca09b55461.png
    Далее кликаем File -> Package Project -> Build Configuration -> Shipping

     407138670_1.thumb.png.29210e95d46fb8fed9f12e9f42550c95.png

    Далее File -> Package Project -> Packaging Settings

    И отмечаем галочку «Include Debug Files»

    330545848_2.thumb.png.9bd4f407877df5ffcba22b8ec3db1be9.png

    1626954791_.thumb.png.61fee43a5c7289f625e5a9a099665578.png

    И, время компилировать!
    File -> Package Project -> Windows -> и выбираем разрядность игры, которую исследуем.

    Зачем это нужно?

    Открываем GHIDRA/IDA, пихаем туда нашу скомпилированную игру и грузим .pdb
    ВНИМАНИЕ: В ГИДРЕ ОТКАЗЫВАЕМСЯ ОТ АВТОАНАЛИЗА И ЗАГРУЖАЕМ .PDB ДО НЕГО!

    Теперь у нас есть листинг, где мы можем найти все подписанные функции движка. Выглядит это так:

    759658866_1.thumb.png.f316669a179e6e12172fd724932dded3.png

    Вот, собственно, и всё. Теперь можно просто по паттерну искать функции в нашей исследуемой игре.

    Для поиска GNames нам понадобиться метод FName::GetNames()
    Для GObjects GUObjectArray()

    1513869002_2.thumb.png.0edc90afa6adf3fb9388ed3fd66f1fc4.png

    Подсказка: при поиске по паттерну, может быть очень много похожих функций. Ориентируйтесь на количество аргументов и тип возвращаемого значения. Также можно использовать(«абьюзить») строки, но об этом в другой раз.

    Зачем ReClass?

    К сожалению, мы с вами будем работать через SDK генератор, который обновлялся последний раз пять лет назад. А вот Epic Games обновляют движок игры примерно раз в полгода. Поэтому, нам нужно будет ручками реверсить классы в движке, и заносить результаты в отдельный файл. Так же никто не отменял, что некоторые компании изменяют движок под свои нужны и могут использовать кастомные типы данных. Поэтому, всё же, нужно будет знать объявление классов для того, чтобы SDK генератор работал правильно.
    Брать эти объявления можно из исходников движка, а через ReClass подтверждать, что они указаны верно для конкретно вашей игры.

    Послесловие.

    Все сказанное выше актуально только для Unreal Engine версии ниже 4.22, так как в версиях выше для GNames используется класс FNameEntryPool, который работает совершенно по-другому.

    Спасибо за чтение и удачи в исследованиях!

    • Плюс 1
  14. 6 часов назад, LuBu сказал:

    сть ли где - нибудь подробный туториал по этому?

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

  15. 7 часов назад, LuBu сказал:

    Вообщем, стоит ли писать свой Injector для внедрения DLL в процесс игры или воспользоваться каким - нибудь готовым типо Guided Hacking DLL Injector.

    У этого инжектора исходный код открыт на гитхабе, изучай, смотри, что может быть тебе подозрительным. у VAC насколько я помню только сигнатурный поиск, то есть, паблик софт лучше не использовать и не копипастить исходники. Другие античиты, особенно платные, типа BE, EAC, и прочих по любому запалят, они ж тоже не дураки, ситуацию, так скажем, мониторят.
    Единственный метод -- пиши свой и ни с кем не делись. Такие дела. 

  16. 13 минут назад, Antonshka сказал:

    Я полагал что загрузка DLL - это простое копирование её байт в память игры. Затем навешивание каким-то образом потоков на нее. Также связывание определенных инструкций игры с определенными функциями в DLL. А в функциях DLL идет каким-то образом получение значений из регистров, с дальнейшим их использованием и применением обратно.

    Вот мое представление об схеме работы internal чита, при DLL. Моя картина в голове.

    Говорю же, мне нужно общее представление об ее работе, на пальцах так сказать. Я же понятия не имею, как там все устроено.

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

  17. 2 часа назад, Antonshka сказал:

     

    Я посмотрел твои трейнеры, - у тебя DLL отдельно от файла EXE.

    Не пробовал помещать DLL в ресурсы EXE, а затем просто оттуда считывать её байты в память игры?

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

    Для меня самое сложное в изучении программирования, - это найти нормальный источник. Где нет "воды", где не обсасывают одну мысль десять минут, где автор действительно объясняет, а не показывает лишь то что он это знает и умеет. Таких пруд пруди в инете. И ты сидишь и тратишь время, как идиот. Книги, ясное дело, самый лучший вариант.

    Я и намеревался почитать про DLL.  Но сперва хотел понять общую картину.

    Самый простой способ, как назвали выше, это CreateRemoteThread с LoadLibrary и путем к твоей длл. Я не понимаю смысла в ресурсах экзешника держать DLL. Зачем?
    Информация про DLL и хуки есть здесь. Если того, что здесь не хватает, гугли сайты. Правда один из хороших закрыли paywall'ом не понятно зачем, но не суть. Информация в основном на английском, но интуитивно понятно.
    Если конкретно по книгам то Джеффри Рихтер "Windows для профессионалов", начиная с главы 19.

    Если хочешь античиты обходить, то меньше чем мануал маппинг делать не выйдет. А это самому загружать, производить релокацию, импорты фиксить, вызывать TLS'ы и прочее. Ибо более менее нормальные античиты в основном ставят хуки на довольно глубокие штуки, такие как LdrLoadDll, LdrpLoadDll, даже на RtlInitUnicodeString некоторые ставят. При том, что мы имеем дело не с ring0 античитом.

  18. 3 часа назад, Antonshka сказал:

     

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

     

    Посмотри мои работы, которые я здесь выкладывал. Не бог весть что, не идеал, но как концепт понять можно. 

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.