dll注入:使用opengl绘制简单的游戏覆盖图 [英] dll injection: drawing simple game overlay with opengl

查看:208
本文介绍了dll注入:使用opengl绘制简单的游戏覆盖图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在3d桌面游戏中绘制自定义的opengl叠加层(例如,steam可以做到这一点). 该叠加层基本上应该能够显示用户所使用的某些变量的状态 可以通过按一些键来影响.像游戏培训师一样思考它. 目标首先是在屏幕上的特定点绘制一些图元.后来我想在游戏窗口中有一个看起来不错的"gui"组件. 游戏使用GDI32.dll中的"SwapBuffers"方法. 目前,我可以将自定义DLL文件注入游戏并挂接"SwapBuffers"方法. 我的第一个想法是将覆盖图插入到该函数中.可以通过将3d绘制模式从游戏切换为2d,然后在屏幕上绘制2d叠加层,然后再次将其切换回来完成,如下所示:

I'm trying to draw a custom opengl overlay (steam does that for example) in a 3d desktop game. This overlay should basically be able to show the status of some variables which the user can affect by pressing some keys. Think about it like a game trainer. The goal is in the first place to draw a few primitives at a specific point on the screen. Later I want to have a little nice looking "gui" component in the game window. The game uses the "SwapBuffers" method from the GDI32.dll. Currently I'm able to inject a custom DLL file into the game and hook the "SwapBuffers" method. My first idea was to insert the drawing of the overlay into that function. This could be done by switching the 3d drawing mode from the game into 2d, then draw the 2d overlay on the screen and switch it back again, like this:

//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);

但是,这对游戏完全没有影响.

However, this does not have any effect on the game at all.

  • 我的方法是否正确,合理(还考虑了我的3d到2d转换代码)?
  • 我想知道最好的方法是在挂钩函数中设计和显示自定义叠加层. (我应该使用Windows窗体之类的东西,还是应该将我的组件与opengl函数组装在一起-线,四边形 ...?)
  • SwapBuffers方法是绘制覆盖图的最佳位置吗?
  • Is my approach correct and reasonable (also considering my 3d to 2d switching code)?
  • I would like to know what the best way is to design and display a custom overlay in the hooked function. (should I use something like windows forms or should I assemble my component with opengl functions - lines, quads ...?)
  • Is the SwapBuffers method the best place to draw my overlay?

任何类似的提示,源代码或教程也将受到赞赏. 顺便说一句,该游戏是反恐精英1.6,我无意在网上作弊.

Any hint, source code or tutorial to something similiar is appreciated too. The game by the way is counterstrike 1.6 and I don't intend to cheat online.

谢谢.

我可以通过使用由"derHass"提出的新的opengl上下文,在游戏的窗口中绘制一个简单的矩形.这是我所做的:

I could manage to draw a simple rectangle into the game's window by using a new opengl context as proposed by 'derHass'. Here is what I did:

//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重叠示例 它仍然非常简单,但是我将尝试在其中添加更多详细信息,文本等.

Here is the result: cs overlay example It is still very simple but I will try to add some more details, text etc. to it.

谢谢.

推荐答案

原则上,如果游戏使用的是OpenGL,则挂在SwapBuffers上是可行的方法.从理论上讲,可能会有一些不同的可绘制对象,您可能必须在交换缓冲区函数中确定哪些是正确的可修改对象.

If the game is using OpenGL, then hooking into SwapBuffers is the way to go, in principle. In theory, there might be sevaral different drawables, and you might have to decide in your swap buffer function which one(s) are the right ones to modify.

但是,这种OpenGL拦截有几个问题:

There are a couple of issues with such kind of OpenGL interceptions, though:

  1. OpenGL是一种状态机.该应用程序可能已经修改了其中的任何GL状态变量.您提供的代码还远远不够完整,无法保证已画出一些东西.例如,如果应用程序恰好启用了着色器,则您所有的矩阵设置都可能无效,并且真正显示在屏幕上的内容取决于着色器. 如果进行深度测试,则您的片段可能位于已绘制的片段后面.如果启用了多边形剔除,则在当前剔除模式下可能会不正确地缠绕图元.如果将颜色蒙版设置为GL_FALSE或绘制缓冲区未设置在您期望的位置,则将不会显示任何内容.

  1. OpenGL is a state machine. The application might have modified any GL state variable there is. The code you provided is far from complete to guarantee that something is draw. For example, if the application happens to have shaders enabled, all your matrix setup might be without effect, and what really would appear on the screen depends on the shaders. If depth testing is on, your fragments might lie behind what already was drawn. If polygon culling is on, your primitive might be incorrectly winded for the currect culling mode. If the color masks are set to GL_FALSE or the draw buffer is not set to where you expect it, nothing will appear.

还请注意,您尝试重置"矩阵也是错误的.您似乎假设当前的矩阵模式为GL_MODELVIEW.但这不是必须的.也可以是GL_PROJECTIONGL_TEXTURE.您还可以将glOrtho应用于当前的投影矩阵而无需先加载身份,因此仅此一个理由就可以使屏幕上什么也不出现.

Also note that your attempt to "reset" the matrices is also wrong. You seem to assume that the current matrix mode is GL_MODELVIEW. But this doesn't have to be the case. It could as well be GL_PROJECTION or GL_TEXTURE. You also apply glOrtho to the current projection matrix without loading identity first, so this alone is a good reason for nothing to appear on the screen.

由于OpenGL是状态机,因此您还必须恢复触摸到的所​​有状态.您已经使用矩阵堆栈push/pop尝试了此操作.但是,例如,您无法还原精确的矩阵模式.如您在1中所见,将需要进行更多状态更改,因此恢复状态将更加复杂.由于您使用的是旧版OpenGL,因此 glPushAttrib() 可能会派上用场.

As OpenGL is a state machine, you also must restore all the state you touched. You already try this with the matrix stack push/pop. But you for example failed to restore the exact matrix mode. As you have seen in 1, a lot more state changes will be required, so restoring it will be more comples. Since you use legacy OpenGL, glPushAttrib() might come handy here.

SwapBuffers不是GL函数,而是操作系统的API之一.它获取一个drawable作为参数,并且仅间接引用任何GL上下文. 它可能是在另一个GL上下文绑定到线程时调用的,或者根本没有.如果您想安全地使用它,则还必须拦截GL上下文创建函数以及MakeCurrent.在最坏的情况下(尽管非常不可能),应用程序在调用SwapBuffers时会将GL上下文绑定到另一个线程,因此在挂钩函数中没有任何更改可以获取上下文.

SwapBuffers is not a GL function, but one of the operating system's API. It gets a drawable as parameter, and does only indirectly refer to any GL context. It might be called while another GL context is bound to the thread, or with none at all. If you want to play it safe, you'll also have to intercept the GL context creation function as well as MakeCurrent. In the worst (though very unlikely) case, the application has the GL context bound to another thread while it is calling the SwapBuffers, so there is no change for you in the hooked function to get to the context.

将所有内容放在一起将提供另一个选择:您可以创建自己的GL上下文,在挂钩的SwapBuffers调用期间临时绑定它,然后再次恢复原始绑定.这样,您根本不会干扰应用程序的GL状态.您仍然可以增加应用程序已渲染的图像内容,因为帧缓冲区是可绘制对象(而不是GL上下文)的一部分.这样做可能会对性能产生负面影响,但它可能是如此之小,以至于您甚至都不会注意到它.

Putting this all together opens up another alternative: You can create your own GL context, bind it temporarily during the hooked SwapBuffers call and restore the original binding again. That way, you don't interfere with the GL state of the application at all. You still can augment the image content the application has rendered, since the framebuffer is part of the drawable, not the GL context. Doing so might have a negative impact on performance, but it might be so small that you never would even notice it.

由于您只想对单个特定应用程序执行此操作,因此另一种方法是通过观察应用程序在SwapBuffers调用期间实际设置的GL状态来找出最小的状态更改.像 apitrace 这样的工具可以为您提供帮助.

Since you want to do this only for a single specific application, another approach would be to find out the minimal state changes which are necessary by observing what GL state the application actually set during the SwapBuffers call. A tool like apitrace can help you with that.

这篇关于dll注入:使用opengl绘制简单的游戏覆盖图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆