PDA

Просмотр полной версии : [Информация] Инжектим на C#| Injection on C#


krukovis
20.06.2012, 22:14
Добрый день!
Считается что C# сложнее для использования инжектов чем Delphi. Хочу раз и навсегда развеять этот миф.

Проблема часто в том, что в C# нет встроенного asm-а, а практически все примеры функций для внедрения выкладываются на Delphi. И каждый программист придумывает для себя свои способы для внедрения байт-кода в процесс игры. Для этой цели существует класс ASM для C#. Он абстрагирует программиста от байт-кода и заменяет его привычными командами asm-а. Чем облегчает жизнь и новичков и тех кто уже пожил.

Хочу с вами поделиться этим классом. Он облегчает перевод функций написанных на Delphi и других языках где есть встроенный asm(С++, Power Basic и др.) .
Чтобы не грузить объяснениями я добавил этот класс в PW FrameWork (а так же добавил несколько функций в него и пару переделал для личных и возможно в будущем ваших целей) и добавил в решение Демо проект по использованию Инжекта на C#, а так же пример функции на Delphi и ее перевод на C# с использованием класса ASM.

Итак во вложении Пример использования класса ASM для Инжекта и PW FrameWork (с моими правками и классом ASM).

Всем комфортного кодинга!

vogel
21.06.2012, 00:29
FASM_Managed ? BlackMagic ?

samosi
21.06.2012, 15:52
krukovis вот у меня вопрос а как передать UInt значение так как wid его требует а в int не влезет wid.
Вот код

private void PickWall(int wid, int type)
{
int intProcID = this.ProcessID;
int Address = 0x0489470;

asm.Pushad();
asm.Mov_EAX(BaseAddress);
asm.Mov_EAX_DWORD_Ptr_EAX();
asm.Mov_EAX_DWORD_Ptr_EAX_Add(0x1c);
asm.Mov_ESI_DWORD_Ptr_EAX_Add(0x34);
asm.Mov_EAX(type);
asm.Push_EAX();
asm.Mov_EDX(wid);//Вот тут та и должно дыть uint а если эго поставить оно орет.
asm.Push_EDX();
asm.Mov_EDX(Address);
asm.Call_EDX();
asm.Popad();
asm.Ret();
asm.RunAsm(intProcID, 0);
}

krukovis
21.06.2012, 16:02
krukovis вот у меня вопрос а как передать UInt значение так как wid его требует а в int не влезет wid.
У меня нормально работало с int.
Вот старая функция:
/// <summary> Поднятие лута и Копка ресурсов(переделано) </summary>
/// <param name="ItemWorldID">WorldID ресурса (SN)</param>
/// <param name="ItemType">Type ресурса (0-лут, 1-шахта)</param>
///
public void PickLoot(int ItemWorldID, int ItemType)
{
int intProcID = ProcessID;
int CallAddress = 0x469b40;
//ASM asm = new ASM();
asm.Pushad();
asm.Mov_ECX_DWORD_Ptr(BaseAddress);
asm.Mov_ECX_DWORD_Ptr_ECX_Add(0x1c);
asm.Mov_ECX_DWORD_Ptr_ECX_Add(0x34);
asm.Push68(ItemType);
asm.Push68(ItemWorldID);
asm.Mov_EAX(CallAddress);
asm.Call_EAX();
asm.Popad();
asm.Ret();
asm.RunAsm(intProcID, 0);
}

Добавлено через 2 минуты
Считывай WID в int и передавай в int. Просто у тебя WID будет отрицательное. Но какая разница. Все нормально отрабатывает.

samosi
21.06.2012, 16:06
Теперь уже понял как обращаться с инжектами на C#. Благодарствую.

Добавлено через 5 минут
krukovis, Вот у меня почему то оно ругаеца что wid uint а вот и сам он 3222277307. В чем может быть проблема.

Добавлено через 9 минут
Так все понял. Надо из игры читать вид как инт. Все работает спс.

krukovis
21.06.2012, 16:20
krukovis, Вот у меня почему то оно ругаеца что wid uint а вот и сам он 3222277307. В чем может быть проблема.
А моя функа работает? Не забудь адрес только поправить на сегодняшний перед тестом.
Проблема в том, что не работает класс ASM с UInt, только с Int или Int32. Передавай в функцию int wid. И считывай MemoryManager.ReadInt. И все будет работать.

Добавлено через 3 минуты
Или конвертируй в Int тут:
asm.Mov_EDX(wid);//Вот тут та и должно дыть uint а если эго поставить оно орет.
меняй на:
asm.Mov_EDX(Convert.ToInt32(wid));

phoenixusa
16.07.2012, 11:10
Движение по координатам, в режиме полета - перс самостоятельно не встает на полет, это у меня косяк или это не закладывалось? (использую твой пример с инжектом)

krukovis
16.07.2012, 11:28
Движение по координатам, в режиме полета - перс самостоятельно не встает на полет, это у меня косяк или это не закладывалось? (использую твой пример с инжектом)
Сам на полет не встает. И в зависимости от того на полете или пешком не меняет режим walk_mode - пешком или на полете. Показано только движение по координатам как самая сложная функция для перевода из ассемблера в методы класса ASM.

/GeG/
22.07.2012, 22:50
Хотел сделать с помощью этого инжекта что-то типа прогулки по вейпоинтам. Но прописав несколько WalkTo, персонаж идёт только в одно место. Подскажите, как можно реализовать такую "прогулку по вейпоинтам".

krukovis
22.07.2012, 23:19
Хотел сделать с помощью этого инжекта что-то типа прогулки по вейпоинтам. Но прописав несколько WalkTo, персонаж идёт только в одно место. Подскажите, как можно реализовать такую "прогулку по вейпоинтам".
Может надо это делать в цикле?
Алгоритм м.б. примерно такой:
Пока не дошли до точки 1 - идем в эту точку.
Как дошли - идем во вторую.
...
Пока не дойдем до последней.

fatalistik
05.08.2012, 10:36
krukovis, Подскажи пожалуйста, как правильно пользоваться классом OffsetRetriever (как я понимаю, он нужен для поиска оффсетов в файле elementclient.exe, верно?)?

krukovis
05.08.2012, 11:29
krukovis, Подскажи пожалуйста, как правильно пользоваться классом OffsetRetriever (как я понимаю, он нужен для поиска оффсетов в файле elementclient.exe, верно?)?

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

whoami
19.09.2012, 13:32
krukovis, на самом деле, он ищет не в процессе, а в файле elementclient.exe на диске, зоторый был запущен :) Нужен для поиска оффсетов и адресов по шаблонам. Например, некий оффсет меняется от версии к версии, но в коде клиента различных версий используется всегда в одной и той же последовательности команд, например:
PUSH ECX
XOR ECX, ECX
MOV EAX, [EDX+OFF_1]

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

Вообще, класс ASM полезный, но слишком сильно дублирует возможности MemoryManager2. Я бы сделал класс, который вообще ничего не знает о процессах, тупо сериализует ассемблерные команды в массив байт, который потом можно было бы записать в память процесса через MemPtr.Bytes, и выполнить с помощью MemPtr.CreateRemoteThread()

krukovis
19.09.2012, 16:49
krukovis, на самом деле, он ищет не в процессе, а в файле elementclient.exe на диске, зоторый был запущен
Да, когда я писал, я думал что он ищет в открытой памяти процесса, а когда решил использовать в проекте PerfectAutoLogin, оказалось, что в файле. Это очень не удобно, если на elementclient навешена обертка - такое часто встречается на фришках.
Я дописал в класс OffsetRetriever несколько методов для работы с открытой памятью. Добавил поиск не только смещений, но еще и адресов функций для инжектов. Пример работы можно посмотреть в PerfectAutoLogin последней версии. Исходники последней версии PWFrameWork могу кинуть в личку. Но это все равно не конечный вариант. Хочу еще улучшить - переводить байт-код в строку и уже эту строку разбирать с помощью регулярных выражений. Мне кажется это должно быть быстрее и позволит составлять маски любой сложности и более гибко. Если есть какие то мысли по этому поводу - прошу озвучить.
Ты больше ничего не делал с фреймворком?
Можешь откомментировать класс MemoryManager2?


Вообще, класс ASM полезный, но слишком сильно дублирует возможности MemoryManager2. Я бы сделал класс, который вообще ничего не знает о процессах, тупо сериализует ассемблерные команды в массив байт, который потом можно было бы записать в память процесса через MemPtr.Bytes, и выполнить с помощью MemPtr.CreateRemoteThread()
Я не понимаю в чем дублирование MemoryManager2. Поясни плиз. Класс ASM как раз ничего не знает о процессах, а просто переводит псевдо-ассемблерные команды в байт код, а уже потом инжектит его.

В данные момент у меня новая версия класса ASM и новый класс для работы с памятью, вместо MemoryManager. Я переписал MemoryManager для работы с несколькими окнами и добавил несколько дополнительных свойств.

Все это было нужно чтобы решить большую проблему при внедрении своего кода в процесс игры. При инжекте кода в процесс игры, через какое то время, память перестает выделяться и инжекты перестают работать. Чтобы решить эту проблему - я переписал класс для работы с памятью. Теперь память у меня выделяется один раз - при открытии памяти и вся работа с памятью строится на работе с этой выделенной страницей. Так же я добавил возможность работы с несколькими окнами.

В паблик пока тоже не выкладывал. Если кому нужно - могу кинуть в личку. Просьбы, соответственно, тоже прошу направлять в ЛС.

whoami
26.09.2012, 14:46
krukovis, регулярные выражения для таких задач - слишком медленные. Хоть и мощная штука.
MemoryManager - это было в самой первой версии PWFW, сделано первоначальным разработчиком библиотеки =) Я её почти не трогал, оставил для совместимости. MemoryManager2 - более удобная штука, плюс позволяет работать с несколькими процессами (в т.ч. с текущим) одновременно, с внутриигровыми списками, мэпами и т.д.
А чтобы память не переставала выделяться - её надо освобождать :)

krukovis
26.09.2012, 15:13
krukovis, регулярные выражения для таких задач - слишком медленные. Хоть и мощная штука.
Ну в общем да :). Я уже подумал в эту сторону, провел эксперименты и отказался.


MemoryManager - это было в самой первой версии PWFW, сделано первоначальным разработчиком библиотеки =) Я её почти не трогал, оставил для совместимости.
Эт я в курсе ). По этому поводу вопроса не было.
MemoryManager2 - более удобная штука, плюс позволяет работать с несколькими процессами (в т.ч. с текущим) одновременно, с внутриигровыми списками, мэпами и т.д.
Вот я и прошу тебя откомментировать код, чтобы было более менее понятно как пользоваться. Потому что на данный момент слабо понятно.

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

half-node
27.09.2012, 21:28
Извините за, может быть, глупый вопрос. Но я совместил руководство по созданию бота с данным проектом. И у меня, возникла определенная трудность на этапе получения данных с клиента.

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

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

Руководство пишет следующее:

DWORD READER::MobStruct(int nom)
{
DWORD buff;
buff = Read_32(BA);
buff = Read_32(buff+D_GA);
buff = Read_32(buff+M_D1);
buff = Read_32(buff+M_D2);
buff = Read_32(buff+M_STRUCT);
buff = Read_32(buff+nom*0x4);
if (buff!=0) return Read_32(buff+0x4); // если значение не 0, значит этот моб существует, вернём адрес его структуры
return 0; //иначе вернём 0
}


В текущем проекте я реализовал это так:

public Int32 MobStruct(int num)
{
Int32 buff;
buff = (m[BaseAddress].Int32 + GameAddress);
buff = (m[buff].Int32 + M_D1);
buff = (m[buff].Int32 + M_D2);
buff = (m[buff].Int32 + HostMobStruct);
buff = (m[buff].Int32 + num * 0x4);

// Если это моб.
if (buff != 0)
{
buff = (this.m[buff].Int32 + 0x4);
return buff;
}
return 0;
}


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

У меня совсем все плохо? :)

krukovis
27.09.2012, 23:03
Извините за, может быть, глупый вопрос. Но я совместил руководство по созданию бота с данным проектом. И у меня, возникла определенная трудность на этапе получения данных с клиента.
Рекомендую ознакомиться с [Ссылки могут видеть только зарегистрированные и активированные пользователи] Там есть примеры по чтению данных из клиента.

half-node
28.09.2012, 02:16
Ох, спасибо большое за ссылку.

Meefki
08.07.2020, 18:01
:ban::ban::ban:Такое огромное спасибо хочется сказать человеку:notme: