roger 发表于 2021-4-13 11:27:39

2021腾讯游戏安全技术竞赛PC客户端初赛writeup

初赛这题与18年的题目的一部分相似。
典型的自由视角解锁问题,常见于各类FPS游戏。
过程:
首先通过IDA静态分析,发现其为OpenGL做的3维图形显示程序
从网上找到了比较类似的代码:
https://blog.csdn.net/szqsdq/article/details/79584409
执行程序后发现了箭头,但是没有发现另一副图画,这引起了我的注意
发现其实移动鼠标是有视野的,但是并没有全面,所以直接联想到FPS游戏中的视角解锁,之前做过D3D游戏的视角解锁挂(没错就是吃鸡),但是没有接触过OpenGL
其实原理都是一样的
这里有篇好文章
https://learnopengl-cn.github.io/01%20Getting%20started/09%20Camera/
这里简要说一下,这里从内存中加载了两幅图,最后是OpenGL绘图
进去之后OpenGL对照源码标记函数,这个没啥好讲的我们想解锁自由视角,就需要控制camera
核心函数就是剩下的就是祭出Detour大法,InlineHook函数,替换
那两个 glm::mat4 坐标为自己设定的值,就能解锁视角很简单,设定好Hook点,同时我们获取了程序glfwGetKey的函数地址,做了键盘的视角控制函数WSAD控制着摄像机的坐标,RT为缩放
之后我们使用DetourCreateProcessWithDll来让DLL注入到进程中,其实最开始用DetourSetDll程序设置程序import注入Dll,结果发生了黑屏图片显示不正常的问题,这个是因为修改了文件头,破坏了最初的拿图片数据的结构,所以只能动态去注入Hook使用Detours的DetourCreateProcessWithDll函数将Dll注入到程序中实现Hook
通过WSAD和RT控制镜头,得到对应的flag:dogod// DllMain
#include "stdafx.h"

#define RVA_glfwGetKey 0x19920

#define RVA_Get_p_windows_HookPoint 0x06542
#define RVA_Key_HookPoint 0x06BDB
#define RVA_Setprojection_HookPoint 0x06CDB
#define RVA_SetView_HookPoint 0x06DEE

glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 3.0f);
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f);
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f);

float fov = 50.0f;

typedef DWORD(__cdecl* pfnglfwGetKey)(DWORD p_windows, DWORD KeyValue);
pfnglfwGetKey m_glfwGetKey;

DWORD p_windows;
HMODULE hModule_EXE;
PVOID p_windows_HookPoint = NULL;
PVOID p_GetKey_HookPoint = NULL;

PVOID p_Setprojection = NULL;
PVOID p_Setview = NULL;

glm::mat4 projection;
glm::mat4 view;

VOID NAKED Get_p_windows()
{
    STACK_FRAME_BEGIN
      __asm {
      mov p_windows, eax
    }
    STACK_FRAME_END
      __asm {
      push p_windows_HookPoint
      ret
    }

}

VOID NAKED prcessInPut()
{
    STACK_FRAME_BEGIN
      if (m_glfwGetKey(p_windows, GLFW_KEY_W) == GLFW_PRESS)
      {
            cameraPos += cameraFront;
      }
    if (m_glfwGetKey(p_windows, GLFW_KEY_S) == GLFW_PRESS)
    {
      cameraPos -= cameraFront;
    }
    if (m_glfwGetKey(p_windows, GLFW_KEY_A) == GLFW_PRESS)
    {
      cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp));
    }
    if (m_glfwGetKey(p_windows, GLFW_KEY_D) == GLFW_PRESS)
    {
      cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp));
    }
    if (m_glfwGetKey(p_windows, GLFW_KEY_R) == GLFW_PRESS)
    {
      fov -= 1.0;
    }
    if (m_glfwGetKey(p_windows, GLFW_KEY_T) == GLFW_PRESS)
    {
      fov += 1.0f;

    }
    view = glm::lookAt(cameraPos, cameraFront + cameraPos, cameraUp);
    projection = glm::perspective(glm::radians(fov), (float)800.0 / (float)600.0, 0.1f, 200.0f);

    STACK_FRAME_END
      __asm {
      push p_GetKey_HookPoint
      ret
    }
}

VOID NAKED Setprojection()
{
    __asm {
      mov ecx, offset projection
      push p_Setprojection
      ret
    }
}

VOID NAKED Setview()
{
    __asm
    {
      mov ecx, offset view
      push p_Setview
      ret
    }
}

BOOL DetourHook()
{
    if (DetourTransactionBegin() == NO_ERROR)
    {
      DetourAttach(&p_windows_HookPoint, Get_p_windows);
      DetourAttach(&p_GetKey_HookPoint, prcessInPut);
      DetourAttach(&p_Setprojection, Setprojection);
      DetourAttach(&p_Setview, Setview);

      if (DetourTransactionCommit() == NO_ERROR)
      {
            return TRUE;
      }
    }
    return FALSE;
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORDul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
      hModule_EXE = GetModuleHandle(NULL);
      m_glfwGetKey = (pfnglfwGetKey)((DWORD)hModule_EXE + RVA_glfwGetKey);

      p_windows_HookPoint = (PVOID)((DWORD)hModule_EXE + RVA_Get_p_windows_HookPoint);
      p_GetKey_HookPoint = (PVOID)((DWORD)hModule_EXE + RVA_Key_HookPoint);
      p_Setprojection = (PVOID)((DWORD)hModule_EXE + RVA_Setprojection_HookPoint);
      p_Setview = (PVOID)((DWORD)hModule_EXE + RVA_SetView_HookPoint);

      DetourHook();
      break;
    case DLL_THREAD_ATTACH:
      break;
    case DLL_THREAD_DETACH:
      break;
    case DLL_PROCESS_DETACH:
      break;
    }
    return TRUE;
}在这里我偷懒了,发现只通过控制镜头的pos和缩放就能看到flag,实际中还有通过鼠标控制镜头朝向,大致的原理都一样。


页: [1]
查看完整版本: 2021腾讯游戏安全技术竞赛PC客户端初赛writeup