本文最初发表在CSDN上:
https://blog.csdn.net/weixin_43632667/article/details/105008506
https://blog.csdn.net/weixin_43632667/article/details/104394222
Android应用当中,很多隐私信息都是以字符串的形式存在的。这些隐私信息是明文,对于软件来说是想当不安全的,如果我们能在打包时对Dex中的字符串加密替换,并在运行时调用解密,这样就能够避免字符串明文存在于Dex中。虽然,无法完全避免被破解,但是加大了逆向提取信息的难度,安全性无疑提高了很多。
目前市面上主要存在两种字符串加密方式:
(1)在开发阶段开发者使用加密后的字符串然后手动调用解密,这种方法工程量太大了,缺点很明显。
(2)编译后修改字节码,然后再动态植入加密后的字符串,最后让其自动调用进行解密,这里重点分析的是第二种。
工具:
代码(MainActivity.java):
jeb3反编译的效果(MainActivity.java):
首先看加密的方法:StringFog采用的是base64+xor(异或)算法
按照安卓程序加密的字符串测试:
输出结果为:
显然跟jeb3里面看到的一样。
ps:Base64 packge 下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi 下载后导入commons-codec-1.14.jar包
那么我们可以借助asm库拦截方法中的每条LDC指令,然后插入该指令即可
总结:字符串加密方法能够较为有效的阻止他人通过字符串搜素定位代码,但是不能防止Hook,总而言之,这只是一个比较普通的混淆方法
java代码将png图片加密:
使用winhex查看发现:
变成了:
然后我们只需要在AS中将编写解密代码即可:
下面是一个简单的测试demo:
测试结果:
此时,我们打开apk查看assert文件时依然无法看到有用的文件
ps:同时我们还可以进行资源路径混淆,详情见:https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md
现在的反编译工具都太先进了,很多纯粹的对抗反编译技术都不在适应了,基本上,我们都可以通过jeb这个强大的反编译工具查看到
但是我们可以将类名进行混淆:
gradle版本在3.4以下时我们使用proguard-rules.pro进行混淆,达到3.4以上时我们使用R8穿插一些proguard规则进行混淆
下面重点研究的是3.4以上版本的情况:
官方文档:https://developer.android.com/studio/build/shrink-code?hl=zh-cn
通用教程:https://www.jianshu.com/p/65027e18c2fe
混淆规则(如下):
这个之前已经写过了:
文档:函数混淆(JNI_Onload).note
链接:http://note.youdao.com/noteshare?id=f6add1ff6a6c4b78aac4a9e27fe390ed&sub=04FF4E2B1F504587A06C69F39C4DF22C
完成程序后,使用AndroidKiller进行修改时,将"我是正版"字符串修改成"我是盗版",在运行程序时,程序会直接闪退
MainActivity:
native-lib.cpp:
activity_main.xml:
在处于调试状态时,Linux会向/proc/pid/status写入一些进程状态信息,比如TracerPid字段会写入调试进程的pid,因此我们可以自己ptrace自己,然后让android_server不能调试
代码如下:
一旦开始调试,就会出现
反反调试思路:nop掉anti_debug01()函数调用
根据第一种分析得出Tracepid的值只要不为0 就能说明进程正在被调试,因此我们只需要检测Tracepid的值是不是0,如果不为0,直接退出就行了
反反调试思路:使用IDA动态调试在函数调用前下断,对比当前TracerPid为4591,将TracerPid对应的寄存器修改为0,达到“0==0”的效果,绕开反调试。
1.需要加密的APK(源APK)
2.壳程序APK
3.加密工具(负责将源APK进行加密和壳DEX合并成新的DEX)
这里面需要注意的字段:
1.checksum文件校验码,使alder32算法校验文件除去magic,checksum外余下的所有文件区域,用于检查文件错误。
2.signature使用SHA-1算法hash除去magic,checksum和signature外余下的所有文件区域,用于唯一识别本文件。
3.file_Size Dex文件的大小。
4.在文件的最后,我们需要标注被加密的apk大小,因此需要增加4个字节。
关注的原因如下:
因为我们需要将一个文件(加密之后的源Apk)写入到Dex中,那么我们肯定需要修改文件校验码(checksum).因为他是检查文件是否有错误。那么signature也是一样,也是唯一识别文件的算法。还有就是需要修改dex文件的大小。
不过这里还需要一个操作,就是标注一下我们加密的Apk的大小,因为我们在脱壳的时候,需要知道Apk的大小,才能正确的得到Apk。那么这个值放到哪呢?这个值直接放到文件的末尾就可以了。
总的来说:我们需要做:修改Dex的三个文件头,将源Apk的大小追加到壳dex的末尾就可以了
根据上述修改后的dex文件样式如下
由原理可知这里需要进行三个步骤了:
1、自己编写一个源程序项目(需要加密的APK)
2、脱壳项目(解密源APK和加载APK)
3、对源APK进行加密和脱壳项目的DEX合并
命名为:SourceApk
MyApplication:
ps:MyApplication的作用:MyApplication类继承Application,查看源码我们知道,Application中有一个attachBaseContext方法,它在Application的onCreate方法执行前就会执行了,这个关键点为后面的加密程序做铺垫。
MainActivity:
就是源程序的一个主要类
SubActivity:
同MainActivity
AndroidManifest.xml
注意一定要加上android:name="com.example.sourceapk.MyApplication"
ProxyActivity:
```
package com.example.packapk;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import android.app.Application;
import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.os.Bundle;
import android.util.ArrayMap;
import android.util.Log;
import dalvik.system.DexClassLoader;
public class ProxyApplication extends Application{
private static final String appkey = "APPLICATION_CLASS_NAME";
private String apkFileName;
private String odexPath;
private String libPath;
}
RelInvoke(反射工具类):
分析:
1.首先通过java的反射,置换掉android.app.ActivityTread中的mClassLoader,作为加载解密出的APK的DexClassLoader,,该DexClassloader既加载了源程序,还以mClassLoader作为其父类,使得资源文件和系统代码能正确的被加载
代码解析:
加密程序的AndroidManifest文件也一定要添加上:
且其他的activity必须和源程序保持一致性
例如:源程序为:
那么加密程序必须和其一模一样
需要源程序apk和加密程序apk的dex文件
完成所有的操作后还需要把新的apk进行签名操作,否则会导致错误发生
本项目的地址 :
github地址:https://github.com/lzh18972615051/AndroidShellCode
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课