腾讯游戏安全技术竞赛决赛第一题writeup
题目描述
题目是用OpenGL ES 3.0编写的一个程序,用textures/container.jpg
作为贴图,去渲染。目的是去寻找绘制出的flag,由于绘制区域限制,移动不到绘制区域。
做题过程
之前没有接触过openGL,相关函数一个个找,浏览了《opengl es 3.0 编程指南》。
贴图绑定:
1 | sub_30604(v23); |
将textures/container.jpg
作为贴图纹理,dword_A1AA0
为顶点数组(36个坐标),得到的结果就是一个立方体(以三角形为单位渲染,6* 2 *3=36)。
在程序中看到一个箭头上布满了箱子,就是以图片纹理渲染出的箱子来布满箭头。
找到的资料都是单个图像渲染,没找到怎么设置贴图目标。
找屏幕显示的地方,sub_30098里看到屏幕清除的函数,下面是一大堆浮点运算。该不会是逆浮点运算过程吧??
找了一下数据来源:dword_AA0FC
在so的init里找到了函数,里面是对着色器代码的复制,还有就是dword_AA0FC
的赋值,数据来源就是dword_9E8D8
。一堆数据,分析之后是浮点数,联系之前顶点坐标也是浮点数组,那么这也是个坐标数组。
一番搜索,glDrawElements和glDrawArrays是绘制函数,在绘制前,调用glUniformMatrix4fv
,通过uniform上传至GPU,来绘制最终的图像。调试中发现传入的指针指向的是空数组。不清楚为什么。从代码来看就是将,dword_AA0FC传入的数据,每个循环处理x和y坐标。刚刚那个座标是一个三维坐标。
没仔细研究一大段的浮点运算具体是干什么的,猜测是三维到二维的映射计算。
把dword_9E8D8数据抠出来。用matplotlib绘制出来。哇!惊喜,这个坐标数组就是绘制图像的坐标数组。
由于旧的题里出现了flag的图片,还是给了不少启示的,所以这题做的还是有点侥幸的。
OpenGL相关
有关OpenGL的知识,需要了解一下几个概念。
这个系列文章写的不错:http://www.cnblogs.com/lijihong/p/5365677.html
vertex(顶点)
在设置贴图映射和绘制对象时会用到顶点。
例如在贴图映射中,会指定贴图所需要映射方式的一个顶点数组。如下是一个浮点数组。
VBO(顶点缓冲对象)
顶点缓冲对象VBO是在显卡存储空间中开辟出的一块内存缓存区,用于存储顶点的各类属性信息,如顶点坐标,顶点法向量,顶点颜色数据等。在渲染时,可以直接从VBO中取出顶点的各类属性数据,由于VBO在显存而不是在内存中,不需要从CPU传输数据,处理效率更高。
1 | static void CreateVertexBuffer() |
Shader(着色器)
图形渲染管线接受一组3D坐标,然后把它们转变为你屏幕上的有色2D像素输出。图形渲染管线可以被划分为几个阶段,每个阶段将会把前一个阶段的输出作为输入。所有这些阶段都是高度专门化的(它们都有一个特定的函数),并且很容易并行执行。正是由于它们具有并行执行的特性,当今大多数显卡都有成千上万的小处理核心,它们在GPU上为每一个(渲染管线)阶段运行各自的小程序,从而在图形渲染管线中快速处理你的数据。这些小程序叫做着色器(Shader)。
在so中的init区段初始化了着色器代码。
sub_30604(v23);
函数中完成了对着色器的创建和编译绑定。
1 | GLuint ShaderProgram = glCreateProgram(); |
详细解释参考:https://blog.csdn.net/cordova/article/details/52495077
图形渲染管线的每个阶段的抽象展示。要注意蓝色部分代表的是我们可以注入自定义的着色器的部分。
摘自:https://www.zhihu.com/question/29163054
贴图纹理
为了实现纹理贴图我们需要做三件事:
将一张贴图加载到OpenGL中
提供纹理坐标和顶点(将纹理对应匹配到顶点上)
并使用纹理坐标从纹理中进行取样操作取得像素颜色
1 | sub_2F79C(*(_DWORD *)(*(_DWORD *)(v10 + 12) + 32), "textures/container.jpg", &v42); |
将textures/container.jpg
作为贴图纹理,dword_A1AA0
为顶点数组(顶点数组是顶点中的截图),得到的结果就是一个立方体(以三角形为单位渲染,6* 2 *3=36)。
函数详解参考:https://blog.csdn.net/cordova/article/details/52825859
帧缓冲区
glUniform函数
uniform修饰符可以指定一个在应用中设置好的变量,它不会在图元处理的过程中发生变化,且在所有的着色阶段之间都是共享的——着色器中的全局变量。
详细参考:https://www.cnblogs.com/android-blogs/p/5454692.html
sub_30098(int a1)
函数中对顶点的x、y坐标处理后会调用到 sub_30EEC(int *a1, int a2, int a3)
,这个函数里就包含了glGetUniformLocation(v5, v4);
和j_glUniformMatrix4fv(v6, 1, 0, v3);
。