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

Блоги

 

Поиск обработчика нажатий клавиш

Основными методами нахождения обработчика нажатий являются поиск(и заморозка потоков для проверки, просто потому, что всегда у обработчика свой поток) и поиск изменяющегося значения при нажатии на клавишу.
  Так или иначе, оба этих способа приведут нас к тому, что игра использует DirectInput или XInput, выбор метода зависит от специфики игры и личного опыта.
Из инструментов для этого лучше всего подойдет x64dbg. Приступим к поиску с вкладки Threads и что мы видим, один из потоков был создан из dinput8.



И раз мы нашли поток, то можем обратиться к базовому адресу потока, таким образом попадаем в тело метода CEm_LL_ThreadProc.
Теперь поставим на этот метод брейкпоинт и перезапустим игру. Посмотрим, откуда происходит создание потока. После перезапуска игры и срабатывания бряка, в стеке вызовов получаем все, что необходимо для продолжения поиска:
      Пробежав быстро по стеку вызовов, находим интересную апишку MapVirtualKeyA выйдя из метода, которая переводит скан-код в код виртуальной клавиши.     Ну что ж, теперь мы знаем где работает обработчик нажатий Directinput, где он переводится, остался последний шаг - узнать, где нажатая нами клавиша используется, это как раз и будет сам обработчик нажатий. На этом этапе уже будет удобней исследовать код в IDA/GHIDRA, поэтому перейдем к ним, оставив отладчик подключенным к процессу. Немного восстановлю код для наглядности:        

partoftheworlD

partoftheworlD

 

Обход r0 защиты процесса

Описание: Расширение возможностей r3 отладчиков. Позволяет подключиться и работать с нужным процессом, который защищен из ядра.   Поддерживаемые ОС: Только 64 бит Windows 8.1 Windows 10   Инструкция: Поместить файл rqz.sys в каталог  C:\ Запустить ваш отладчик Запустить файл irp.exe (Требуются права администратора) Указать ID процесса отладчика из списка Теперь, при помощи своего отладчика, вы можете открывать защищенные из ядра процессы и работать с ними   password: ghlru     ENJOY      

JustHack

JustHack

 

HwID ban bypass

Supported OS: 64 bit only Windows 8.1 Windows 10   How to use it: Place the hwid.sys file in the directory  C:\ Run the ldr.exe file (Administrator rights required) Delete the file C:\hwid.sys   password: ghlru     ENJOY    

JustHack

JustHack

 

Unity + ML (Python)

Unity — среда для тренировки искусственного интеллекта. Ниже пример обучения ИИ для игры в гонки.     В новой версии Unity много изменений, если кому интересно на официальном сайте много информации по обновлениям

MasterGH

MasterGH

 

[Left 4 Dead 2] Опыт в подсветке мобов

Для примера возьмем 2 игры: CSGO и Left 4 Dead 2, в них используется Source Engine, и как можно подумать подсветка должна реализовываться одинаково, но не тут-то было.   Давайте взглянем на процесс инициализации предметов (включая игроков) в CSGO: Как можем здесь увидеть для каждого объекта при инициализации резервируется место в структуре подсветки и возвращается ID в этой структуре, который отличный от ID игрока.     Внутри GetGlowIndex:     Прелести наследования, т.е. есть класс, который наследуется для любых предметов и инициализирует структуру подсветки, даже для обычных занавесок или телевизора.
 
Вот только в L4D2 ничего такого нет, тут все куда более просто или оптимизировано, структура подсветки наследуется только для боссов (танк, курильщик и т.д.) и игроков, а подсветка ведется постоянно нужно лишь изменить уровень прозрачности. А вот структура определяющая подсветку для мобов (обычных зараженных) является динамической из-за чего заполняется только при определенных условиях, это создает некоторые сложности с подсветкой т.к. придется вручную выделять память под каждого моба и заполнять структуру определяющую подсветку, но просто так записав значение по определенным адресам не выйдет из-за подсчета объектов в структуре. Но мы ведь не пальцем деланные, немного пореверсив находим функцию инициализации, правда перед вызовом необходимо получить указатель на моба, это делается с помощью вызова виртуальной функции, которая принимает id и возвращает указатель на структуру. На выходе получаем это:    

partoftheworlD

partoftheworlD

 

Вызов внутреигровых функций

Так, давно что-то ничего не писал в блог
Собственно время пришло

Данная статья является примером метода о котором рассказано в данном видео   Рассмотрим вызов игровой функции на примере перовой части игры Dishonored 
В данном примере будем восполнять себе количество маны, которая в игре не может регенерироваться полностью после использования череды способностей

Для начала нам необходимо найти само значение маны, благо оно храниться 4мя байтами в памяти и тут нет ничего сложного
Теперь когда у нас есть адрес маны или же указатель на данный адрес, нам необходимо найти метод который как раз и перезаписывает значение
Делается это очень просто (F6)
Нас интересует инструкция которая перезаписывает значение 1 раз
Выходим на эту инструкцию в дизассемблере и ставим брейк
Вот мы и нашли инструкцию, далее просто выходим из него (Кнопка Execute till return)
Для того чтобы вызвать метод, необходимо узнать и проанализировать его параметры. Этим и займемся
  В метод передается 2 параметра, один из которых находится в ecx (Указатель на базовый класс)
А второй передается в регистре ecx, до инструкции которая перезапишет значение
Данный кусок:
push ecx
mov ecx,esi
Регистр edx содержит все время один и тот же не изменяющийся адрес, т.е он статичен
Распишу параметры чтобы было более нагляднее
push ecx (Значение 50 в данный момент)
mov ecx, esi (В ecx записывается значение из esi (0x0AD0A000))
Теперь если немного проанализировать, то можно понять что 50 - это значение маны, которое будет присвоено игроку после применения способности
А 0x0AD0A000 это указатель на начало структуры игрока, т.е PlayerController* player; Таким образом метод выглядит так: ManaMethod(PlayerController* player, int ManaOut);

Теперь можно приступать к написанию самого кода на c++, чтобы вызывать этот внутреигровой метод (При этом заранее найдем работающий указатель на класс игрока PlayerController)
Для вызова метода нам необходимо определить его соглашение о вызове, т.е в каком порядке туда передаются аргументы
Посмотреть все соглашения можно тут https://ru.wikipedia.org/wiki/Соглашение_о_вызове
Немного почитав можно увидеть что это соглашение __thiscall thiscall — соглашение о вызовах, используемое компиляторами для языка C++ при вызове методов классов в объектно-ориентированном программировании. Аргументы функции передаются через стек, справа налево. Очистку стека производит вызываемая функция. Соглашение thiscall отличается от cdecl соглашения только тем, что указатель на объект, для которого вызывается метод (указатель this), записывается в регистр ecx.
В самом коде объявляем этот метод для его вызова далее
  //Метод принимает PlayerController* и ManaOut //0x00AB17C0 - адрес которых хранился в edx и он статичен typedef void*(__thiscall * _ManaType)(PlayerController* Player, int Mana); _ManaType ManaFunc = (_ManaType)(0x00AB17C0); Остается только написать вызов этого метода и на этом дело будет сделано /*PlayerConroller.h */ struct PlayerController { public: char pad_0000[2656]; //0x0000 int Mana; //0x0A60 }; /*Метод который вызывается при создании потока из dll*/ void onAttach() { while (true) { if (GetAsyncKeyState(VK_END)) { PlayerController* Player = reinterpret_cast<PlayerController*>(*(DWORD*)(Base + 0x01052DE8)); //Получаем указатель на игрока PlayerController* ManaFunc(Player, 100); } Sleep(150); } } Собственно на этом моменте статья закончена
При нажатии на кнопку END внутри игры, мана восполняется до 100 единиц

roma912

roma912

Bypass EAC, BE, MRAC [Clean screenshots]

Обход функции, снятия скринов античитами.   03.01.2020    Undetected Поддерживаемые системы:  x64 only Windows 7+   Поддерживаемые режимы игры: Windowed mode FullScreen   Инструкция: Для запуска требуются права администратора Запустить файл Запустить игру Играть В зависимости от античита, скрины не будут сниматься или будут чистые   ENJOY  

JustHack

JustHack

 

[IDA/GHIDRA/radare2] Немного о сигнатурных модулях и FLIRT

Начнем с FLIRT(Fast Library Identification and Recognition Technology).
Суть технологии проста - экономия времени, вместо ручного восстановления библиотечных функций, используются сигнатурные файлы сгенерированные из статических библиотек с помощью утилит, которые идут в комплексе с IDA SDK, которые по ходу анализа переименовывают функции найденный с помощью сигнатур.
Сигнатурный файлы выглядит так:

  Например, мы знаем, что игра X использует Lua для выполнения скриптов, но сама длл луа вшита в файл, а не идет в комплексе рядом с ним, из-за чего мы не можем увидеть импортируемые функции, а значит придется потратить кучу времени, чтобы вручную по исходникам восстановить их. И тут на помощь приходит FLIRT, подключаем сигнатурный модуль в процесс анализа


и буквально через пару секунд функции начинаются помечаться как библиотечные и подписываться. Пока IDA работает, реверсер отдыхает.
  У GHIDRA есть подобный функционал, но называется Function ID. И чтобы базы для гидры не генерировать руками, есть готовый скрипт, но для начала совету прочитать статью автора, чтобы не было вопросов по использованию скрипта:
https://blog.threatrack.de/2019/09/20/ghidra-fid-generator/

partoftheworlD

partoftheworlD

 

[Raft] Генерация кодов локаций

С недавним обновлением Raft в игре изменили радар, теперь необходимо ввести код из 4-х цифр, который является частотой, чтобы радар показал координаты, найти массив с координатами и кодами слишком просто, и поэтому мы будем генерировать коды без какого-либо воздействия на память игры. Открыв dnSpy необходимо найти участок кода, отвечающий за генерацию частот.

  Восстановив код и запустив для проверки, обнаружились некоторые проблемы: 1.       Cид используется 1 раз при создании нового мира. 2.       Частота состоит из 4 цифр, из-за чего очень много сидов будет подходить под значение первой частоты, которая дается в начале игры, поэтому придется брутить и генерировать все возможные частоты для 2-4 локаций.     На генерацию сидов ушло порядка 30 минут, 90000+ возможных сидов и лишь 1 правильный набор кодов.  Занятие было бессмысленным, но это был отличный способ занять вечер.   Seed: 1276855 ------------------------------ 9839 1106 5814 8084 ------------------------------

partoftheworlD

partoftheworlD

 

Наработки по сканеру указателей основанному на отладке

Разработка этого плагина началась с того, что Dark Souls 3 начал выеживаться, а именно не работал сканер указателей, в целом этот "плагин" бесполезная, но точная(в теории) вещь для большинства игр.
Может быть кто-то более опытный в Lua захочет его доделать. Осталось сделать 3 пункта: Нормальный парсинг инструкций   Парсинг...ну что тут сказать, в Lua паттерны это какой-то regex после авиакатастрофы попавший в аварию на машине скорой.      

partoftheworlD

partoftheworlD

 

CE Lua 7.0 Поиск по формуле

В таблице поиска есть колонки ссылающиеся на название Lua перменных: "value" и "previousvalue"   А что можно делать?   Сравнивать текущее и предыдущие значения вместе или по отдельности, в том числе на разных вкладках CE   Примеры: value == 65 value == 0x65 (или поставить галку hex) value ~= 65 (или поставить галку not) Можно и такое  сравнение сделать после поиска неизвестного используя математические функции: math.abs(value - previousvalue) < 10 Можно делать различные комбинации:  and (логическое И). or (логическое ИЛИ). not (логическое НЕ). + (сложение); - (вычитание); * (умножение); / (деление); ^ (возведение в степень); % (остаток от деления). == (равно); ~= (не равно); < (меньше); > (больше); <= (меньше или равно); >= (больше или равно).   Что на счет xor? Можно написать функцию xor   Пишем глобальную функцию сначала: function BitXOR(a,b)--Bitwise xor local p,c=1,0 while a>0 and b>0 do local ra,rb=a%2,b%2 if ra~=rb then c=c+p end a,b,p=(a-ra)/2,(b-rb)/2,p*2 end if a<b then a=b end while a>0 do local ra=a%2 if ra>0 then c=c+p end a,p=(a-ra)/2,p*2 end return c end А потом применяем даже отдельные функции  как в этом примере "value > 0 and BitXOR(value, 100) "   А может быть я хочу только 100 первых результатов     CheckCount100() and value > 0 and BitXOR(value, 50)     Также хочу добавить те адреса, которые предположительно являются указателями getAddressSafe('['..value..']')~=nil   Или наоборот не являются указателями getAddressSafe('['..value..']')==nil   Еще можно попробовать добавить 50 красных и  50 синих указателей в таблицу CE, но это уже задание кому интересно.   Можно в теории сравнивать адреса со значениями известных адресов и даже с известными указателями, с метками. Но поиск может затянуться, если адресов очень много.   Можно попробовать указать условие, что значение адреса должно находиться в X структуре или в её вероятных указателях. Или попробовать оставить только одинаковые значения адресов, т.е. повторяющихся более 1 раза. Или попробовать искать только те адреса,  к которым применимы сразу несколько условий чтобы не кликать их постоянно: (изменилось) И (больше 0) И (меньше 10000) (не изменилось) И (больше 0) И (меньше 10000)

MasterGH

MasterGH

 

CppHackGame CTF Challenge Решение задания

Рассмотрим решение задания из   Начало стандартное, ищем строку с сообщением об ошибке, переходим по перекрестным ссылкам и находим инструкцию проверки. Теперь зайдем в эту функцию и начнем разбирать.
  .text:00002173 cmp username_lenth, 10h .text:0000217A mov esi, offset username .text:0000217F movsd xmm0, ds:dbl_7D48 ; // xmm0 = 2.0 .text:00002187 cmovnb esi, username .text:0000218E movd xmm1, ebx .text:00002192 cvtdq2pd xmm1, xmm1 .text:00002196 call _libm_sse2_pow_precise .text:0000219B movsx eax, byte ptr [esi+ebx] ; // v0 = esi[ebx] получаем символ из массива .text:0000219F imul eax, ebx ; // v1 = v0 * idx .text:000021A2 inc ebx ; // idx++ .text:000021A3 cvttsd2si ecx, xmm0 .text:000021A7 cdq .text:000021A8 idiv ecx ; // v2 = v1 % pow(2, idx) .text:000021AA add edi, edx ; // checksum += v2 Немного восстановили функцию, это что-то похожее на генерацию чексуммы из строки. Приведем это в человеческий вид   username = 'UserName' checksum = 0 for idx in range(len(username)): v1 = ord(username[idx]) * idx v2 = v1 % pow(2, idx) checksum += v2 print(checksum) Спускаемся немного ниже и видим инструкции, которые проверяют чексуммы, введенного пароля и имени пользователя. while (tmp_checksum != input_checksum): checksum -= char_value_ char_value_ = *tmp_checksum++; Зная  алгоритм проверки, можем написать кейген. Для этого необходимо генерировать новые символы и отнимать от чек суммы значение, пока чексумма не станет равна 0   def generate_password(checksum): g_check = 0 password = '' tmp = 0 while True: char = random.randint(0x21, 0x2E) # генерируем символы, можно выбрать любые tmp = checksum - g_check # вычисление временной чексуммы if tmp // 0x56 == 0: # небольшая проверка последнего символа, чтобы избежать символов, которые будут нечитаемыми # после некоторых тестов 0x56 было более подходящим значением с минимальным выводом мусора. password += chr(tmp) break g_check += char # вычисление сгенерированной чек суммы password += chr(char) # добавление символа в строку с сгенерированным паролем print(password)      

partoftheworlD

partoftheworlD

 

[Dark Souls 3] Автоматический поиск указателей не находит выхода в указанную структуру

После двух дней тестов Cheat Engine 6.8.3/7, оказалось что автоматический поиск указателей не работает в некоторых играх, каких-то определенных причин для этого нет. В пути к скану указателей, а так же в название скана нет кириллицы, пробелов и всякого такого. В других играх или в том же CE туториале сканер указателей работает как и должен, в общем тут точно не обошлось без магии. Выглядит все это так:     Пока у меня только 2 варианта решения этой проблемы: 1. Использовать ручной поиск указателей. 2. Писать свой сканер.

partoftheworlD

partoftheworlD

 

CppHackGame CTF Challenge

CppHackGame - это очень маленькая текстовая RPG игра.
Тем не менее, эта игра предназначена для челленджа по взлому. Сможешь ли, ты убить гоблина и забрать сундук?     Правила: Разрешено использовать любые инструменты, разрешено патчить только код относящийся к игроку/гоблину.   Скачать cpphackgame.exe

partoftheworlD

partoftheworlD

 

DS3

PhyreEngine

// velocity. used for backstab detection
// speed the opponent is approaching at. Player doesnt need to know their own. Idealy would like just if sprinting or not, actual velocity isnt important
// -0.04 slow walk
// -0.13 walk
// -0.16 - 18 sprint


wireshark filter

((udp.port >= 27000 && udp.port <= 27030) or udp.port == 3478 or udp.port == 4379 or udp.port == 4380 or (udp.port >= 50000 && udp.port <= 50003)) or ((tcp.port >= 27014 && tcp.port >= 27050) or tcp.port == 50050)


NS_SPRJ::WorldChrManImp - (48 8B 1D ? ? ? ? 48 8B F9 48 85 DB 74 40) 48 8B 0D ? ? ? ? 48 85 C9 74 09 48 8B 89 ? ? ? ? EB 03 49 8B CD 4D 85 FF 74 60 48 85 C9 74 0E 48 8B 01 FF 90 ? ? ? ? 4C 8B E0 EB 03
NS_SPRJ::WorldChrManImp + 80] = NS_SPRJ::PlayerIns
NS_SPRJ::PlayerIns + 1f90] = ptr_table
ptr_table + 18] = NS_SPRJ::SprjChrDataModule

NS_SPRJ::WorldChrManImp + 1d0/1ce8] = EntityList

EntityMax = 100

EntityList + idx * 0x38 - список игроков/npc       ds3.rcnet

partoftheworlD

partoftheworlD

 

Форуму 10 лет

11 декабря 2019 года форуму Gamehacklab исполнится 10 лет. Это дата первого пользователя форума.   Поздравляю всех:  активных пользователей, высший состав форума, админов и модеров, старожил, помогаторов, тех кто был на форуме очень давно и перестал заходить.   Отдельно @Xipho, @srg91, @partoftheworlD, @Garik66, @LIRW, @SER[G]ANT, @gmz. Извините, если кого-то персонально  пропустил.   Можно пожелать всем бесконечного энтузиазма на тему поиска сигнатур и значений, сравнении структур и стеков, дизассемблирования и ассемблирования. Энтузиазма в программировании на  C++ и WinAPI. Энтузизма в том, чтобы найти универсальное решение при создании любого чита для любой игры.   P.S. Для энтузиазма. Подкину идею. Мне нравится видеть, как наборы инструкций можно условно разделить на: математические, логические, ветвления, чтения и записи и другие. При этом математические на мой взгляд наиболее выделяются, т.к. они заставляют в игре всему меняться. Хотя логические инструкции тоже могут что-то менять, но по ощущениям не так явно менять, как математические инструкции. По математическим в основном меняются перемещение камеры и перемещение персонажа и изменяются игровые значения.  Можно отдизассемблировать весь игровой код и найти все математические операции и точно некоторые из них связаны с будущими читами. Это всякие добавить, отнять, умножить, разделить. Не думаю, что их будет за тысячу даже, которые именно нужны для читов, а не те которые что-то рассчитывают не понятно что) Если руки дойдут, то возьму IDA да пройдусь по какой-нибудь игре с поиском всех математических инструкций, поставлю на них счетчик срабатывания да прогуляюсь в игре персонажем... Если будет время...

MasterGH

MasterGH

 

[Skyrim] Как генерировать уникальную отмычку, чтобы стражники Вайтрана не прострелили колено

Статья должна была выйти вместе с видео, но мне лень было её писать.   В прошлом видео я показывал, как это работает и настало время для того, чтобы рассказать, как это делалось. Да можно было писать свое значение на прямую в значение разблокировки замка, но это скучно и вообще какой-то дет.сад.     На деле все оказалось довольно странно, вместо обычной генерации рандомного значения, в скайриме используется двухуровневая т.е. сначала одна функция генерирует одно значение, результат которой влияет на результат второй функции.   Рассмотрим код, хотя в нем особо комментировать нечего, я разделил его на блоки, чтобы проще воспринимались стадии работы алгоритма.     Дальше можно в ручную уже посчитать текущее значение для открытия замка:
  v5 = 9.615000725f * 0.5; // 4.8075003625 v6 = v5 - 90.f; // -85.1924996375 v7 = 90.f - v5; // 85.1924996375 link = &qword_7FF6A0CEED70 LockPick->unlock_Value = ( v7 - v6 ) * (GenerateRandomValue(link, 0xFFFFFFFF) * 2.328306437E-10) + v6; LockPick->unlock_Value = 170.38 * (0xAE504DB6 * 2.328306437E-10) + -85.1924996375 LockPick->unlock_Value = 170.38 * (2924498432.00 * 2.328306437E-10) + -85.1924996375 LockPick->unlock_Value = 170.38 * (0.68) + -85.1924996375 LockPick->unlock_Value = 30.82 И проверяем в отладчике:     Генератор отмычек готов.      

partoftheworlD

partoftheworlD

 

Книги

Немного обновил и упорядочил книги из личного хранилища, может кому пригодятся. (Возможно это считается за пиратством, так что ссылку буду выдавать в личных сообщениях, на форуме или в дискорде) В архив входят:  

partoftheworlD

partoftheworlD

 

История о том, как я для юнити писал автосплитер

Начнем с того, что теперь я ненавижу юнити, так, что моей ненавистью можно питать пару крупных городов еще и останется.
Проблема возникла с тем, что у игры есть свои значения проверяющие загружена игра или нет, но получить к ним доступ через указатель оказалось невозможным. Перепробовав около 50 разных способов и потратив 1.5 недели, решил залезть в управление памятью юнити, возможно что-то интересно окажется там. Доков и исходников нет и поэтому - Реверсим, реврсим, вертим крутим и делаемся всякие непотребства с памятью и...   Бам, оказалось( возможно это чистое совпадение), но UnityPlayer использует статические адреса для "работы" с CFG.
CFG/CF это Control Flow Guard -  механизм защиты Windows, нацеленный на усложнения процесса эксплуатации бинарных уязвимостей в пользовательских и ядреных приложения.   Сам механизма проводит валидацию неявных вызовов, предотвращающая перехват потока исполнения, например переписывая таблицы виртуальных функций. Именно этим мы и воспользуемся, но для начала найдем максимум информации о CFG и его внутреннем устройстве.   Итак, когда игра не загружена то, адреса должны указывать на статические данные внутри UnityPlayer.dll, но после загрузки игры выделяться, например в куче. Зная это, можем приступать к поиску. В итоге нашелся статический адрес указывающий на старшую часть указателя, который работает с CFG, когда игра находится в меню или загружается, то старшая часть равна 7FFX( X - значение от 0 до F), но когда игра загружена, то значение меняется на адрес кучи. Что-то типа: Static - 7FFFDEADBEEF Heap   - 01EFDEADBEEF   Значит берем старшую часть, уменьшаем её для более простого сравнения используя:
  value & 0xFFF В итоге, получаем значение которое можем засунуть для проверки в автосплитере, если игра не загружена, то значение равно от 4080 до 4095, но если игра загружена, то значение меньше 600, но на всякий случай, я указал:   value < 4080   И на этом все, на все про все у меня ушло где-то 2.5-3 недели, просто чтобы узнать состояние игры. В общем, было интересно и стало более понятно как юнити работает с памятью. 
Желаю всем подобных заданий, это ведь интересней, чем патрончики накручивать.

partoftheworlD

partoftheworlD

 

Большое исследование - моментальное редактирование

Уже множество раз разными участниками форума поднимался вопрос о внедрении своих функций (например на С++) в чужой процесс и что бы они там правильно исполнялись.
То есть что бы можно было написать свой код, потом включить компиляцию, и функция добавляется в чужой процесс без всяких проблем, на неё можно послать поток игры, сделать прыжок и так далее, изменять когда хочешь на высоком уровне, а не на ассемблере.
Мною было проведено исследование в котором было поставлена цель сделать это, и по итогам это вполне возможно! и это просто замечательно! ☺️
Нужно просто написать внедряющую часть, которая учитывает различные моменты и восстанавливает зависимости функции в новом процессе.

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

Добавлены видео:
Скучное видео в котором делается AOBscan для автоматического поиска
Часть 5, в которой код приводится в порядок и создаются универсальные функции, а потом демонстрируется автоматическое размещение на разные адреса, это лучшее видно в плане принципа работы и кода?   Демонстрация того что можно сделать, но уже на 64 бит ☺️  

imaginary

imaginary

×

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

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