在android平台hook OpenGL es的API
来源:互联网 发布:淘宝账号登录不了 编辑:程序博客网 时间:2024/06/18 14:40
在android平台上(其他平台也差不多),OpenGL es API的调用是通过一个一个跳转表实现的。这个跳转表的首地址被保存到当前线程的TLS ( Thread Local Storage)中。
我们来看一下Android系统中相关的源代码。我这里引用的是android 4.4.2的代码,不同版本中源码文件所在的位置略有不同。
先来看frameworks\native\opengl\libs\GLES2\gl2.cpp
#if defined(__arm__) && !USE_SLOW_BINDING #define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n" #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ asm volatile( \ GET_TLS(r12) \ "ldr r12, [r12, %[tls]] \n" \ "cmp r12, #0 \n" \ "ldrne pc, [r12, %[api]] \n" \ : \ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \ [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \ : \ );#elif defined(__mips__) && !USE_SLOW_BINDING #define API_ENTRY(_api) __attribute__((noinline)) _api #define CALL_GL_API(_api, ...) \ register unsigned int _t0 asm("t0"); \ register unsigned int _fn asm("t1"); \ register unsigned int _tls asm("v1"); \ register unsigned int _v0 asm("v0"); \ asm volatile( \ ".set push\n\t" \ ".set noreorder\n\t" \ ".set mips32r2\n\t" \ "rdhwr %[tls], $29\n\t" \ "lw %[t0], %[OPENGL_API](%[tls])\n\t" \ "beqz %[t0], 1f\n\t" \ " move %[fn],$ra\n\t" \ "lw %[fn], %[API](%[t0])\n\t" \ "movz %[fn], $ra, %[fn]\n\t" \ "1:\n\t" \ "j %[fn]\n\t" \ " move %[v0], $0\n\t" \ ".set pop\n\t" \ : [fn] "=c"(_fn), \ [tls] "=&r"(_tls), \ [t0] "=&r"(_t0), \ [v0] "=&r"(_v0) \ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \ : \ );#else #define API_ENTRY(_api) _api #define CALL_GL_API(_api, ...) \ gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ if (_c) return _c->_api(__VA_ARGS__);#endif#define CALL_GL_API_RETURN(_api, ...) \ CALL_GL_API(_api, __VA_ARGS__) \ return 0;extern "C" {#include "gl3_api.in"#include "gl2ext_api.in"#include "gl3ext_api.in"}列举几行gl3_api.in中的代码,宏展开后其实就是一个个GLES的函数实现
void API_ENTRY(glActiveTexture)(GLenum texture) { CALL_GL_API(glActiveTexture, texture);}void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) { CALL_GL_API(glAttachShader, program, shader);}void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar* name) { CALL_GL_API(glBindAttribLocation, program, index, name);}以上的代码相当于定义了所有GLES API的实现,只不过这些实现都是简单的跳转。在arm平台下的实现很简单,首先通过协处理指令获取TLS指针,通过查表找到相应的函数指针,直接将pc跳转到该地址,这样可以省去函数调用的开销。为了更清楚的了解函数跳转表的结构,我们来看一下getGlThreadSpecific的实现。位置在frameworks\native\opengl\libs\hooks.h
struct gl_hooks_t { struct gl_t { #include "entries.in" } gl; struct gl_ext_t { __eglMustCastToProperFunctionPointerType extensions[MAX_NUMBER_OF_GL_EXTENSIONS]; } ext;};#undef GL_ENTRY#undef EGL_ENTRYEGLAPI void setGlThreadSpecific(gl_hooks_t const *value);// We have a dedicated TLS slot in bionicinline gl_hooks_t const * volatile * get_tls_hooks() { volatile void *tls_base = __get_tls(); gl_hooks_t const * volatile * tls_hooks = reinterpret_cast<gl_hooks_t const * volatile *>(tls_base); return tls_hooks;}inline EGLAPI gl_hooks_t const* getGlThreadSpecific() { gl_hooks_t const * volatile * tls_hooks = get_tls_hooks(); gl_hooks_t const* hooks = tls_hooks[TLS_SLOT_OPENGL_API]; return hooks;}其中entries.in是GLES的API的列表。TLS_SLOT_OPENGL_API在bionic\libc\private\bionic_tls.h中定义,值为3。即函数跳转表的结构是这样的。
有一点需要注意的是,API跳转表的首地址指针是在eglMakeCurrent调用中写入到当前线程的TLS中的,与此同时如果当前的context正在被另一个线程使用,那么前一个线程的TLS中API跳转表的指针会被置空。EGL就是通过这种方式实现一个context在同一时刻只能被一个线程使用的。
基于以上的信息,我们可以很容易的将GLES的调用重定向到我们自己的函数中来,即修改跳转表中的函数地址即可。代码如下
struct gl_hooks_t {struct gl_t {void* foo1;// glActiveShaderProgramEXTvoid* foo2;// glActiveTexture} gl;};GL_APICALL void GL_APIENTRY my_glActiveTexture(GLenum texture){LogInfo("my_glActiveTexture %u", texture);}#define TLS_SLOT_OPENGL_API 3void glesApiHookTest(){void *tls_base = NULL;asm volatile("mrc p15, 0, r12, c13, c0, 3""\n\t""mov %0, r12""\n\t": "=r" (tls_base));LogInfo("tls_base %p", tls_base);if (tls_base == NULL) {return;}gl_hooks_t * volatile * tls_hooks =reinterpret_cast<gl_hooks_t * volatile *>(tls_base);gl_hooks_t * hooks = tls_hooks[TLS_SLOT_OPENGL_API];LogInfo("hooks %p", hooks);void* origFunPtr = hooks->gl.foo2;// function list in android code/frameworks/Native/Opengl/Libs/Entries.inhooks->gl.foo2 = (void*)my_glActiveTexture;// will call to "my_glActiveTexture" functionglActiveTexture(999);hooks->gl.foo2 = origFunPtr;}更彻底一些的做法是直接修改TLS中跳转表的入口地址,一次性hook所有的API。
那么现在问题来了,我们为啥要hook GLES的API呢?嗯,典型的应用场景包括:
- 外挂
- Debug
- 对第三方应用/引擎做一些深度定制
0 0
- 在android平台hook OpenGL es的API
- OpenGL es 在android平台的移植性问题
- 在 Android* 平台上设置原生 OpenGL ES*
- Android API Guides---OpenGL ES
- OpenGL ES 的 EGL API
- android的opengl es
- 关于Android平台中OpenGL ES应用的初步研究
- Android OpenGL ES(三):OpenGL ES API 命名习惯
- OpenGL ES 在 Android 中对 GLU 的原生支持
- 安卓平台OpenGL ES的调用
- 懂iOS平台的OpenGL ES请进
- Android下的OpenGl ES
- Android的OpenGL Es开发
- 学习android的opengl es
- OpenGL ES的API简单分析
- cocos2d-x在android上call to OpenGL ES API with no current context
- OPenGL ES常用API:
- OpenGL ES常用API
- Codeforces 611D:New Year and Ancient Prophecy DP 分块记录最后一个
- windows注册表编程
- 【IOI2001】【poj1195】Mobile phones(二维树状数组)
- POJ 2785 4 Values whose Sum is 0(折半枚举)
- java环境变量设置以及常见问题解决方法
- 在android平台hook OpenGL es的API
- how to open files as sudo
- MySQL数据库使用命令小结
- VPN连接
- 图片常用处理
- Python接入天气预报api
- WEB架构师成长之路之一-走正确的路
- poj 3666 Making the Grade (有序序列,离散化dp)
- FilterDispatcher已被标注为过时解决办法 >>> FilterDispatcher <<< is deprecated!