20120701

Раз немного передохнули, подытожим. Вспомним нашу программку на ассемблере, рисующую прямоугольник. Там это выглядело примерно так:

.wmpaint:
invoke BeginPaint,[hwnddlg],ps
mov [hDC],eax
invoke Rectangle,[hDC],10,10,30,30
invoke EndPaint,[hwnddlg],ps
jmp .processed

Значит, хочет наше окно себя нарисовать. В очередь сообщений прилетает WM_PAINT. Согласно [документации]:

The WM_PAINT message is sent when the system or another application makes a request to paint a portion of an application's window.

Типа, раз такой праздник произошёл, значит окно хочет себя перерисовать. Перво-наперво ему же надо узнать, где рисовать, да? Вызываем [BeginPaint], сообщаем ему хэндл нашего окна и структуру, для чего-то там необходимую. Нам, в общем-то, до лампочки, для чего именно - она просто есть и всё.
В ответ на бегинпейнт (НачатьРисовать, лол) нам приходит хитрая штука под названием Handle  to Device Context, если чуть более по-русски - это хэндл связки видеокарты с монитором. Типа, то место, где рисовать можно, ну то есть холст, потому как видеокарт и мониторов всяких - тьма тьмущая, вот и сделали такое клёвое обощение.

Значит, теперь у нас есть некоторая поверхность (монитор-то плоский!), где можно чего-нибудь эдакого накалякать. Берём и калякаем, вызывав Rectangle, рисующую прямоугольник.

После всего этого безобразия нам надо сообщить, что безобразие закончилось - вызываем EndPaint, ЗакончитьРисовать.
И на выход.

Вот, собственно, с Direct3D всё примерно точно так же обстоит - у нас есть указатель на устройство, очень похожий на hDC, т.е. то, где рисовать. Мы говорим:

BeginScene();

Мол, давай рисовать!

Рисуем...

И затем говорим:

EndScene();

Хватит это терпеть! Довольно!
Вот и во всех играх та же самая фигня происходит. Они делают себе место для рисования, каждый кадр говорят BeginScene(), рисуют всё, что им надо, а затем говорят EndScene() и показывают всё это на экране. Разработчикам не надо париться ни о модели видеокарты, ни о мониторе - просто РИСАТЬ и всё. Удобно!

Тут прискакиваем мы, все в белом и на соответствующем коне, толпы пищащих поклонниц сопровождают нас и кидаются в нас нижним бельём. Нам вдруг ВЗДУМАЛОСЬ игру обмануть и нарисовать в её королевстве что-то ещё. В чём логика:

BeginScene();
РисуемВсёИгровое();
EndScene();


Нам надо взять и нарисовать что-то своё после всего игрового. Удобнее всего это сделать прямо перед вызовом EndScene(), типа вот так:

BeginScene();
РисуемВсёИгровое();
РисуемЧужое();
EndScene();

Хитрые человеки уже давно смекнули, что можно же сделать инъекцию и подменить собой вызов EndScene:

BeginScene();
РисуемВсёИгровое();
CustomEndScene();

void CustomEndScene() {
DrawRectangle();
DrawText();
EndScene();

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

Вот таким вот нехитрым образом и работает большинство хаков, связанных с графикой - начиная с wallhack и maphack, заканчивая экранными меню.

Сложность состоит в том, чтобы найти EndScene() и указатель на устройство, который где-то до этого получает игра, потому что только лишь зная указатель на устройство мы можем что либо рисовать. Собственно, скоро мы вооружимся OllyDbg и пойдём наш пример курочить. To be continued!

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

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

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