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]