20140803

D3D: Chameleon Wallhack

Привет, ребята! Для начала, вот видео:


А [вот] ссылка на репозиторий с исходным кодом.

Значит, скачали вы исходники, взяли любимый компилятор и любимую IDE, скомпилировали это дело и ничего не поняли. В видео я, отсылась к предыдущим статьям и урокам, рассказываю о том, что мы написали логгер, позволяющий нам узнать некоторую необходимую для нашей бурной деятельности информацию. А именно - stride, или номер куска экрана, который мы сейчас будем рисовать, и NumVertiles, аргумент функции [DrawIndexedPrimitive], который показывает нам количество вершин того куска, который мы будем рисовать. Мир игры состоит из моделек, модельки - из полигонов. Полигон - это треугольник, то есть у него три вершины. На модельки, собственно, сверху натянуты текстуры, чтобы было видно, что металл - это металл, оружие - это оружие, а враги - это враги. Нашли мы, значит, нужную нам текстуру. Дальше видим такой кусок кода:

pDev->SetRenderState(D3DRS_ZENABLE, false);
pDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
pDev->SetTexture(0, red);
oDrawIndexedPrimitive(pDev, PrimType, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
pDev->SetRenderState(D3DRS_ZENABLE, true);
pDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
pDev->SetTexture(0, green);

Что мы тут делаем? А всё просто, как выяснилось. Функция [SetRenderState] позволяет нам задать параметры отображения того, что мы сейчас будем отображать. Тут важно помнить, что мы ещё пока ничего рисовать не пытались. У этой самой функции всего два аргумента - что мы меняем и на что мы меняем. Первым вызовом мы утверждаем, будто нужно выключить буфер глубины. Что это такое? Это перспектива, если вдруг так будет понятнее. Экран монитора - он плоский, а игра хочет казаться трёхмерной, так что ей нужно как-то трёхмерность симулировать. Вот эта вот штука отвечает за то, что мы видеть должны, а что - нет. Например, когда какой-то объект находится за стеной. Игра при отрисовке постоянно думает, что и как ей рисовать. Вот небольшая схемка:

0            1             2
             |                   
X -----------|-------------O
             | 

X - это мы. Палочки - это стена перед нами, а O - это нечто за этой стеной. Циферки обозначают позицию одного относительно другого в этом самом буфере глубины. У кого цифра 1 - того мы и видим, у кого больше - значит он чем-то от нас закрыт. Если товарищ О выйдет из-за стены, то у него Z-order (позиция в буфере глубины) станет равным 1, так что игра должна будет его перед нами отрисовать и в результате мы его увидим.

Если отключить буфер глубины, то игра решит, что все игровые объекты в поле нашего зрения находятся перед нами - то есть нету никаких препятствий и никто никого не перекрывает. Получится каша, потому что одновременно будут рисоваться стены, мебель, пол, потолок, оружие, гранаты, люди, враги, союзники, словом - всё. Для того, чтобы вычленить из этой каши то, что нам нужно, мы и использовали наш логгер. В общем-то, только у нужных нам объектов мы буфер глубины и отключили. Давайте вернёмся к коду, а то я заболтался. Отключив буфер глубины, мы говорим, что текущий объект мы будем рисовать сплошным цветом. Сразу после этого мы вызываем функцию [SetTexture], которая указывает, что мы будем использовать текстуру по имени red - красненькую. Напомню, что пока мы ещё ничего не рисовали и не пытались даже. Что мы делаем следующей строчкой? Верно, рисуем, вызвав оригинальную функцию рисования вместо нашей перехваченной.

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

Что получается в результате таких жутких махинаций? А получается так, что выбранная нами моделька рисуется через стены красным, а перед нами - зелёным. Эта фича отличает Chameleon wallhack от обычного. В обычном мы просто выключали бы буфер глубины и всё, а тут удобно, с подсветочкой.

Тэк-с. Я упоминал текстуры. Собственно, чуть ниже, в перехваченной функции [EndScene], мы их и создаём. Тут я в подробности вдаваться не буду, так как этот кусок кода я нашёл и честно скопировал себе, скажу только, что цвет мы задаём вот в этой строчке:

((PDWORD)d3dlr.pBits)[xy] = 0xFF00FF00;

Тут нас интересуют последние три пары чисел шестнадцатиричного значения. Догадливые уже поняли, что это RGB, он же - Red Green Blue, то есть три цветовых канала. Первые две цифры в том числе выше - это прозрачность, которая не используется в данном случае, как я понял. Собственно, FF0000 - это красный, 00FF00 - это зелёный, а 0000FF - это синий. Значения лежат в пределах от 00 до FF. Подходящий цвет можно выбрать в любом графическом редакторе или же в интернете найти.

В той же перехваченной EndScene мы первой строчкой узнаём ViewPort - это, собственно, то, куда мы смотрим, когда играем. Узнаём мы его затем, чтобы выводить туда текст, так что после создания текстур мы создаём шрифт и пишем им на экран, в данном случае - включён ли наш wallhack.

На этом, в принципе, можно бы было и остановиться, но есть ещё одна важная деталь. В комментариях некоторые люди жаловались, что игра вылетает с ошибкой при попытке сделать alt+tab или поменять разрешение экрана. Это чинится перехватом функции [Reset], в которой мы уничтожаем наши текстуры и шрифт, чтобы они не засоряли видеокарту и пересоздались, дабы игра снова могла их рисовать.

Вот теперь - всё. До новых встреч! (:

Комментариев нет:

Отправить комментарий

Не люблю мат и низкий уровень грамотности. Чем конкретнее поставите свой вопрос и чем лучше он будет выглядеть - тем большая вероятность на мой ответ. :)