Funkcja w pliku DLL wyświetlająca obraz lub punkt (injection)

0

Witam.
Potrzebuję stworzyć plik .dll, który będę mógł zainjectować do gry przez plik .exe (injector). Celem jest stworzenie na środku ekranu jakiegoś punktu lub dodać grafikę, która odwzorowywałaby celownik. I teraz moje pytanie, czy wystarczy w takim pliku .dll stworzyć funkcje wyświetlającą taką grafikę lub punkt, czy jednak to nie wystarczy? Mógłby ktoś poinstruować jak taką funkcję wykonać?

0

To całkiem trudne :). Musisz wiedzieć, w jaki sposób zmodyfikować i komunikować się z interfejsem aplikacji (np. poprzez hookowanie jego interfejsu DirectX / Direct3D), czyli najpierw musisz wykonać analizę aplikacji EXE, później napisać hookowanie tych interfejsów, musisz dowiedzieć się kiedy wyświetlić ten celownik (w którym momencie), czyli musisz znaleźć w aplikacji kod który aktywuje moment, gdzie to ma być wyświetlone, podrzucić kod, który będzie aktywował wyświetlanie tego celownika i zrealizuje powrót do kodu aplikacji.

2

@Bartosz Wójcik, niekoniecznie.
Zależy z jakim rendererem mamy to zrobić.

Jeśli chodzi o opengl no to sprawa jest całkiem prosta. Szukasz wywołania SwapBuffers, i dokładnie przed tym wywołaniem robisz Jump Hooka do swojego kodu i tam odkładasz wszystkie potrzebne stany na stos / w zmienne, ustawiasz stany jakie chcesz, rysujesz coś, i przywracasz wszystkie stany, i wykonujesz dalej co tam w kodzie gry jest czyli te SwapBuffers. Mniej więcej w ten sposób to steam robi. Jedyna różnica to taka, że oni robią "Detours" funkcji SwapBuffers. Tobie nie polecam tego robić bo możesz nadpisać detours tej funkcji ze steama, i steam już nic nie narysuje.

A jeśli chodzi o directx no to sprawa jest już troszeczkę trudniejsza. Musisz znaleźć w kodzie gry moment gdzie jest koniec renderowania, i do tego pobrać wskaźnik na IDirect3DDevice9 albo inne ustrojstwo jeśli gra korzysta z czegoś nowszego, i odłożyć wszystkie stany na stos / w zmienne, ustawiasz swoje stany, rysujesz coś, i przywracasz stany. Aby znaleźć ten kod gdzie jest koniec renderowania możesz poszukać wywołania funkcji IDirect3DDevice9::Present. Nie pamiętam niestety czy jest to virtual, ale prawdopodobnie jest. Więc mógłbyś po vtabeli dojść gdzie to jest wywoływane.

Jak chcesz to robić na openglu, to kod jak odkładać stany i rysować:

/* =========================================================================

  Project: ETS2MP @ core (Client)
  File:    ../graphics/gl/GLRenderer.h

  Copyright (c) 2013+ - ETS2MP Team
  All rights reserved.

   This software is distributed WITHOUT ANY WARRANTY; without even
   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
   PURPOSE. See the license file to get more information.

========================================================================= */

#pragma once

#include <graphics/Renderer.h>

#include <gl/gl.h>
#include <gl/glu.h>
#include <glext.h>

class CGLRenderer : public CRenderer
{
public:
	class CStateBlock
	{
	private:
		GLint m_viewport[4];
		GLint m_drawFboId;
		GLint m_readFboId;
		GLboolean m_colorWriteMask[4];
		GLfloat m_projectionMatrix[16];
		GLfloat m_colorMatrix[16];
		GLfloat m_modelMatrix[16];
		GLint m_currentProgram;
		GLint m_programPipelineBinding;
		GLint m_elementArrayBufferBinding;
		GLfloat m_textureMatrix[16];
	public:
		CStateBlock();
		~CStateBlock();

		bool Capture();
		bool Apply();
	};

private:
	HGLRC m_pDevice;
	CStateBlock m_StateBlock;

public:
	CGLRenderer();
	virtual ~CGLRenderer();

	virtual void Init(void* pDevice);
	virtual void Destroy();

	virtual const char* GetName() { return "OpenGL"; }

	virtual void EndFrame();

	static CGLRenderer* s_pInstance;

	static CGLRenderer* Get() { return s_pInstance; }

	bool PreDraw();
	bool PostDraw();
public:
	void(__stdcall *glEnable)(GLenum cap);
	void(__stdcall *glDisable)(GLenum cap);
	GLenum(__stdcall *glGetError)(void);

	void(__stdcall *glGetBooleanv)(GLenum pname, GLboolean * data);
	void(__stdcall *glGetDoublev)(GLenum pname, GLdouble * data);
	void(__stdcall *glGetFloatv)(GLenum pname, GLfloat * data);
	void(__stdcall *glGetIntegerv)(GLenum pname, GLint * data);
	void(__stdcall *glGetInteger64v)(GLenum pname, GLint64 * data);
	void(__stdcall *glGetBooleani_v)(GLenum target, GLuint index, GLboolean * data);
	void(__stdcall *glGetIntegeri_v)(GLenum target, GLuint index, GLint * data);
	void(__stdcall *glGetFloati_v)(GLenum target, GLuint index, GLfloat * data);
	void(__stdcall *glGetDoublei_v)(GLenum target, GLuint index, GLdouble * data);
	void(__stdcall *glGetInteger64i_v)(GLenum target, GLuint index, GLint64 * data);

	void(__stdcall *glDrawElements)(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices);
	void(__stdcall *glBindBuffer)(GLenum target, GLuint buffer);
	void(__stdcall *glGenBuffers)(GLsizei n, GLuint * buffers);
	void(__stdcall *glBufferData)(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage);
	void(__stdcall *glUseProgram)(GLuint program);
	void(__stdcall *glBlendFunc)(GLenum sfactor, GLenum dfactor);
	void(__stdcall *glAlphaFunc)(GLenum func, GLclampf ref);
	void(__stdcall *glEnableClientState)(GLenum cap);
	void(__stdcall *glDrawArrays)(GLenum mode, GLint first, GLsizei count);
	void(__stdcall *glFlush)(void);
	void(__stdcall *glMatrixMode)(GLenum mode);
	void(__stdcall *glLoadIdentity)(void);
	void(__stdcall *glOrtho)(GLdouble left, GLdouble right, GLdouble bottom,	GLdouble top, GLdouble nearVal, GLdouble farVal);
	void(__stdcall *glViewport)(GLint x, GLint y, GLsizei width, GLsizei height);
	void(__stdcall *glBegin)(GLenum mode);
	void(__stdcall *glEnd)(void);
	void(__stdcall *glVertex3f)(GLfloat x, GLfloat y, GLfloat z);
	void(__stdcall *glPushAttrib)(GLbitfield mask);
	void(__stdcall *glPushClientAttrib)(GLbitfield mask);
	void(__stdcall *glBindFramebuffer)(GLenum target, GLuint framebuffer);
	void(__stdcall *glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
	void(__stdcall *glTranslatef)(GLfloat x, GLfloat y, GLfloat z);
	void(__stdcall *glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha);
	void(__stdcall *glDepthMask)(GLboolean flag);
	void(__stdcall *glDepthRange)(GLclampd zNear, GLclampd zFar);
	GLboolean(__stdcall *glIsEnabled)(GLenum cap);
	GLint(__stdcall *glRenderMode)(GLenum mode);
	void(__stdcall *glDisableClientState)(GLenum array_);
	void(__stdcall *glPixelStorei)(GLenum pname, GLint param);
	void(__stdcall *glShadeModel)(GLenum mode);
	void(__stdcall *glPixelZoom)(GLfloat xfactor, GLfloat yfactor);
	void(__stdcall *glBindProgramPipeline)(GLuint pipeline);
	void(__stdcall *glActiveTextureARB)(GLenum texture);
	void(__stdcall *glLoadMatrixf)(const GLfloat *m);
	void(__stdcall *glPopClientAttrib)(void);
	void(__stdcall *glPopAttrib)(void);
	void(__stdcall *glColor4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
	void(__stdcall *glGenVertexArrays)(GLsizei n, GLuint *arrays);
	void(__stdcall *glBindVertexArray)(GLuint array_);
	void(__stdcall *glEnableVertexAttribArray)(GLuint index);
	void(__stdcall *glDisableVertexAttribArray)(GLuint index);
	void(__stdcall *glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized,	GLsizei stride, const GLvoid * pointer);
	void(__stdcall *glVertexPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);
	void(__stdcall *glColorPointer)(GLint size,	GLenum type, GLsizei stride, const GLvoid * pointer);
	void(__stdcall *glTexCoordPointer)(GLint size, GLenum type, GLsizei stride, const GLvoid * pointer);
	void(__stdcall *glDeleteBuffers)(GLsizei n, const GLuint * buffers);
};

void* GetGLFunc(const char* name);

// EOF 
/* =========================================================================

  Project: ETS2MP @ core (Client)
  File:    ../graphics/gl/GLRenderer.cpp

  Copyright (c) 2013+ - ETS2MP Team
  All rights reserved.

   This software is distributed WITHOUT ANY WARRANTY; without even
   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
   PURPOSE. See the license file to get more information.

========================================================================= */

#include "GLRenderer.h"

#include <offsets.h>
#include <Logger.h>

CGLRenderer* CGLRenderer::s_pInstance = 0;

CGLRenderer::CGLRenderer()
	: m_pDevice(0)
{
	s_pInstance = this;
}

CGLRenderer::~CGLRenderer()
{
	s_pInstance = 0;
}

void CGLRenderer::Init(void* pDevice)
{
	m_pDevice = (HGLRC)pDevice;

#define GL_MISSING_FUNC(name) \
	printf("Cannot find %s function!", name);

#define LOAD(name) \
	*(void **)&name = GetGLFunc(#name); \
	if (!name) { \
		GL_MISSING_FUNC(#name); \
	}

	LOAD(glEnable);
	LOAD(glDisable);
	LOAD(glGetError);

	LOAD(glGetBooleanv);
	LOAD(glGetDoublev);
	LOAD(glGetFloatv);
	LOAD(glGetIntegerv);
	LOAD(glGetInteger64v);
	LOAD(glGetBooleani_v);
	LOAD(glGetIntegeri_v);
	LOAD(glGetFloati_v);
	LOAD(glGetDoublei_v);
	LOAD(glGetInteger64i_v);

	LOAD(glDrawElements);
	LOAD(glBindBuffer);
	LOAD(glGenBuffers);
	LOAD(glBufferData);
	LOAD(glUseProgram);
	LOAD(glBlendFunc);
	LOAD(glAlphaFunc);
	LOAD(glEnableClientState);
	LOAD(glDrawArrays);
	LOAD(glFlush);
	LOAD(glMatrixMode);
	LOAD(glLoadIdentity);
	LOAD(glOrtho);
	LOAD(glViewport);
	LOAD(glBegin);
	LOAD(glEnd);
	LOAD(glVertex3f);
	LOAD(glPushAttrib);
	LOAD(glPushClientAttrib);
	LOAD(glBindFramebuffer);
	LOAD(glColorMask);
	LOAD(glTranslatef);
	LOAD(glBlendEquationSeparate);
	LOAD(glDepthMask);
	LOAD(glDepthRange);
	LOAD(glIsEnabled);
	LOAD(glRenderMode);
	LOAD(glDisableClientState);
	LOAD(glPixelStorei);
	LOAD(glShadeModel);
	LOAD(glPixelZoom);
	LOAD(glBindProgramPipeline);
	LOAD(glActiveTextureARB);
	LOAD(glLoadMatrixf);
	LOAD(glPopClientAttrib);
	LOAD(glPopAttrib);
	LOAD(glColor4ub);
	LOAD(glGenVertexArrays);
	LOAD(glBindVertexArray);
	LOAD(glEnableVertexAttribArray);
	LOAD(glDisableVertexAttribArray);
	LOAD(glVertexAttribPointer);
	LOAD(glVertexPointer);
	LOAD(glColorPointer);
	LOAD(glTexCoordPointer);
	LOAD(glDeleteBuffers);
}

void CGLRenderer::Destroy()
{
	m_pDevice = 0;
}

#pragma pack(push, 1)

struct Vertex
{
	float x, y, z;
	//float u, v;
	unsigned color;

	Vertex() { };
	Vertex(float _x, float _y, float _z, float _u, float _v, unsigned _rgba)
	{
		x = _x;
		y = _y;
		z = _z;
		//u = _u;
		//v = _v;
		color = _rgba;
	}
};

#pragma pack(pop)

void CGLRenderer::EndFrame()
{
	PreDraw();

	glBegin(GL_TRIANGLES);

	glColor4ub(255, 0, 0, 255);
	glVertex3f(100.0f, 100.0f, 0.0f);					// top left

	glColor4ub(0, 255, 0, 255);
	glVertex3f(200.0f, 100.0f, 0.0f);					// top right

	glColor4ub(0, 0, 255, 255);
	glVertex3f(100.0f, 500.0f, 0.0f);					// bottom

	glEnd();

	/*GLuint VertexArrayID;
	glGenVertexArrays(1, &VertexArrayID);
	glBindVertexArray(VertexArrayID);

	const int numverts = 6;
	Vertex vertices[numverts];
	vertices[0] = Vertex(100, 100, 0, 0, 0, 0xF0F0FFF0);
	vertices[1] = Vertex(200, 100, 0, 0, 0, 0xF0F0FFF0);
	vertices[2] = Vertex(100, 500, 0, 0, 0, 0xF0F0FFF0);
	vertices[3] = Vertex(500, 100, 0, 0, 0, 0xF0F0FFF0);
	vertices[4] = Vertex(700, 100, 0, 0, 0, 0xF0F0FFF0);
	vertices[5] = Vertex(500, 500, 0, 0, 0, 0xF0F0FFF0);

	GLuint triangleVertexBufferId;
	glGenBuffers(1, &triangleVertexBufferId);
	glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBufferId);
	glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * numverts, &vertices[0].x, GL_STATIC_DRAW);

	glEnableVertexAttribArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, triangleVertexBufferId);

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);

	glDrawArrays(GL_TRIANGLES, 0, numverts);
	glDisableVertexAttribArray(0);

	glDeleteBuffers(1, &triangleVertexBufferId);*/
        // to na górze działa, tylko trzeba shader napisać żeby kolor uzyskać i inne ciekawe rzeczy

	PostDraw();
}

bool CGLRenderer::PreDraw()
{
	m_StateBlock.Capture();

	GLint viewport[4];
	CGLRenderer::Get()->glGetIntegerv(GL_VIEWPORT, viewport);

	RECT r;
	r.left = viewport[0];
	r.top = viewport[1];
	r.right = r.left + viewport[2];
	r.bottom = r.top + viewport[3];

	CGLRenderer::Get()->glViewport(r.left, r.top, r.right, r.bottom);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;

	CGLRenderer::Get()->glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
	CGLRenderer::Get()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);

	CGLRenderer::Get()->glColorMask(true, true, true, true);

	CGLRenderer::Get()->glMatrixMode(GL_PROJECTION);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
	{
		return false;
	}
		

	CGLRenderer::Get()->glLoadIdentity();

	CGLRenderer::Get()->glOrtho(r.left, r.right, r.bottom, r.top, -1.0, 1.0);

	CGLRenderer::Get()->glTranslatef(0.f, 0.f, 0.f);

	CGLRenderer::Get()->glMatrixMode(GL_COLOR);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
	{
		return false;
	}
		

	CGLRenderer::Get()->glMatrixMode(GL_MODELVIEW);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
	{
		return false;
	}
		
	CGLRenderer::Get()->glLoadIdentity();

	CGLRenderer::Get()->glTranslatef(0.f, 0.f, 0.f);

	CGLRenderer::Get()->glEnable(GL_BLEND);
	CGLRenderer::Get()->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	CGLRenderer::Get()->glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);

	CGLRenderer::Get()->glDisable(GL_CULL_FACE);
	CGLRenderer::Get()->glDisable(GL_ALPHA_TEST);
	CGLRenderer::Get()->glDisable(GL_STENCIL_TEST);
	CGLRenderer::Get()->glDisable(GL_SCISSOR_TEST);
	CGLRenderer::Get()->glDisable(GL_LIGHTING);
	CGLRenderer::Get()->glDisable(GL_DEPTH_TEST);
	CGLRenderer::Get()->glDisable(GL_FOG);

	CGLRenderer::Get()->glDepthMask(false);

	CGLRenderer::Get()->glDepthRange(0.f, 1.f);

	CGLRenderer::Get()->glDisable(GL_COLOR_MATERIAL);
	CGLRenderer::Get()->glDisable(GL_COLOR_LOGIC_OP);
	CGLRenderer::Get()->glDisable(GL_NORMALIZE);

	if (CGLRenderer::Get()->glIsEnabled(GL_FRAMEBUFFER_SRGB))
	{
	}
	else // default
	{
	}

	CGLRenderer::Get()->glDisable(GL_CLIP_DISTANCE0);
	CGLRenderer::Get()->glDisable(GL_CLIP_DISTANCE1);
	CGLRenderer::Get()->glDisable(GL_CLIP_DISTANCE2);
	CGLRenderer::Get()->glDisable(GL_CLIP_DISTANCE3);
	CGLRenderer::Get()->glDisable(GL_CLIP_DISTANCE4);
	CGLRenderer::Get()->glDisable(GL_CLIP_DISTANCE5);
	CGLRenderer::Get()->glDisable(GL_COLOR_SUM);
	CGLRenderer::Get()->glDisable(GL_POLYGON_OFFSET_POINT);
	CGLRenderer::Get()->glDisable(GL_POLYGON_OFFSET_LINE);
	CGLRenderer::Get()->glDisable(GL_POLYGON_OFFSET_FILL);

	if (CGLRenderer::Get()->glRenderMode(GL_RENDER) == 0) // default
	{
	}
	else
	{
	}

	CGLRenderer::Get()->glDisableClientState(GL_COLOR_ARRAY);
	CGLRenderer::Get()->glDisableClientState(GL_EDGE_FLAG_ARRAY);
	CGLRenderer::Get()->glDisableClientState(GL_INDEX_ARRAY);
	CGLRenderer::Get()->glDisableClientState(GL_NORMAL_ARRAY);
	CGLRenderer::Get()->glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	CGLRenderer::Get()->glDisableClientState(GL_VERTEX_ARRAY);

	CGLRenderer::Get()->glEnable(GL_DITHER);

	CGLRenderer::Get()->glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
	CGLRenderer::Get()->glPixelStorei(GL_UNPACK_LSB_FIRST, 0);
	CGLRenderer::Get()->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
	CGLRenderer::Get()->glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
	CGLRenderer::Get()->glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
	CGLRenderer::Get()->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

	CGLRenderer::Get()->glShadeModel(GL_SMOOTH);

	CGLRenderer::Get()->glPixelZoom(1.f, 1.f);

	CGLRenderer::Get()->glUseProgram(0);

	CGLRenderer::Get()->glBindProgramPipeline(0);

	CGLRenderer::Get()->glActiveTextureARB(GL_TEXTURE0);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_CUBE_MAP);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_RECTANGLE);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_3D);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_2D);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_1D);

	CGLRenderer::Get()->glActiveTextureARB(GL_TEXTURE1);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_CUBE_MAP);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_RECTANGLE);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_3D);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_2D);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_1D);

	CGLRenderer::Get()->glActiveTextureARB(GL_TEXTURE2);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_CUBE_MAP);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_RECTANGLE);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_3D);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_2D);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_1D);

	CGLRenderer::Get()->glActiveTextureARB(GL_TEXTURE3);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_CUBE_MAP);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_RECTANGLE);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_3D);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_2D);
	CGLRenderer::Get()->glDisable(GL_TEXTURE_1D);

	CGLRenderer::Get()->glActiveTextureARB(GL_TEXTURE0);

	CGLRenderer::Get()->glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
	CGLRenderer::Get()->glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);

	CGLRenderer::Get()->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
	{
		return false;
	}
		
	CGLRenderer::Get()->glMatrixMode(GL_TEXTURE);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
	{
	}
	else
	{
		CGLRenderer::Get()->glLoadIdentity();
		CGLRenderer::Get()->glTranslatef(0.000000, 0.000000, 0.000000);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_1D);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_3D);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_RECTANGLE);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_CUBE_MAP);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_GEN_R);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_GEN_S);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_GEN_T);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_GEN_Q);
		CGLRenderer::Get()->glEnable(GL_TEXTURE_2D);
		CGLRenderer::Get()->glDisable(GL_TEXTURE_CUBE_MAP);
		CGLRenderer::Get()->glDisable(GL_VERTEX_PROGRAM_ARB);
		CGLRenderer::Get()->glDisable(GL_FRAGMENT_PROGRAM_ARB);
	}

	CGLRenderer::Get()->glDepthRange(0.f, 1.f);
	CGLRenderer::Get()->glColor4ub(255, 255, 255, 255);

	CGLRenderer::Get()->glDisable(GL_TEXTURE_2D);

	return true;
}

bool CGLRenderer::PostDraw()
{
	m_StateBlock.Apply();

	return true;
}

CGLRenderer::CStateBlock::CStateBlock()
{

}

CGLRenderer::CStateBlock::~CStateBlock()
{

}

bool CGLRenderer::CStateBlock::Capture()
{
	CGLRenderer::Get()->glGetIntegerv(GL_VIEWPORT, m_viewport);

	CGLRenderer::Get()->glPushAttrib(GL_CURRENT_BIT | GL_POINT_BIT | GL_LINE_BIT | GL_POLYGON_BIT
		| GL_POLYGON_STIPPLE_BIT | GL_PIXEL_MODE_BIT | GL_LIGHTING_BIT | GL_FOG_BIT
		| GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_VIEWPORT_BIT
		| GL_TRANSFORM_BIT | GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_HINT_BIT
		| GL_EVAL_BIT | GL_LIST_BIT | GL_TEXTURE_BIT | GL_SCISSOR_BIT);

	CGLRenderer::Get()->glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT | GL_CLIENT_VERTEX_ARRAY_BIT | 0x0004 | 0x0008 |
		0x0010 | 0x0020 | 0x0040 | 0x0080
		| 0x0100 | 0x0200 | 0x0400 | 0x0800
		| 0x1000 | 0x2000 | 0x4000 | 0x8000
		| 0x10000 | 0x20000 | 0x40000 | 0x80000
		| 0x100000 | 0x200000 | 0x400000 | 0x800000
		| 0x1000000 | 0x2000000 | 0x4000000 | 0x8000000
		| 0x10000000 | 0x20000000 | 0x40000000 | 0x80000000);

	CGLRenderer::Get()->glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &m_readFboId);
	CGLRenderer::Get()->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &m_drawFboId);

	CGLRenderer::Get()->glGetBooleanv(GL_COLOR_WRITEMASK, m_colorWriteMask);

	CGLRenderer::Get()->glMatrixMode(GL_PROJECTION);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;

	CGLRenderer::Get()->glGetFloatv(GL_PROJECTION_MATRIX, m_projectionMatrix);

	CGLRenderer::Get()->glMatrixMode(GL_COLOR);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;

	CGLRenderer::Get()->glGetFloatv(GL_COLOR_MATRIX, m_colorMatrix);

	CGLRenderer::Get()->glMatrixMode(GL_MODELVIEW);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;

	CGLRenderer::Get()->glGetFloatv(GL_MODELVIEW_MATRIX, m_modelMatrix);

	if (CGLRenderer::Get()->glRenderMode(GL_RENDER) == 0) // default
	{
	}
	else
	{
	}

	CGLRenderer::Get()->glGetIntegerv(GL_CURRENT_PROGRAM, &m_currentProgram);

	CGLRenderer::Get()->glGetIntegerv(GL_PROGRAM_PIPELINE_BINDING, &m_programPipelineBinding);


	CGLRenderer::Get()->glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &m_elementArrayBufferBinding);

	CGLRenderer::Get()->glMatrixMode(GL_TEXTURE);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
	{
	}
	else
	{
		CGLRenderer::Get()->glGetFloatv(GL_TEXTURE_MATRIX, m_textureMatrix);
	}

	return true;
}

bool CGLRenderer::CStateBlock::Apply()
{
	RECT r;
	r.left = m_viewport[0];
	r.top = m_viewport[1];
	r.right = r.left + m_viewport[2];
	r.bottom = r.top + m_viewport[3];

	CGLRenderer::Get()->glMatrixMode(GL_PROJECTION);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;
	
	CGLRenderer::Get()->glLoadMatrixf(m_projectionMatrix);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;

	CGLRenderer::Get()->glMatrixMode(GL_TEXTURE);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;
	
	CGLRenderer::Get()->glLoadMatrixf(m_textureMatrix);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;

	CGLRenderer::Get()->glColorMask(m_colorWriteMask[0], m_colorWriteMask[1], m_colorWriteMask[2], m_colorWriteMask[3]);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;

	CGLRenderer::Get()->glMatrixMode(GL_MODELVIEW);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;
	CGLRenderer::Get()->glLoadMatrixf(m_modelMatrix);

	CGLRenderer::Get()->glBindFramebuffer(GL_READ_FRAMEBUFFER, m_readFboId);
	CGLRenderer::Get()->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_drawFboId);
	CGLRenderer::Get()->glPopClientAttrib();
	CGLRenderer::Get()->glPopAttrib();
	CGLRenderer::Get()->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayBufferBinding);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;
	CGLRenderer::Get()->glUseProgram(m_currentProgram);
	CGLRenderer::Get()->glBindProgramPipeline(m_programPipelineBinding);
	CGLRenderer::Get()->glViewport(r.left, r.top, r.right, r.bottom);
	if (CGLRenderer::Get()->glGetError() != GL_NO_ERROR)
		return false;

	return true;
}

void* GetGLFunc(const char* name)
{
	void *p = 0;

	char namecpy[MAX_PATH] = { 0 };
	strncpy(namecpy, name, sizeof(namecpy));
	namecpy[sizeof(namecpy)-1] = '\0';

	HMODULE hOpenGL = LoadLibraryA("opengl32.dll");
	PROC(__stdcall *pfnwglGetProcAddress)(LPSTR str) = (PROC(__stdcall *)(LPSTR))GetProcAddress(hOpenGL, "wglGetProcAddress");
	if (!pfnwglGetProcAddress)
	{
		Error(L"Can not resolve wglGetProcAddress address!");
	}
	else
	{
		p = (void *)pfnwglGetProcAddress(namecpy);
		if (p == 0 || (p == (void*)0x1) || (p == (void*)0x2) || (p == (void*)0x3) || (p == (void*)-1))
		{
			p = (void *)GetProcAddress(hOpenGL, namecpy);
		}
	}
	FreeLibrary(hOpenGL);
	return p;
} 

Czyli trzeba po prostu wywołać raz Init z device (chociaż nie jest koniecznie posiadania device w openglu w tym momencie), a później przy kończeniu renderowania przez grę EndFrame (jak mówiłem, najlepiej dokładnie przed SwapBuffers).

3

Opis jak wykonać w dx9:
A więc potrzebujemy znać wskaźnik na IDirect3D9, który tworzony jest przez to:

IDirect3D9 * WINAPI Direct3DCreate9(UINT SDKVersion); 

I teraz wiadome jest, że na zalinkowanie tego są dwie metody:

  • statyczne
  • dynamiczne
    Statyczne linkowanie będzie oznaczało, że w importach w pliku exe będzie ta funkcja, a dynamiczne, że funkcja zostanie pobrana za pomocą GetProcAddress z d3d9.dll.
    W większości gier pewnie będzie to linkowanie dynamiczne, i będzie to wyglądało +/- tak:
v3 = sub_488050((int)"d3d9.dll");
  if ( v3 )
    v2 = GetProcAddress((HMODULE)v3, "Direct3DCreate9");
  dword_10DE7DC = (int)v2; 

Oczywiście stringi da się zakodować, i rozkodować przed samym callem GetProcAddress, dlatego jeśli nie możemy tego znaleźć, no to wiadome jest, że trzeba zrobić Detours funkcji GetProcAddress, wyświetlić argumenty, wyświetlić trochę stosu, i znaleźć adres do którego wraca gra po wywołaniu tejże funkcji. Powyżej widzimy, że adres jest zapisywany do globalnej, więc teraz wystarczy poszukać gdzie ona jest wykorzystywana.
Jednak jeśli trudno będzie to znaleźć to można zrobić inny myk:
Pobieramy adres tego Direct3DCreate9 używając GetProcAddress i robimy do tego detours. A w swojej funkcji najpierw callujemy prawdziwy Direct3DCreate9, zapisujemy sobie adres.
Jeśli już będziemy mieli wskaźnik na IDirect3D9 no to w tej klasie jest metoda:

    STDMETHOD(CreateDevice)(THIS_ UINT Adapter,D3DDEVTYPE DeviceType,HWND hFocusWindow,DWORD BehaviorFlags,D3DPRESENT_PARAMETERS* pPresentationParameters,IDirect3DDevice9** ppReturnedDeviceInterface) PURE;
 

Dodam, że jest to virtual a więc występuje vtabela. A więc bierzemy ten wskaźnik co mieliśmy, i bierzemy adres vtabeli, i 16 adres pod tą vtabelą (16 * 4 = 64 offset w bajtach) to jest D3D9CreateDevice. I do tego też robimy detours, w swojej funkcji callujemy prawdziwe tworzenie device, ale równocześnie zapisujemy pointer do IDirect3DDevice. Tym samym mamy już całkiem niezłe pole manewru. Bierzemy vtabelę IDirect3DDevice i 16 (64 offset w bajtach) adres to IDirect3DDevice9::Present. Robimy detours do tego i już mamy wszystko co nam potrzeba.

Trochę kodu do rysowania:

void CGraphics::Begin()
{
	ComplexRenderPush();

	m_pDevice->GetTexture(0, (IDirect3DBaseTexture9**)&m_pCurrentTexture);

	// Cache values
	m_pDevice->GetRenderState(D3DRS_SRGBWRITEENABLE, &m_dwSRGBWriteEnable);
	m_pDevice->GetSamplerState(0, D3DSAMP_SRGBTEXTURE, &m_dwSRGBTexture);

	m_pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
	m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
	m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
	m_pDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
	m_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	m_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	m_pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
	m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
	m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
	m_pDevice->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, 0);
	m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
	m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
	m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
	m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
	m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
	m_pDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
	m_pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);

	m_pDevice->SetTexture(0, 0);

	m_pDevice->SetPixelShader(NULL);
	m_pDevice->SetVertexShader(NULL);

	m_pDevice->SetStreamSource(NULL, 0, 0, 0);
}

void CGraphics::End()
{
	m_pDevice->SetTexture(0, (IDirect3DBaseTexture9*)m_pCurrentTexture);
	m_pDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, m_dwSRGBWriteEnable);
	m_pDevice->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, m_dwSRGBTexture);

	m_pCurrentTexture = NULL;

	ComplexRenderPop();
}

void CGraphics::ComplexRenderPush()
{
	if (m_pStateBlock)
		m_pStateBlock->Capture();
}

void CGraphics::ComplexRenderPop()
{
	if (m_pStateBlock)
		m_pStateBlock->Apply();
} 
IDirect3DStateBlock9 * m_pStateBlock;
void CGraphics::Render()
{
	Begin();
	D3DVIEWPORT9 vpOld;
	m_pDevice->GetViewport(&vpOld);

	RECT ClientRect = { 0 };
	GetClientRect(CInput::GetSingleton()->GetHwnd(), &ClientRect);
	float fWindowWidth = (float)(ClientRect.right - ClientRect.left);
	float fWindowHeight = (float)(ClientRect.bottom - ClientRect.top);

	D3DVIEWPORT9 vp;
	vp.X = 0; vp.Y = 0; vp.Width = (unsigned long)fWindowWidth; vp.Height = (unsigned long)fWindowHeight;
	vp.MaxZ = 1.0f; vp.MinZ = 0.0f;
	m_pDevice->SetViewport(&vp);

	// rysowanie
	this->DrawRectangle(100, 100, 200, 300, 0xFFFFFFFF);

	m_pDevice->SetViewport(&vpOld);
	End();
}

void CGraphics::DrawRectangle(float fX, float fY, float fWidth, float fHeight, unsigned ulColor)
{
	D3DVERTEX vertex[4];
	vertex[0] = D3DVERTEX(fX, fY, 0.0f, 1.0f, ulColor);
	vertex[1] = D3DVERTEX((fX + fWidth), fY, 0.0f, 1.0f, ulColor);
	vertex[2] = D3DVERTEX((fX + fWidth), (fY + fHeight), 0.0f, 1.0f, ulColor);
	vertex[3] = D3DVERTEX(fX, (fY + fHeight), 0.0f, 1.0f, ulColor);
	short indices[6] = { 0, 1, 2, 0, 2, 3 };

	m_pDevice->SetTexture(0, NULL);

	m_pDevice->SetPixelShader(NULL);
	m_pDevice->SetVertexShader(NULL);

	m_pDevice->SetStreamSource(NULL, 0, 0, 0);

	m_pDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
	m_pDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], D3DFMT_INDEX16, &vertex[0], sizeof(D3DVERTEX));
}

struct D3DVERTEX
{
	float fX, fY, fZ, fRHW;
	unsigned long ulColor;

	D3DVERTEX()
	{
		fX = fY = fZ = fRHW = 0.f;
		ulColor = 0xFF000000;
	}

	D3DVERTEX(float _x, float _y, float _z, float _rhw, unsigned long _color)
	{
		fX = _x;
		fY = _y;
		fZ = _z;
		fRHW = _rhw;
		ulColor = _color;
	}
};
 

Oczywiście wszystko da się zrobić omijając detours, tylko trzeba wiedzieć gdzie hooki robić. Opis samego hookowania sobie darowałem, bo myślę, że każdy kto chce sobie poradzi.

Dodam tylko, że nigdy nie testowałem sposobu z hookowaniem Present, ale prawdopodobnie zadziała. Mi hooki lepiej robić :-)

1 użytkowników online, w tym zalogowanych: 0, gości: 1