Comments 61
UFO just landed and posted this here
Продолжайте, очень интересно посмотреть на эмуляцию поведения.
0
А вот у меня есть вопросик из соседней области: а как бы вывести свои какие-то данные прямо в игровом окне (или поверх) в полноэкранном режиме? Например какую-то картинку. Ибо в полноэкранном режиме может быть только одно окно. Может как-то после того, как игра отрисует свою сцену, можно к сцене добавить, например, какой-то полигончик с текстуркой?
0
Насколько я знаю софт который использует OSD(on-screen display)/Screen overlay работает или напрямую с видеобуфером, или инжектится в вызовы direct3d.
0
если речь идет о вмешательстве в игровой процесс, то незаметного способа в полноэкранном режиме нет. Незаметный же способ в общем случае — обычно достают всю информацию о сцене через ReadProcessMemory, и необходимую информацию (например положение остальных игроков) рисуют на втором окне (отдельное приложение), которое располагается поверх основного, имеет прозрачную форму, находится в топе, не имеет границ и фокуса. При этом основное окно, чаще всего можно сделать тоже borderless, приближаясь по картинке к fullscreen.
+1
В принципе можно, но будет кривовато. Для этого перехватываем например Present, который отвечает за вывод буфера на экран:
STDMETHOD(Present)(THIS_ CONST RECT* pSourceRect,CONST RECT* pDestRect,HWND hDestWindowOverride,CONST RGNDATA* pDirtyRegion) PURE;
Затем вызываем BeginScene, рисуем, вызываем EndScene и наконец вызываем оригинальный Present.0
Интересно, к чему вся эта интрига с ручным рассчетом адресов и ассемблером, если можно взять Detours или madCodeHook и вешать хуки просто по именам функций или методов интерфейсов.
0
Мой знакомый однажды в своих целях спрятал все текстуры в LA2, чтобы можно было видеть игроков сквозь стены и ограды (от них остались только остовные деревья). Поделился с людьми — обвинили в кейлоггерстве или вроде того, расстроился и больше никогда ни с кем не делился =\
+2
Так тут серия статей намечается чтобы вы сами могли себе сделать. Свой код в кейлоггерстве не обвинишь.
0
Насколько я помню, текстуры легко отключались переключением рендерера в wireframe режим, вполне штатный для движка. Другое дело, что для правки конфига нужно было знать приватный RSA ключ, который, впрочем, на 99% фришек был дефолтный.
0
Кто может помочь восстановить алгоритм одной небольшой функции из сишной библиотеки? Самому к сожалению не хватает знаний ASM/C чтобы разобрать псевдокод полученный в Ida. Извините за оффтоп.
-7
Вам на toster.ru
+3
Попробуйте плагин Hex-Rays
0
Его и использовал, получил
Но не все в нем понимаю, например что значат ~ перед переменными, что за byte_4004(просто еще одна переменная?) и тд.
псевдокод
//----- (00000CBC) --------------------------------------------------------
int __fastcall kEncode(int a1, int a2, int a3, int a4)
{
int v4; // r3@2
if ( a1 == 1 )
v4 = crc((const char *)a2, (const char *)a3, (char *)a4);
else
v4 = 1;
return v4;
}
//----- (00000D0C) --------------------------------------------------------
int __fastcall crc(const char *a1, const char *a2, char *a3)
{
size_t v3; // r3@10
char *v5; // [sp+4h] [bp-28h]@1
const char *v6; // [sp+8h] [bp-24h]@1
const char *v7; // [sp+Ch] [bp-20h]@1
signed int v8; // [sp+10h] [bp-1Ch]@1
size_t v9; // [sp+14h] [bp-18h]@1
unsigned int v10; // [sp+18h] [bp-14h]@12
char *s; // [sp+1Ch] [bp-10h]@1
signed int v12; // [sp+20h] [bp-Ch]@1
unsigned int n; // [sp+24h] [bp-8h]@12
v7 = a1;
v6 = a2;
v5 = a3;
v8 = -1;
v9 = -1;
s = 0;
v12 = 0;
while ( v12 <= 2 )
{
if ( (signed int)v9 <= 0 )
{
++v12;
if ( v12 == 1 )
{
s = (char *)v7;
v9 = strlen(v7);
}
else if ( v12 == 2 )
{
s = (char *)v6;
v9 = strlen(v6);
}
}
else
{
s += v9;
}
if ( v12 <= 2 )
{
v3 = v9;
if ( (signed int)v9 >= 20480 )
v3 = 20480;
n = v3;
memcpy(byte_4004, s, v3);
v10 = n;
while ( v10 )
{
--v10;
if ( !(v10 & 1) )
byte_4004[v10] = ~byte_4004[v10];
}
v8 = make_crc(v8, (int)byte_4004, n);
v9 -= n;
}
}
sprintf(v5, (const char *)&unk_25FC, v8);
return 0;
}
//----- (00000EE4) --------------------------------------------------------
int make_crc32_table()
{
unsigned int v1; // [sp+4h] [bp-10h]@2
signed int i; // [sp+8h] [bp-Ch]@1
signed int j; // [sp+Ch] [bp-8h]@2
for ( i = 0; i <= 255; ++i )
{
v1 = i;
for ( j = 0; j <= 7; ++j )
{
if ( v1 & 1 )
v1 = (v1 >> 1) ^ 0xEDB88320;
else
v1 >>= 1;
}
crc32_table[i] = v1;
}
return 0;
}
// EE4: using guessed type int make_crc32_table(void);
//----- (00000FC4) --------------------------------------------------------
int __fastcall make_crc(int a1, int a2, unsigned int a3)
{
unsigned int v4; // [sp+4h] [bp-20h]@1
int v5; // [sp+8h] [bp-1Ch]@1
int v6; // [sp+Ch] [bp-18h]@1
unsigned int i; // [sp+14h] [bp-10h]@3
v6 = a1;
v5 = a2;
v4 = a3;
if ( !initcrc )
{
initcrc = 1;
make_crc32_table();
}
for ( i = 0; i < v4; ++i )
v6 = crc32_table[(unsigned __int8)(*(_BYTE *)(v5 + i) ^ v6)] ^ ((unsigned int)v6 >> 8);
return ~v6;
}
// EE4: using guessed type int make_crc32_table(void);
Но не все в нем понимаю, например что значат ~ перед переменными, что за byte_4004(просто еще одна переменная?) и тд.
0
А почему вам так не нравится подход со сканированием пикселей и имитацией нажатий? Грамотная реализация, особенно если заменить сканирование экрана на прослушку трафика (я в свое время через pcap делал), вычисляется только анализом поведения. Напротив, взаимодействие с процессом вычисляется защитой на раз-два, зачастую даже без хуков на уровне драйвера ядра.
-2
Просто потому, что пиксели — это гадание на кофейной гуще (особенно если в игре есть погода и время суток), трафик — несомненно информативен, но read only, а имитация занимает полностью ваш ПК и что бы работать на нем Вам понадобиться виртуальная машина, которая съест дополнительно 2Гб RAM и 40Гб HDD, а если два окна или 3? Даже при грамотной реализации, это все трудоемко и не надежно. А вот вычислить защитой можно все на самом деле и здесь главное уметь хорошо прятать — о чем я тоже буду писать
0
Позвольте уточнить, трафик read-only только в случае с pcap.
Как минимум, трафик можно редактировать посредством прокси(из готовых решений — тот же WPF-или-как-там-его-и-его-аналоги). Защита от подобных программ далеко не всегда работает, взять тот же Hackshield в Archeage. Кроме того, это — довольно универсальный способ.
Кроме того, зачастую довольно удобно управлять поведением игры при помощи упомянутого dll-inject'а и перехватом нужных функций. Это, кстати говоря, решает проблему с окнами — dll много памяти не скушает, всю работу, по факту, выполняет клиент. Кроме того, если у клиента нет проверки на checksum, а защита не расчитана на подобные экзерсисы, можно поправить таблицу импорта и подгружать dll уже на старте приложения, а не перетыкать ее инжектором.
Еще довольно неплох в плане подхода micromacro — есть базовые функции для работы с памятью, а вся логика строится на lua/xml(код/путевые точки). Главный минус — вряд ли будет работать с адекватной защитой.
Со сканированием пикселей — согласен, сам такой подход не пробовал, но для комплексных задач представляется довольно сложным в реализации и несколько ограниченным в функционале.
За способ, описанный в статье, отдельное спасибо(особенно — за шарп), интересный подход. Еще вместо расчета офсета вручную можно было бы применить GetProcAddress, но это работает только для экспортированных функций.
И по поводу следующих статей — однозначно писать!
Как минимум, трафик можно редактировать посредством прокси(из готовых решений — тот же WPF-или-как-там-его-и-его-аналоги). Защита от подобных программ далеко не всегда работает, взять тот же Hackshield в Archeage. Кроме того, это — довольно универсальный способ.
Кроме того, зачастую довольно удобно управлять поведением игры при помощи упомянутого dll-inject'а и перехватом нужных функций. Это, кстати говоря, решает проблему с окнами — dll много памяти не скушает, всю работу, по факту, выполняет клиент. Кроме того, если у клиента нет проверки на checksum, а защита не расчитана на подобные экзерсисы, можно поправить таблицу импорта и подгружать dll уже на старте приложения, а не перетыкать ее инжектором.
Еще довольно неплох в плане подхода micromacro — есть базовые функции для работы с памятью, а вся логика строится на lua/xml(код/путевые точки). Главный минус — вряд ли будет работать с адекватной защитой.
Со сканированием пикселей — согласен, сам такой подход не пробовал, но для комплексных задач представляется довольно сложным в реализации и несколько ограниченным в функционале.
За способ, описанный в статье, отдельное спасибо(особенно — за шарп), интересный подход. Еще вместо расчета офсета вручную можно было бы применить GetProcAddress, но это работает только для экспортированных функций.
И по поводу следующих статей — однозначно писать!
0
Очень напомнило, как когда-то на 2-ом курсе в качестве курсовика по ассемблеру написали с однокурсником бота, который тоже работает засчёт перехвата функций.
Как внедриться в чужой процесс брали здесь: rsdn.ru/article/baseserv/IntercetionAPI.xml#EIEAC
А вот описанный в той же статье метод перехвата не подошёл, поэтому DirectX многопоточен. Так что преподаватель подсказал сделать как в Detours (гуглить: file:huntusenixnt99.pdf).
Вот видосики, где бот играет, может и про него статью напишем: www.youtube.com/user/thbotproject/videos
Сайт бота: thbot.kt15.ru/
Теперь насчёт технических деталей: мы тоже перехватывали, руками вытаскивая offset из vtable. А потом, когда всё уже сделали, поняли, что можно было C-шное API перехватывать.
Как внедриться в чужой процесс брали здесь: rsdn.ru/article/baseserv/IntercetionAPI.xml#EIEAC
А вот описанный в той же статье метод перехвата не подошёл, поэтому DirectX многопоточен. Так что преподаватель подсказал сделать как в Detours (гуглить: file:huntusenixnt99.pdf).
Вот видосики, где бот играет, может и про него статью напишем: www.youtube.com/user/thbotproject/videos
Сайт бота: thbot.kt15.ru/
Теперь насчёт технических деталей: мы тоже перехватывали, руками вытаскивая offset из vtable. А потом, когда всё уже сделали, поняли, что можно было C-шное API перехватывать.
+8
Посмотрел видосики… Нео и Агент Смит нервно курят, глядя на эту анимешную девочку, как она проскакивает между пуль…
+8
Спасибо) Вот только тактики нашему боту не хватает, он думает про текущий момент и всё.
А про Вашего бота, конечно же, жду продолжение, ведь бот для MMORPG — это в разы интереснее!
А про Вашего бота, конечно же, жду продолжение, ведь бот для MMORPG — это в разы интереснее!
0
У шариков линейное движение, вы можете знать их траектории, вычислив их скорость по 2м точкам например и найти места где они не пролетают с учетом времени движения до этих мест и сразу двигаться к ним
0
Эх, если бы всё так просто. Вот, гляньте как движутся пульки на 1:06: youtu.be/6xWvr-TAR1w?t=1m6s
+3
Если думает только про текущий момент — как так круто получилось реализовать безумные увороты и сбор бонусов?
0
В каждый момент есть позиция, к которой бот стремится добраться. Когда на экране нет бонусов и врагов, то это заданная позиция. Когда нет бонусов и есть враги, то это позиция напротив врага, а когда есть бонусы, то это позиция одного из них.
Бот пытается в неё добраться, но при этом анализирует все пульки в небольшом радиусе вокруг себя и избегает их. Примерно так.
Бот пытается в неё добраться, но при этом анализирует все пульки в небольшом радиусе вокруг себя и избегает их. Примерно так.
0
UFO just landed and posted this here
Это всё конечно здорово, но в очередной раз про x86 и DX9.
А современный мир использует x64 и DX11.
А современный мир использует x64 и DX11.
0
Про пару магических чисел сказали, а об остальных умолчали :) Почему 5 и 7 при чтении?
0
У Вас есть 2 варианта узнать =)
- Почитать документацию по АСМу
- Дождаться следующей части
0
Видимо автор таким образом пытается определить сколько места в начале функции потребуется для записи инструкций хука, что сделано крайне некошерно
-1
Давайте будем конструктивными, как бы Вы сделали?
+1
Для таких целей используют дизассемблер длин, иначе нет никакой горантии что пролог функции не будет повреждён. Вы ведь не имеете 100% представления сколько инструкций будут перезаписаны
0
Абсолютно с Вами согласен, но написание своего Length Disassembler'а заслуживает отдельной статьи, а так как мы перехватываем известную функцию на известной архитектуре, с которой я естественно предварительно познакомил свой дизасемблер, то возникает резонный вопрос: «А зачем?»
+1
Никто не гарантирует что пролог будет во всех бинарниках одинаковым и будет начинатся именно с конкретной инструкции, это нигде не документировано и не факт что вы не нарвётесь на уже установленный хук. Конечно оно может работать и так, но это всёравно будет не корректная реализация(см. реализацию движков перехватчиков). Что касается готового дизассемблера длин, то на ASM\С\С++ с этим проблем нету, как на дела обстаят на .net я не в курсе.
+1
Очень интересно! Как раз на днях задавался таким вопросом, как написать бота для мморпг. Жду продолжения. Попробую реализовать нечто похожее по примерам.
-3
Спасибо большое за хорошую статью. Мне всегда была интересна эта тема, но до стремления изучить её так и не дошло. Благодаря вашим статьям мне удастся изучить принципы и методы в этой области. Буду с нетерпением ждать продолжения.
Спасибо.
Спасибо.
-5
Warden в состоянии определить подмену адресов в IAT, будьте осторожны с этим!
Вообще статьи как таковой нет, вопрос «писать или нет» вместился бы в комментарий.
Вообще статьи как таковой нет, вопрос «писать или нет» вместился бы в комментарий.
+1
Наносимый «вред» для разработчика игры измеряется, например, в количестве установок бота * средние потери. Допустим, Blizzard как-то терпит последних 3.5 линуксоида с вайном (вот уж где поле для внедрений… подход с внедрением своего графического слоя у форка вайн ака winex прожил пару лет), но любой среднестатистический ботик, подгружающий дллку, будет убит через n инсталлов, да еще и улучшит ситуацию с детектированием последующих версий :) Делать «для себя и красиво» можно, да, даже если оно будет стоить месяца работы, работать на трех машинах в связке и анализировать сразу и трафик, и графику, и еще и менять трафик…
Линкану www.unknowncheats.me/forum/anti-cheat-bypass/60881-gameguard-d3d-vtable-hooks-get-detected.html, даже самая занюханная защита уже умеет сканировать память процесса в поиске очевидных дыр, с учетом проверки окружения (dll, менее важно — драйвера), вот так с ходу не верится, что в 2015 остались недетектируемые способы напакостить в win-процессе.
Линкану www.unknowncheats.me/forum/anti-cheat-bypass/60881-gameguard-d3d-vtable-hooks-get-detected.html, даже самая занюханная защита уже умеет сканировать память процесса в поиске очевидных дыр, с учетом проверки окружения (dll, менее важно — драйвера), вот так с ходу не верится, что в 2015 остались недетектируемые способы напакостить в win-процессе.
+2
С другой стороны, способов сделать неотключаемую защиту не осталось еще раньше… Хотя, конечно же, снятие защиты требует совсем других познаний, нежели написание бота.
0
недетектируемые способы напакостить в win-процессеЧерез hardware breakpoint-ы, например?
0
Плюсую, я писал чит для Dota 2 который не обнаруживается VAC именно с HB. Кстати, сам процесс разработки был гораздо более сложен и интересен, чем то, что предлагает автор. Хуки vtable уже давно обнаруживаются. Хуки с EndScene тоже. Мне ещё пришлось написать внедрение shared-библиотек в рантайме, и всё это было под Linux (это тоже заслуживает отдельной статьи). В общем, я бы с радостью поделился, но не могу, ибо чит приватный и писался не для себя :D
0
Очень интересно было бы почитать про используемые подходы. Сам чит тут вряд ли кому-то нужен.
Может быть получится не нарушая условий написать статью?
Может быть получится не нарушая условий написать статью?
0
Тут дело в том, что приватные читы не привлекают внимания и их не фиксят годами (иногда вообще не фиксят). А как только я напишу статью, появятся желающие повторить это => метод привлечёт внимание => ставит под угрозу чит. И да, читы запрещены и к тому же вредят коммюнити.
0
Просвятите, пожалуйста, в чем сложность прочитать debug регистры? Многие упаковщики с легкостью детектят это и успешно снимают железные брейкпоинты.
0
В том, что, фигурально выражаясь, кто раньше встал — того и тапки. В ring3 эти регистры нельзя прочитать напрямую (будет #GP), поэтому в Win32 для usermode-приложения есть только один способ — через структуру
В первом случае достаточно сесть поверх этих двух функций, и игнорировать Dr#. Во втором надежнее всего будет сесть поверх
Что касается обнаружения самого факта отладки — если не садиться внутри кода приложения, а только на экспорты, то анализ времени выполнения ничего не даст — приложение принципиально не может гарантировать, сколько будет выполняться тот или иной вызов DirectX. Есть еще всякие экзотические способы типа недокументированного изменения EAX после вызова
CONTEXT
, которую можно получить несколькими путями. Самый очевидный — GetThreadContext()
, чтобы задетектить отладку, и SetThreadContext()
, чтобы ее снять. Второй способ — спровоцировать SEH-исключение, посмотреть CONTEXT *ContextRecord
в _except_handler()
и поменять при необходимости.В первом случае достаточно сесть поверх этих двух функций, и игнорировать Dr#. Во втором надежнее всего будет сесть поверх
KiDispatchException
и просто возвращать копию контекста вместо самого контекста, с которой потом поступать по усмотрению.Что касается обнаружения самого факта отладки — если не садиться внутри кода приложения, а только на экспорты, то анализ времени выполнения ничего не даст — приложение принципиально не может гарантировать, сколько будет выполняться тот или иной вызов DirectX. Есть еще всякие экзотические способы типа недокументированного изменения EAX после вызова
OutputDebugString
, но это тоже, в принципе, просто обходится.+3
А что насчет анализа времени выполнения GetThreadContext()?..
0
А сколько она должна выполняться на самом деле, например? С учетом того, что поток в любой момент может переключиться и что операционная система, в принципе, не обязана совсем честно обслуживать все потоки, с учетом того, что кому-то может придти в голову сожрать всю оперативку и начать свопиться, или вообще в системе есть антивирус… Мало ли по какой причине функции могут выполняться неодинаковое время :) Эта защита надежно работает только против трассировки процессов — когда между двумя вызовами должно пройти, скажем, порядка 20 мс, а проходит 5 сек — значит, кто-то сидит и вдумчиво жмет F10 в софтайсе.
0
Можно же позвать системный вызов NtGetContextThread через sysenter, и тогда перехватывать его необходимо еще в ядре. Еще мне помнится, некоторые программы сами себя отлаживают, тем самым не давая прицепить к себе еще один отладчик.
0
Насколько мне извесно процесс не может подключиться как отладчик сам к себе, для этого требуется дополнительный процесс
+2
Ну так и на KiDispatchException иначе, чем через ядро, не сядешь — потому что в SEH chain встраиваться хоть и можно, но бессмысленно, т.к. у процесса есть контроль над своим SEH chain, и при желании процесс может посмотреть, кто там есть чужой и всех оттуда попросить. С другой стороны — разве сейчас для кого-то проблема сделать простейший драйвер-перехватчик?
И, как выше верно заметили, сам себя отладить не получится. К счастью, в нашем случае необязательно отлаживать процесс официально — т.к. мы уже в ядре, нам не нужны привилегии отладчика чтобы поменять контекст потока, добавить туда отладочные регистры и словить брекпоинт.
И, как выше верно заметили, сам себя отладить не получится. К счастью, в нашем случае необязательно отлаживать процесс официально — т.к. мы уже в ядре, нам не нужны привилегии отладчика чтобы поменять контекст потока, добавить туда отладочные регистры и словить брекпоинт.
+1
Чем параноидальнее защита, тем больше у неё ложных срабатываний. Потому что в процесс постоянно ломится и внедряется огромная куча всего — всякие перехватчики клавиатурных нажатий, антивирусные сканеры, всевозможные «управляющие центры» для видео и звука, компоненты настроек устройств ввода вроде мыши и т.д.
Запустив процесс в OllyDebug, легко увидеть, сколько в адресное пространство процесса грузится явно посторонних DLL. Особенно много всякой фирменной мелочёвки грузится внутрь процесса при игре на ноутах. Каталогизировать сигнатуры всего этого хлама не так-то просто даже для такой большой компании, как Blizzard.
В итоге разработчики защит оказываются меж двух огней: сделай мало проверок — и ботоводы будут творить что хотят. Сделай слишком много проверок — и техподдержку завалят жалобами, что игра не запускается, да ещё и на игровых форумах основательно польют грязью.
В итоге всегда остаётся достаточное количество дыр, через которые можно пролезть. И если вы пишете бот для себя, то его могут никогда не обнаружить, т.к. целенаправленно ловят лишь массовые программы, а одиночки оказываются в позиции Неуловимого Джо.
Запустив процесс в OllyDebug, легко увидеть, сколько в адресное пространство процесса грузится явно посторонних DLL. Особенно много всякой фирменной мелочёвки грузится внутрь процесса при игре на ноутах. Каталогизировать сигнатуры всего этого хлама не так-то просто даже для такой большой компании, как Blizzard.
В итоге разработчики защит оказываются меж двух огней: сделай мало проверок — и ботоводы будут творить что хотят. Сделай слишком много проверок — и техподдержку завалят жалобами, что игра не запускается, да ещё и на игровых форумах основательно польют грязью.
В итоге всегда остаётся достаточное количество дыр, через которые можно пролезть. И если вы пишете бот для себя, то его могут никогда не обнаружить, т.к. целенаправленно ловят лишь массовые программы, а одиночки оказываются в позиции Неуловимого Джо.
+2
Почему сразу не на С#? (Я писал бота без ассемблера и его не палили!)
Почему нужно именно вставлять ассембелерный код в вставки в С#?
Увеличена скорость роботы бота? Контроль пакетов или как понять?
В чем подвох? :)
Почему нужно именно вставлять ассембелерный код в вставки в С#?
Увеличена скорость роботы бота? Контроль пакетов или как понять?
В чем подвох? :)
0
Sign up to leave a comment.
Пишем бота для MMORPG с ассемблером и дренейками. Часть 0