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

keng

Ветераны
  • Постов

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

  • Посещение

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

    55

Весь контент keng

  1. jmp обычно используется в хуках, но тут проще дизассемблером пройтись, как мне кажется. Вряд ли там сильно большой объем кода.
  2. Привет! Ты можешь узнать, по какому адресу DLL загрузилась в память. Получаем адреса (А0-А1), с которого и по который могут идти джампы. Далее ищем во всех модулях опкод jmp (0xE9)+XXXXXXX, где "XXXXXXX" - относительный адрес от местонахождения вызовы до А0-А1. Все, что влезает в пределы А0-А1 - прыгнет в адресное пространство DLL.
  3. Можно - я не могу ни push в develop сделать, ни свою ветку отправить. Или все-таки надо через форки работать?
  4. @MasterGH, если вдруг еще актуально (?), я могу попробовать потыкать db чтобы он принял пулреквест на функцию открытия нужного окна из lua. Проблема только в том, что db очень уж неохотно принимает пулл-реквесты, а свою версию репозитория я не могу постоянно поддерживать в актуальном состоянии.
  5. При написании поста, в нижнем-правом углу (над кнопкой "Отправить") есть кнопка, там можно картинки вставлять. Опять же, мне найденное тобой кажется вполне похожим на правду, я на этом шаге банально скармливал начало матрицы (адрес первого байта) своей программе и проверял, корректно она работает или нет. Штука в том, что работать будет только с одним-единственным адресом. Когда запихиваешь свою DLL в другой процесс (по сути, заставляя его эту DLL загрузить в себя самостоятельно) они оказываются в общем виртуальном адресном пространстве, так что можно хоть напрямую к нужным адресам обращаться, хоть какой-нибудь memcpy байты из одного адреса в другой копировать. WPM нужна только чтобы из своего процесса читать память другого, то есть залезать в чужое адресное пространство.
  6. Занятно. У меня немного не так - версионирование 2-значное, master выливается в релиз, dev выливается на пред-прод, хотфиксы при этом можно делать в dev, все остальное отпочковывается от dev и имеет имена вида bug_N_name, где N - номер задачи в трекере, name - короткое описание (не больше 2-3 слов), bug - тип задачи (feature, bug, refactoring, typo и тд). Никакой код не сможет залиться в ветку более старшего уровня, если он не покрыт тестами.
  7. Хорошая привычка: видишь новое слово - иди с ним в гугл. DX и OGL - это две библиотеки для работы с 3D-графикой. В общем и целом, именно через них в играх рисуется вся графика (видеокартой). В этом самом мире 3D-графики очень удобно ориентироваться при помощи матриц (в том числе видовой, про которую ты вопросы задаешь). Задать какому-то объекту позицию, поменять ему размер, покрутить его - это все матрицами и делается (ууу, математика!). Вот. Я в своем видео показывал способ, как можно только через СЕ и чучуть программирования сделать все необходимое, чтобы порисовать в окне игры. На самом деле, задача там одна - суметь правильно спроецировать игровые координаты (самих игроков) на монитор. И все. За этим матрица видовая и нужна в данном случае. Второй вариант - это заставить игру самостоятельно рисовать нужное тебе, перехватив нужный вызов DX или OGL. По сути, там идет бесконечный цикл вроде такого: ПокаНеВышлиИзИгры: Рисуем() Рисуем() Рисуем() Один вызов функции "Рисуем" - это один кадр на экране. Их количество в секунду - это FPS. И можно сделать так, что ты вклиниваешься в этот цикл и в конце каждого вызова дорисовываешь немного своего. Например, обводишь игроков в рамочки. Вот так вот. PS: Я в видео упоминал, что нашел несколько адресов, которые были сильно похожи на части нужной матрицы (16 значений подряд, матрицы там 4х4 элемента), а дальше я просто сидел и проверял, какая сработает. Это долгий и муторный способ, но, думаю, всегда рабочий.
  8. Привет! Как минимум, видовая матрица существует в единственном экземпляре - это раз. Два - проще ее найти, перехватив вывод графики (direct3d там или opengl - на выбор), чем искать вручную. PS: Только что пересмотрел свое видео на эту тему - скажи-ка, что именно ты из него не понял? Вроде бы, алгоритм поиска там довольно банальный получается.
  9. @Xipho, то, что уведомления на форуме не исчезают сами - это баг или фича? Смотришь, что кто-то оставил тебе ЛС, смотришь ЛС, уведомление при этом не исчезает. Последний хром, если вдруг.
  10. Тут можно начать с выяснения того, как игра определяет - смотрит персонаж в сундук или нет. Я думаю, @Garik66 может с этим помочь.
  11. Я думал сделать обзор на эту штуковину, но больно уж криво она (как минимум, у меня) работает.
  12. Привет! Эта штука называется Ultimap и [вот], например, пример.
  13. И почистил тему. Народ, кто писал ссылки для Гарика по поводу чистки от малвари - продублируйте ему в ЛС, пожалуйста.
  14. Не могу точно сказать. Наверняка можно глянуть где-нибудь в Source SDK, например.
  15. Самое простое - искать ось Z. Встал на месте - делаешь поиск неизвестного. Затем поднялся на лестницу или залез на ящик - отвеиваешь "увеличилось". Слез обратно - "уменьшилось". Или посмотри в памяти рядом со здоровьем - обычно все в одной куче лежит. PS: Ты ведь это все не с основного своего steam-аккаунта делаешь, правда?
  16. Я думаю, что если возникает много однообразных вопросов по одной и той же теме (или игре), то это стоит оформлять в FAQ и закреплять где-то в верху раздела.
  17. Ты после смещения 0x2AC забыл прочитать полученный адрес.
  18. Привет! У игрока есть несколько "слотов" под то, что можно выбрать. Для простоты я буду считать, что это винтовка, пистолет и нож. Одновременно выбрать можно только что-то одно. Исходя из того, что выбрано, будет рисоваться та или иная модель оружия (т.е. может быть несколько разных ножей/пистолетов/винтовок). Как это искать? Самое простое - поиском цифры слота. Предполагаешь, что винтовка - это 1, пистолет - это 2, а нож - это 3. Ищешь целое число при помощи Cheat Engine или другого сканера памяти. Если ничего не нашлось, то можно пробовать неизвестное изначально значение и "увеличилось/уменьшилось". Если и это не дало результатов, то неизвестное и "изменилось/не изменилось". В результате найдется адрес, который будет изменяться в зависимости от выбранного типа оружия. Второй вариант - найти структуру игрока, который это самое оружие держит, и изучить ее содержимое, выбирая при этом разные виды оружия. Удобнее всего при этом вообще больше ничего в игре не изменять, т.к. в структуре игрока содержится много всего и трудно будет найти нужное значение, если изменяться будет одновременно половина. Собственно, про оффсет от начала этой структуры ты (скорее всего) и говоришь в первом посте. Дальше уже - дело техники, что с этим делать.
  19. keng

    Так держать?

    Дорогие читатели! Мне продолжать этот бложек в текстово-картиночном формате (возможно - с гифками!) или же перейти обратно на формат видеолекций? А может, текстовые статьи дополнять видеопояснениями? Я никак не могу определиться, потому что мне очень странно на камеру объяснять и писать текст (код). Помогите мне определиться, пжлст (в комментариях).
  20. Не-не-не, стоп! Почему оверлей не будет работать в полноэкранном режиме? Там никаких проблем не должно быть.
  21. keng

    Движочек. Начало.

    Привет, читатель! Ты сейчас читаешь это, потому что в тебе есть интерес ко взлому игр и низкоуровневому программированию, ибо этот мини-блог будет посвящен как раз этой тематике. Если конкретнее, то я постараюсь показать и рассказать о том, как пишутся движки для трейнеров. Если ты вдруг не в курсе, то трейнер - это программа, позволяющая всячески изменять поведение компьютерной игры. Например, сделать ГГ (главного героя) бессмертным или же выдать ему миллион игровых очков. В общем, сделать нечто такое, чего штатный игровой процесс не подразумевает. Если ты вообще не понимаешь, о чем идет речь, то сначала поищи в интернете, как создаются читы для игр, а потом уже возвращайся сюда. Я буду предполагать, что взламывать игры (искать значения в памяти и немного пользоваться отладчиком/дизассемблером) ты уже умеешь. Итак, поехали! Весь исходный код я буду хранить в репозитории на github, ссылку на него и на нужный коммит буду выдавать в конце статей, если это потребуется. С чего начнем? А начнем мы с выбора инструментов. Мои коллеги по цеху давно и очень успешно создают подобные этому обучающие материалы, но на высокоуровневых языках - C++ и C#, а местами и на Delphi. К счастью, мы от подобного избавлены, так что выбор у нас один - Ассемблер. Первая проблема заключается в том, что их много и они местами сильно различаются, так что отныне и в обозримом будущем я буду использовать [flat assembler]. Идешь на сайт в раздел "Download" и качаешь последнюю версию flat assembler for Windows (на момент написания этой статьи - 1.71.63). Скачанный архив нужно куда-то распаковать и можно запускать местную среду разработки - fasmw.exe. А вот и код на сегодня: ; main.asm format PE GUI 4.0 include 'win32wxp.inc' invoke ExitProcess,0 data import library kernel32,'KERNEL32.DLL' import kernel32,\ ExitProcess,'ExitProcess' end data Что происходит? ААА! Да ну, все в порядке. Разберем построчно. Символ точки с запятой обозначает комментарий. Сразу берем за правило, что в каждом файле исходного кода первой же строчкой будет идти его имя. В местной среде разработке (как и в любой другой) есть возможность запустить программу на исполнение, предварительно ее скомпилировав (если язык разработки является компилируемым). В твоем случае нужно выбрать меню "Run->Run" или ткнуть F9. Если звезды сложатся удачно, то с виду ничего не произойдет. Отсутствие ошибок - это половина успеха! Но вернемся к разбору исходного кода. Первой осмысленной с точки зрения компилятора строчкой идет вторая. Она указывает, что же за формат такой должен получиться на выходе. Формат, в смысле - исполняемого файла. EXE, то есть. В Windows основным таким форматом является PE, он же Portable Executable. Подробнее про него можно почитать в Интернете, например [тут]. GUI говорит компилятору о том, что это будет приложение с графическим интерфейсом пользователя, а не консольно-текстовое, что нам и нужно. И пока хватит с этой строчки, подробности про нее можно почитать на сайте ассемблера в разделе Documentation. Далее у нас идет директива include. Тут все просто - компилятор ищет файл с таким именем и банально вставляет вместо всей этой строчки его содержимое, как есть. Или ругается, если что-нибудь пошло не так. Если ты очень любопытен, то можешь найти этот файл в папке с ассемблером и посмотреть, что в нем написано. Пока что я скажу, что в нем описываются функции WinAPI - это такой здоровенный набор функций Windows, из которых и состоят, по факту, все программы. Запустить программу? WinAPI! Открыть файл? WinAPI! Поменять картинку на рабочем столе? WinAPI! И вот так всегда. Все в Windows сводится к большой стопке разных функций WinAPI, вызванных в нужном порядке. Хочешь подробнее прямо сейчас - ищи в Интернете (подсказка: MSDN). Что там идет дальше? Точно! Единственный, на самом деле, кусочек реального кода программы, а не какой-то вспомогательной фигни. invoke - это вызов функции. После этой команды идет имя функции и ее аргументы, если они есть. Самая настоящая команда ассемблера! На самом деле, конечно, это макрос, но об этом потом. Как бы это выглядело в реальной жизни? Представь, что надо заварить 10 чашек чая. И даже есть функция (по сути - просто набор действий) под названием "СделатьЧай". Что должна делать эта функция? Взять чашку, насыпать в нее чай, налить кипяток, добавить сахар, перемешать. Так и пишем: СделатьЧай: 0. Взять чашку 1. Насыпать в чашку чай 2. Налить в чашку кипяток 3. Добавить в чашку сахар 4. Перемешать Допустим, что мы пишем на ассемблере программу, которая заваривает чай. И что "СделатьЧай" - это функция WinAPI. Вот так будет выглядеть ее вызов: invoke СделатьЧай Ага! Ты сразу спросишь - "а нафига ноль в конце той строчки? что еще за аргументы такие?". Аргумент - это просто некое значение, передаваемое функции в момент ее вызова. Например, "СделатьЧай, 10 раз". Если бы наша функция, делающая чай, принимала аргумент "Количество" и была бы написана так, что был бы в ней цикл - "делать чай, пока количество не станет равным 0, после каждой чашки отнимать от количества 1", то делала бы она за один вызов 10 чашек и вместо: invoke СделатьЧай ; 0 чашка invoke СделатьЧай ; 1 чашка invoke СделатьЧай ; 2 чашка invoke СделатьЧай ; 3 чашка invoke СделатьЧай ; 4 чашка invoke СделатьЧай ; 5 чашка invoke СделатьЧай ; 6 чашка invoke СделатьЧай ; 7 чашка invoke СделатьЧай ; 8 чашка invoke СделатьЧай ; 9 чашка Можно было бы написать всего лишь: invoke СделатьЧай,10 ; 10 раз И оно бы внутри в цикле 10 раз вызвалось. Удобно ведь? Конечно! И места меньше занимает. Функция у нас вызывается всего одна - "ExitProcess" с аргументом в виде нуля. Знатоки английского языка могут догадаться, что эта функция делает. Завершает процесс. Выходит. Совсем. Да, все так - все, что программа делает на данный момент - это успешно завершает свою работу. Успешно, потому что аргумент у нее "0". Аргумент этой функции - это так называемый код возврата. Он сильно нужен (зачем-то) Windows и она решает именно по коду возврата, хорошо ли было программе во время работы или плохо. Вот случись ошибка - завершаешь программу с не-нулевым кодом возврата и все, Windows об этом будет знать. Когда-то давно это была единственная возможность узнать результат работы - эти самые коды возврата были описаны в документации к программам. Так-то! Итак, выяснилось, что оно начинает работу и сразу же ее завершает, зато успешно. Ну а что, надо ведь начинать с чего-то, верно? Остался последний кусок. Кусок этот отвечает за предоставление нашей программе доступа к WinAPI. Эти все функции - не магия и не само собой оно работает, а где-то в системе хранится. Если точнее, то хранится в библиотеках, которые имеют расширение DLL, хотя тоже являются исполняемыми файлами. Да, они тоже исполняемые, просто не умеют сами запускаться - их должен загрузить в себя другой процесс (работающий EXE файл) и можно будет вызывать функции загруженной библиотеки. То, какие функции можно вызывать, а какие нельзя, определяется библиотекой, а процесс, загрузивший ее, может только попросить указать ему место, где в библиотеке нужные ему функции лежат. Этим и занимается секция data import - end data. Мы указываем, что нам нужно загрузить библиотеку kernel32.dll, а из нее - функцию по имени ExitProcess. Что происходит при запуске? EXE-файл загружает библиотеку. Та сообщает ему, где искать адрес функции ExitProcess. После этот самый адрес и подставляется команде invoke. Такой вот компилятор умный. На этом пока закончим. [Репозиторий] на github. [Коммит].
  22. Собственно, в этом весь мой вопрос и заключается - зачем этим всем заниматься в managed-среде. Ну банально же не для этого язык.
  23. Тогда я бы посмотрел на пример кода.
×
×
  • Создать...

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

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