PDA

Просмотр полной версии : PW FrameWork 2.0 - новый взгляд на инструмент для ботостроения


krukovis
27.09.2012, 22:47
Всем привет!
Решил выложить свой вариант PW FrameWork. Назвал я его PW FrameWork 2.0.
Совместимости между первоначальной версией и версией 2.0 нет.
Он переделан из первой версии и в нем использованы наработки TBXin и whoami и возможно еще кого то.

Классы, которые я изменял имеют пометку krukovis. Остальные классы из проекта исключены, до лучших времен.
Так они не откомментированы и как их использовать мне пока не понятно. Если разберусь - включу в проект.

Немного общих комментариев по классам:

Общий упор сделан на ООП - объектно ориентированное программирование. Я все старался представить в виде самостоятельных объектов. И все взаимодействие в виде взаимодействия объектов.


WinApi - просто сборник win api. Вынесен в отдельный класс для удобства поиска.

ClientFinder - с этого класс начинается подключение к клиенту.
Он принимает в качестве аргументов: базовый адрес клиента, смещение к структуре игры, смещение к структуре персонажа и смещение к адресу имени персонажа.
Возвращает список окон, если получится определить имя персонажа - то в виде имен персонажа, если нет - в виде имен окон.
Окно представленно классом ClientWindow.

MemoryWork - основной класс для работы с памятью.
В нем собраны удобные функции для чтения памяти и представления полученных данных в нужном формате: Int32, Int16, String и т.д
Этот класс основной для всех следующих классов, т.к. работа идет с памятью.
Он принимает в качестве аргумента класс ClientWindow и работает именно с этим окном. Что примечательно, можно создать экземпляр класса
MemoryWork для любого запущенного окна игры и можно будет работать из одной программы с несколькими окнами. Можно управлять хоть целой командой.

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

PacketSender - класс облегчающий использование пакетов. А точнее отправляющий пакеты. Принимает в качестве аргумента класс Packet.
Packet - статический класс - огромная база пакетов. Все очень в удобном виде.

OffsetRetriever - класс для поиска смещений и адресов по маске. Как пользоваться - пример в исходниках.

OffsetsAndAddresses - сборник смещений и адресов, использующихся в других классах

GraphicUserInterface - это набор классов описыващий графические объекты в игре и позволяющий запускать различные кнопки.
и
GameStructs - класс описывающий игровые структуры.

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

При такой реализации с ними очень легко работать. Наример, чтобы нажать на кнопку нужно сделать следующее:
Создать экземпляр класса PWGUI:
PWGUI GUI = new PWGUI(SelectedWindow);//где SelectedWindow - это какое то окно PW описанное с помощью класса ClientWindow.
И работать с его свойствами и методами, как вы обычно привыкли:
//отображаем форму Win_LoginButton - форму ввода логина и пароля
GUI.Form("Win_LoginButton").Visible = true;
//открываем окно смены сервера:
GUI.Form("Win_LoginButton").Control("Btn_ChangeServer").CommandStart();
Аналогично можно работать с персонажем:
//получаем класс игры для запущенного окна
PWGameWindow game_window = new PWGameWindow(SelectedWindow);
//объявляем host-игрока для данного окна игры
PWHostPlayer MyPersonage = game_window.HostPlayer;
//Использовать Смерчь у приста
MyPersonage.UseSkill(127);
//Сесть в медитацию
MyPersonage.MeditationStart();
и т.д.

Все свойства и методы откомментированны и по описанию в навигаторе можно понять что делает то или иное свойство или метод

[Ссылки могут видеть только зарегистрированные и активированные пользователи]

Основным желанием было наметить пути командной разработки и дальнейшего улучшения фреймворка для общего блага.

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

Класс для работы с игрой только начат - в нем я только наметил основные моменты и я предлагаю его дополнять и расширять совместными усилиями.
Если вы будете выкладывать код с исправлениями или улучшениями - обязательным требованием будут комментарии и следование общей концепции (по аналогии).
Со своей стороны буду оказывать любую помощь и поддержку. Все объясню и расскажу. Весь новый код буду вставлять в исходный проект и выкладывать на форуме.

Исходники PW FrameWork 2.0 и пример можно скачать из вложения. Замените адреса для своего клиента перед использованием!

N00bSa1b0t
27.09.2012, 22:51
А ты баг с памятью исправил, который был у TBX1in и whoami?

Goooooogle
27.09.2012, 22:54
Во спасибо Я со старым вообще ничего не понял тут хоть более просто!

krukovis
27.09.2012, 22:54
А ты баг с памятью исправил, который был у TBX1in и whoami?
Баг с тем, что память переставала выделяться? Исправил. Память теперь выделяется один раз при открытии и дальше все классы, если что то нужно инжектить - инжектят в эту страницу.

Goooooogle
28.09.2012, 00:23
переделал оффсеты под руоф скачать ([Ссылки могут видеть только зарегистрированные и активированные пользователи])

N00bSa1b0t
28.09.2012, 00:47
Баг с тем, что память переставала выделяться
Баг с тем, что занятая память не удалялась :)

Угу, баг есть. Никто не любит читать мсдн.

WinApi.VirtualFreeEx(memory.OpenedProcessHandle, memory.FuncAllocMemory, Asm.Length, WinApi.FreeType.Release);

А должно быть
WinApi.VirtualFreeEx(memory.OpenedProcessHandle, memory.FuncAllocMemory, 0, WinApi.FreeType.Release);

иначе память не удалится, ибо как гласит МСДН

If the dwFreeType parameter is MEM_RELEASE, dwSize must be 0 (zero).

krukovis
28.09.2012, 07:46
Баг с тем, что занятая память не удалялась
Вот так вот :). Значит можно переписывать PW FW. :)
Ну или пусть будет как есть - страница выделяется. Вся работа идет на этой странице. Все удобно.
Для меня важнее, чтобы мы общими усилиями описали основные параметры персонажа и прочих структур. Основной упор сделан на это.
Вот ты будешь сейчас писать софтину свою - возьми за основу PW 2.0 и что нибудь да допишешь в структуру перса. И я тоже сейчас буду писать кой чего - тоже допишу. Выложим вместе - будет польза обоим и еще куче народу.
Алгоритмы программы - не нужны. Только структура персонажа и дочерних структур.

N00bSa1b0t
28.09.2012, 12:15
Вот ты будешь сейчас писать софтину свою - возьми за основу PW 2.0
У меня уже свой фреймворк на основе фреймворка от whoami =)
Идея была примерно такая же:

Есть класс pwProcess в нем класс pwgame а там уже hostplayer с разными функциями типа:


var party = PW.Game.HostPlayer.GetParty();
PW.Game.HostPlayer.Assist(party[0]);
...
PW.Game.HostPlayer.UseItem(found, cooldown);
..
var players = PW.Game.HostPlayer.NearestPlayers_Get();


Только у меня еще модульная структура, чтоб не всю либу сразу подключать к своим проектам. Например, для геобота не нужны функции работы с группой, игроками итп =)

krukovis
28.09.2012, 14:45
Только у меня еще модульная структура, чтоб не всю либу сразу подключать к своим проектам. Например, для геобота не нужны функции работы с группой, игроками итп =)
Что за модульная структура? Подробнее плиз.

Добавлено через 2 минуты
переделал оффсеты под руоф скачать
Так там заменить только адреса нужно было. Все остальное совпадает. Можешь просто скопировать сюда адреса для руофа - для замены.

N00bSa1b0t
28.09.2012, 15:21
Что за модульная структура? Подробнее плиз.
Я пока думаю, как ее правильно реализовать. пока остановился на таком способе.

Например, делаю я простую ингейм утилитку. Например вот как EnemyDetector. Отображает список рядом находящихся игроков и выводит инфу о них.
В этой утилите не нужны функции работы с группой, с мобами, со скиллами, с чатом, функции движения, полета итп. Нужны функции только чтения списка игроков и все.

Например в иксо-боте не нужен список игроков рядов, но нужен автопот, скан мобов, движение итп.

Чтобы каждый раз не тащить за собой всю огромную либу, я её разбил на модули: Чат, группа, игроки, мобы, движение, скиллы итп.

krukovis
28.09.2012, 21:13
Чтобы каждый раз не тащить за собой всю огромную либу, я её разбил на модули: Чат, группа, игроки, мобы, движение, скиллы итп.
Это у тебя несколько dll-ок что ли?

N00bSa1b0t
28.09.2012, 23:18
Это у тебя несколько dll-ок что ли?
Нет - одна, просто в зависимости от проекта по разному компилируется.

Kitsune
29.09.2012, 00:28
в зависимости от проекта по разному компилируется
Использовать директивы на уровне компилятора - моветон.

N00bSa1b0t
29.09.2012, 12:17
Использовать директивы на уровне компилятора - моветон.
Это первое, что пришло мне в голову и пока меня устраивает :) Хотя возможно потом данный механизм будет изменен.

krukovis
29.09.2012, 16:32
Это первое, что пришло мне в голову и пока меня устраивает Хотя возможно потом данный механизм будет изменен.
Экономить 100кБ - бред же... :) Или какую проблему ты этим решаешь?

N00bSa1b0t
29.09.2012, 17:14
какую проблему ты этим решаешь?
Скажем так, я пока не настолько щедрый, чтоб выкладывать свои наработки в паблик :) Т.к. в саму либу внедрены функции, которые активно использует мой иксобот, и я не хочу их распространять (там всякие интересные алгоритмы, типа поиска пути в иксах c учетом стен и перепада высот и все такое), то таким образом я получаю, что в тех софтинах, что идут на продажу в либе не будет содержаться тех функций, которые я не хочу никому давать.

Блин, я ща пьяный, надеюсь, что моя мысля понятна :D

half-node
02.10.2012, 00:49
Всем доброго времени суток.
У меня возникла небольшая проблема.
На поиск близлежащего лута, есть такой код, вырезка:

int c = memory.ChainReadInt32(0xA571E0, 0x1C, 0x1C, 0x28, 0x14);

string[][] names = new string[c][];

for (int i = 0; i < c; i++)
{
names[i] = new string[2]
{
memory.ChainReadString_Unicode(0xA571E0, 0x1C, 0x1C, 0x28, 0x18, (i*0x4), 0x4, 0x168, 0x0),
(memory.ChainReadInt32(0xA571E0, 0x1C, 0x1C, 0x28, 0x18, (i * 0x4), 0x4, 0x110)).ToString()
};
}


Ну вот. Кол-во лута я получаю правильное.
А вот WID и Name по каждому нет. На выходе с именем пустая строка, а с идентификатором нуль.

Офсеты брал с соответствующей темы для руофа.

Пожалуйста, помогите понять, где я ошибся.
Спасибо!

Добавлено через 27 минут
Я понял в чем была моя ошибка.
И малость изменил код.
Но в итоге, получаю в именах пустые значения, а в WID отрицательные значения:

string[][] names = new string[0][];

for (int i = 0; i < 0x300; i++)
{
if (memory.ChainReadInt16(0xA571E0, 0x1C, 0x1C, 0x28, 0x18, (i * 0x4), 0x4, 0x110) != 0)
{
Array.Resize(ref names, names.Length + 1);
names[names.Length - 1] = new string[2]
{
memory.ChainReadString_Unicode(0xA571E0, 0x1C, 0x1C, 0x28, 0x18, (i*0x4), 0x4, 0x168, 0x0),
(memory.ChainReadInt32(0xA571E0, 0x1C, 0x1C, 0x28, 0x18, (i * 0x4), 0x4, 0x110)).ToString()
};
}
}

krukovis
02.10.2012, 07:52
Но в итоге, получаю в именах пустые значения, а в WID отрицательные значения:

memory.ChainReadString_Unicode(0xA571E0, 0x1C, 0x1C, 0x28, 0x18, (i*0x4), 0x4, 0x168, 0x0),
Не правильно читаешь строку. Вторым параметром нужно указывать максимальную длину строки.
memory.ChainReadString_Unicode(0xA571E0, 32, 0x1C, 0x1C, 0x28, 0x18, (i*0x4), 0x4, 0x168, 0x0)


(memory.ChainReadInt32(0xA571E0, 0x1C, 0x1C, 0x28, 0x18, (i * 0x4), 0x4, 0x110)).ToString()
Отрицательное число на выходе - это нормально для WID лута. Либо читай в UInt, либо выводи в Hex, либо вообще не парься по поводу
"отрицательности".
Я обычно отображаю в Hex:
memory.ChainReadInt32(0xA571E0, 0x1C, 0x1C, 0x28, 0x18, (i * 0x4), 0x4, 0x110)).ToString("X")
Т.к. сами WID смысла не несут. WID нужно только для сравнения.

whoami
03.10.2012, 19:23
Я когда свой софт писал - делал упор на оптимизацию скорости. Т.к. на ТВ или тиграх и так клиент может притормаживать, а с аналогом "EnemyDetector" всё может вообще отвалиться. Поэтому, например, поля объектов максимально кэшируются, читаются не поштучно (например, MemPtr.Int32) а сразу пачками (например, с помощью структуры с explicit layout). Можно сделать всю такую ООП-шную объектную модель с классами типа PWMob, у которого были бы свойства X, Y, Z, Level, IsAggressive, IsAttacking и т.д. Было бы очень удобно писать боты, но с оптимизацией был бы полный швах... Я думаю, если добить идею инпроцессного режима, то там оптимизация была бы не нужна и такой подход был бы более уместен.

krukovis
04.10.2012, 07:22
Можно сделать всю такую ООП-шную объектную модель с классами типа PWMob, у которого были бы свойства X, Y, Z, Level, IsAggressive, IsAttacking и т.д.
Ну как видишь в этом направлении я и задал вектор развития проекта. И туда и двигаюсь. Пока наращиваю класс Персонажа. Класс пати описан. Делать софт на порядок удобнее.
но с оптимизацией был бы полный швах...
Пинг 500-600 мс средний. Время работы программы (чтение памяти и обработка данных) 20-30 мс. Ожидание в потоке 1000 мс. Получается что 90% времени программа просто ничего не делает. Так что вопрос оптимизации, как я считаю, не стои'т.

Основная задача - сделать удобный инструмент для создания софта. И в этом нам поможет ООП.


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

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

whoami
04.10.2012, 14:39
krukovis, ну вот пробежать по сотне персонажей (на ТВ максимум может быть 160 игроков) - получить их координаты, имя, уровень/культавацию, ID, ID клана, жив/мёртв, хирки, привязка каты, для таргета - ещё ХП/МП/бафы, плюс ещё мобов обработать - выбрать петов друлей и мистиков. Тут уже в 20 мс уложиться трудно. и обновляюсь я раз в 500 мс, а пинг чтобы на ТВ играть - лучше иметь не больше 150 мс.

Для внедрения .NET-кода в ПВ у меня код есть, часть - даже в паблик выкладывал. Смысл в том, что там есть используется альтернативная версия ProcessMemory, которая не лезет в память другого процесса, а работает с текущим, потоки создаёт не через CreateRemoteThread, а через CreateThread и т.д.

Добавлено через 22 часа 4 минуты

А должно быть
WinApi.VirtualFreeEx(memory.OpenedProcessHandle, memory.FuncAllocMemory, 0, WinApi.FreeType.Release);


А у меня вот с таким вариантом после второй отправки пакета падает клиент. Что не так?

krukovis
15.10.2012, 09:55
А у меня вот с таким вариантом после второй отправки пакета падает клиент. Что не так?
Инектится в пустую страницу видимо. А ты в каком варианте используешь? В своем FW или в FW 2.0 ?

silk
15.10.2012, 10:25
А вот что происходит дальше - не очевидно. Как обращаться к памяти из внедренной DLL?
дальше происходит все то же самое, как и со своим процессом. Поскольку dll находится в адресном пространстве клиента, то обращение к памяти клиента идет через обычную арифметику указателей. :)

krukovis
16.10.2012, 11:15
дальше происходит все то же самое, как и со своим процессом. Поскольку dll находится в адресном пространстве клиента, то обращение к памяти клиента идет через обычную арифметику указателей.
В теории я это все знаю. В музыке кода бы. В идеале - С#.

phoenixusa
25.12.2012, 12:00
krukovis, почему не хочешь хранить смещения в отдельном файле (например ini)? чтобы при выходе обновы только изменить адреса, без перекомпиляции проекта?

krukovis
26.12.2012, 08:18
krukovis, почему не хочешь хранить смещения в отдельном файле (например ini)? чтобы при выходе обновы только изменить адреса, без перекомпиляции проекта?

Почему не хочу? Хочу )), но:
Обновы бывают двух видов:
1) Большие - когда меняются адреса и структуры функций.
2) Маленькие - когда меняются только адреса.
В первом случае ini-файл не спасет, т.к. в ini не опишешь структуру функции. А во втором, ini-файл - не элегантное решение, ведь я выложил исходники, где показываю как использовать Offset Retriever и ini-файл вообще становится не нужным.

Da4Da4
11.02.2013, 14:45
krukovis, можешь если не затруднит описать принцип работы класса Offset Retriever. из кода класса было понятно, что ты производишь поиск поиск по файлу elementclient.exe или в памяти процесса. Поиск адресов и офсетов выполняешь по шаблону. вот только не понятно что они из себя представляют, и на основании чего составляются?

krukovis
15.02.2013, 20:11
вот только не понятно что они из себя представляют, и на основании чего составляются?
Шаблоны представляют с собой байт-код записанный в виде строки без пробелов и разделенных знаком ?. Знак ? - обозначает адрес или оффсет длинной DWORD = 4 байта.
Разберем поиск оффсета на примере поиска базового адреса.

Базовый адрес мы можем найти с помощью описанного на форуме мануала или посмотреть в этой теме. ([Ссылки могут видеть только зарегистрированные и активированные пользователи])

Для текущей версии RUOFF он равен 0x00B8FBCC

1. Для начала открываем elementclient.exe в OllyDbg 2.01 ([Ссылки могут видеть только зарегистрированные и активированные пользователи])

[Ссылки могут видеть только зарегистрированные и активированные пользователи]

2. Дальше находим первое вхождение константы 0x00B8FBCC. Делается это так:

Тыкаем в свободное пространство правой кнопкой мыши
[Ссылки могут видеть только зарегистрированные и активированные пользователи]
Выбираем поиск
[Ссылки могут видеть только зарегистрированные и активированные пользователи]
Константы
[Ссылки могут видеть только зарегистрированные и активированные пользователи]

3. Нажимаем ОК и находим первое вхождение:
[Ссылки могут видеть только зарегистрированные и активированные пользователи]

4. Эта константа применяется в очень многих функциях, т.к. это базовый адрес. Но наша задача - найти такую функцию, которая с большой вероятностью не будет изменяться долгое время. Я потыкал дальше еще несколько раз Ctrl+L - это сочетание значит "Искать тоже самое дальше". И нашел вот такой кусок кода, который с большой вероятностью будет оставаться таким же очень долгое время. Я так думаю, потому что там используется только один базовый регистр EAX и несколько PUSH 0 в исключительной конфигурации:
[Ссылки могут видеть только зарегистрированные и активированные пользователи]

5. Дальше мы можем использовать эту *с большой долей вероятности* постоянную часть функции и сделать из нее МАСКУ. Для этого нам нужно скопировать этот кусок кода как байт-код:
[Ссылки могут видеть только зарегистрированные и активированные пользователи]

6. Дальше откроем блокнот и вставим туда то, что находится в буфере и увидим вот такой байт-код:
"A1 CC FB B8 00 6A 00 6A 00 6A 00 8B 48 1C 6A 00
6A 00"
Красным выделил BA.

Нам он нужен для поиска Базового адреса, поэтому мы заменяем базовый адрес на ? и удаляем пробелы.

Получаем: "A1?6A006A006A008B481C6A006A00"

Теперь мы можем использовать эту маску для поиска Базового адреса в автоматическом режиме.

По поводу поиска адресов функций я расскажу как нибудь в другой раз.

Добавлено через 8 минут
Чтобы убедиться, что это уникальное сочетание можно проверить на клиенте 1.3.4-1.3.6
С этого времени это сочетание не менялось:
[Ссылки могут видеть только зарегистрированные и активированные пользователи]
И скорей всего уже не поменяется.
И мы можем увидеть, что на Cerera.org 1.3.4-1.3.6 базовый адрес 926FD4.
А посмотрим что нам говорит эта тема ([Ссылки могут видеть только зарегистрированные и активированные пользователи]):
Flugel PW, клиент 1.3.4 версии, сборка 2265, версия обновления 50
BaseAdress=00926FD4
GameAdress=0092764C

Da4Da4
18.02.2013, 16:58
Большое спасибо за подробное объяснение.
В принципе мои предположения были верными, но все же не было полной уверенности.

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

dobik
23.04.2013, 22:59
Кто-нибудь знает адрес
//адрес gui-функции
public static int gui_function_address = 0x77F1D0;

для текущей версии клиента?
И остальные из раздела GUI?

Пробую с GUI разобраться, но не знаю адреса для него.

krukovis
24.04.2013, 08:56
Кто-нибудь знает адрес
//адрес gui-функции
public static int gui_function_address = 0x77F1D0;

для текущей версии клиента?
И остальные из раздела GUI?

Адрес для GUI можно определить с помощью Автологина из подписи для любого клиента начиная с 1.4.4 и выше.
А так же для этого есть специальная тема Адреса и оффсеты ([Ссылки могут видеть только зарегистрированные и активированные пользователи]). Там выкладываются все адреса и смещения для различных версий клиента PW.

FriendsKenny
07.09.2013, 11:15
В ф-ии public static byte[] PetUseSkill(int skillID, int targetWID)
которая формирует пакет исп-ия скилла пета, один лишний 0х0

krukovis
08.09.2013, 10:59
В ф-ии public static byte[] PetUseSkill(int skillID, int targetWID)
которая формирует пакет исп-ия скилла пета, один лишний 0х0

Очень может быть. Эти функции писались еще под 1.4.Х

FriendsKenny
08.09.2013, 20:40
Пытаюсь перевести инжект AutoPath ([Ссылки могут видеть только зарегистрированные и активированные пользователи]) на ассемблер фреймворка.

int x = -1558;
int y = 776;
int z = 252;

pushad
MOV EDI,y
MOV ESI,x
MOV EAX,DWORD PTR DS:[BA] // base_addr
PUSH 0
PUSH EDI
MOV ECX,DWORD PTR DS:[EAX+0x1C]
PUSH ESI
PUSH 0
PUSH 0
PUSH 0
PUSH 0x14A
mov edx,0x0441A60 //ф-я
call edx


MOV EDX,DWORD PTR DS:[BA]
XOR EAX,EAX
MOV AL,0
PUSH 0
MOV ECX,DWORD PTR DS:[EDX+0x1C]
MOV EDX,z
PUSH EAX
PUSH EDX
PUSH 1
PUSH 0
PUSH 0
PUSH 0x14A
mov edx,0x0441A60 //ф-я
CALL edx
popad


Который успешно работает в билдере.
На фреймворке получилось так:


public void XOR_EAX_EAX()
{
this.Asmcode = this.Asmcode + "33C0";
}

public void MOV_AL_0()
{
this.Asmcode = this.Asmcode + "B000";
}

ASM asm = new ASM(memory);
asm.Pushad();
asm.Mov_EDI((int)y);
asm.Mov_ESI((int)x);
asm.Mov_EAX_DWORD_Ptr(GameOffsets.base_address);
asm.Push6A(0);
asm.Push_EDI();
asm.Mov_ECX_DWORD_Ptr_EAX_Add(0x1C);
asm.Push_ESI();
asm.Push6A(0);
asm.Push6A(0);
asm.Push6A(0);
asm.Push6A(0x14A);
asm.Mov_EDX(0x0441A60);
asm.Call_EDX();

asm.Mov_EDX_DWORD_Ptr(GameOffsets.base_address);
asm.XOR_EAX_EAX();
asm.MOV_AL_0();
asm.Push6A(0);
asm.Mov_ECX_DWORD_Ptr_EDX_Add(0x1C);
asm.Mov_EDX((int)z);
asm.Push_EAX();
asm.Push_EDX();
asm.Push6A(1);
asm.Push6A(0);
asm.Push6A(0);
asm.Push6A(0x14A);
asm.Mov_EDX(0x0441A60);
asm.Call_EDX();
asm.Popad();
asm.Ret();
asm.RunAsm();


Но в таком варианте персонаж просто стоит на месте, клиент не вылетает. Где я ошибся?

krukovis
09.09.2013, 10:29
Но в таком варианте персонаж просто стоит на месте, клиент не вылетает. Где я ошибся?
Мне страшно представить как ты это пытаешься запустить. Я выкладывал пример использования. Посмотри, пожалуйста.

FriendsKenny
09.09.2013, 17:32
asm.Push6A(0x14A); заменил на asm.Push68(0x14A);
Заработало =)

krukovis
10.09.2013, 23:05
Push68

Push68 - это тот пуш, который в байт-коде выглядит как
68 00 00 0A 14 == push 0x14

Smertig
11.09.2013, 00:25
asm.Push6A(0x14A); заменил на asm.Push68(0x14A);

68 00 00 0A 14 == push 0x14
Добавлю. Push 6A не пушит числа больше 127=0x7F

A117
22.09.2013, 16:40
При отправке пакета клиент падает.
Объясните, пожалуйста, почему это происходит и как поправить.

FriendsKenny
24.09.2013, 14:48
При отправке пакета клиент падает.
Объясните, пожалуйста, почему это происходит и как поправить.

Логично предположить что дело в адресе ф-ии отправки пакета

vogel
24.09.2013, 15:18
И поправить можно изменив устаревший адрес - на новый.

A117
24.09.2013, 23:20
Адрес функции поменял первым делом - клиент все равно падает. Сперва думал что неправильный адрес, но потом сам получил то же значение.
До последнего обновления работал такой пакет (после соответствующей подстановки) "\x60\x8B\x0D\x00\x00\x00\x00\x8B\x49\x20\x68\x11\x 11\x11\x11\x68\x22\x22\x22\x22\xB8\x33\x33\x33\x33 \xFF\xD0\x61\xC3"
То что формируется фреймворком довольно сильно отличается и по длине и по содержанию.
Попутный вопрос: как найти ассемблерный код самой функции?

krukovis
25.09.2013, 08:50
То что формируется фреймворком довольно сильно отличается и по длине и по содержанию.
Попутный вопрос: как найти ассемблерный код самой функции?

В истории были случаи изменения пакета. Поправьте пакет и проверьте.

Ассемблерный код какой функции? В общем случае ассемблерный код любой функции можно увидеть в файле elementclient.exe открыв ее в деббагере.

A117
25.09.2013, 20:59
Перешел в дебаггере по адресу PackCall=006F55E0,
там обнаружился такой код:

PUSH -1
PUSH 00AD1C38
MOV EAX,DWORD PTR FS:[0]
PUSH EAX
MOV DWORD PTR FS:[0],ESP
SUB ESP,18
PUSH EBX
PUSH ESI
PUSH EDI
MOV EDI,ECX
PUSH 7
CALL 008263B0

Я так понимаю это и есть код функции отправки пакета, который нужно вставить в PacketSender.Send(byte[] packet)?

krukovis
26.09.2013, 10:27
Я так понимаю это и есть код функции отправки пакета, который нужно вставить в PacketSender.Send(byte[] packet)?
Метод .Send класса PacketSender принимает в качестве аргумента packet (переводится как пакет) типа массив байт byte[].
В фреймворк добавлена библиотека пакетов. Класс Packets скорей всего или что то в этом роде. Я выкладывал пример использования фреймворка для отправки пакетов. Посмотри, пожалуйста.

A117
27.09.2013, 21:15
Я не точно выразился. Имелось ввиду не параметр функции а сам ассемблерный код

ASM asm = new ASM(this.memory);
asm.Pushad();
asm.Mov_EAX(PWOffssAndAddrss.packet_function_addre ss);
asm.Mov_ECX_DWORD_Ptr(PWOffssAndAddrss.base_addres s);
asm.Mov_ECX_DWORD_Ptr_ECX_Add(0x20);
asm.Mov_EDI(memory.PacketAllocMemory);
asm.Push6A(packet.Length);
asm.Push_EDI();
asm.Call_EAX();
asm.Popad();
asm.Ret();
asm.RunAsm();

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

A117
29.09.2013, 13:51
Вопрос решился


8B 15 6C8BC300 - mov edx,[elementclient.exe+838B6C]
6A 04 - push 04
56 - push esi
8B 4A 20 - mov ecx,[edx+20]
E8 BBFCFCFF - call elementclient.exe+2F55E0



ASM asm = new ASM(this.memory);
asm.Pushad();

asm.Mov_EDX_DWORD_Ptr(OFFSET.base_address); //0x00C38B6C
asm.Push68(packet.Length);
asm.Push68(memory.PacketAllocMemory);
asm.Mov_ECX_DWORD_Ptr_EDX_Add(0x20);
asm.Mov_EAX(OFFSET.packet_function_address); //0x006F55E0
asm.Call_EAX();

asm.Popad();
asm.Ret();
asm.RunAsm();


Спасибо всем кто помогал.

A117
04.10.2013, 23:17
Как заставить персонажа двигаться? В фреймворке не нашел ничего похожего на перемещение.

dimonpw2
03.01.2014, 21:39
Вопрос, что я тут делаю не так?

string[] Value = new string[this.CountNPC];
for (int i = 0; i < this.CountNPC; i++)
{
Value[i] = memory.ChainReadString_Unicode(0xB8FBCC, 50, 0x1C,0x1C, 0x24, 0x18, (i * 4),0x4, 0x260, 0);
}
return Value;
Нужно сканировать область на NPC\Мобы, но в результате выводит пустые строки.
Воспользовался библиотекой PWFrameWork 2.0. Версия клиента 1.4.6, офсеты брал с этой темки. На офе получилось соответственно с офсетами под 1.5.0. А под 1.4.6 не хочет. Перепробовал множество вариантов цепочек, после цифры "50" вставлять 1 раз "0х1С", i умножать на "0x4", но все-ровно.
Заранее спасибо.

phoenixusa
12.01.2014, 21:20
см. тут [Ссылки могут видеть только зарегистрированные и активированные пользователи]

VitMitS
12.05.2014, 13:49
Народ перерыл весь форум, почему решил спросить тут - тоже пишу в Net.
Не могу понять как поставить перса на медитацию (страна грез)
Проблема в том что я относительно новичек в данной области. Перечитал много по Cheat Engine, ollydbg, мозги взрываются и не черта не пойму. По сути я пытался поймать пакет который отправляется при запуске медитации.
у меня есть функция чесно украденная с бота PW_TARAKAN (конечно переписанная), на отправку пакетов.

Public Shared Sub SendPacket(ByVal packet As Byte(), ByVal pid As Integer)
If packet.Length > 0 Then
Dim num As Integer
Dim buffer As Byte()
Dim bytes As Byte()
Dim ptr2 As IntPtr
Dim ptr As IntPtr = WinAPI.OpenProcess(ProcessAccessFlags.All, False, pid)
Dim VirtualAE = WinAPI.VirtualAllocEx(ptr, 0, &H9C4, AllocationType.Commit, MemoryProtection.ReadWrite)
Dim WritePM = (VirtualAE + &H7D0)
WinAPI.WriteProcessMemory(ptr, WritePM, packet, packet.Length, num)
buffer = New Byte() {&H60, &HB8, &HE0, &H55, &H6F, 0, &H8B, 13, &H6C, &H8B, &HC3, 0, &H8B, &H49, &H20, &HBF, 0, 0, 0, 0, &H6A, 0, &H57, &HFF, &HD0, &H61, &HC3}
bytes = BitConverter.GetBytes(Offsets.F_SEND_PACKET)
Array.Copy(bytes, 0, buffer, 2, 4)
bytes = BitConverter.GetBytes(Offsets.BA)
Array.Copy(bytes, 0, buffer, 8, 4)
bytes = BitConverter.GetBytes(WritePM)
Array.Copy(bytes, 0, buffer, 16, 4)
bytes = BitConverter.GetBytes(packet.Length)
Array.Copy(bytes, 0, buffer, 21, 1)
WinAPI.WriteProcessMemory(ptr, VirtualAE, buffer, &H1B, num)
WinAPI.CreateRemoteThread(ptr, IntPtr.Zero, 0, VirtualAE, IntPtr.Zero, 0, ptr2)
WinAPI.VirtualFreeEx(ptr, VirtualAE, &H1B, FreeType.Release)
End If
End Sub


Научился заходить на локу. выходить с локи,
полностью написал свой ГЕО, со старцем, школьным учителем, волченком, в общем со всей рутиной в мире, осталось только загнать перса на медитацию по завершению всей рутины. Научите пожалуйста. :sad:

x3max
16.05.2014, 19:14
В контейнере C22 (0x22):
{00, 0x86, 00, 00, 00, 00, 0x01} - включить медитацию в Грёзах
{00, 0x86, 00, 00, 00, 00, 00} - выключить

VitMitS
14.06.2014, 23:36
Вот тут надо по править: Я в ассемблере не очень,

public void Call_EDX()
{
this.Asmcode = this.Asmcode + "FFD2";
}

public void Call_ESI()
{
this.Asmcode = this.Asmcode + "FFD2";
}

2 разные команды с одним кодом, там кстати такое часто встречается, буду сюда писать, сам не знаю как исправить.


public void Lea_EAX_DWORD_Ptr_EAX_Add(int addre)
{
if ((addre <= 127) && (addre >= -128))
{
this.Asmcode = this.Asmcode + "8D40" + intTohex(addre, 2);
}
else
{
this.Asmcode = this.Asmcode + "8D80" + intTohex(addre, 8);
}
}
public void Lea_EAX_DWORD_Ptr_ESP_Add(int addre)
{
if ((addre <= 127) && (addre >= -128))
{
this.Asmcode = this.Asmcode + "8D40" + intTohex(addre, 2);
}
else
{
this.Asmcode = this.Asmcode + "8D80" + intTohex(addre, 8);
}
}

Smertig
14.06.2014, 23:50
public void Call_ESI()
{
this.Asmcode = this.Asmcode + "FFD2";
}
"FFD6"

public void Lea_EAX_DWORD_Ptr_ESP_Add(int addre)
{
if ((addre <= 127) && (addre >= -128))
{
this.Asmcode = this.Asmcode + "8D4424" + intTohex(addre, 2);
}
else
{
this.Asmcode = this.Asmcode + "8D8424" + intTohex(addre, 8);
}
}

krukovis
15.06.2014, 09:07
Если так исправить, то получается что тут задваивается:


public void Lea_EAX_DWORD_Ptr_ESP_Add(int addre)
{
if ((addre <= 127) && (addre >= -128))
{
this.Asmcode = this.Asmcode + "8D4424" + intTohex(addre, 2);
}
else
{
this.Asmcode = this.Asmcode + "8D8424" + intTohex(addre, 8);
}
}

public void Lea_EAX_DWORD_Ptr_EBP_Add(int addre)
{
if ((addre <= 127) && (addre >= -128))
{
this.Asmcode = this.Asmcode + "8D4424" + intTohex(addre, 2);
}
else
{
this.Asmcode = this.Asmcode + "8D8424" + intTohex(addre, 8);
}
}

Smertig
15.06.2014, 14:24
Для
public void Lea_EAX_DWORD_Ptr_EBP_Add(int addre)
this.Asmcode = this.Asmcode + "8D4424" + intTohex(addre, 2);
8D4501

this.Asmcode = this.Asmcode + "8D8424" + intTohex(addre, 8);
8D8511

Вообще, это можно смотреть через OllyDbg/Cheat Engine.

krukovis
16.06.2014, 09:39
Вообще, это можно смотреть через OllyDbg/Cheat Engine.
Конечно можно. Но у тебя ж это под рукой все.

Fess88
29.06.2014, 19:54
Подскажите, с помощью данного фреймворка можно отправлять пакеты на покупку-продажу чего-либо на ауке?

Vbrz
30.06.2014, 15:26
//Быть интимным хз что

Вообще-то это целоваться =)

//Положить что то джину (видимо камни, чтобы джин мог использовать свои скилы)
public static byte[] FeedEquippedGenie(int cellIndex, int itemAmount)

А это переводится как "покормить джина" Тт То есть заправить.

Хорошая тема по пакетам тут есть, видимо во много оттуда и взято:
[Ссылки могут видеть только зарегистрированные и активированные пользователи]

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

fenix2559
07.08.2014, 19:52
Помогите. Нужно найти ресурсы в опредёлнном радиусе.

bestbeer
27.09.2014, 18:49
Пытаюсь юзать инжект скила исспользуя переписанный фрейм.

Delphi:
CallAddress:=Pointer($0047CBF0);
P1:=aPParams^.Param1;//DWord скил
Po1:=Pointer(P1);//pointer
asm
pushad

MOV ECX,DWORD PTR DS:[$0C9DFAC]
MOV EDX,DWORD PTR DS:[ECX+$1C]
MOV ESI,DWORD PTR DS:[EDX+$30]

push -1 // -1
push 0
push 0

mov ecx,Po1 // указатель на скил
push ecx

mov ecx,esi

CALL CallAddress

popad
end;


Vb:
Injector.Clear()

Injector.Pushad()

Injector.Mov_ECX_DWORD_Ptr(&HC9DFAC)
Injector.Mov_EDX_DWORD_Ptr_ECX_Add(&H1C)
Injector.Mov_ESI_DWORD_Ptr(&H1C + &H30)

Injector.Push68(-1)
Injector.Push6A(0)
Injector.Push6A(0)

Injector.Mov_ECX_DWORD_Ptr(113)

Injector.Push_ECX()

Injector.Mov_ECX_ESI()

Injector.Call_DWORD_Ptr(&H47CBF0)

Injector.Popad()
Injector.Ret()

Injector.RunAsm()

Дыбы выявить проблему тестил инжект на ассист - проблем нет. Инжект на скил крашит клиент, реализация в дельфи рабочая. Что может быть не так?

Desmond Hume
27.09.2014, 21:47
Пытаюсь юзать инжект скила исспользуя переписанный фрейм.

Delphi:
CallAddress:=Pointer($0047CBF0);
P1:=aPParams^.Param1;//DWord скил
Po1:=Pointer(P1);//pointer
asm
pushad

MOV ECX,DWORD PTR DS:[$0C9DFAC]
MOV EDX,DWORD PTR DS:[ECX+$1C]
MOV ESI,DWORD PTR DS:[EDX+$30]

push -1 // -1
push 0
push 0

mov ecx,Po1 // указатель на скил
push ecx

mov ecx,esi

CALL CallAddress

popad
end;


Vb:
Injector.Clear()

Injector.Pushad()

Injector.Mov_ECX_DWORD_Ptr(&HC9DFAC)
Injector.Mov_EDX_DWORD_Ptr_ECX_Add(&H1C)
Injector.Mov_ESI_DWORD_Ptr(&H1C + &H30)

Injector.Push68(-1)
Injector.Push6A(0)
Injector.Push6A(0)

Injector.Mov_ECX_DWORD_Ptr(113)

Injector.Push_ECX()

Injector.Mov_ECX_ESI()

Injector.Call_DWORD_Ptr(&H47CBF0)

Injector.Popad()
Injector.Ret()

Injector.RunAsm()

Дыбы выявить проблему тестил инжект на ассист - проблем нет. Инжект на скил крашит клиент, реализация в дельфи рабочая. Что может быть не так?
Не юзал это фреймворк, но попробую тыкнуть пальцем в небо.
Injector.Mov_ESI_DWORD_Ptr(&H1C + &H30)
Injector.Mov_ESI_DWORD_Ptr_EDX_Add(&H30)

bestbeer
27.09.2014, 22:08
Не юзал это фреймворк, но попробую тыкнуть пальцем в небо.
Injector.Mov_ESI_DWORD_Ptr_EDX_Add(&H30)

Такого в фрейме нет.

Smertig
28.09.2014, 00:06
Injector.Mov_ECX_DWORD_Ptr(113)
?!
Это что? Аналог строки:
mov ecx,Po1 // указатель на скил
?

Если там указатель, то 113 - явно не то значение. Если именно ID скилла, то ладно.


Injector.Push68(-1)
Injector.Push6A(0)
Injector.Push6A(0)

Injector.Mov_ECX_DWORD_Ptr(?!?!) // советую точно понять, что туда передаётся

Injector.Push_ECX()

Injector.Mov_ECX_DWORD_Ptr(&HC9DFAC)
Injector.Mov_ECX_DWORD_Ptr_ECX_Add(&H1C)
Injector.Mov_ECX_DWORD_Ptr_ECX_Add(&H30)

Injector.Mov_EAX_DWORD(&H47CBF0) // можно использовать вариант и как у вас, но я сомневаюсь, что инжектор просчитывает относительную адресацию в памяти
Injector.Call_EAX()

bestbeer
28.09.2014, 02:57
?!
Это что? Аналог строки:
mov ecx,Po1 // указатель на скил



Injector.Mov_ECX_DWORD_Ptr(113)


"B971000000" (строка из фрейма)

Также я не совсем понимаю как в клиенте генерируется такие байты "683CF9FF" , они всегда одинаковы и не меняются.

Код из олидебагера:

004E8F83 |. E8 683CF9FF CALL 0047CBF0 ; \elementclient.0047CBF0


Тоже но из фрейма:
Injector.Call_Adr(&H47CBF0)

"E8F0CB4700"

Остальное сходится. (Pushad(), Injector.Popad(), Injector.Ret() я не сверял.)

Также я добавил в фрейм недостающую операцию"Mov_ESI_DWORD_Ptr_EDX_Add" думаю она необходима.

vb:
Public Sub Mov_ESI_DWORD_Ptr_EDX_Add(addre As Integer)
If (addre <= 127) AndAlso (addre >= -128) Then
Me.Asmcode = Me.Asmcode & "8B72" & intTohex(addre, 2)
Else
Me.Asmcode = Me.Asmcode & "8BB2" & intTohex(addre, 8)
End If
End Sub

krukovis
28.09.2014, 10:30
Основная цель класса ASM - генерировать опкод - массив байт, который потом инжектится. В Delphi класс ASM не нужен, т.к. там Делфи умеет воспрнимать Ассемблер и сам переводит его в опкод, который потом и инжектится. Этот опкод должен точно совпадать с функцией из клиента, меняться могут только параметры функции. Например номер скилла или координаты или еще что. Вы можете открыть OllyDbg и вписать туда функцию на Delphi - они пишутся на Ассемблере и их написать не сложно. Олька переведет эту функцию в опкод и вы сможете сравнить этот опкод с тем, что генерирует ваш класс ASM. Если все совпадает - значит функция написана правильно. Если не совпадает, значит у вас где то ошибка. И ее лекго можно обнаружить просто глазами.

bestbeer
29.09.2014, 03:19
Вобщем я сумел понять свои ошибки.(а может и не сумел :d и мне повезло.)

Вобщем нужно добавить в фрейм функцию "Mov_ESI_DWORD_Ptr_EDX_Add" и немного изменить сам инжект.

vb:
Injector.Clear()

Injector.Pushad()

Injector.Mov_ECX_DWORD_Ptr(&HC9DFAC)

Injector.Mov_EDX_DWORD_Ptr_ECX_Add(&H1C)

Injector.Mov_ESI_DWORD_Ptr_EDX_Add(&H30)

Injector.Push6A(&HFF) '-1

Injector.Push6A(0)

Injector.Push6A(0)

Injector.Mov_ECX(113)

Injector.Push_ECX()

Injector.Mov_ECX_ESI()

Injector.Mov_EDI(&H47CBF0)

Injector.Call_EDI()

Injector.Popad()
Injector.Ret()

Injector.RunAsm()

Вот так работает.

Hilling
09.01.2015, 13:27
Подскажите пожалуйста как в АСМ классе значения с типом uint использовать? Там все MOV-функции в качестве параметров тип int принимают. А мне, например, надо wid моба затолкать, который в int не поместится. Я, конечно, поменял его на uint, но сдается мне это некорректно. Мне неизвестно как в этом случае следующие функции нужно поменять (и нужно ли вообще):

private string hex(int address)
{
string str = address.ToString("X");
return str;
}

public string intTohex(int value, int num)
{
string str1 = null;
string str2 = "";
str1 = "0000000" + this.hex(value);
str1 = str1.Substring(str1.Length - num, num);
for (int i = 0; i <= str1.Length / 2 - 1; i++)
{
str2 = str2 + str1.Substring(str1.Length - 2 - 2 * i, 2);
}
return str2;
}

Кто сталкивался - не оставайтесь безучастны :sceptic:

Smertig
09.01.2015, 16:24
Подскажите пожалуйста как в АСМ классе значения с типом uint использовать? Там все MOV-функции в качестве параметров тип int принимают.
Перевести это число в int (может стать отрицательным, ничего страшного) и послать в MOV. В памяти числа отличаются только размером (1, 2, 4 байта), но выглядят совершенно одинаково.
К примеру, 0xFFFFFFFF - это -1, если int, или 2^32-1, если uint. Но в памяти это один и тот же 0xFFFFFFFF

Arsen0208
30.04.2016, 23:03
Вопрос по поводу Packet. Если ввести правильный IDшник то все работает но у мобов (даже у мобов на одной поляне) разные IDшники. Не подскажете как прочитать именно имя моба?

Hilling
01.05.2016, 01:33
Так же как и ID, только считываешь строку. Так же считываешь д оструктуры моба, только вместо смещения ID подставляешь смещение имени. Раньше было +288 +0. Проверяешь по имени нужный это тебе моб или нет. Если да, то считываешь у этого же моба WID и подставляешь в пакет.

Arsen0208
01.05.2016, 02:42
Фигня в том что ID я получаю вот так:
return memory.ReadInt32(this.Structure + PWOffssAndAddrss.host_player_target_wid_offset);

Но не вкурсе существует ли оффсет Имени Таргета. Искать через СЕ тоже не варик я так понял.
Думал может сделать отдельный класс под монстра с его структурой и использовать его как и класс ХостПлэера но не понял что там со структурой Мобов.

P.S. ботовод-самоучка, могу нести бред не понимая этого./dgs

sabbaot01
21.05.2016, 20:37
простите за нубский вопрос. это на каком языке? c++ или c#
не понимаю с чего начать, если ни разу не программер, но что-нибудь создать хочется, в виде джинокача или геобота

krukovis
22.05.2016, 09:14
Это на C#. Это утилита для среднего уровня программирования. Там возможно уже все устарело, т.к. писалось несколько лет назад. А может и нет. Я давно отошел от разработок под PW. Вообще удивлен, что это кому-то еще интересно. А не проще воспользоваться уже написанным готовым софтом. Ребята же постоянно что-то выкладывают. Были раньше и платные программы достаточно хорошего уровня.

Hilling
22.05.2016, 12:54
Фрейморк хороший, понравилась структура и вообще работа с ним в целом. За что огромное спасибо автору. Однако пришлось практически отказаться от работы с ним, так как запущенные программы, после пары часов работы, крашили клиент игры. Либо я рукожоп, либо с памятью что-то. Скорее первое. Как-то так.

В целом он не устарел, оффсеты/адреса поменять и вперед.

krukovis
23.05.2016, 10:27
NoobSaibot писал про какие то проблемы при работой с памятью в самом начале обсуждения и приводил даже код исправления. Я не помню устранил я их или нет. Можете попробовать посмотреть его посты и посмотреть устранены ли проблемы.

Hilling
23.05.2016, 18:28
Я пробовал менять. Но за данным исправлением потянулась целая цепочка других исправлений. В общем, ничего у меня не вышло :)