android软件破解初步

此文总结于看雪安卓安全白皮书第9章

破解重点于核心功能存在于那端,若在服务端只能尽可能分析交互数据手动仿造

1.试用版软件

常见类型
免费试用:过一定期限后无法使用,理论上存在完整数据,可破解
演示版:只有部分功能演示用,本地无数据,不可破解
限制版:部分功能付费开启,视情况定,看是否有功能数据。

关于示例1:

  1. createPackageContext用于获取其它程序的context,甚至可执行其它软件的代码,要求有相同的用户id(manifest标签中的android:sharedUserID)与签名。当俩个程序用户id相同时,这俩个程序运行在同一个进程空间。
  2. java的加密解密类:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    取key 参数为种子
    public static byte[] getRawKey(byte[] seed) throws Exception {
    KeyGenerator kgen = KeyGenerator.getInstance("AES"); //key生产者,生成指定算法的key
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); //安全随机
    sr.setSeed(seed); //设置seed
    kgen.init(128, sr); // 192 and 256 bits may not be available //指定密匙大小和随机源
    SecretKey skey = kgen.generateKey(); //生成一个密钥 同一个key同一次使用生成的是一个,但一次运行多次生成的不同
    byte[] raw = skey.getEncoded(); //返回基本编码格式的密钥
    return raw;
    }
    加密 参数1:key 参数2:明文 返回密文
    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); //key的规格与值
    Cipher cipher = Cipher.getInstance("AES"); //密码初始
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec); //密码设置key
    byte[] encrypted = cipher.doFinal(clear);
    return encrypted;
    }
    解密 参数1:key 参数2密文 返回明文
    private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); //key的规格与值
    Cipher cipher = Cipher.getInstance("AES"); //密码实例
    cipher.init(Cipher.DECRYPT_MODE, skeySpec); //用key设置密码
    byte[] decrypted = cipher.doFinal(encrypted); //解密
    return decrypted;
    }

2.序列号保护

用户提供机器码,厂商用注册机生成注册码,用户用注册码使用软件,一般软件注册码保证机器/用户对应

3.网络验证

未成功
网络分析可以使用android移植版的tcpdump工具。位于模拟器下的/system/xbin/下。
adb shell tcpdump -p -vv -s 0 -w /sdcard/xxx.pcap
之后用 adb pull /scard/xxx.pcap取出用wireshark分析即可

网上还有种思路是pc开热点用wireshark分析虚拟网卡即可。但我的ws识别不出虚拟网卡……?

4.应用内付费

这个建议写一个应用试试。
应用实现一个服务与广播接收器,该服务与付费服务(由支付宝等提供)沟通,用户操作结果通过广播/服务返回,应用再随意处理。

5.向商店查询

通过应用商点app接口向商店查询用户已买app

6.重启验证

将得到的信息保存本地。之后应用在执行各种功能,步骤时检验文件核心的检验步骤可放在native层。
示例中:

  1. JNI_OnLoad加载时调用。JNIEnv表示java环境,不可跨线程,因此设置java native函数对应地址表没问题,JavaVM代表虚拟机,主要就是线程相关
  2. 由native层验证判断后调用java层代码实现功能。
  3. JNI中对应的java native函数的名字不一定是javah生成的那样。
    1
    2
    3
    4
    5
    (*env)->RegisterNatives(env,native_class, methods, num){
    //把java类的native函数对应到原生函数中,手动。自动的话是按javah生成的对应,这里没有包含javah生成的头文件
    //参1:jclass:要对应的java类
    //参2:JNINativeMethod数组,表明了java类中方法的名字,元数据,原生函数地址
    //参3:参数2数组length

7.Mono初探

Mono使linux上可运行.NET c#程序。untiy使用该方法跨平台,游戏安全中重点了解。
目前只找到官网资料:http://www.mono-project.com/
基本原理与java同,就是c#脚本编译为il语言的dll之后用mono实现的clr运行时jit(时时编译为原生)或者aot(提前编译为原生)运行。
此时就可以动态修改代码实现热更新。crl虚拟机也是基于栈的。

现在unity又实现了IL2CPP功能,可以讲IL再编译为c++代码,由于c++有许多跨平台编译器,所以可以编译成多平台运行。但是由于内存管理等语言特性需要小虚拟机管理,同时由于可执行代码的复杂度增加失去热更新。

总结:学好c++与c++逆向,什么都好说