个人手机凭什么不给我爽——Xposed Hook混淆且加固后的APP

前阵子刚从总公司撸了一台Google亲儿子Nexus 6,Root后并刷了Xposed,刚想爽一把,结果其中一个APP打开后就这幅德行了。 java

没办法,既然不让我爽,我本身亲自动手撸。

分析APK

最基本的分析能够用Android Studio,咱们将安装包拷贝到Android Studio打开的工程目录下,粗略查看下 android

dex文件中居然没有 com.huimai365的包,并且lib下面的so文件居然占比达到了50%多。内心顿时凉了半截,我擦,这是加固了呀!
不行,做为一线程序猿,怎么能轻言放弃!

脱壳

通过百般思考(google),我终于找到了一个傻瓜式脱壳工具dumpDex,没想到还挺好用的 git

咱们“点击脱壳”后,在 /data/data/com.huimai365/dump文件夹下发现了不少dex文件,感受离成功又进了一步!
接下来就是体力活了,咱们把dex所有pull下来,逐个用dex2jar工具将dex转为jar。为此我写了一个批量操做的脚本,“xxx”目录存放的是全部的dex文件

dir=../xxx/
 
for file in $dir/*; do
    ./d2j-dex2jar.sh $file
done
复制代码

而后用JD-GUI寻找咱们须要的包名com.huimai365,幸运的是我终于终于找到了,不幸的是特么代码混淆。小伙子能够呀! github

分析代码

咱们先用脚指头分析下,这种检测Xposed基本在ApplicationonCreate方法中去执行,而后进行弹窗。好,那咱们就寻找下他们本身实现的Application类。 apache

而后分析 onCreate中的方法
我发现有个 ar.a();的方法,点进去一看,果真!(这里只是展现部分代码)这里不只检测Xposed,居然还想关闭Xposed,沃日!

public class ar
{
  public static void a()
  {
    try
    {
      Field localField = ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedBridge").getDeclaredField("disableHooks");
      localField.setAccessible(true);
      localField.set(null, Boolean.valueOf(true));
      return;
    }
    catch (Throwable localThrowable) {}
  }
  
  public static boolean a(Context paramContext)
  {
    return (b(paramContext)) || (c(paramContext)) || (b()) || (c());
  }
  
  private static boolean b(Context paramContext)
  {
    paramContext = paramContext.getPackageManager().getInstalledApplications(128);
    if (paramContext == null) {
      return false;
    }
    paramContext = paramContext.iterator();
    boolean bool = false;
    if (paramContext.hasNext())
    {
      ApplicationInfo localApplicationInfo = (ApplicationInfo)paramContext.next();
      if (localApplicationInfo.packageName.equals("de.robv.android.xposed.installer"))
      {
        ac.d("HookDetection", "Xposed found on the system.");
        bool = true;
      }
      if (!localApplicationInfo.packageName.equals("com.saurik.substrate")) {
        break label92;
      }
      ac.d("HookDetection", "Substrate found on the system.");
      bool = true;
    }
    label92:
    for (;;)
    {
      break;
      return bool;
    }
  }
  
  private static boolean c()
  {
    try
    {
      Object localObject = ClassLoader.getSystemClassLoader().loadClass("de.robv.android.xposed.XposedHelpers").newInstance();
      if (localObject != null) {
        if ((!a(localObject, "fieldCache")) && (!a(localObject, "methodCache")))
        {
          boolean bool = a(localObject, "constructorCache");
          if (!bool) {}
        }
        else
        {
          return true;
        }
      }
    }
    catch (Throwable localThrowable) {}
    return false;
  }
}
复制代码

Hook方法

从上面的分析看,咱们只要Hook ar中的a()a(Context paramContext)方法就好了。那么就动手吧!bash

public class XposedHookInit implements IXposedHookLoadPackage {
    private static final String TAG = "XposedHookInit";

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        if ("com.huimai365".equals(lpparam.packageName)) {
            Log.e(TAG, "Find 优品惠 " + lpparam.packageName);
            hookCheckoutXposed(lpparam.classLoader);
        }
    }

    private void hookCheckoutXposed(ClassLoader classLoader) {
        XposedHelpers.findAndHookMethod("com.huimai365.util.ar", classLoader, "a", new XC_MethodReplacement() {
            @Override
            protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                Log.e(TAG, "Replace close xposed");
                return null;
            }
        });

        XposedHelpers.findAndHookMethod("com.huimai365.util.ar", classLoader, "a", Context.class, new XC_MethodReplacement() {
            @Override
            protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                Log.e(TAG, "Replace find xposed");
                return false;
            }
        });
    }
}
复制代码

但是事情并无想象的那么简单,报错了 app

2019-01-17 12:46:17.038 5888-5888/? E/Xposed: de.robv.android.xposed.XposedHelpers$ClassNotFoundError: java.lang.ClassNotFoundException: com.huimai365.util.ar
        at de.robv.android.xposed.XposedHelpers.findClass(XposedHelpers.java:71)
        at de.robv.android.xposed.XposedHelpers.findAndHookMethod(XposedHelpers.java:260)
        at com.example.xposeddemo.XposedHookInit.hookCheckoutXposed(XposedHookInit.java:35)
        at com.example.xposeddemo.XposedHookInit.handleLoadPackage(XposedHookInit.java:20)
        at de.robv.android.xposed.IXposedHookLoadPackage$Wrapper.handleLoadPackage(IXposedHookLoadPackage.java:34)
        at de.robv.android.xposed.callbacks.XC_LoadPackage.call(XC_LoadPackage.java:61)
        at de.robv.android.xposed.callbacks.XCallback.callAll(XCallback.java:106)
        at de.robv.android.xposed.XposedInit$2.beforeHookedMethod(XposedInit.java:134)
        at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:340)
        at android.app.ActivityThread.handleBindApplication(<Xposed>)
        at android.app.ActivityThread.-wrap2(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1546)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6121)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
        at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:107)
     Caused by: java.lang.ClassNotFoundException: com.huimai365.util.ar
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:400)
        at external.org.apache.commons.lang3.ClassUtils.getClass(ClassUtils.java:823)
复制代码

分析问题

为何明明有这个类,却ClassNotFoundError呢?去了解下加固原理,才知道原来APP加壳以后,更改了classloader,所以咱们用本来的classloader是会报类没法被找到的异常的。该APP使用的是腾讯的乐固,咱们看到AndroidManifest.xml里面的application已经被替换为com.tencent.StubShell.TxAppEntry ide

那咱们再来看看 TxAppEntry这个类,就在没有加壳的 classes.dex文件中。

protected void attachBaseContext(Context paramContext)
  {
    super.attachBaseContext(paramContext);
    SystemClassLoaderInjector.fixAndroid(paramContext, this);
    if (!b(this)) {
      return;
    }
    d(paramContext);
    a(this);
  }
复制代码

原来就在这里更改了classloader,那咱们获取更改后classloader,而后再Hook不就好了?!OK,OK,OK,咱们换个姿式再来一次工具

public class XposedHookInit implements IXposedHookLoadPackage {
    private static final String TAG = "XposedHookInit";

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        if ("com.huimai365".equals(lpparam.packageName)) {
            Log.e(TAG, "Find 优品惠 " + lpparam.packageName);
            XposedHelpers.findAndHookMethod("com.tencent.StubShell.TxAppEntry", lpparam.classLoader,
                    "attachBaseContext", Context.class, new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                            super.afterHookedMethod(param);
                            //获取到Context对象,经过这个对象来获取classloader
                            Context context = (Context) param.args[0];
                            //获取classloader,以后hook加固后的就使用这个classloader
                            ClassLoader realClassLoader = context.getClassLoader();
                            //下面就是将classloader修改为壳的classloader就能够成功的hook了
                            hookCheckoutXposed(realClassLoader);

                        }
                    });
        }
    }

    private void hookCheckoutXposed(ClassLoader classLoader) {
        XposedHelpers.findAndHookMethod("com.huimai365.util.ar", classLoader, "a", new XC_MethodReplacement() {
            @Override
            protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                Log.e(TAG, "Replace close xposed");
                return null;
            }
        });

        XposedHelpers.findAndHookMethod("com.huimai365.util.ar", classLoader, "a", Context.class, new XC_MethodReplacement() {
            @Override
            protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                Log.e(TAG, "Replace find xposed");
                return false;
            }
        });

    }
}
复制代码

结局

啊,整个世界清静了。随着身体的一阵哆嗦,这个APP变得索然无味……

总结

其实本人在这里也只是将各类工具整合起来,大部分的知识都是从网上获取的。但愿能有个抛砖引玉的做用,让各位读者能有一点收获。再者,真心膜拜这些造工具的大牛,看来我还有很长的路要走呀!oop

其实这也是我第一次写技术文章,我特地放在了掘金上,由于这是我最喜欢的一个国内平台(没有之一),但愿掘金愈来愈好,勿忘初心!

参考资料

抱歉,Xposed真的能够随心所欲——5.我本身刷的Xposed凭什么不给我用

dumpDex-Android脱壳

Android逆向之路---脱壳360加固

相关文章
相关标签/搜索