美文网首页
记一次BUG查找

记一次BUG查找

作者: 0一缕星光0 | 来源:发表于2019-11-13 11:56 被阅读0次

缘起

[#1314729 java.lang.NullPointerException]
Attempt to invoke virtual method 'void android.webkit.WebView.loadUrl(java.lang.String)' on a null object reference
com.hao.ad.e.e$1.run(FragmentHelper.java:22)

很明显,就是一个普通的空指针异常,但是不同之处在于反编译出来的包里面竟然找不到com.hao.ad这个包,公司开发组一直也没有解决掉这个问题。

发展

本人接到任务,优化APP的启动,在Profiler中又再次发现了这个奇怪的包,关键是他的启动占据了我们宝贵的UI线程接近1s的时间:

com.hao.ad启动占据1S的宝贵时间
可以推测com.hao.ad是通过context获取到mainLooper,再构造一个handler绑定mainLooper,最后在通过handler.post(runnable)的方式,将他的代码运行到UI线程的。

初见

通过经典的二分查找,在众多第三方库中找到了MainSDK.init(context,···)这个函数,将其注释掉之后发现启动的trace中就没有com.hao.ad这个包的运行代码了。到这里问题就解决了,召集产品确认是否把这个SDK关掉就万事大吉了。

深入

作为码农的我怎么能放弃这次学习的机会呢,必然要到源码里一探究竟的:

// NoeSdk_1_5.0.0.jar!/com/boh/ejskhc/MainSDK.class
class MainSDK extends Thread(){
    // ···
    (new MainSDK()).start();
    // ···
}

可见,完美符合预期,的确是在一个线程中跑的,那么怎么post到UI线程的呢,在他的包里面继续寻找:

// NoeSdk_1_5.0.0.jar!/com/boh/ejskhc/h.class
Runnable var5 = new Runnable() {
                    public final void run() {
                        try {
                            h.a;
                            int var1x = (new f(i.b(var2.a))).a(var2, var1);
                            com.tao.admin.loglib.b.a(com.tao.admin.loglib.a.a().d() ? ": ".concat(String.valueOf(var1x)) : "");
                        } catch (Exception var2x) {
                        }
                    }
                };
                b.submit(var5);

再一次完美的对应上预期了,注意到这里有一段拼接字符串的操作,难不成是拼接com.hao.ad?继续探究下代码,就从var1x出发:

// NoeSdk_1_5.0.0.jar!/com/boh/ejskhc/f.class
static String b(int var0) {
        return "m" + var0 + ".jar";
    }
f(String var1) throws NullPointerException {
        var1 = MainSDK.a().getFilesDir().getAbsolutePath() + "/" + var1;
        this.a = new File(var1);
    }

又一次对上了,通过拼接了一个绝对路径/m数字.jar字符串打开了一个jar包,那么就应该出现DexClassLoader来记载这个包,继续寻找:

// NoeSdk_1_5.0.0.jar!/com/boh/ejskhc/f.class
  File var3 = MainSDK.a().getDir("dex", 0);
            Class var6;
            Object var7 = (var6 = (new DexClassLoader(this.a.toString(), var3.getAbsolutePath(), (String)null, ClassLoader.getSystemClassLoader().getParent())).loadClass(var1.d + "." + var1.e)).newInstance();
            Class[] var4;
            (var4 = new Class[2])[0] = Context.class;
            var4[1] = Map.class;
            return (Integer)var6.getMethod("load", var4).invoke(var7, MainSDK.a(), var2);

完美!基本确认就是这个问题了,还差最后一步,找到这个绝对路径/m数字.jar,给本次侦探盖棺定论!

反击

导出所有位于我们/data/data/包名/目录下的文件,寻找m数字.jar这个文件:

导出包名下所有文件
经过查找,找到了两个名称符合的文件m1.jar&&m7.jar
对这两个文件进行反编译,查看里面的dex文件:
m7.har中包含com.hao.ad
完美!

结案

抓贼要抓脏,一步步分析下来确认了就是这个第三方合作的SDK偷偷运行线程动态添加dex文件,并且把代码post到UI线程,不仅拖慢了我们APP的启动,还不定时的报一个崩溃!

总结

本次探案过程用到了这些相关工具好相关知识:

  1. profiler,启动过程分析
  2. DexClassLoader,动态dex加载
  3. 反射
  4. 二分查找
  5. adb相关
  6. apktool

相关文章

  • 记一次BUG查找

    缘起 [#1314729 java.lang.NullPointerException]Attempt to in...

  • 这算不算BUG?

    大家可能都听说过BUG,但是你真的知道BUG的由来么?我也常常说,但这是第一次正经地查找什么是BUG。 知识普及来...

  • 05. getWriter()has already been

    记一次bug fixed: getWriter()has already been called for this...

  • 08.插件之FindBugs

    FindBugs是一个在Java程序中查找bug的程序,它查找bug模式的实例,也就是可能出错的代码实例。Find...

  • 解Bug之路:记一次JVM堆外内存泄露Bug的查找

    前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理...

  • 解Bug之路-记一次JVM堆外内存泄露Bug的查找

    前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理...

  • 记一次BUG

    一、如何快速的给大量轨迹点打上区划代码?1、高德爬取街道中心点,行政区划中心点和边界。2、精度要求较高的,将边界加...

  • 记一次bug

    错误细节,用户名无法拖动,其他的栏都可以对应的长短拖动(表头和表格内容一起动) 代码: 错误原因,在第一栏这个fi...

  • 记一次BUG

    这里审核出错 后台写的: 出错原因,这里判断也examine_status ==1,这里不行,这成Boolean了...

  • 记一次JVM堆外内存泄露Bug的查找

    前言 JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理...

网友评论

      本文标题:记一次BUG查找

      本文链接:https://www.haomeiwen.com/subject/avhhictx.html