内容纲要

Android 加固与反反编译

dex加固原理

从反编译的成本来看汇编代码强度要比SMALI代码要高,所以DEX保护代码一般都使用C/C++实现。

新dex的生成

https://juejin.cn/post/6844903952345989134

image-20210926230623554

image-20210926230728427

image-20210926234053328

image-20211020202754421

img

dex文件标识的修改

将一个文件(加密之后的源Apk)写入到Dex中,那么肯定需要修改文件校验码(checksum),因为他是检查文件是否有错误。那么signature也是一样,也是唯一识别文件的算法。还有就是需要修改dex文件的大小。

不过这里还需要一个操作,就是标注一下我们加密的Apk的大小,因为我们在脱壳的时候,需要知道Apk的大小,才能正确的得到Apk。那么这个值放到哪呢?这个值直接放到文件的末尾就可以了。

即:修改Dex的header的checksum, signature, fileSize,将源Apk的大小追加到壳dex的末尾

.so加固原理

SO加固分有源码SO加固和无源码SO加固。

有源码SO加固:需要特定的代码或者编译器支持,可对代码进行加密,混淆甚至虚拟化保护,开发人员可通过主动插入混淆代码到源码内或通过。

无源码SO加固:通过壳对SO进行保护,保护方式以代码加密的形式居多,混淆和虚拟化还未成熟,兼容性和性能难以保证。

由于Android平台的性能限制,SO层做虚拟化对性能影响较大,远不及Windows平台的成熟,大部分SO加固还是以代码加密为主。

SO属于ELF格式文件。

关于elf文件

http://yocosqamaq.top/%e3%80%90%e7%9f%a5%e8%af%86%e7%82%b9%e3%80%91elf%e6%96%87%e4%bb%b6/

so文件加载过程

SO加载过程简单描述就是将SO中的代码和数据按照编译时预定的结构,加载到内存,然后进行重定位,即修复必要的数据信息,修复完成后就能保证所有代码的正常执行。

SO加载流程如下:

○ Linker优先从内存中查找已加载的SO,如果SO已加载,则直接返回handle。

○ 如SO没有加载需要新建soinfo结构体,并将SO加载到内存。

○ 执行预加载prelink_image,读取SO中dynamic字段中的内容,初始化重定位需要的数据。

○ 执行link_image,修复内存中的数据,完成重定位。

○ 执行SO中的Init以及Initarray中的函数。

image-20220718205556379

从加载流程看,可以得出以下几点:

1.重定位完成之前,SO中的代码不会主动执行,代码都在Linker中执行。

2.最先执行的代码为Init,其次是Init_array。

因存在这一特性,任何做过加密的SO,只要在SO内函数执行函数前对加密数据进行修复,就能达到加固的目的。其中大部分加固都是利用Init或Init_arrray中的函数来进行解密,也可以在任何一个确定的时机完成解密,如Android下可利用JNI_OnLoad函数,但这种方式只适用于Android下特殊的SO。

加固方法

Section加密的主要分两步:

  1. 将需加密的代码放入特定Section,在加密代码被执行前执行解密逻辑。

  2. 编译后的文件,使用工具对特定Section进行加密,即对Section区间的内容加密。

UPX以及类UPX的SO加固

UPX加固SO的做法是只加固代码段,数据段和重定位相关的结构都保留在文件中,利用原SO的重定位信息完成SO重定位,通过插入的INIT节对代码进行解密,本质上和Section加密类似,只是放大了加密范围,并添加修改Init节的操作。通过命令readelf -d sopath,仍可以看到原SO内的数据和原SO一致,但Section已被破坏无法查看。

代码混淆

有源码的代码混淆一般可通过插入花指令或通过带混淆功能的编译器进行编译,对生成的代码进行混淆。无源码的代码混淆需要借助壳,对原SO的指令进行抽离,然后对抽离的代码做混淆转换。

参考

https://dun.163.com/news/p/5dade874c7314d289a72d31911f372a4

常见加固工具

关于加固工具

image-20210928234044752

梆梆

下载梆梆加固工具

使用apktoolbox进行签名

adb install -t *.apk

注:对frida有反制机制,无法通过通用脱壳方法脱壳

可以用DexExtractordrizzleDumper进行脱壳

360加固

大概原理

将原有的dex隐藏, 在运行时解压, 并且通过修改app的类加载器的方式实现加固,同时具备反调试功能,能避免将dex在内存中还原。还有深度的压缩技术,加固的同时,对 classes.dex文件今夕压缩,能使加固后的包体变小。

逆向

用360protector对自己写的一个apk进行加固,

AndroidManifest.xml

<application android:allowBackup="true" android:appComponentFactory="androidx.core.app.CoreComponentFactory" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:name="com.stub.StubApp" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.Wallet">
    <meta-data android:name="second" android:value="t0" />
    <activity android:exported="true" android:name="com.huawei.wallet.Auth">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <activity android:configChanges="0xe0" android:exported="false" android:name="com.alipay.sdk.app.H5PayActivity" android:screenOrientation="3" />
    <activity android:configChanges="0xe0" android:exported="false" android:name="com.alipay.sdk.app.H5AuthActivity" android:screenOrientation="3" />
    <meta-data android:name="TMS_ShellConfig" android:value="com.tencent.mapsdk.BuildConfig" />
  </application>

看到application的name为stubApp

Application类比程序中的其他类启动的都要早,因此在分析Android程序中,需要先查看该程序是否具有Application类,如果有,就要看看它的oncreate()方法是否做了一些影响逆向分析的初始化工作

Application和Activity,Service一样是Android框架的一个系统组件,当Android程序启动时系统会创建一个Application对象,用来存储系统的一些信息。Android系统自动会为每个程序运行时创建一个Application类的对象且只创建一个,所以Application可以说是单例(singleton)模式的一个类。

查看StubApp的attachBaseContext

image-20220718143326591

image-20220718143401822

会对当前目录下的libjiagu进行读取,应用原本数据应该在此,会在运行时动态释放并解密,并且该类内有一堆native方法

一般是将assets目录中的so文件拷贝到程序的沙盒目录下:/data/data/xxx/files/..;然后再用System.load进行加载,通过查看可以得知源程序apk已经被加密了,就是存放在这里的so中。

源程序加密之后就存放在那几个目录下,一般是:dex文件尾部,libs目录,assets目录。

onCreate方法:

image-20220718151349621

猜测为反射指向原dex的方法

在apk解压缩后的assets目录下,找到libjiagu.so

image-20220718144434037

ida打开,寻找mmap函数(负责把文件内容映射到进程的虚拟内存空间),加载libjiagu.so文件

image-20220718173254878

360二代加固脱壳方法总结

手脱360壳案例详解

爱加密

image-20220718200744750

爱加密手脱实例

加固.so文件识别

("libsecexe.so", "梆梆加固免费版");
("libsecmain.so", "梆梆加固免费版");
("libSecShell.so", "梆梆加固免费版");
("secData0.jar", "梆梆加固免费版");
("libSecShell-x86.so", "梆梆加固免费版");

("libDexHelper.so", "梆梆企业版");
("libDexHelper-x86.so", "梆梆企业版");
("classes.jar", "梆梆加固定制版");
("DexHelper.so", "梆梆加固定制版");

("libtup.so", "腾讯加固");
//("libexec.so", "腾讯加固");
("libshell.so", "腾讯加固");
("mix.dex", "腾讯加固");
("mixz.dex", "腾讯加固");
("libshella-xxxx.so", "腾讯加固");
("libshellx-xxxx.so", "腾讯加固");

("libtosprotection.armeabi-v7a.so", "腾讯御安全");
("libtosprotection.armeabi.so", "腾讯御安全");
("libtosprotection.x86.so", "腾讯御安全");
("tosversion", "腾讯御安全");
("libTmsdk-xxx-mfr.so", "腾讯御安全");

("aliprotect.dat", "阿里加固");
("libsgmain.so", "阿里加固");
("libsgsecuritybody.so", "阿里加固");
("libmobisec.so", "阿里加固");
("libfakejni.so", "阿里加固");
("libzuma.so", "阿里加固");
("libzumadata.so", "阿里加固");
("libpreverify1.so", "阿里加固");

("kdpdata.so", "几维加固");
("dex.dat", "几维加固");
("libkdp.so", "几维加固");
("libkwscmm.so", "几维加固");
("libkwscr.so", "几维加固");
("libkwslinker.so", "几维加固");

("libexec.so", "爱加密");
("libexecmain.so", "爱加密");
("ijiami.dat", "爱加密");
("ijiami.ajm", "爱加密");
("af.bin", "爱加密");
("signed.bin", "爱加密");

("libchaosvmp.so", "娜迦");
("libddog.so", "娜迦");
("libfdog.so", "娜迦");
("libedog.so", "娜迦");

("libprotectClass.so", "360加固");
("libjiagu.so", "360加固");
("libjiagu_art.so", "360加固");
("libjiagu_x86.so", "360加固");

("libcmvmp.so", "中国移动安全加固");
("libmogosec_dex.so", "中国移动安全加固");
("libmogosec_sodecrypt.so", "中国移动安全加固");
("libmogosecurity.so", "中国移动安全加固");

("libbaiduprotect.so", "百度加固");
("baiduprotect1.jar", "百度加固");
("baiduprotect.jar", "百度加固");

("libuusafe.jar.so", "UU安全加固");
("libuusafe.so", "UU安全加固");
("libuusafeempty.so", "UU安全加固");

("dp.arm-v7.so.dat", "DexProtect加固");
("dp.arm.so.dat", "DexProtect加固");

("libegis.so", "通付盾加固");
("libNSaferOnly.so", "通付盾加固");

("libreincp.so", "珊瑚灵御加固");
("libreincp_x86.so", "珊瑚灵御加固");

("libnqshield.so", "网秦加固");

("libnesec.so", "网易易盾");

("libAPKProtect.so", "APKProtect加固");

("libx3g.so", "顶象技术加固");

("libitsec.so", "海云安加固");

("libapssec.so", "盛大加固");

("librsprotect.so", "瑞星加固");

("libapktoolplus_jiagu.so", "apktoolplus加固");

来源:https://www.cnblogs.com/wf-l5201314/p/9714019.html

各代加固

img

第一代

操作列表:

  1. Dex字符串加密
  2. 资源文件加密
  3. 对抗反编译
  4. 反调试
  5. 自定义DexClassLoader

开发阶段中将程序划分为加载(Loader)也称为壳(shell)和关键代码(payload)也称为原始程序

运行时加载部分(Loader)会先运行起来,解密释放关键代码(payload),然后加载器利用动态加载技术加载执行关键代码(payload)。

由于动态加载技术主要依赖于java的动态加载机制,所以要求关键逻辑部分必须进行解压,并且释放到文件系统。这种动态加载技术不足之处在于:1.这一解压释放机制就给攻击者留下直接获取对应文件的机会;2.可以通过hook虚拟机关键函数,进行dump出原始的dex文件数据。

dexloader

PathClassLoader是Android默认使用的类加载器,一个apk中的Activity等类便是在其中加载。
DexClassLoader可以加载任意目录下的dex/jar/apk/zip文件,比PathClassLoader更灵活,是实现插件化、热修复以及dex加壳的重点。
Android8.0新引入InMemoryDexClassLoader,从名字便可看出是用于直接从内存中加载dex。

第二代

Dex抽取与So加固:

  1. Dex Method代码抽取到外部(通常企业版)
  2. Dex动态加载
  3. So加密
  4. 对抗第一代出现的脱壳方法

具体流程:

  1. 关键逻辑以加密的方式存储在apk中
  2. 运行时加载部分将关键逻辑释放到内存
  3. 加载部分调用虚拟机内部接口加载

兼容性:需要针对4.0+(dalvik)和5.0+(art)有不同的实现方式。

可以从以下几方面对抗:

内存中的dex文件头会被清除,防止在dump文件中被找到;

破坏dex文件结构,例如增加一些错误数据,提高恢复的成本;

但payload被加载后在内存中是连续的,利用GDB等工具dump内存可以直接找到payload;

第三代

Dex动态解密与So混淆:

  1. Dex Method代码动态解密
  2. So代码膨胀混淆
  3. 对抗前代出现的脱壳方法

流程:

发布阶段将原始dex内的函数内容(code item)清除,单独移到一个文件中,运行阶段将函数内容重新恢复到对应的函数体。

恢复的时间点有几个方式:

A、加载之后恢复函数内容到dex壳所在的内存区域

B、加载之后将函数内容恢复到虚拟机内部的结构体上:虚拟机读取dex文件后内部对每一个函数有一个结构体,这个机构体上有一个指针指向函数内容,可以通过修改这个指针修改对应的函数内容。

C、拦截虚拟机内与查找执行代码相关的函数,返回函数内容。

缺陷与对抗:

指令抽离技术与虚拟机的JIT(即时编译技术)有冲突,无法发挥最大性能。

仍旧可以通过自定义虚拟机,在解释器的代码上记录函数内容,然后遍历触发所有函数,从而获取全部函数内容,最终重组成一个完整的dex文件。目前已有自动化脱壳工具可以在指令抽离技术中脱壳。

第四代

指令转换/VMP

第四代加固技术使用自定义的解释器来避免第三代的缺陷。但自定义的解释器无法直接调用Android系统内的其他函数,必须使用Java的JNI接口进行调用。

实现方式:

A、dex文件内的函数被标记为native,内容被抽离并转换成一个符合JNI要求的动态库。动态库内通过JNI和Android系统进行交互。

B、dex文件内的函数被标记为native,内容被抽离并转换成自定义的指令格式,该格式使用自定义接收器执行,和A一样需要使用JNI和Android系统交互。

缺陷与对抗:

不论A方案还是B方案,都需要通过虚拟机提供的JNI接口与虚拟机进行交互,攻击者可以直接将指令转换/VMP加固方案当做黑盒,通过自定义的JNI接口对象,对黑盒背部进行探测、记录和分析得到完整的dex文件。

此外,此VMP加固只保护了Java代码,没有做到使用VMP技术来保护c/c++等代码。

第五代

虚拟机源码保护

虚拟机源码保护加固是使用虚拟机技术保护所有的代码,包括Java,Kotlin,c/c++,oc,objective-c等。

虚拟机源码保护为用户提供一套完整的工具链,首先把用户待保护的核心代码编译成中间的二进制文件,随后生成独特的虚拟机源码保护执行环境和只能在该环境下执行的程序。

虚拟机源码保护会在App内部隔离出来独立的执行环境,该核心代码的运行程序在此独立的执行环境里运行。即便App被破解,这部分核心代码仍然不可见。

生成的虚拟机源码保护拥有独特的可变指令集,极大的提高了指令跟踪。逆向分析的难度。同时,虚拟机源码保护还提供了反调试能力和监控能力。虚拟机源码保护可通过自身的探针感知环境的变化,实时探测到外界对本环境的调试、注入等非正常执行流程的变化,将调试动作引到程序陷阱,并发出警报,进而进行实时更新,提高安全强度。

参考

https://mbd.baidu.com/newspage/data/landingsuper?rs=4149673581&ruk=WhbDMN66ossny6ndZhvOkw&isBdboxFrom=1&pageType=1&urlext=%7B%22cuid%22%3A%220u-H8luI2ug7avfYga-H8liT28jVa28H_a2xug8wviKz0qqSB%22%7D&context=%7B%22nid%22%3A%22news_9479007193156281304%22%7D

https://yantaoyu.gitbooks.io/android/content/jia-gu-si-kao-ff08-jie-jian-ff09.html

脱壳工具的使用

https://github.com/hluwa/FRIDA-DEXDump

FRIDA-DEXDump说明

frida

frida是一款基于python + javascript 的hook框架,可运行在android, ios, linux, winosx等各平台,主要使用动态二进制插桩技术。

image-20210926234946007

image-20210926235009285

frida安装+hook实战

frida dexdump

安装

模拟器安装drozer与电脑端连接

模拟器安装frida进行脱壳

adb shell getprop ro.product.cpu.abi adb查看版本

frida-server-android-x86下载地址

如果出现断连,将自己电脑上的adb替换模拟器MEmu下的adb

博客有问题,应该是用adb push

adb push frida-server-12.11.7-android-x86 /data/local/tmp

frida-ps -U 查看pid

image-20210927161948425

完整流程

模拟器打开drozer,在模拟器MEmu下打开cmd,adb连接,adb shell进入su权限模式(#)下,运行frida-server后,运行pc端下载的dexdump下的main.py文件(-n 程序名字 、-p 程序pid号,也可不写),得到的dex会存放在脚本下的文件夹里

注意事项

模拟器的frida-server和电脑端pip3下载的frida的版本要一致

DexExtractor

下载地址

DexExtractor使用方法

linux上安装Android studio,配置api19的arm虚拟机报/dev/kvm is not found

sudo apt install qemu-kvm

sudo kvm-ok
需要BIOS下Security中的Intel virtualization Technology设为enable

system.img路径

linux路径:/home/Android/Sdk/system-images/android-19/default/armeabi-v7a/

windows路径:C:\Users\yocosqamaq\AppData\Local\Android\Sdk\system-images\android-19\default\armeabi-v7a\

drizzleDumper

基于内存搜索的Android脱壳工具

源码地址:https://github.com/DrizzleRisk/drizzleDumper

源码分析

http://yocosqamaq.top/%e3%80%90%e7%9f%a5%e8%af%86%e7%82%b9%e3%80%91drizzledumper/

基于frida的编写工具

安装aapt

加固apk的逆向分析

jeb打开apk,发现分析结果十分短小

image-20211221164209018

对AW进行分析

image-20211221164305490

发现加载了DexHelper.so文件,是梆梆企业版加固

可以看到有个H类,进入查看

image-20211221164614509

加载了一些native函数

libDexHelper.so文件为arm架构,libDexHelper-x86.so文件为x86架构,由于ida对arm的分析不如下x86,所以,将x86的拖入ida32