【问题标题】:dll injection: drawing simple game overlay with opengldll注入:用opengl绘制简单的游戏覆盖
【发布时间】:2016-03-28 03:23:15
【问题描述】:

我正在尝试在 3d 桌面游戏中绘制自定义 opengl 叠加层(例如 Steam 就是这样做的)。 这个叠加层基本上应该能够显示用户的一些变量的状态 可以通过按一些键来影响。把它想象成一个游戏教练。 目标首先是在屏幕上的特定点绘制一些图元。稍后我想在游戏窗口中有一个漂亮的“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 窗体之类的东西,还是应该用 opengl 函数组装我的组件 - 线、四边形 ...?)
  • 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 它仍然很简单,但我会尝试添加更多细节、文本等。

谢谢。

【问题讨论】:

  • 确保它实际上正在加载,例如。用 printf。此外,如果游戏请求核心配置文件,其中已删除不推荐使用的立即模式和矩阵函数,这将不起作用。
  • @ColonelThirtyTwo Jup 它正在加载。我用一个简单的 glClearColor(GL_COLOR_BUFFER_BIT) 对其进行了测试-> 整个屏幕呈现红色。我怀疑 Counterstrike 1.6 是否使用核心配置文件,因为这款游戏已经过时了。 (我假设)它仍在使用旧的矩阵函数。我已经通过向 glPopMatrix 和 glMatrixMode 方法添加断点对其进行了测试。即使这不是立即模式的明确证据,但游戏使用它而不是仅使用着色器更有意义。

标签: c++ opengl overlay dll-injection


【解决方案1】:

如果游戏使用 OpenGL,原则上连接到SwapBuffers 是可行的方法。理论上,可能有几个不同的可绘制对象,您可能必须在交换缓冲区函数中决定哪些是要修改的正确对象。

不过,此类 OpenGL 拦截存在几个问题:

  1. OpenGL 是一个状态机。应用程序可能已经修改了任何 GL 状态变量。您提供的代码远未完成,无法保证绘制某些内容。例如,如果应用程序碰巧启用了着色器,那么您的所有矩阵设置可能都无效,屏幕上真正出现的内容取决于着色器。 如果深度测试已开启,您的片段可能位于已绘制的内容后面。如果启用了多边形剔除,则对于当前剔除模式,您的图元可能会被错误地缠绕。如果颜色掩码设置为 GL_FALSE 或绘图缓冲区未设置为您期望的位置,则不会出现任何内容。

    另请注意,您尝试“重置”矩阵也是错误的。您似乎假设当前的矩阵模式是GL_MODELVIEW。但事实并非如此。它也可以是GL_PROJECTIONGL_TEXTURE。您还可以将glOrtho 应用于当前投影矩阵,而无需先加载身份,因此仅此一项就可以很好地说明屏幕上不会出现任何内容。

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

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

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

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

【讨论】:

  • 我绝对推荐使用专用的 OpenGL 上下文进行叠加。关于上下文切换开销,…_ARB_context_flush_control 扩展为您提供了很大的回旋余地。 opengl.org/registry/specs/KHR/context_flush_control.txt
  • 你如何在你不拥有的上下文中使用上下文刷新控制的东西?您可以使新上下文不刷新,但主上下文会。交换每个 SwapBuffers 调用的上下文会破坏性能,并且在我尝试过的至少一张 AMD 卡上也不能正常工作。这也是 Mumble(VOIP/覆盖游戏应用程序)所做的,它也遇到了同样的问题。见stackoverflow.com/questions/39713133/…
  • @aggieNick02:嗯,从概念上讲,你也可以挂钩到上下文创建中......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多