• 网秦安全盾 原理分析


    环境:
    手机: 中兴 u887
    系统 android2.3.5
    调试器: IDA pro 6.5

    一:加固前后对比
    加固前 classes.dex 大小如下:

    加固后 classes.dex 大小如下:

    那原来的 classes.dex 去那儿了呢?我们再来对比下资源目录下都多了些什么?
    加固前的:

    加固后的: 

    Lib 目录:

    加固后:

    比较发现多了些文件,具体这些文件有什么用请看下面分析。

    二:java 层概述
    1.通过反编译看,从 AndroidManifest.xml 文件中的 application 项可以看出壳的入口为:

    2.简单分析 com.nqshield.NqApplication 类都做了些什么?
    .不能反编译成 java 代码,直接看 smali 代码吧。
    在 NqApplication 类 method protected attachBaseContext(Landroid/content/Context;)V
    中都分别调用了这些函数:
    3..invoke-static{p0},Lcom/nqshield/Common;->loadXShellLib(Landroid/content/Cont
    ext)V
    从名字可以看出是加载 so 库,并注册 JNI 函数。
    通过分析 JNI 方法注册到 Dalvik 虚拟机的过程,可以得到 java 层 native 函数与 so 层函数
    对应的关系为:
    native nq10 -> b9df1ce797fd03603fd7137afff2957
    native nq11 -> eb5993d402df42eac47e82555b7ae31
    native nq12 -> fa3f3a501e8754e88bed48c128ef90
    native nq13 -> abc020d3ee6fbc05ab1ed6b4da7252d
    native nq14 -> e300588cc034bcbaa7d61
    (*如有不清楚如何分析这个过程的可以参考学习罗升阳 的文章)
    4..invoke-static{p0},Lcom/nqshield/Common;->CopyBinaryFile(Landroid/content/Con
    text;)V
    该函数是将 assets 文件夹中的 DexToLoad.apk 与 nqdata 拷贝到/data/data+包名/.cache
    目录中,然后调用 nq10 函数,(该函数会在下面分析)。
    5..invoke-static{p0},Lcom/nqshield/jniExport;->getDexClassLoader(Landroid/conte
    nt/Context;)Ljava/lang/ClassLoader;
    该函数通过调用 DEXClassLoader 完成对加密的/data/data+包名/.cache/DexToLoad.apk 的
    动态加载,内存中解密 DexToLoad.apk 并组合 odex, 完成动态加载。 (详细过程看 so 层分
    析) 。
    类似下面的样子:

    6.invoke-virtual{v0,p0,v1,v2},Lcom/nqshield/jniExport;->nq12(Landroid/content/C
    ontext;Ljava/lang/ClassLoader;I)V
    传入 getDexClassLoader 返回值。
    7.invoke-virtual{v0,v1,v2},Lcom/nqshield/jniExport;->nq13(Ljava/lang/String;I)V
    so 层分析
    8.最后在.method public onCreate()V 中调用
    invoke-virtual {v0, v1, v2}, Lcom/nqshield/jniExport;->nq14(Ljava/lang/String;I)V
    三:so 层分析:
    1.通过 readelf -S libnqshield.so 查看 so 信息,发现 INIT_ARRAY 不为空,

    用 IDA 打开 so,G 到 INIT_ARRAY 中的地址去看看.

    对应 so 函数名被混淆了,动态分析发现这些函数都是解密字符串用的,根据传进的数字解
    密相应的字符。

    下面是传入要解密的字符串。

    110 代表解密后的字符为: nq10
    115 代表解密后的字符为: (Ljava/lang/String;Ljava/lang/String;I)V
    111 代表解密后的字符为:nq11
    等等...以此类推
    2.JNI_OnLoad 中都做了些什么?
    第一个函数 fork 一个子进程,并创建一个线程,线程函数如下所示

    inotify 是一种文件系统的变化通知机制,如文件增加、删除等事件可以立刻让用户态得知,
    int wd = inotify_add_watch (fd, path, mask); 用于添加一个 watch
    fd 是 inotify_init() 返回的文件描述符, path 是被监视的目标的路径名(即文件名或目
    录名), mask 是事件掩码, 在头文件 linux/inotify.h 中定义了每一位代表的事件。可以
    使用同样的方式来修改事件掩码,即改变希望被通知的 inotify 事件。Wd 是 watch 描述
    符。
    在 arch-armusrincludelinux inotify.h 头文件中定如下:
    #define IN_OPEN 0x00000020
    ,根据线程函数可以看出它是监视/proc/pid/maps 的打开事件.
    (*不明白的可以点这里 http://blog.csdn.net/myarrow/article/details/7096460)

    我猜测这个线程的功能可能是做反注入用的。
    2.解密字符串
    传入数字 79 代表解密后的字符为: com/nqshield/jniExport
    3.注册 JNI 函数
    对应关系
    native nq10 -> b9df1ce797fd03603fd7137afff2957
    native nq11 -> eb5993d402df42eac47e82555b7ae31
    native nq12 -> fa3f3a501e8754e88bed48c128ef90
    native nq13 -> abc020d3ee6fbc05ab1ed6b4da7252d
    native nq14 -> e300588cc034bcbaa7d61
    4.下面对这几个函数进行分析
    nq10 函数在 java 层 CopyBinaryFile 函数中被调用到,我们在 so 中对
    b9df1ce797fd03603fd7137afff2957 函数下断点,动态分析看它都做了些什么?
    函数里面调用了 result = initEnv(a5, "DexToLoad.dex", "DexToLoad.apk", &s);
    进入该函数分析,该函数对 libdvm.so 与 libnativehelper.so 中的操作文件等一些函数进
    行 hook 如下图:

    我 们 分 别 对 这 几 个 hook 函数 (myopen,myread 等 ) 下 好 断 点 , 当 java 层 调 用
    getDexClassLoader 函数时会走到这些 hook 函数中,b9df1ce797fd03603fd7137afff2957
    函数就分析完成了。
    5.java 层的 CopyBinaryFile 函数执行完后就要执行 getDexClassLoader 函数了,该函数是
    调用 DexClassesLoader 动态加载 DexToLoad.apk,继续动态走,断在 myopenh 函数中,该函数
    会判断是不是打开 DexToLoad.apk 文件,如果是就会创建一个 DexToLoad.apk.zip 文件。
    接着来到 myopen 函数中,判断是否打开 DexToLoad.apk,如果是会调用函数 access 判断
    /data/data/yiqi.bazi/.cache/DexToLoad.apk 是否存在,存在就打开它并将其读取到指定
    内存,然后解密,如下图:

    6.组合生成 ODEX:
    下会根据 ODEX 结构图进行组合:

    (*该图来自 “ Android 软件安全与逆向分析” 一书,如有对该结构不明白的地方可以
    去阅读这本书,书里有详细讲解)。
    首先使用 zlib 函数 inflateInit2_与 inflate 对上面解密出来的 DexToLoad.apk 数据从
    classes.dex 标志后进行解压得到 dex 数据, 在 inflateEnd 处下断 F9 执行, 如果要脱壳的
    话,这个时候是最佳的 dump 时机,可得到完整的 Dex 数据。(组合完后会对 dex 做些手脚)接
    下来会按照上图 odex 结构图进行组合,
    在解压出来的 dex 前写入 ODEX 文件头如下图所示:

    打开/data/dalvik-cache/mnt@asec@yiqi.bazi-1@pkg.apk@classes.dex 读取依赖库到 dex
    后面,如下图:

    打开/data/data/yiqi.bazi/.cache/nqdata 读取辅助数据到依赖库后面,如下图:

    组合完后就是 vm 加载过程了。
    7. 接着 java 层调用 nq12 nq13 nq14 函数
    反射调用 LoadedApk.mApplication, LoadedApk.mClassLoader,
    ActivityThread.mInitialApplication,
    ActivityThread.mAllApplications 等值,将其重新
    指向目标 Application 和 ClassLoader。确保系统
    稍后构造组件时能正确的加载到目标类。
    三: 到此分析完成,最后,将控制权给目标 Application。

    完。

    样本及文档下载

    http://yunpan.cn/cA3U6hctfwfj3 (提取码:9b1e)

    当把学习当成一种习惯!
  • 相关阅读:
    安装Eclipse for MAC 苹果版
    visual studio code emmet 插件不提示?解决方案
    支付宝付款页面调整屏幕亮度
    浅谈iOS需要掌握的技术点
    Objective-C 编程艺术 (Zen and the Art of the Objective-C Craftsmanship 中文翻译)
    ios开发数据库版本迁移手动更新迭代和自动更新迭代艺术(-)
    ios 添加到cell 上的button点击无效!扩大button的点击区域(黑魔法)
    个人中心模块-拍照剪裁上传
    利用js与java交互
    显示gif动画(帧动画的播放)
  • 原文地址:https://www.cnblogs.com/2014asm/p/4106309.html
Copyright © 2020-2023  润新知