前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Android][Security] Android 逆向之安全防护基本策略

[Android][Security] Android 逆向之安全防护基本策略

作者头像
wOw
发布2020-01-20 17:15:45
1.3K0
发布2020-01-20 17:15:45
举报
文章被收录于专栏:wOw的Android小站wOw的Android小站

对抗反编译

混淆

使用混淆主要可以减小包的大小。混淆对于安全保护来说,只是增加了阅读难度而已。混淆不会把关键代码混淆掉,比如MainActivity,Application等,可以通过分析smali和阅读jar包定位代码。

资源混淆也是换汤不换药,针对加载资源代码getString(2131230929)进行进制转换,变成16进制,从public.xml里面查找对应的资源,就能定位到资源内容。

签名保护

这个是防止二次打包验证,但是,对于java代码的签名保护,可以很容易地进行修改smali代码绕过验证。

手动注册native方法

安全性也不是很高,只是一种会增加破解成本的方式。一般Native方法根据命名规则生成头文件然后写cpp代码,这种方式属于静态注册。手动动态注册是复写JNI_OnLoad方法,在该函数中手动注册方法名和对应的方法签名,方法名可以自定义,这样避免了静态注册的命名规则,让破解者难以根据规律找到要破解的方法。不过破解者可以分析JNI_OnLoad函数的汇编代码找到register函数找到注册的native方法。

反调试检测

IDA进行so动态调试是基于进程的注入技术,然后使用linux中ptrace机制,进行调试目标进程的附加操作。

ptrace机制有一个特点:如果一个进程被调试了,在它进程status文件中有一个字段TracerPid会记录调试者的进程id值

cat /proc/pidxx/status 可以看到TracerPid字段

方法是检测该TracerPid值,大于0就退出。但破解者会通过IDA工具给JNI_OnLoad下断点,检测轮询代码,使用nop指令跳过检测指令。

对抗Xposed

原理

Zygote

在Android系统中App进程都是由Zygote进程“孵化”出来的。Zygote进程在启动时会创建一个虚拟机实例,每当它“孵化”一个新的应用程序进程时,都会将这个Dalvik虚拟机实例复制到新的App进程里面去,从而使每个App进程都有一个独立的Dalvik虚拟机实例。

Zygote进程在启动的过程中,除了会创建一个虚拟机实例之外还会将Java Rumtime加载到进程中并注册一些Android核心类的JNI(Java Native Interface,Java本地接口)方法。一个App进程被Zygote进程孵化出来的时候,不仅会获得Zygote进程中的虚拟机实例拷贝,还会与Zygote进程一起共享Java Rumtime,也就是可以将XposedBridge.jar这个Jar包加载到每一个Android App进程中去。安装Xposed Installer之后,系统app_process将被替换,然后利用Java的Reflection机制覆写内置方法,实现功能劫持。下面我们来看一下细节。

Hook和Replace

Xposed Installer框架中真正起作用的是对方法的Hook和Replace。在Android系统启动的时候,Zygote进程加载XposedBridge.jar,将所有需要替换的Method通过JNI方法hookMethodNative指向Native方法xposedCallHandler,这个方法再通过调用handleHookedMethod这个Java方法来调用被劫持的方法转入Hook逻辑。

上面提到的hookMethodNativeXposedBridge.jar中的私有的本地方法,它将一个方法对象作为传入参数并修改Dalvik虚拟机中对于该方法的定义,把该方法的类型改变为Native并将其实现指向另外一个B方法。

换言之,当调用那个被Hook的A方法时,其实调用的是B方法,调用者是不知道的。在hookMethodNative的实现中,会调用XposedBridge.jar中的handleHookedMethod这个方法来传递参数。handleHookedMethod这个方法类似于一个统一调度的Dispatch例程,其对应的底层的C++函数是xposedCallHandler。而handleHookedMethod实现里面会根据一个全局结构hookedMethodCallbacks来选择相应的Hook函数并调用他们的beforeafter函数,当多模块同时Hook一个方法的时候Xposed会自动根据Module的优先级来排序。

调用顺序如下:A.before -> B.before -> original method -> B.after -> A.after。

img
img

检测

在做Android App的安全防御中检测点众多,Xposed Installer检测是必不可少的一环。对于Xposed框架的防御总体上分为两层:Java层和Native层。

Java层检测

需要说明的是,Java层的检测基本只能检测出基础的Xposed Installer框架,而不能防护其对App内方法的Hook,如果框架中带有反检测则Java层检测大多不起作用。

下面列出Java层的检测点,仅供参考。

① 通过PackageManager查看安装列表

最简单的检测,我们调用Android提供的PackageManager的API来遍历系统中App的安装情况来辨别是否有安装Xposed Installer相关的软件包。

代码语言:javascript
复制
PackageManager packageManager = context.getPackageManager();
List applicationInfoList = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo applicationInfo: applicationInfoList) {
    if (applicationInfo.packageName.equals("de.robv.android.xposed.installer")) {
        // is Xposed TODO... }
    }

通常情况下使用Xposed Installer框架都会屏蔽对其的检测,即Hook掉PackageManager的getInstalledApplications方法的返回值,以便过滤掉de.robv.android.xposed.installer来躲避这种检测。

② 自造异常读取栈

Xposed Installer框架对每个由Zygote孵化的App进程都会介入,因此在程序方法异常栈中就会出现Xposed相关的“身影”,我们可以通过自造异常Catch来读取异常堆栈的形式,用以检查其中是否存在Xposed的调用方法。

代码语言:javascript
复制
try {
    throw new Exception("blah");
} catch(Exception e) {
    for (StackTraceElement stackTraceElement: e.getStackTrace()) {
        // stackTraceElement.getClassName() stackTraceElement.getMethodName() 是否存 在Xposed
    }
}
E/GEnvironment: no such table: preference (code 1): while compiling: SELECT keyguard_show_livewallpaper FROM preference
...
at com.meituan.test.extpackage.ExtPackageManager.checkUpdate(ExtPackageManager.java:127)
at com.meituan.test.MiFGService$1.run(MiFGService.java:41)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5072)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
...
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:609)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132) //发现Xposed模块
at dalvik.system.NativeStart.main(Native Method)

③ 检查关键Java方法被变为Native JNI方法

当一个Android App中的Java方法被莫名其妙地变成了Native JNI方法,则非常有可能被Xposed Hook了。由此可得,检查关键方法是不是变成Native JNI方法,也可以检测是否被Hook。

通过反射调用Modifier.isNative(method.getModifiers())方法可以校验方法是不是Native JNI方法,Xposed同样可以篡改isNative这个方法的返回值。

④ 反射读取XposedHelper类字段

通过反射遍历XposedHelper类中的fieldCachemethodCacheconstructorCache变量,读取HashMap缓存字段,如字段项的key中包含App中唯一或敏感方法等,即可认为有Xposed注入。

img
img
代码语言:javascript
复制
boolean methodCache = CheckHook(clsXposedHelper, "methodCache", keyWord);

private static boolean CheckHook(Object cls, String filedName, String str) {
    boolean result = false;
    String interName;
    Set keySet;
    try {
        Field filed = cls.getClass().getDeclaredField(filedName);
        filed.setAccessible(true);
        keySet = filed.get(cls)).keySet();
        if (!keySet.isEmpty()) {
            for (Object aKeySet: keySet) {
                interName = aKeySet.toString().toLowerCase();
                if (interName.contains("meituan") || interName.contains("dianping") ) {
                    result = true;
                    break;
                	} 
                }
            }
		...
    return result;
}
Native层检测

由上文可知,无论在Java层做何种检测,Xposed都可以通过Hook相关的API并返回指定的结果来绕过检测,只要有方法就可以被Hook。如果仅在Java层检测就显得很徒劳,为了有效提搞检测准确率,就须做到Java和Native层同时检测。每个App在系统中都有对应的加载库列表,这些加载库列表在/proc/下对应的pid/maps文件中描述,在Native层读取/proc/self/maps文件不失为检测Xposed Installer的有效办法之一。由于Xposed Installer通常只能Hook Java层,因此在Native层使用C来解析/proc/self/maps文件,搜检App自身加载的库中是否存在XposedBridge.jar、相关的Dex、Jar和So库等文件。

代码语言:javascript
复制
bool is_xposed()
{
   bool rel = false;
   FILE *fp = NULL;
   char* filepath = "/proc/self/maps";
   ...
   string xp_name = "XposedBridge.jar";
   fp = fopen(filepath,"r")) 
   while (!feof(fp))                                 
   {
       fgets(strLine,BUFFER_SIZE,fp);                    
       origin_str = strLine;
       str = trim(origin_str);
       if (contain(str,xp_name))
       {
           rel = true; //检测到Xposed模块
           break;
       }
   }
	...
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 对抗反编译
    • 混淆
      • 签名保护
        • 手动注册native方法
          • 反调试检测
          • 对抗Xposed
            • 原理
              • Zygote
              • Hook和Replace
            • 检测
              • Java层检测
              • Native层检测
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档