利用 bytehook 修复 EGL_BAD_ALLOC 异常

287 阅读2分钟

日志分析

image.png

典型的NE问题,而且该crash集中在 <=android9 的版本上,可以粗估一下该问题属于系统bug,在android10上得到了官方修复

一般碰到这种疑似系统bug的,可以去issueTracker里 搜索一下关键字 issue

堆栈分析

这里看ne的crash 可以推测出,是libhwui.so 这个库发生了异常,关键就是看 在哪里挂掉的 根据函数的信息可以得出

调用链路是 libhwui.so 调用了 libegl.so中的某个关键函数 挂掉了

到这里其实就有希望解决了, plt-hook 方案是较为适合这种场景的

源码分析

hwui 这个so中 在某种情况下 会抛出fatal异常,其实就是create了一个空的surface image.png

image.png

这里其实就是返回值是个null,写法比较绕

#define EGL_NO_SURFACE                    EGL_CAST(EGLSurface,0)
#define EGL_CAST(type, value) (static_cast<type>(value))

到这里解决思路就有了, 可以hook eglCreateWindowSurface这个函数, 发现他是null的时候 就修改一下返回值 为我们自己写死的一个地址值, 这样至少不会让他走进fatal 异常里

另外因为我们是写死的一个地址值,这里eglSurfaceAttrib 函数也要hook,判断第二个参数值为我们的地址值时 就直接返回,否则可能会引发其他故障

image.png

android10的修复代码如下

image.png

关键代码

// 创建虚假地址 来欺骗 低版本的 eglSurfaceAttrib
static void *getFakeAddr() {
    if (fakeAddr == NULL) {
        fakeAddr = malloc(1);
    }
    return fakeAddr;
}
static void *hacker_eglCreateWindowSurface_automatic(void *a, void *b, void *c, const void *d) {
    BYTEHOOK_STACK_SCOPE();
    void *ret = BYTEHOOK_CALL_PREV(hacker_eglCreateWindowSurface_automatic, a, b, c, d);
    if (ret == NULL) {
        ret = getFakeAddr();
    } 
    return ret;
}
static void *hacker_eglSurfaceAttrib_automatic(void *a, void *b, void *c, void *d) {
    BYTEHOOK_STACK_SCOPE();

    // 如果是虚假地址,直接返回
    if (b == getFakeAddr()) {
        return (void *) 1;
    }
    return BYTEHOOK_CALL_PREV(hacker_eglSurfaceAttrib_automatic, a, b, c, d);
}
 void *k = (void *) hacker_eglCreateWindowSurface_automatic;
 void *t = (void *) hacker_eglSurfaceAttrib_automatic;
    bytehook_hook_single(
            "libhwui.so",
            NULL,
            "eglCreateWindowSurface",
            k,
            NULL,
            NULL);

    bytehook_hook_single(
            "libhwui.so",
            NULL,
            "eglSurfaceAttrib",
            t,
            NULL,
            NULL);