师傅tql,请问你得签名文件是怎么编译得啊?我编译出来得sig匹配不到函数啊
PC客户端初赛赛题解题报告
概述
本题是一个windows 32位opengl游戏程序,打开发现是一个3d游戏,视角移动受限,未提供坐标移动功能,无法看到屏幕中央箭头指向的区域。
使用ida搜索字符串可以发现使用的glfw版本为3.3,并且使用了opengl es。
由于glfw库采用静态编译,程序中大量调用其api函数而缺少符号信息,为了更方便的分析,从官网现在了glfw 3.3的lib库(https://github.com/glfw/glfw/releases/download/3.3.3/glfw-3.3.3.zip),使用ida的flair功能制作函数sig库,具体命令如下:
pcf glfw3_mt.lib
sigmake glfw3_mt.pat glfw3_mt.sig
将sig放入ida识别,即可成功识别部分库函数。
而对于题目中中大量虚表函数引用,其地址为动态导入,有函数名字符串其实更方便我们识别,例如下面的导入代码:
void sub_404710()
{
if ( dword_466D24 )
{
sub_418CB0("glColorMaski");
sub_418CB0("glGetBooleani_v");
sub_418CB0("glGetIntegeri_v");
sub_418CB0("glEnablei");
sub_418CB0("glDisablei");
sub_418CB0("glIsEnabledi");
sub_418CB0("glBeginTransformFeedback");
sub_418CB0("glEndTransformFeedback");
sub_418CB0("glBindBufferRange");
sub_418CB0("glBindBufferBase");
sub_418CB0("glTransformFeedbackVaryings");
sub_418CB0("glGetTransformFeedbackVarying");
sub_418CB0("glClampColor");
sub_418CB0("glBeginConditionalRender");
sub_418CB0("glEndConditionalRender");
sub_418CB0("glVertexAttribIPointer");
sub_418CB0("glGetVertexAttribIiv");
sub_418CB0("glGetVertexAttribIuiv");
sub_418CB0("glVertexAttribI1i");
sub_418CB0("glVertexAttribI2i");
sub_418CB0("glVertexAttribI3i");
sub_418CB0("glVertexAttribI4i");
sub_418CB0("glVertexAttribI1ui");
sub_418CB0("glVertexAttribI2ui");
sub_418CB0("glVertexAttribI3ui");
sub_418CB0("glVertexAttribI4ui");
sub_418CB0("glVertexAttribI1iv");
sub_418CB0("glVertexAttribI2iv");
sub_418CB0("glVertexAttribI3iv");
sub_418CB0("glVertexAttribI4iv");
sub_418CB0("glVertexAttribI1uiv");
sub_418CB0("glVertexAttribI2uiv");
sub_418CB0("glVertexAttribI3uiv");
sub_418CB0("glVertexAttribI4uiv");
sub_418CB0("glVertexAttribI4bv");
sub_418CB0("glVertexAttribI4sv");
sub_418CB0("glVertexAttribI4ubv");
sub_418CB0("glVertexAttribI4usv");
sub_418CB0("glGetUniformuiv");
sub_418CB0("glBindFragDataLocation");
sub_418CB0("glGetFragDataLocation");
sub_418CB0("glUniform1ui");
sub_418CB0("glUniform2ui");
sub_418CB0("glUniform3ui");
sub_418CB0("glUniform4ui");
sub_418CB0("glUniform1uiv");
sub_418CB0("glUniform2uiv");
sub_418CB0("glUniform3uiv");
sub_418CB0("glUniform4uiv");
sub_418CB0("glTexParameterIiv");
sub_418CB0("glTexParameterIuiv");
sub_418CB0("glGetTexParameterIiv");
sub_418CB0("glGetTexParameterIuiv");
sub_418CB0("glClearBufferiv");
sub_418CB0("glClearBufferuiv");
sub_418CB0("glClearBufferfv");
sub_418CB0("glClearBufferfi");
glGetStringi = sub_418CB0("glGetStringi");
sub_418CB0("glIsRenderbuffer");
sub_418CB0("glBindRenderbuffer");
sub_418CB0("glDeleteRenderbuffers");
sub_418CB0("glGenRenderbuffers");
sub_418CB0("glRenderbufferStorage");
sub_418CB0("glGetRenderbufferParameteriv");
sub_418CB0("glIsFramebuffer");
sub_418CB0("glBindFramebuffer");
sub_418CB0("glDeleteFramebuffers");
sub_418CB0("glGenFramebuffers");
sub_418CB0("glCheckFramebufferStatus");
sub_418CB0("glFramebufferTexture1D");
sub_418CB0("glFramebufferTexture2D");
sub_418CB0("glFramebufferTexture3D");
sub_418CB0("glFramebufferRenderbuffer");
sub_418CB0("glGetFramebufferAttachmentParameteriv");
glGenerateMipmap = (int (__stdcall *)(_DWORD))sub_418CB0("glGenerateMipmap");
sub_418CB0("glBlitFramebuffer");
sub_418CB0("glRenderbufferStorageMultisample");
sub_418CB0("glFramebufferTextureLayer");
sub_418CB0("glMapBufferRange");
sub_418CB0("glFlushMappedBufferRange");
glBindVertexArray = (int (__stdcall *)(_DWORD))sub_418CB0("glBindVertexArray");
glDeleteVertexArrays = (int (__stdcall *)(_DWORD, _DWORD))sub_418CB0("glDeleteVertexArrays");
glGenVertexArrays = (int (__stdcall *)(_DWORD, _DWORD))sub_418CB0("glGenVertexArrays");
sub_418CB0("glIsVertexArray");
}
}
这样大大提高了程序可读性。
程序流程
从winmain函数开始分析,首先程序读取了其文件数据中的两个纹理图案数据:
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
char *v4; // esi
DWORD v5; // ebx
HANDLE v6; // eax
void *v7; // edi
void *v8; // ebx
DWORD v9; // edi
HANDLE v10; // eax
void *v11; // esi
LONG lDistanceToMove; // [esp+Ch] [ebp-110h]
void *lpBuffer; // [esp+10h] [ebp-10Ch]
LPVOID lpBuffera; // [esp+10h] [ebp-10Ch]
DWORD NumberOfBytesRead; // [esp+14h] [ebp-108h]
CHAR Filename; // [esp+18h] [ebp-104h]
v4 = (char *)hInstance + *(_DWORD *)((char *)hInstance + *((_DWORD *)hInstance + 15) + 0x54);
memset(&Filename, 0, 0x100u);
GetModuleFileNameA(hInstance, &Filename, 0x100u);
lDistanceToMove = *((_DWORD *)v4 - 2);
sub_407380(&dword_465FE4, *((_DWORD *)v4 - 3));
lpBuffer = (void *)dword_465FE4;
v5 = dword_465FE8 - dword_465FE4;
v6 = CreateFileA(&Filename, 0x80000000, 1u, 0, 3u, 0x80u, 0);
v7 = v6;
if ( v6 != (HANDLE)-1 )
{
SetFilePointer(v6, lDistanceToMove, 0, 0);
NumberOfBytesRead = 0;
ReadFile(v7, lpBuffer, v5, &NumberOfBytesRead, 0);
CloseHandle(v7);
}
lpBuffera = (LPVOID)*((_DWORD *)v4 - 4);
sub_407380((int *)&::lpBuffer, *((_DWORD *)v4 - 5));
v8 = ::lpBuffer;
v9 = dword_465FF8 - (_DWORD)::lpBuffer;
v10 = CreateFileA(&Filename, 0x80000000, 1u, 0, 3u, 0x80u, 0);
v11 = v10;
if ( v10 != (HANDLE)-1 )
{
SetFilePointer(v10, (LONG)lpBuffera, 0, 0);
NumberOfBytesRead = 0;
ReadFile(v11, v8, v9, &NumberOfBytesRead, 0);
CloseHandle(v11);
}
return sub_4064D0();
}
接着进入关键的sub_4064D0,该函数就是一个较为典型的opengl 3d程序,使用标准的MVP模型构建,使用shader着色器渲染游戏。
signed int sub_4064D0()
{
glfwInit();
glfwWindowHint(0x22002, 3);
glfwWindowHint(0x22003, 3);
glfwWindowHint(0x22008, 0x32001);
v0 = glfwCreateWindow(800, 600, (int)"XDDDDDDDDD", 0, 0);
window = v0;
if ( !v0 )
{
glfwTerminate();
return -1;
}
sub_418D00(v0);
sub_419330((int)window, (int)sub_407100);
glfwSetWindowSizeCallback((int)window, (int)sub_407120);
sub_419A30(window, 208897, 212995);
if ( !sub_4051B0() )
return -1;
glEnable(2929);
sub_4060D0(&v41, v30, v3); // shader init?
*(_OWORD *)v64 = xmmword_455340;
v65 = xmmword_456AA0;
v66 = xmmword_455470;
v67 = xmmword_4554D0;
v68 = xmmword_455560;
v69 = xmmword_455320;
v70 = xmmword_456AE0;
v71 = xmmword_456A90;
v72 = xmmword_455450;
v73 = xmmword_455300;
v74 = xmmword_455540;
v75 = xmmword_4554A0;
v76 = xmmword_455500;
v77 = xmmword_456A70;
v78 = xmmword_4552A0;
v79 = xmmword_455550;
v80 = xmmword_456A60;
v81 = xmmword_456AC0;
v82 = xmmword_456A80;
v83 = xmmword_455530;
v84 = xmmword_4552D0;
v85 = xmmword_4554B0;
v86 = xmmword_455470;
v87 = xmmword_455460;
v88 = xmmword_455560;
v89 = xmmword_455330;
v90 = xmmword_456AB0;
v91 = xmmword_456A40;
v92 = xmmword_455450;
v93 = xmmword_4552F0;
v94 = xmmword_455340;
v95 = xmmword_456AB0;
v96 = xmmword_456A50;
v97 = xmmword_455460;
v98 = xmmword_455300;
v99 = xmmword_4552D0;
v100 = xmmword_456AD0;
v101 = xmmword_4554F0;
v102 = xmmword_4554C0;
v103 = xmmword_455560;
v104 = xmmword_455540;
v105 = xmmword_455480;
v106 = xmmword_4554E0;
v107 = xmmword_456A30;
v108 = xmmword_455520;
glGenVertexArrays(1, &v63);
glGenBuffers(1, &v59);
glBindVertexArray(v63);
glBindBuffer(34962, v59);
glBufferData(34962, 720, v64, 35044);
glVertexAttribPointer(0, 3, 5126, 0, 20, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, 5126, 0, 20, 12);
glEnableVertexAttribArray(1);
glGenTextures(1, &v61);
glBindTexture(3553, v61);
glTexParameteri(3553, 10242, 10497);
glTexParameteri(3553, 10243, 10497);
glTexParameteri(3553, 10241, 9729);
glTexParameteri(3553, 10240, 9729);
dword_465FC4 = 1;
v4 = sub_409D00(dword_465FE8 - dword_465FE4, dword_465FE4, &v43, &v42, (int *)&v62);
v5 = v4;
if ( v4 )
{
glTexImage2D(3553, 0, 6407, v43, v42, 0, 6407, 5121, v4);
glGenerateMipmap(3553);
}
j___free_base(v5);
glGenTextures(1, &v60);
glBindTexture(3553, v60);
glTexParameteri(3553, 10242, 10497);
glTexParameteri(3553, 10243, 10497);
glTexParameteri(3553, 10241, 9729);
glTexParameteri(3553, 10240, 9729);
v6 = sub_409D00(dword_465FF8 - (_DWORD)lpBuffer, (int)lpBuffer, &v43, &v42, (int *)&v62);
v7 = v6;
if ( v6 )
{
glTexImage2D(3553, 0, 6407, v43, v42, 0, 6408, 5121, v6);
glGenerateMipmap(3553);
}
j___free_base(v7);
v8 = v41;
glUseProgram(v41);
v46 = 15;
v45 = 0;
LOBYTE(lpMem) = 0;
gl_init_str(&lpMem, "texture1", 8u);
v109 = 0;
v9 = &lpMem;
if ( v46 >= 0x10 )
v9 = lpMem;
v10 = glGetUniformLocation(v8, v9, 0);
glUniform1i(v10);
v109 = -1;
sub_407420(&lpMem);
v46 = 15;
v45 = 0;
LOBYTE(lpMem) = 0;
gl_init_str(&lpMem, "texture2", 8u);
v109 = 1;
v11 = &lpMem;
if ( v46 >= 0x10 )
v11 = lpMem;
v12 = glGetUniformLocation(v8, v11, 1);
glUniform1i(v12);
v109 = -1;
sub_407420(&lpMem);
if ( !sub_419650((int)window) )
{
_libm_sse2_tan_precise();
v41 = 0;
*(float *)&v43 = 1.0 / (float)0.3926990926265717;
v62 = 1.0 / (float)((float)0.3926990926265717 * 1.3333334);
do
{
flt_465FBC = glfwGetTime();
if ( sub_419920((int)window, 256) == 1 )
sub_419370((int)window, 1);
glClearColor(1045220557, 1050253722, 1050253722, 1065353216);
glClear(16640);
glActiveTexture(33984);
glBindTexture(3553, v61);
glActiveTexture(33985);
glBindTexture(3553, v60);
glUseProgram(v8);
sub_409640(&v41);
v47 = v62;
v48 = v43;
v50 = 0xBF800000;
v49 = 0xBF80419A;
v51 = 0xBE4D0148;
v46 = 15;
v45 = 0;
LOBYTE(lpMem) = 0;
gl_init_str(&lpMem, "projection", 0xAu);
v109 = 2;
v13 = &lpMem;
if ( v46 >= 0x10 )
v13 = lpMem;
v14 = glGetUniformLocation(v8, v13, 1);
glUniformMatrix4fv(v14);
v109 = -1;
if ( v46 >= 0x10 )
{
v15 = (char *)lpMem;
if ( v46 + 1 >= 0x1000 )
{
if ( (unsigned __int8)lpMem & 0x1F
|| (v16 = *((_DWORD *)lpMem - 1), v16 >= (unsigned int)lpMem)
|| (v15 = (char *)lpMem - v16, (char *)lpMem - v16 < (char *)4)
|| (unsigned int)v15 > 0x23 )
{
LABEL_53:
_invalid_parameter_noinfo_noreturn(v15);
}
v15 = (char *)*((_DWORD *)lpMem - 1);
}
j_j___free_base(v15);
}
v35 = *(float *)&dword_464CC4 + *(float *)&qword_464CAC;
v36 = *(float *)&dword_464CC8 + *((float *)&qword_464CAC + 1);
v37 = *(float *)&dword_464CCC + *(float *)&dword_464CB4;
sub_4092A0(&v35);
v46 = 15;
v45 = 0;
LOBYTE(lpMem) = 0;
gl_init_str(&lpMem, "view", 4u);
v109 = 3;
v17 = &lpMem;
if ( v46 >= 0x10 )
v17 = lpMem;
v18 = glGetUniformLocation(v8, v17, 1);
glUniformMatrix4fv(v18);
v109 = -1;
if ( v46 >= 0x10 )
{
v15 = (char *)lpMem;
if ( v46 + 1 >= 0x1000 )
{
if ( (unsigned __int8)lpMem & 0x1F )
goto LABEL_53;
v19 = *((_DWORD *)lpMem - 1);
if ( v19 >= (unsigned int)lpMem )
goto LABEL_53;
v15 = (char *)lpMem - v19;
if ( (char *)lpMem - v19 < (char *)4 || (unsigned int)v15 > 0x23 )
goto LABEL_53;
v15 = (char *)*((_DWORD *)lpMem - 1);
}
j_j___free_base(v15);
}
v46 = 15;
v45 = 0;
LOBYTE(lpMem) = 0;
glBindVertexArray(v63);
v20 = 0;
v21 = dword_46601C;
if ( (dword_466020 - (signed int)dword_46601C) >> 2 )
{
v32 = 0x3F800000;
v33 = 0x3E99999A;
v34 = 0x3F000000;
do
{
v22 = v21[v20 + 1];
v23 = v21[v20 + 2];
v56 = v21[v20];
v57 = v22;
v58 = v23;
sub_407F30(&v52);
v25 = (__int128 *)sub_4086F0(v24, (__m128 *)&v31, (float *)&v56);
v52 = *v25;
v53 = v25[1];
v54 = v25[2];
v55 = v25[3];
v26 = (__int128 *)sub_408850(&v32);
v40 = 15;
v39 = 0;
LOBYTE(v38) = 0;
v52 = *v26;
v53 = v26[1];
v54 = v26[2];
v55 = v26[3];
gl_init_str(&v38, "model", 5u);
v109 = 4;
v27 = &v38;
if ( v40 >= 0x10 )
v27 = v38;
v28 = glGetUniformLocation(v8, v27, 1);
glUniformMatrix4fv(v28);
v109 = -1;
if ( v40 >= 0x10 )
{
v15 = (char *)v38;
if ( v40 + 1 >= 0x1000 )
{
if ( (unsigned __int8)v38 & 0x1F )
goto LABEL_53;
v29 = *((_DWORD *)v38 - 1);
if ( v29 >= (unsigned int)v38 )
goto LABEL_53;
v15 = (char *)v38 - v29;
if ( (char *)v38 - v29 < (char *)4 || (unsigned int)v15 > 0x23 )
goto LABEL_53;
v15 = (char *)*((_DWORD *)v38 - 1);
}
j_j___free_base(v15);
}
v40 = 15;
v39 = 0;
LOBYTE(v38) = 0;
glDrawArrays(4, 0, 36);
v20 += 3;
v21 = dword_46601C;
}
while ( v20 < (dword_466020 - (signed int)dword_46601C) >> 2 );
}
sub_418D80((int)window);
sub_419310();
}
while ( !sub_419650((int)window) );
}
glDeleteVertexArrays(1, &v63);
glDeleteBuffers(1, &v59);
glfwTerminate();
return 0;
}
其中,游戏使用sub_407120监听鼠标移动事件:
float __usercall sub_407120@<eax>(int a1, double a2, double a3)
{
int v3; // xmm3_4
int v4; // xmm4_4
float v5; // xmm0_4
float v6; // xmm2_4
float v7; // xmm1_4
float v8; // xmm2_4
float v9; // xmm2_4
float v10; // xmm1_4
int v11; // xmm0_4
int v12; // xmm0_4
float v13; // xmm1_4
signed int v14; // xmm0_4
float v15; // ST0C_4
float v16; // ST10_4
float v17; // ST08_4
double v18; // xmm0_8
__m128 v19; // xmm1
__m128 v20; // xmm2
__m128 v21; // xmm0
float result; // eax
float v23; // [esp+0h] [ebp-1Ch]
if ( byte_464C90 )
{
*(float *)&v3 = a2;
byte_464C90 = 0;
*(float *)&v4 = a3;
v5 = *(float *)&v3;
dword_464C98 = v3;
v6 = *(float *)&v4;
dword_464C9C = v4;
dword_466018 = v3;
dword_46602C = v4;
}
else
{
v3 = dword_464C98;
v4 = dword_464C9C;
v5 = *(float *)&dword_466018;
v6 = *(float *)&dword_46602C;
}
v7 = (float)((float)(a2 - v5) * 0.1) + *(float *)&dword_465FF0;
v8 = v6 - a3;
v9 = (float)(v8 * 0.1) + *(float *)&dword_466028;
if ( (v7 >= 70.0 || v7 <= -70.0) && v7 <= 110.0 && v7 >= -110.0 && v9 <= 30.0 && v9 >= -30.0 )
{
v10 = *(float *)&v4 - a3;
*(float *)&v11 = a2;
dword_464C98 = v11;
*(float *)&v12 = a3;
v13 = (float)(v10 * 0.1) + *(float *)&dword_465FB8;
dword_464C9C = v12;
v14 = 1118961664;
v23 = (float)((float)(a2 - *(float *)&v3) * 0.1) + *(float *)&dword_464C94;
*(float *)&dword_464C94 = (float)((float)(a2 - *(float *)&v3) * 0.1) + *(float *)&dword_464C94;
dword_465FB8 = LODWORD(v13);
if ( v13 > 89.0 || (v14 = -1028521984, v13 < -89.0) )
{
v13 = *(float *)&v14;
dword_465FB8 = v14;
}
sub_405290();
sub_405290();
v15 = (float)(v23 * 0.017453292) * (float)(v13 * 0.017453292);
sub_4052B0();
v16 = v13 * 0.017453292;
sub_4052B0();
v17 = (float)(v23 * 0.017453292) * (float)(v13 * 0.017453292);
v18 = (float)((float)((float)((float)(v13 * 0.017453292) * (float)(v13 * 0.017453292)) + (float)(v15 * v15))
+ (float)(v17 * v17));
_libm_sse2_sqrt_precise();
v19 = (__m128)0x3F800000u;
*(float *)&v18 = v18;
v19.m128_f32[0] = 1.0 / *(float *)&v18;
v20 = v19;
v21 = v19;
v20.m128_f32[0] = v19.m128_f32[0] * v15;
v21.m128_f32[0] = v19.m128_f32[0] * v16;
qword_464CAC = (unsigned __int128)_mm_unpacklo_ps(v20, v21);
result = v19.m128_f32[0] * v17;
*(float *)&dword_464CB4 = v19.m128_f32[0] * v17;
}
return result;
}
可以看出,其本质是通过修改view矩阵中的视角信息实现的,同时也发现了视角受限的逻辑:
if ( (v7 >= 70.0 || v7 <= -70.0) && v7 <= 110.0 && v7 >= -110.0 && v9 <= 30.0 && v9 >= -30.0 )
此外,通过分析代码,不难发现dword_464CC4、dword_464CC8、qword_464CAC这三个全局变量就代表了view矩阵中的视角所在的坐标位置。
解题
视角限制
通过ida的keypatch插件,可以很轻松的将该处逻辑限制去掉,使其无论如何都jmp到视角移动代码处即可
坐标移动
我们已经知道可以通过修改上述的三个全局变量进行坐标移动,为了看清箭头所指区域,我们需要移动到一个合适的位置和视角,但我们并不知道哪里才是合适的位置,所以我制作了一个游戏作弊程序,方便我们人工的找到这个位置,这个任务使用Cheat Engine来完成最合适不过了,这样节省了很多编写作弊程序代码的时间,附件给出了我制作的ct作弊脚本。我注册了w、a、s、d、q、e六个热键分别控制x、y、z方向上的坐标移动。
flag
最终我找到了如下坐标,能够较为清楚的看清箭头所指区域,即flag:dogod