美文网首页
记一次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查找

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