dll 注入:使用 opengl 绘制简单的游戏叠加层
dll injection: drawing simple game overlay with opengl
我正在尝试在 3d 桌面游戏中绘制自定义 opengl 叠加层(例如 steam 就是这样做的)。
这个覆盖图基本上应该能够显示用户需要的一些变量的状态
可以通过按一些键来影响。把它想象成一个游戏教练。
目标首先是在屏幕上的特定点绘制一些图元。后来我想在游戏window中有一个好看的"gui"组件。
游戏使用了GDI32.dll中的"SwapBuffers"方法。
目前我能够将自定义 DLL 文件注入游戏并挂钩 "SwapBuffers" 方法。
我的第一个想法是将覆盖图插入到该函数中。这可以通过将游戏的 3d 绘图模式切换为 2d,然后在屏幕上绘制 2d 叠加层并再次切换回来来完成,如下所示:
//SwapBuffers_HOOK (HDC)
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glOrtho(0.0, 640, 480, 0.0, 1.0, -1.0);
//"OVERLAY"
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex2f(0, 0);
glVertex2f(0.5f, 0);
glVertex2f(0.5f, 0.5f);
glVertex2f(0.0f, 0.5f);
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
SwapBuffers_OLD(HDC);
但是,这对游戏没有任何影响。
- 我的做法是否正确合理(还要考虑我的3d转2d代码)?
- 我想知道在挂钩函数中设计和显示自定义叠加层的最佳方法是什么。 (我应该使用类似 windows 形式的东西还是应该 assemble 我的带有 opengl 函数的组件 - 线,四边形
...?)
- SwapBuffers 方法是绘制叠加层的最佳位置吗?
也欢迎任何类似的提示、源代码或教程。
顺便说一句,游戏是反恐精英1.6,我不打算在线作弊。
谢谢。
编辑:
通过使用 'derHass' 提议的新 opengl 上下文,我可以设法在游戏 window 中绘制一个简单的矩形。这是我所做的:
//1. At the beginning of the hooked gdiSwapBuffers(HDC hdc) method save the old context
GLboolean gdiSwapBuffersHOOKED(HDC hdc) {
HGLRC oldContext = wglGetCurrentContext();
//2. If the new context has not been already created - create it
//(we need the "hdc" parameter for the current window, so the initialition
//process is happening in this method - anyone has a better solution?)
//Then set the new context to the current one.
if (!contextCreated) {
thisContext = wglCreateContext(hdc);
wglMakeCurrent(hdc, thisContext);
initContext();
}
else {
wglMakeCurrent(hdc, thisContext);
}
//Draw the quad in the new context and switch back to the old one.
drawContext();
wglMakeCurrent(hdc, oldContext);
return gdiSwapBuffersOLD(hdc);
}
GLvoid drawContext() {
glColor3f(1.0f, 0, 0);
glBegin(GL_QUADS);
glVertex2f(0,190.0f);
glVertex2f(100.0f, 190.0f);
glVertex2f(100.0f,290.0f);
glVertex2f(0, 290.0f);
glEnd();
}
GLvoid initContext() {
contextCreated = true;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 640, 480, 0.0, 1.0, -1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0, 0, 0, 1.0);
}
结果如下:
cs overlay example
它仍然很简单,但我会尝试添加更多细节、文本等。
谢谢。
如果游戏使用的是 OpenGL,原则上挂接到 SwapBuffers
是可行的方法。理论上,可能有几个不同的可绘制对象,您可能必须在交换缓冲区函数中决定哪些是正确的修改对象。
不过,此类 OpenGL 拦截存在一些问题:
OpenGL 是一个状态机。应用程序可能已经修改了现有的任何 GL 状态变量。您提供的代码远未完成,无法保证绘制某些内容。例如,如果应用程序碰巧启用了着色器,则所有矩阵设置可能都没有效果,屏幕上真正显示的内容取决于着色器。
如果开启了深度测试,您的片段可能位于已绘制的内容后面。如果启用了多边形剔除,则您的图元可能会针对当前剔除模式错误缠绕。如果颜色遮罩设置为 GL_FALSE
或绘图缓冲区未设置为您期望的位置,则不会出现任何内容。
另请注意,您对 "reset" 矩阵的尝试也是错误的。您似乎假设当前矩阵模式是 GL_MODELVIEW
。但这不一定是这种情况。它也可以是 GL_PROJECTION
或 GL_TEXTURE
。您还可以将 glOrtho
应用于当前投影矩阵,而无需先加载恒等式,因此仅此一项就是屏幕上不显示任何内容的充分理由。
由于 OpenGL 是一个状态机,您还必须恢复您所触及的所有状态。您已经使用矩阵堆栈 push/pop 尝试过此操作。但是,例如,您未能恢复精确的矩阵模式。正如您在 1 中看到的,将需要更多的状态更改,因此恢复它会更复杂。由于您使用旧版 OpenGL,glPushAttrib()
在这里可能会派上用场。
SwapBuffers
不是 GL 函数,而是操作系统的 API 之一。它获取一个可绘制对象作为参数,并且仅间接引用任何 GL 上下文。 它可能在另一个 GL 上下文绑定到线程时被调用,或者根本没有 none。 如果你想安全地玩它,你还必须拦截GL上下文创建函数以及MakeCurrent
。在最坏的(尽管不太可能)情况下,应用程序在调用 SwapBuffers
时将 GL 上下文绑定到另一个线程,因此挂钩函数中没有任何更改可以获取上下文。
将这些放在一起开辟了另一种选择:您可以创建自己的 GL 上下文,在挂钩 SwapBuffers
调用期间临时绑定它,然后再次恢复原始绑定。这样,您根本不会干扰应用程序的 GL 状态。您仍然可以增加应用程序呈现的图像内容,因为帧缓冲区是可绘制对象的一部分,而不是 GL 上下文。这样做可能会对性能产生负面影响,但它可能很小,您甚至都不会注意到它。
由于您只想对单个特定应用程序执行此操作,另一种方法是通过观察应用程序在 SwapBuffers 调用期间实际设置的 GL 状态来找出必要的最小状态更改。 apitrace 之类的工具可以帮助您。
我正在尝试在 3d 桌面游戏中绘制自定义 opengl 叠加层(例如 steam 就是这样做的)。 这个覆盖图基本上应该能够显示用户需要的一些变量的状态 可以通过按一些键来影响。把它想象成一个游戏教练。 目标首先是在屏幕上的特定点绘制一些图元。后来我想在游戏window中有一个好看的"gui"组件。 游戏使用了GDI32.dll中的"SwapBuffers"方法。 目前我能够将自定义 DLL 文件注入游戏并挂钩 "SwapBuffers" 方法。 我的第一个想法是将覆盖图插入到该函数中。这可以通过将游戏的 3d 绘图模式切换为 2d,然后在屏幕上绘制 2d 叠加层并再次切换回来来完成,如下所示:
//SwapBuffers_HOOK (HDC)
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glOrtho(0.0, 640, 480, 0.0, 1.0, -1.0);
//"OVERLAY"
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex2f(0, 0);
glVertex2f(0.5f, 0);
glVertex2f(0.5f, 0.5f);
glVertex2f(0.0f, 0.5f);
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
SwapBuffers_OLD(HDC);
但是,这对游戏没有任何影响。
- 我的做法是否正确合理(还要考虑我的3d转2d代码)?
- 我想知道在挂钩函数中设计和显示自定义叠加层的最佳方法是什么。 (我应该使用类似 windows 形式的东西还是应该 assemble 我的带有 opengl 函数的组件 - 线,四边形 ...?)
- SwapBuffers 方法是绘制叠加层的最佳位置吗?
也欢迎任何类似的提示、源代码或教程。 顺便说一句,游戏是反恐精英1.6,我不打算在线作弊。
谢谢。
编辑:
通过使用 'derHass' 提议的新 opengl 上下文,我可以设法在游戏 window 中绘制一个简单的矩形。这是我所做的:
//1. At the beginning of the hooked gdiSwapBuffers(HDC hdc) method save the old context
GLboolean gdiSwapBuffersHOOKED(HDC hdc) {
HGLRC oldContext = wglGetCurrentContext();
//2. If the new context has not been already created - create it
//(we need the "hdc" parameter for the current window, so the initialition
//process is happening in this method - anyone has a better solution?)
//Then set the new context to the current one.
if (!contextCreated) {
thisContext = wglCreateContext(hdc);
wglMakeCurrent(hdc, thisContext);
initContext();
}
else {
wglMakeCurrent(hdc, thisContext);
}
//Draw the quad in the new context and switch back to the old one.
drawContext();
wglMakeCurrent(hdc, oldContext);
return gdiSwapBuffersOLD(hdc);
}
GLvoid drawContext() {
glColor3f(1.0f, 0, 0);
glBegin(GL_QUADS);
glVertex2f(0,190.0f);
glVertex2f(100.0f, 190.0f);
glVertex2f(100.0f,290.0f);
glVertex2f(0, 290.0f);
glEnd();
}
GLvoid initContext() {
contextCreated = true;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 640, 480, 0.0, 1.0, -1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0, 0, 0, 1.0);
}
结果如下: cs overlay example 它仍然很简单,但我会尝试添加更多细节、文本等。
谢谢。
如果游戏使用的是 OpenGL,原则上挂接到 SwapBuffers
是可行的方法。理论上,可能有几个不同的可绘制对象,您可能必须在交换缓冲区函数中决定哪些是正确的修改对象。
不过,此类 OpenGL 拦截存在一些问题:
OpenGL 是一个状态机。应用程序可能已经修改了现有的任何 GL 状态变量。您提供的代码远未完成,无法保证绘制某些内容。例如,如果应用程序碰巧启用了着色器,则所有矩阵设置可能都没有效果,屏幕上真正显示的内容取决于着色器。 如果开启了深度测试,您的片段可能位于已绘制的内容后面。如果启用了多边形剔除,则您的图元可能会针对当前剔除模式错误缠绕。如果颜色遮罩设置为
GL_FALSE
或绘图缓冲区未设置为您期望的位置,则不会出现任何内容。另请注意,您对 "reset" 矩阵的尝试也是错误的。您似乎假设当前矩阵模式是
GL_MODELVIEW
。但这不一定是这种情况。它也可以是GL_PROJECTION
或GL_TEXTURE
。您还可以将glOrtho
应用于当前投影矩阵,而无需先加载恒等式,因此仅此一项就是屏幕上不显示任何内容的充分理由。由于 OpenGL 是一个状态机,您还必须恢复您所触及的所有状态。您已经使用矩阵堆栈 push/pop 尝试过此操作。但是,例如,您未能恢复精确的矩阵模式。正如您在 1 中看到的,将需要更多的状态更改,因此恢复它会更复杂。由于您使用旧版 OpenGL,
glPushAttrib()
在这里可能会派上用场。SwapBuffers
不是 GL 函数,而是操作系统的 API 之一。它获取一个可绘制对象作为参数,并且仅间接引用任何 GL 上下文。 它可能在另一个 GL 上下文绑定到线程时被调用,或者根本没有 none。 如果你想安全地玩它,你还必须拦截GL上下文创建函数以及MakeCurrent
。在最坏的(尽管不太可能)情况下,应用程序在调用SwapBuffers
时将 GL 上下文绑定到另一个线程,因此挂钩函数中没有任何更改可以获取上下文。
将这些放在一起开辟了另一种选择:您可以创建自己的 GL 上下文,在挂钩 SwapBuffers
调用期间临时绑定它,然后再次恢复原始绑定。这样,您根本不会干扰应用程序的 GL 状态。您仍然可以增加应用程序呈现的图像内容,因为帧缓冲区是可绘制对象的一部分,而不是 GL 上下文。这样做可能会对性能产生负面影响,但它可能很小,您甚至都不会注意到它。
由于您只想对单个特定应用程序执行此操作,另一种方法是通过观察应用程序在 SwapBuffers 调用期间实际设置的 GL 状态来找出必要的最小状态更改。 apitrace 之类的工具可以帮助您。