dll注入:用opengl

时间:2015-12-21 23:25:58

标签: c++ opengl overlay dll-injection

我试图在3D桌面游戏中绘制自定义opengl叠加层(例如蒸汽就是这样)。 这个叠加应该基本上能够显示用户的一些变量的状态 可以通过按某些键来影响。把它想象成一个游戏训练师。 目标是首先在屏幕上的特定点绘制一些基元。后来我想要一个漂亮的外观" gui"游戏窗口中的组件。 游戏使用" SwapBuffers"来自GDI32.dll的方法。 目前,我能够将自定义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窗体这样的东西,还是应该用opengl函数组装我的组件 - line,quads ...?)
  • SwapBuffers方法是绘制叠加层的最佳位置吗?

任何类似的提示,源代码或教程也值得赞赏。 顺便说一下,这场比赛是反击1.6并且我不打算在网上作弊。

感谢。

编辑:

我可以设法通过使用由“derHass”提出的新的opengl上下文在游戏的窗口中绘制一个简单的矩形。这是我做的:

//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 它仍然非常简单,但我会尝试添加更多细节,文本等。

感谢。

1 个答案:

答案 0 :(得分:1)

如果游戏使用的是OpenGL,那么原则上可以选择挂钩SwapBuffers。从理论上讲,可能存在各种不同的drawable,您可能必须在交换缓冲区函数中决定哪一个是正确的修改。

但是这种OpenGL拦截存在一些问题:

  1. OpenGL是一个状态机。应用程序可能已经修改了任何GL状态变量。您提供的代码远非完整,无法保证绘制内容。例如,如果应用程序恰好启用了着色器,则所有矩阵设置可能都没有效果,并且屏幕上真正显示的内容取决于着色器。 如果进行深度测试,您的碎片可能会落后于已绘制的碎片。如果启用了多边形剔除,则对于当前剔除模式,您的图元可能会被错误地蜿蜒。如果颜色蒙版设置为GL_FALSE或者绘图缓冲区未设置到您期望的位置,则不会显示任何内容。

    另请注意,您尝试“重置”矩阵也是错误的。您似乎假设当前矩阵模式为GL_MODELVIEW。但事实并非如此。它也可以是GL_PROJECTIONGL_TEXTURE。您还可以在不首先加载标识的情况下将glOrtho应用于当前投影矩阵,因此仅此一项就是没有任何内容出现在屏幕上的好理由。

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

  3. SwapBuffers不是GL函数,而是操作系统的API之一。它得到一个drawable作为参数,并且只间接引用任何GL上下文。 当另一个GL上下文绑定到线程时,或者根本没有GL上下文时,可能会调用它。如果你想安全地玩它,你还必须截取GL上下文创建函数以及MakeCurrent。在最糟糕的情况下(尽管非常不可能),应用程序在调用SwapBuffers时将GL上下文绑定到另一个线程,因此在钩子函数中没有任何变化可以到达上下文。

  4. 将所有这些放在一起会打开另一种选择:您可以创建自己的GL上下文,在挂钩的SwapBuffers调用期间临时绑定它并再次恢复原始绑定。这样,您根本不会干扰应用程序的GL状态。您仍然可以扩充应用程序渲染的图像内容,因为帧缓冲区是drawable的一部分,而不是GL上下文。这样做可能会对性能产生负面影响,但它可能会非常小,以至于您甚至都不会注意到它。

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