通过对App进行加固保护,梆梆可以有效防止移动应用在运营推广过程中被破解、盗版、二次打包、注入、反编译等破坏,保障程序的安全性、稳定性,对移动应用的整体逻辑结构进行保护,保证了移动应用的用户体验。

一、梆梆加固逆向分析过程

首先我们通过对APK加固前后文件结构的比较,来了解梆梆加固对APK文件所做的处理。为了使分析过程足够简单,我新建一个最简单的测试程序,并上传到梆梆加固,整个加固过程大概需要4天的时间才可以完成,这是一个漫长的等待过程。

该测试程序包含了Activity、Service、ContentProvider、BroadcastRecevier四大组件、Application、普通类、Jni调用等7类对象,目的就是全面的了解梆梆的加固效果。

1. apk加固前后静态文件结构及动态运行时对比分析

(1)加固前后静态文件结构变化(左为加固前,右为加固后)

加固后apk新增以下文件:

  • assets\meta-data\manifest.mf  //APK文件列表SHA1-Digest
  • assets\meta-data\rsa.pub        //RSA公钥信息
  • assets\meta-data\rsa.sig         //数字签名文件
  • assets\classes.jar                    //已加密原classes.dex文件
  • assets\com.example.hellojni    //ARM平台二进制可执行文件
  • assets\com.example.hellojni.x86  //x86功能同上
  • libs\armeabi\libsecexe.so        //ARM平台共享库文件
  • libs\x86\libsecexe.so               //x86功能同上

加固后修改文件:

  • AndroidMainfest.xml  //(如果应用配置有Application信息,则该文件加固前后相同,如果应用未配置Application信息,则该文件加固前后不相同,梆梆会配置Application信息为自己实现类)
  • classes.dex

对classes.dex进行反编译,观察代码树结构变化:(左为加固前,右为加固后)

 

(2)加固前后动态运行时变化

运行原程序,系统仅创建一个相关进程,但是加固的程序,系统会为其同时创建三个相关程序进程:

进程启动顺序:597进程创建605进程,605进程又创建了607进程

通过查看maps文件获取597进程映射文件信息:

通过map文件可以看出,597进程为主进程,Android各组件在该进程中运行。

605和607进程并无与apk文件相关文件信息,通过cmdline查看启动参数:

初步怀疑该进程为assets\com.example.hellojni可执行文件运行结果。

2. 梆梆加固保护效果分析

我们通过逆向分析加固后的app,来看看梆梆加固对app的保护效果。

程序代码的第一执行点是Application对象,首先查看TestApplication类对象。

程序的Util类完成大部分的java层逻辑:

ACall类主要完成对libsecexe.so JNI的调用:

查看libsecexe.so文件导出函数,发现所有函数名都经过加密处理,与我们平时jni调用产生的函数名并不同。平时jni产生的函数名应该为这样格式:Java_com_secapk_wrapper_ACall_{函数名}。

抗静态分析:

  • Util类通过MyClassLoader完成对加密classes.jar的动态加载,内存中解密classes.jar,完成动态加载。
  • jni方法对应so函数名的混淆。

抗动态调试:

  • 当使用IDA动态调试该程序时,程序无法建立连接调试。

梆梆加固可以常用的有效的逆向分析方法。

二、梆梆加固技术实现关键点猜想

1. 如何使DexClassLoader动态加载组件具有生命周期?

根据APK文件是否在AndroidManifest.xml配置Applicaiton信息,梆梆加固会做不同的处理。

通过上传Applicaiton不同配置的APK文件,我们发现:

  • 当APK配置有Applicaition信息时,梆梆加固重写Application类
  • 当APK未配置Application信息时,梆梆加固新建类,并在AndroidManifest.xml中配置自己Application类

因此Applicaiton就是程序的第一执行点。

我们知道DexClassLoader加载的类是没有组件生命周期的,也就是说即使DexClassLoader通过对dex的动态加载完成了对组件类的加载,当系统启动该组件时,还会出现加载类失败的异常。我已经在“Android APK加壳技术方案”中提出了一种使DexClassLoader加载组件类具有生命周期的方法。

运行加固后的程序并通过Mat内存分析工具查看类加载情况:

如上图所示,组件类的加载类已经被修改为com.secapk.wrapper.MyClassLoader类,可以得出结论,该方式和我提出方式基本相同,通过修改系统组件类ClassLoader来实现。

2. 如何混淆native方法在so库函数对应关系?

jni方法注册方式有两种:

  • 通过javah产生函数头,该种方式产生的方法具有固定的格式。该方式使逆向分析人员比较容易获取java层native方法对应的本地方法。
  • 在JNI_OnLoad方法中手动注册jni方法,不易查找对应关系。

使用第二种方式可以实现混淆java层native方法和so函数的对应关系。

[cpp] view plain copy
  1. #include <string.h>
  2. #include <jni.h>
  3. JNIEXPORT jstring JNICALL abcdefghijklmn( JNIEnv* env,jobject thiz )
  4. {
  5. return (*env)->NewStringUTF(env, "Hello from JNI !");
  6. }
  7. JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
  8. {
  9. JNIEnv* env = NULL;
  10. jint result = -1;
  11. if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
  12. return JNI_ERR;
  13. }
  14. JNINativeMethod gMethods[] = {
  15. { "stringFromJNI", "()Ljava/lang/String;", (void*)abcdefghijklmn },
  16. };
  17. jclass clazz = (*env)->FindClass(env, "com/example/hellojni/HelloJni");
  18. if (clazz == NULL) {
  19. return JNI_ERR;
  20. }
  21. if ((*env)->RegisterNatives(env, clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0){
  22. return JNI_ERR;
  23. }
  24. /* success -- return valid version number */
  25. result = JNI_VERSION_1_4;
  26. return result;
  27. }

以上代码中的字符串都是明文(比如“stringFromJNI”),如果这些文明字符串都换成密文的话,再通过运行时解密,相应的对应关系更不易看出。

3. 如何使DexClassLoader加载加密的dex文件?

虽然不了解梆梆加固是怎么做的,不过通过分析它的运行逻辑,我推测了一种可行的实现方案:了解该方案需要对Android DexClassLoader的整个加载流程需要有清晰的了解。

首先推断assets\classes.jar是一个加密的jar包。正常的DexClassLoader加载的流程如下:会有一个DexOpt产生odex过程。但是梆梆加固后的应用DexClassLoader加载过程并没有该过程的log信息。

推断加密的jar包里面含有odex文件,如果不是odex文件的话,DexClassLoader肯定会在运行时释放未加密的odex文件到目录,这样的话被保护的逻辑也就泄露了。

DexClassLoader加载过程会在java层和C层产生不同的数据结构,java层并没有实质性的数据,所有的数据都在c层,我们可用通过底层代码完成dex数据的解析。底层dex分析是可以支持byte[]数组的,解密odex数据,传递过去就行了。这样java层就可以调用了。

以下是大概伪代码实现步骤:

[cpp] view plain copy
  1. int loadDex(char * dexFileName)
  2. {
  3. char *dvm_lib_path = "/system/lib/libdvm.so";
  4. void * handle;
  5. DvmGlobals gDvm;
  6. handle = dlopen( dvm_lib_path, int mode);
  • 读取dexFileName文件内容并解密到byte数组。

调用dexFileParse函数解析byte数组为DexFile

\dalvik\libdex\DexFile.c

DexFile* dexFileParse(const u1* data, size_t length, int flags)//dlsym(handle, "dexFileParse");

  • 调用allocateAuxStructures转换DexFile为DvmDex(由于该方法为static方法,因此需要按照其逻辑自行实现)。

\dalvik\vm\DvmDex.c

static DvmDex* allocateAuxStructures(DexFile* pDexFile)

  • 添加DvmDex到gDvm.userDexFiles

\dalvik\vm\Init.c

struct DvmGlobals gDvm; //gDvm = dlsym(handle, "gDvm");

  • 修改MyDexClassLoader中的mDexs对象的mCookie值

mCookie主要用于映射底层DvmDex数据——DexClassLoader.mDexs[0].mCookie值

4. so如何实现程序的反调试?

同Linux反调试基本原理相同,这里提供一种方式就是在JNI_Onload中调用ptrace方法,ptrace被广泛用于调试(比如IDA)和进程代码注入(比如LBE,金山等权限管理功能实现),一个进程只能被一个进程ptrace,如果你自己调用ptarce,这样其它程序就无法通过ptrace调试或者向您的程序进程注入代码。

ptrace(PTRACE_TRACEME,0 ,0 ,0);

通过本人实验,该种方式可以实现so的反调试。

三、总结

通过以上分析,梆梆加固的确可以有效防止移动应用在运营推广过程中被破解、盗版、二次打包、注入、反编译等破坏,不过如果Android恶意软件也通过这种方式加固保护,这将会给移动安全分析人员带来巨大的挑战,因为安全分析人员经常使用的代码静态逻辑分析和动态调试分析在该情况下都失效了。

梆梆官方声称不会对恶意软件进行加固,的确在加固的过程中发现存在安全软件扫描信息和云测试处理流程,不过这些措施只能减少而不能彻底杜绝恶意软件通过梆梆加固保护。如何不被恶意软件利用是梆梆需要解决的问题。

爱加密和梆梆加固的破解方法

By Bob Pan

梆梆与爱加密都使用了将原有的dex隐藏, 在运行时解压, 并且通过修改app的类加载器的方式实现加固. 参考: AndoridAPK反逆向解决方案:梆梆加固原理探寻

然而, 不管如何隐藏dex, 最终在运行时都必须释放到内存, 所以本文的思路是从内存中找到解密后的dex文件, 进而得到加固前的apk.

爱加密

爱加密的app并没有做反调试的保护. 打开app之后直接使用gdb连接, 然后用gcore, 产生core dump.

使用ps查看pid

使用gdb连接pid

使用gcore产生core dump

将产生的core.1033复制回电脑, 并使用编辑器打开, 通过类名找到dex中string-data段, 然后通过查找’dex.035’可以找到多离string-data最近的个dex头. dex文件头偏移32的整形值就是dex的文件长度. 使用dd命令可以从内存中抠出dex.

通过类名找string-data段

找到最近的dex文件头(0x4f87a08)和dex文件大小0x07c0

使用dd抠出dex

这个文件是个完整的dex文件, 并且可以被dexdump直接打印

梆梆

梆梆加固的程序做了anti-ptrace, 表现为使用gdb --pid 连接不上对应的进程, 利用kernel-model打印ptrace的记录, 可以看出梆梆

l  使用了3个进程互相ptrace.

l  发送错误指令来检查ptrace是否被劫持(反回值是-3行, 尝试让1568进程继续执行, 但是1568并未被ptrace, 必须出错),

l  利用ptrace修改另一个进程的数据(action是5的行).

ptrace系统调用的记录, 右边是ptrace的参数

虽然连不上1552, 但是dalvik是一个多线程的程序, 里面包含主进程, gc线程, binder线程等, 虽然我们用gdb连不上主线程, 但是我们可以连上其他线程, 这些线程的tid在/proc/[pid]/task/目录下.

Gdb连接任意一个tid

拿到coredump后与爱加密一样做相同的处理, 可以拿到dex.

总结

爱加密和梆梆通过隐藏dex确实可以让大部分静态分析工具找不到执行代码, 但是在动态运行的时候无可避免的需要将dex在内存中还原. 虽然梆梆做了反调试, 但是通过其他方式也同样可以获取其内存. 通过本文的方法分析其内存然后恢复dex, 更进一步可以完全恢复原始apk. 从这个角度说, 爱加密和梆梆的加固形同虚设.

Andorid 关于PTRACE ptrace(PTRACE_TRACEME,0 ,0 ,0);相关推荐

  1. libgstreamer-1.0.so.0: cannot open shared object file: No such file or directory

    1. 问题现象 error while loading shared libraries: libgstreamer-1.0.so.0: cannot open shared object file: ...

  2. c+语言+null,C/C++语言中NULL、'\0’和0的区别

    NULL.'\0'和0的值是一样的,都是0,不过它们的表现形式不一样: 1. NULL: 即空指针,不过在C和C++中并不一样.在VS 2013的库文件string.h中可以看到如果定义. 1 /* ...

  3. Ubuntu14.04 64位机上安装cuda8.0+cudnn5.0操作步骤

    查看Ubuntu14.04 64位上显卡信息,执行: lspci | grep -i vga lspci -v -s 01:00.0 nvidia-smi 第一条此命令可以显示一些显卡的相关信息:如果 ...

  4. Spring Cloud Alibaba 基础教程:Nacos 生产级版本 0.8.0

    Spring Cloud Alibaba 基础教程:Nacos 生产级版本 0.8.0 昨晚Nacos社区发布了第一个生产级版本:0.8.0.由于该版本除了Bug修复之外,还提供了几个生产管理非常重要 ...

  5. Silverlight 3发布新版3.0.50106.0

    微软1月19日发布Silverlight 3新版本3.0.50106.0. 该版本主要修复以下几个问题: 问题一: 当使用图形硬件加速功能(GPU)的时候,如果GPU驱动报错,Silverlight ...

  6. AS1.0(2.0)中的XML示例

    虽然Flash早就升级为AS3.0,但是FMS的服务端编程依然仅支持AS1.0(2.0),服务端与.net通讯的最简单方式莫过于请求一个RESTful的webService或wcf,通过它们返回的xm ...

  7. 多数编程语言里的0.1+0.2≠0.3?

    作者 | Parul Malhotra 译者 | Raku 出品 | AI科技大本营(ID:rgznai100) 我们从小就被教导说0.1+0.2=0.3,但是在奇妙的计算机编程世界里面,事情变得不一 ...

  8. flannel原理初探针对0.1.0版本

    flannel flannel是针对k8s设计的三层的网络解决方案.在k8s中为了使pod之间能够使用一种偏平的网络架构,从而完成跨Pod的网络通信. 官网给的原理图如下: flannel 使用TUN ...

  9. GTX 1080Ti + cuda8.0 + cuDNN6.0 安装及测试

    GPU 显卡厂商已经安装好了,直接安装 cuda8.0 + cuDNN6.0 我这里的显卡是 GTX 1080 Ti cuda安装 我下载的是cuda8.0的是deb格式的1.9个G地址:https: ...

  10. PouchContainer 发布 0.3.0 版本,支持 Kubernetes 拥抱 CNCF 生态

    划重点 PouchContainer 是一款轻量级.开源的富容器技术,拥有快速高效.隔离性强.可移植性高.资源占用少等特性,可以帮助企业快速实现存量业务容器化,同时提高超大规模下数据中心的物理资源利用 ...

最新文章

  1. 一本关于 女仆小说的构思,有能力写的看下
  2. php请求接口数据,php curl请求接口并获取数据的示例代码
  3. mysql 随机选择数据_从MySQL随机选取数据
  4. android闹钟例子,自己软件中调用android系统闹钟
  5. 云原生生态周报 Vol.9| K8s v1.15 版本发布
  6. pip通过阿里源安装
  7. POJ 2106-Boolean Expressions,双栈运用类似表达式求值!
  8. sql union和unmion all区别
  9. 洞察药监局数据,挖掘万亿价值
  10. 基于xxtea算法文件加密工具
  11. AI技术的苹果iPhone XS Max双卡双待7纳米6.5寸512GB顶配12799元(公号回复“苹果AI”下载PDF资料)
  12. java创建一个自己的类库_建立并使用自己的类库
  13. JAVA练习——集合练习题(HashSet,TreeSet)产生随机数不能重复,去掉重复元素,将集合中重复元素去掉,字符串倒序输出,倒序输出整数,倒序排列对象
  14. AndroidStudio报错 AAPT: error: resource xxx (aka com.example.ouchaixun:drawable/back) not found
  15. 参数估计的均方误差(MSE),偏置(Bias)与方差(Variance)分解,无偏估计
  16. 单因素模糊评价matlab,用matlab进行模糊综合评判
  17. linux搭建虚拟化平台报告,Centos部署KVM虚拟化平台(可跟做)
  18. zcmu--1931: wjw的剪纸(dfs+枚举)
  19. 昵图网共享分下载代包下素材nipic呢图下载币图网设计素材下载
  20. Java Resources是什么

热门文章

  1. JSONObject没有parseObject和fromObject方法的巨坑!!!
  2. python美化excel_Python 使用 prettytable 库打印表格美化输出功能
  3. 中国智慧水务行业发展前景及趋势
  4. Windows API一日一练 13 TranslateMessage函数
  5. vue基础--模板语法、常用指令:v-if、v-show、v-for、虚拟DOM、v-once、v-cloak、v-text、v-html、v-bind、v-on、自定义指令
  6. 计算机开机就显示搜索结果,win7系统开机总会显示搜索框的原因和解决方法
  7. IntelliJ IDEA 修改滚动条颜色
  8. 修改chrome 滚动条颜色
  9. Nginx及rewrite跳转
  10. 为什么现在的开发都要懂测试了?这一份书单告诉你!